Files
frontend/app/moderatorHistoryRequest/page.jsx
fullofempt 0df52352a8 WIPVOLONT
2025-12-14 21:14:55 +05:00

278 lines
8.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import React, { useEffect, useState } from "react";
import { FaBell, FaUser } from "react-icons/fa";
import TabBar from "../components/TabBar";
import ModeratorRequestModal from "../components/ModeratorRequestDetailsModal";
const API_BASE = process.env.NEXT_PUBLIC_API_BASE_URL;
const statusMap = {
approved: { label: "Принята", color: "#94E067" },
rejected: { label: "Отклонена", color: "#E06767" },
};
const HistoryRequestModeratorPage = () => {
const [requests, setRequests] = useState([]);
const [selectedRequest, setSelectedRequest] = useState(null);
const [moderatorName, setModeratorName] = useState("Модератор");
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) return;
const token = getAccessToken();
if (!token) return;
try {
const res = await fetch(`${API_BASE}/users/me`, {
headers: {
Accept: "application/json",
Authorization: `Bearer ${token}`,
},
});
if (!res.ok) return;
const data = await res.json();
const fullName =
[data.first_name, data.last_name].filter(Boolean).join(" ").trim() ||
data.email;
setModeratorName(fullName);
} catch {
// дефолт остаётся
}
};
fetchProfile();
}, []);
// история модерации: только approved / rejected
useEffect(() => {
const fetchHistory = 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}/moderation/requests/my`, {
method: "GET",
headers: {
Accept: "application/json",
Authorization: `Bearer ${token}`,
},
});
const text = await res.text();
let data = null;
if (text) {
try {
data = JSON.parse(text);
} catch {
data = null;
}
}
if (!res.ok) {
let msg = "Не удалось загрузить историю заявок";
if (data && typeof data === "object" && data.error) {
msg = data.error;
} else if (text) {
msg = text;
}
setError(msg);
setLoading(false);
return;
}
const list = Array.isArray(data) ? data : [];
// status: { request_status: "approved" | "rejected", valid: true }
const filtered = list.filter((item) => {
const s = String(item.status?.request_status || "").toLowerCase();
return s === "approved" || s === "rejected";
});
const mapped = filtered.map((item) => {
const rawStatus = String(
item.status?.request_status || ""
).toLowerCase();
const m = statusMap[rawStatus] || {
label: rawStatus || "Неизвестен",
color: "#E2E2E2",
};
const created = new Date(item.created_at);
const date = created.toLocaleDateString("ru-RU");
const time = created.toLocaleTimeString("ru-RU", {
hour: "2-digit",
minute: "2-digit",
});
return {
id: item.id,
title: item.title,
description: item.description,
status: m.label,
statusColor: m.color,
date,
time,
createdAt: date,
fullName: item.requester_name,
rejectReason: item.moderation_comment || "",
address: item.city ? `${item.city}, ${item.address}` : item.address,
rawStatus, // "approved" | "rejected"
};
});
setRequests(mapped);
setLoading(false);
} catch (e) {
setError(e.message || "Ошибка сети");
setLoading(false);
}
};
fetchHistory();
}, []);
const handleOpen = (req) => {
// пробрасываем rawStatus, чтобы модалка знала настоящий статус
setSelectedRequest({
...req,
status: req.rawStatus,
});
};
const handleClose = () => {
setSelectedRequest(null);
};
const handleModeratedUpdate = (updated) => {
setRequests((prev) =>
prev.map((r) =>
r.id === updated.id ? { ...r, rawStatus: updated.status } : r
)
);
};
return (
<div className="min-h-screen w-full bg-[#90D2F9] flex justify-center px-4">
<div className="relative w-full max-w-md flex flex-col pb-20 pt-4">
{/* Header */}
<header className="flex items-center justify-between mb-4">
<div className="flex items-center gap-2">
<div className="w-8 h-8 rounded-full border border-white flex items-center justify-center">
<FaUser className="text-white text-sm" />
</div>
<p className="font-montserrat font-extrabold text-[20px] leading-[22px] text-white">
{moderatorName}
</p>
</div>
<button
type="button"
className="w-8 h-8 rounded-full border border-white flex items-center justify-center"
>
<FaBell className="text-white text-sm" />
</button>
</header>
<h1 className="font-montserrat font-extrabold text-[20px] leading-[22px] text-white mb-3">
История заявок
</h1>
{error && (
<p className="mb-2 text-xs font-montserrat text-red-200">
{error}
</p>
)}
{/* Список заявок */}
<main className="space-y-3 overflow-y-auto pr-1 max-h-[80vh]">
{loading && (
<p className="text-white text-sm font-montserrat">
Загрузка истории...
</p>
)}
{!loading && requests.length === 0 && !error && (
<p className="text-white text-sm font-montserrat">
История модерации пуста
</p>
)}
{requests.map((req) => (
<button
key={req.id}
type="button"
onClick={() => handleOpen(req)}
className="w-full text-left bg-white rounded-xl px-3 py-2 flex flex-col gap-1"
>
<div className="flex items-center justify-between gap-2">
<span
className="inline-flex items-center justify-center px-2 py-0.5 rounded-full font-montserrat text-[12px] font-semibold text-white"
style={{ backgroundColor: req.statusColor }}
>
{req.status}
</span>
<div className="text-right leading-tight">
<p className="font-montserrat text-[10px] text-black">
{req.date}
</p>
<p className="font-montserrat text-[10px] text-black">
{req.time}
</p>
</div>
</div>
<p className="font-montserrat font-semibold text-[15px] leading-[18px] text-black mt-1">
{req.title}
</p>
<p className="font-montserrat text-[11px] text-black/80">
{req.fullName}
</p>
<p className="font-montserrat text-[10px] text-black/70">
{req.address}
</p>
<div className="mt-2 w-full bg-[#94E067] rounded-lg py-3 flex items-center justify-center">
<span className="font-montserrat font-bold text-[15px] leading-[18px] text-white">
Развернуть
</span>
</div>
</button>
))}
</main>
{selectedRequest && (
<ModeratorRequestModal
request={selectedRequest}
onClose={handleClose}
onModerated={handleModeratedUpdate}
/>
)}
<TabBar />
</div>
</div>
);
};
export default HistoryRequestModeratorPage;