217 lines
6.9 KiB
JavaScript
217 lines
6.9 KiB
JavaScript
"use client";
|
||
|
||
import React, { useState } from "react";
|
||
import { FaTimesCircle } from "react-icons/fa";
|
||
|
||
const API_BASE = process.env.NEXT_PUBLIC_API_BASE_URL;
|
||
|
||
const AcceptPopup = ({ request, isOpen, onClose }) => {
|
||
const [loading, setLoading] = useState(false);
|
||
const [error, setError] = useState("");
|
||
|
||
if (!isOpen || !request) return null;
|
||
|
||
const title = request.title;
|
||
const description =
|
||
request.description ||
|
||
"Описание недоступно. Откройте заявку для подробностей.";
|
||
|
||
const baseAddress = request.address || "Адрес не указан";
|
||
const city = request.city ? `, ${request.city}` : "";
|
||
const place = `${baseAddress}${city}`;
|
||
|
||
let deadline = "Не указано";
|
||
if (request.desired_completion_date) {
|
||
const d = new Date(request.desired_completion_date);
|
||
if (!Number.isNaN(d.getTime())) {
|
||
const datePart = d.toLocaleDateString("ru-RU", {
|
||
day: "2-digit",
|
||
month: "2-digit",
|
||
});
|
||
const timePart = d.toLocaleTimeString("ru-RU", {
|
||
hour: "2-digit",
|
||
minute: "2-digit",
|
||
});
|
||
deadline = `${datePart}, ${timePart}`;
|
||
}
|
||
}
|
||
|
||
const phone = request.contact_phone || request.phone;
|
||
const contactNotes = request.contact_notes || request.contactNotes;
|
||
|
||
const urgencyText = (() => {
|
||
switch (request.urgency) {
|
||
case "low":
|
||
return "Низкая";
|
||
case "medium":
|
||
return "Средняя";
|
||
case "high":
|
||
return "Высокая";
|
||
case "urgent":
|
||
return "Срочно";
|
||
default:
|
||
return null;
|
||
}
|
||
})();
|
||
|
||
const getAccessToken = () => {
|
||
if (typeof window === "undefined") return null;
|
||
const saved = localStorage.getItem("authUser");
|
||
const authUser = saved ? JSON.parse(saved) : null;
|
||
return authUser?.accessToken || null;
|
||
};
|
||
|
||
// тут полностью логика отклика
|
||
const handleClick = async () => {
|
||
if (!API_BASE || !request.id) {
|
||
setError("Некорректная заявка (нет id)");
|
||
return;
|
||
}
|
||
const accessToken = getAccessToken();
|
||
if (!accessToken) {
|
||
setError("Вы не авторизованы");
|
||
return;
|
||
}
|
||
|
||
try {
|
||
setLoading(true);
|
||
setError("");
|
||
|
||
console.log("POST отклик", {
|
||
url: `${API_BASE}/requests/${request.id}/responses`,
|
||
requestId: request.id,
|
||
});
|
||
|
||
const res = await fetch(`${API_BASE}/requests/${request.id}/responses`, {
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
Accept: "application/json",
|
||
Authorization: `Bearer ${accessToken}`,
|
||
},
|
||
// по схеме тело обязательно, просто пустой объект допустим [file:598]
|
||
body: JSON.stringify({}),
|
||
});
|
||
|
||
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;
|
||
}
|
||
console.error("Ответ API /responses:", msg);
|
||
setError(msg);
|
||
setLoading(false);
|
||
return;
|
||
}
|
||
|
||
await res.json(); // VolunteerResponse [file:598]
|
||
setLoading(false);
|
||
onClose();
|
||
} catch (e) {
|
||
setError(e.message || "Ошибка сети");
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
||
{/* затемнение */}
|
||
<div
|
||
className="absolute inset-0 bg-black/40"
|
||
onClick={onClose}
|
||
/>
|
||
|
||
{/* карточка поверх всего */}
|
||
<div className="relative z-50 w-full max-w-[400px] bg-white rounded-2xl px-4 pt-4 pb-6 flex flex-col mt-50">
|
||
{/* крестик */}
|
||
<button
|
||
type="button"
|
||
onClick={onClose}
|
||
className="absolute top-4 right-4 text-[#FF9494]"
|
||
>
|
||
<FaTimesCircle className="w-5 h-5" />
|
||
</button>
|
||
|
||
{/* Заголовок */}
|
||
<h2 className="font-montserrat font-extrabold text-[20px] leading-[22px] text-[#90D2F9] mb-1">
|
||
Задача
|
||
</h2>
|
||
<p className="text-[20px] leading-[14px] mt-5 font-montserrat mb-5">
|
||
{title}
|
||
</p>
|
||
|
||
{/* Только время выполнить до */}
|
||
<div className="flex items-center gap-3 mb-3">
|
||
<div className="w-full h-[40px] bg-[#90D2F9] rounded-full flex flex-col items-center justify-center">
|
||
<span className="text-[12px] leading-[11px] text-white font-semibold mb-1">
|
||
Выполнить до
|
||
</span>
|
||
<span className="text-[15px] leading-[13px] text-white font-semibold">
|
||
{deadline}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Описание + доп.инфа */}
|
||
<div className="w-full bg-[#E4E4E4] rounded-[20px] px-3 py-3 mb-3 max-h-[40vh] overflow-y-auto">
|
||
<p className="text-[15px] leading-[20px] font-montserrat text-black whitespace-pre-line">
|
||
{description}
|
||
</p>
|
||
|
||
{urgencyText && (
|
||
<p className="mt-2 text-[12px] leading-[16px] font-montserrat text-black">
|
||
<span className="font-semibold">Срочность: </span>
|
||
{urgencyText}
|
||
</p>
|
||
)}
|
||
{phone && (
|
||
<p className="text-[12px] leading-[16px] font-montserrat text-black">
|
||
<span className="font-semibold">Телефон: </span>
|
||
{phone}
|
||
</p>
|
||
)}
|
||
{contactNotes && (
|
||
<p className="text-[12px] leading-[16px] font-montserrat text-black">
|
||
<span className="font-semibold">Комментарий к контакту: </span>
|
||
{contactNotes}
|
||
</p>
|
||
)}
|
||
{error && (
|
||
<p className="mt-2 text-[12px] leading-[16px] font-montserrat text-red-500">
|
||
{error}
|
||
</p>
|
||
)}
|
||
</div>
|
||
|
||
{/* Данные места */}
|
||
<div className="w-full flex flex-col gap-3 mb-4">
|
||
<p className="font-montserrat text-[20px] leading-[19px] font-medium">
|
||
Данные:
|
||
</p>
|
||
<p className="text-[15px] leading-[12px] font-montserrat">
|
||
Место: {place}
|
||
</p>
|
||
</div>
|
||
|
||
{/* Кнопка отклика внизу */}
|
||
<button
|
||
type="button"
|
||
onClick={handleClick}
|
||
disabled={loading}
|
||
className="mt-auto w-full h-[40px] bg-[#94E067] rounded-[10px] flex items-center justify-center disabled:opacity-60"
|
||
>
|
||
<span className="font-montserrat font-bold text-[16px] leading-[19px] text-white">
|
||
{loading ? "Отправка..." : "Откликнуться"}
|
||
</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default AcceptPopup;
|