astro_avtourist/frontend/src/components/reviews/ReviewFormContainer.tsx

147 lines
5.4 KiB
TypeScript
Raw Normal View History

import { createSignal, onMount, Show } from "solid-js";
import ReviewForm from "./ReviewForm";
interface ToastMessage {
type: "success" | "error";
message: string;
}
interface User {
id: string;
name: string;
email: string;
avatar?: string;
}
export default function ReviewFormContainer() {
const [isAuthenticated, setIsAuthenticated] = createSignal(false);
const [currentUser, setCurrentUser] = createSignal<User | undefined>(undefined);
const [isLoading, setIsLoading] = createSignal(true);
const [toast, setToast] = createSignal<ToastMessage | null>(null);
const showToast = (message: ToastMessage): void => {
setToast(message);
setTimeout(() => setToast(null), 3000);
};
onMount(async () => {
try {
const response = await fetch("/api/auth/me", {
method: "GET",
credentials: "include",
});
const data = await response.json();
if (data.authenticated && data.user) {
setIsAuthenticated(true);
setCurrentUser({
id: data.user.id,
name: data.user.name || "Пользователь",
email: data.user.email,
avatar: data.user.avatar,
});
}
} catch (error) {
console.error("[ReviewForm] Ошибка проверки авторизации:", error);
} finally {
setIsLoading(false);
}
});
const handleSubmit = async (data: {
name: string;
surname: string;
profession: string;
rating: number;
text: string;
}) => {
try {
const response = await fetch("/api/reviews", {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify({
name: data.name,
surname: data.surname,
profession: data.profession,
rating: data.rating,
text: data.text,
}),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || "Failed to create review");
}
showToast({ type: "success", message: "Спасибо! Ваш отзыв отправлен на модерацию." });
} catch (error) {
console.error("[ReviewForm] Ошибка создания отзыва:", error);
showToast({ type: "error", message: "Не удалось отправить отзыв. Попробуйте позже." });
}
};
return (
<>
<Show when={toast()}>
{(t) => (
<div
class={`fixed bottom-4 right-4 px-6 py-3 rounded-xl shadow-lg transition-all duration-300 z-50 ${
t().type === "success"
? "bg-green-500 text-white"
: "bg-red-500 text-white"
}`}
>
{t().message}
</div>
)}
</Show>
<Show when={isLoading()}>
</Show>
<Show when={!isLoading()}>
<Show when={isAuthenticated()} fallback={
<div class="mx-auto" style="max-width: 700px;">
<div class="bg-linear-to-br from-gray-50 to-gray-100 rounded-2xl p-8 md:p-12 border border-gray-200 text-center" style="background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);">
<div class="w-20 h-20 mx-auto mb-6 rounded-full flex items-center justify-center" style="background: linear-gradient(135deg, rgba(37, 99, 235, 0.2) 0%, rgba(30, 64, 175, 0.3) 100%);">
<svg class="w-10 h-10 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/>
</svg>
</div>
<h4 class="text-xl font-semibold text-gray-900 mb-3">
Авторизуйтесь, чтобы оставить отзыв
</h4>
<p class="text-gray-600 mb-6">
Чтобы поделиться своим опытом, пожалуйста, войдите в личный кабинет.
</p>
<a
href={`/auth/sign-in?redirect=${encodeURIComponent(window.location.pathname)}`}
class="inline-flex items-center justify-center font-semibold transition-all duration-300 rounded-md cursor-pointer px-6 py-3 text-lg"
style="background: linear-gradient(to bottom, #2563eb, #1e40af); color: white; box-shadow: 0 2px 4px rgba(37, 99, 235, 0.3);"
>
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"/>
</svg>
Войти в кабинет
</a>
<p class="mt-4 text-sm text-gray-600">
Нет аккаунта?{" "}
<a
href={`/auth/sign-up?redirect=${encodeURIComponent(window.location.pathname)}`}
class="font-medium hover:underline"
style="color: #2563eb;"
>
Зарегистрироваться
</a>
</p>
</div>
</div>
}>
<ReviewForm onSubmit={handleSubmit} user={currentUser()} />
</Show>
</Show>
</>
);
}