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

217 lines
6.9 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, { 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;