WIPVOLONT
This commit is contained in:
@@ -1,16 +1,90 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { FaUserCircle, FaStar } from "react-icons/fa";
|
||||
import TabBar from "../components/TabBar";
|
||||
|
||||
const API_BASE = process.env.NEXT_PUBLIC_API_BASE_URL;
|
||||
|
||||
const ModeratorProfilePage = () => {
|
||||
const router = useRouter();
|
||||
|
||||
const fullName = "Иванов Александр Сергеевич";
|
||||
const birthDate = "12.03.1990";
|
||||
const rating = 4.8;
|
||||
const [profile, setProfile] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const getAccessToken = () => {
|
||||
if (typeof window === "undefined") return null;
|
||||
const saved = localStorage.getItem("authUser");
|
||||
const authUser = saved ? JSON.parse(saved) : null;
|
||||
return authUser?.accessToken || null;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fetchProfile = async () => {
|
||||
if (!API_BASE) {
|
||||
setError("API_BASE_URL не задан");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
const token = getAccessToken();
|
||||
if (!token) {
|
||||
setError("Вы не авторизованы");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/users/me`, {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
let msg = "Не удалось загрузить профиль";
|
||||
try {
|
||||
const data = await res.json();
|
||||
if (data.error) msg = data.error;
|
||||
} catch {
|
||||
const text = await res.text();
|
||||
if (text) msg = text;
|
||||
}
|
||||
setError(msg);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await res.json(); // UserProfile[web:598]
|
||||
setProfile(data);
|
||||
setLoading(false);
|
||||
} catch (e) {
|
||||
setError(e.message || "Ошибка сети");
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchProfile();
|
||||
}, []);
|
||||
|
||||
const fullName =
|
||||
profile &&
|
||||
([profile.first_name, profile.last_name].filter(Boolean).join(" ") ||
|
||||
profile.email);
|
||||
|
||||
const rating =
|
||||
profile && profile.volunteer_rating != null
|
||||
? Number(profile.volunteer_rating)
|
||||
: null;
|
||||
|
||||
const birthDateText = profile?.created_at
|
||||
? new Date(profile.created_at).toLocaleDateString("ru-RU")
|
||||
: "—";
|
||||
|
||||
const email = profile?.email || "—";
|
||||
const phone = profile?.phone || "—";
|
||||
|
||||
return (
|
||||
<div className="min-h-screen w-full bg-[#90D2F9] flex justify-center px-4">
|
||||
@@ -32,72 +106,99 @@ const ModeratorProfilePage = () => {
|
||||
|
||||
{/* Карточка профиля */}
|
||||
<main className="bg-white rounded-3xl p-4 flex flex-col items-center gap-4 shadow-lg">
|
||||
{/* Аватар */}
|
||||
<FaUserCircle className="text-[#72B8E2] w-20 h-20" />
|
||||
|
||||
{/* ФИО и рейтинг */}
|
||||
<div className="text-center space-y-1">
|
||||
{/* <p className="font-montserrat font-extrabold text-[16px] text-black">
|
||||
ФИО
|
||||
</p> */}
|
||||
<p className="font-montserrat font-bold text-[20px] text-black">
|
||||
{fullName}
|
||||
{loading && (
|
||||
<p className="font-montserrat text-[14px] text-black">
|
||||
Загрузка профиля...
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Рейтинг + звезды */}
|
||||
<div className="mt-2 flex items-center justify-center gap-2">
|
||||
<span className="font-montserrat font-semibold text-[14px] text-black">
|
||||
Рейтинг: {rating.toFixed(1)}
|
||||
</span>
|
||||
<div className="flex gap-1">
|
||||
{[1, 2, 3, 4, 5].map((star) => (
|
||||
<FaStar
|
||||
key={star}
|
||||
size={18}
|
||||
className={
|
||||
star <= Math.round(rating)
|
||||
? "text-[#F6E168] fill-[#F6E168]"
|
||||
: "text-[#F6E168] fill-[#F6E168]/30"
|
||||
}
|
||||
/>
|
||||
))}
|
||||
{error && !loading && (
|
||||
<p className="font-montserrat text-[12px] text-red-500">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{!loading && profile && (
|
||||
<>
|
||||
{/* Аватар */}
|
||||
{profile.avatar_url ? (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
src={profile.avatar_url}
|
||||
alt="Аватар"
|
||||
className="w-20 h-20 rounded-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<FaUserCircle className="text-[#72B8E2] w-20 h-20" />
|
||||
)}
|
||||
|
||||
{/* ФИО и рейтинг */}
|
||||
<div className="text-center space-y-1">
|
||||
<p className="font-montserrat font-bold text-[20px] text-black">
|
||||
{fullName}
|
||||
</p>
|
||||
|
||||
{rating != null && (
|
||||
<div className="mt-2 flex items-center justify-center gap-2">
|
||||
<span className="font-montserrat font-semibold text-[14px] text-black">
|
||||
Рейтинг: {rating.toFixed(1)}
|
||||
</span>
|
||||
<div className="flex gap-1">
|
||||
{[1, 2, 3, 4, 5].map((star) => (
|
||||
<FaStar
|
||||
key={star}
|
||||
size={18}
|
||||
className={
|
||||
star <= Math.round(rating)
|
||||
? "text-[#F6E168] fill-[#F6E168]"
|
||||
: "text-[#F6E168] fill-[#F6E168]/30"
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Контакты и день рождения */}
|
||||
<div className="w-full bg-[#72B8E2] rounded-2xl p-3 text-white space-y-1">
|
||||
<p className="font-montserrat text-[12px]">
|
||||
Дата рождения: {birthDate}
|
||||
</p>
|
||||
<p className="font-montserrat text-[12px]">
|
||||
Почта: example@mail.com
|
||||
</p>
|
||||
<p className="font-montserrat text-[12px]">
|
||||
Телефон: +7 (900) 000-00-00
|
||||
</p>
|
||||
</div>
|
||||
{/* Контакты и «дата рождения» как дата регистрации */}
|
||||
<div className="w-full bg-[#72B8E2] rounded-2xl p-3 text-white space-y-1">
|
||||
<p className="font-montserrat text-[12px]">
|
||||
Дата регистрации: {birthDateText}
|
||||
</p>
|
||||
<p className="font-montserrat text-[12px]">Почта: {email}</p>
|
||||
<p className="font-montserrat text-[12px]">
|
||||
Телефон: {phone}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Кнопки */}
|
||||
<div className="w-full flex flex-col gap-2 mt-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => router.push("/valounterProfileSettings")}
|
||||
className="w-full bg-[#E0B267] rounded-full py-2 flex items-center justify-center"
|
||||
>
|
||||
<span className="font-montserrat font-extrabold text-[14px] text-white">
|
||||
Редактировать профиль
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="w-full bg-[#E07567] rounded-full py-2 flex items-center justify-center"
|
||||
>
|
||||
<span className="font-montserrat font-extrabold text-[14px] text-white">
|
||||
Выйти из аккаунта
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
{/* Кнопки */}
|
||||
<div className="w-full flex flex-col gap-2 mt-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => router.push("/moderatorProfileSettings")}
|
||||
className="w-full bg-[#E0B267] rounded-full py-2 flex items-center justify-center"
|
||||
>
|
||||
<span className="font-montserrat font-extrabold text-[14px] text-white">
|
||||
Редактировать профиль
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="w-full bg-[#E07567] rounded-full py-2 flex items-center justify-center"
|
||||
onClick={() => {
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.removeItem("authUser");
|
||||
}
|
||||
router.push("/");
|
||||
}}
|
||||
>
|
||||
<span className="font-montserrat font-extrabold text-[14px] text-white">
|
||||
Выйти из аккаунта
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</main>
|
||||
|
||||
<TabBar />
|
||||
|
||||
Reference in New Issue
Block a user