"use client"; import { useState, useEffect, useCallback } from "react"; interface FileAttachment { name: string; url: string; size: number; } interface Message { id: string; authorId: string; text: string; files: FileAttachment[] | null; isRead: boolean; createdAt: string; author: { id: string; name: string; role: string }; } interface QuestionSummary { id: string; title: string; status: "OPEN" | "CLOSED"; unreadCount: number; updatedAt: string; user: { id: string; name: string }; course: { id: string; title: string } | null; } interface QuestionDetail { id: string; title: string; status: "OPEN" | "CLOSED"; createdAt: string; user: { id: string; name: string }; messages: Message[]; } function formatDate(iso: string) { return new Date(iso).toLocaleString("ru", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit", }); } function formatFileSize(bytes: number) { if (bytes < 1024) return `${bytes} Б`; if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} КБ`; return `${(bytes / 1024 / 1024).toFixed(1)} МБ`; } export function QuestionSplitView({ currentUserId }: { currentUserId: string }) { const [questions, setQuestions] = useState([]); const [selectedId, setSelectedId] = useState(null); const [detail, setDetail] = useState(null); const [tab, setTab] = useState<"open" | "closed">("open"); const [replyText, setReplyText] = useState(""); const [sending, setSending] = useState(false); const [closing, setClosing] = useState(false); const [error, setError] = useState(""); const [listError, setListError] = useState(""); const [listLoading, setListLoading] = useState(true); const fetchList = useCallback(async () => { setListError(""); setListLoading(true); try { const res = await fetch("/api/questions"); if (!res.ok) { setListError("Не удалось загрузить вопросы"); return; } const data = await res.json(); setQuestions(data); } catch { setListError("Не удалось загрузить вопросы"); } finally { setListLoading(false); } }, []); useEffect(() => { fetchList(); }, [fetchList]); async function selectQuestion(id: string) { setSelectedId(id); setReplyText(""); setError(""); const res = await fetch(`/api/questions/${id}`); if (res.ok) { const data = await res.json(); setDetail({ ...data, messages: data.messages.map((m: Message & { createdAt: string }) => ({ ...m, files: m.files as FileAttachment[] | null, })), }); fetchList(); } } async function handleReply() { if (!replyText.trim() || !selectedId) return; setSending(true); setError(""); try { const res = await fetch(`/api/questions/${selectedId}/messages`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ text: replyText.trim() }), }); if (!res.ok) throw new Error("Ошибка отправки"); const msg = await res.json(); setDetail((prev) => prev ? { ...prev, messages: [...prev.messages, msg] } : null ); setReplyText(""); fetchList(); } catch { setError("Не удалось отправить ответ"); } finally { setSending(false); } } async function handleClose() { if (!selectedId) return; setClosing(true); try { const res = await fetch(`/api/questions/${selectedId}/close`, { method: "PATCH", }); if (!res.ok) throw new Error("Ошибка закрытия"); setDetail((prev) => (prev ? { ...prev, status: "CLOSED" } : null)); fetchList(); } catch { setError("Не удалось закрыть вопрос"); } finally { setClosing(false); } } const filtered = questions.filter((q) => tab === "open" ? q.status === "OPEN" : q.status === "CLOSED" ); return (
{/* Left panel */}
{/* Tabs */}
{(["open", "closed"] as const).map((t) => ( ))}
{/* Question list */}
{listError && (

{listError}

)} {listLoading && (

Загрузка...

)} {!listLoading && filtered.length === 0 && (

Нет вопросов

)} {filtered.map((q) => ( ))}
{/* Right panel */}
{!detail ? (

Выберите вопрос

) : ( <> {/* Thread header */}

{detail.title}

{detail.user.name} ·{" "} {new Date(detail.createdAt).toLocaleDateString("ru", { day: "numeric", month: "long", })}

{detail.status === "OPEN" && ( )}
{/* Messages */}
{detail.messages.map((msg) => { const isMine = msg.authorId === currentUserId; return (

{msg.author.name} · {formatDate(msg.createdAt)}

{msg.text}

{msg.files && msg.files.length > 0 && ( )}
); })}
{/* Reply form */}
setReplyText(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); handleReply(); } }} disabled={detail.status === "CLOSED"} placeholder={ detail.status === "CLOSED" ? "Вопрос закрыт" : "Написать ответ..." } className="flex-1 text-sm px-3 py-2 outline-none" style={{ border: "1px solid var(--border)", background: "var(--background)", color: "var(--foreground)", }} />
{error && (

{error}

)}
)}
); }