import { useState } from "react"; import { useQueryClient } from "@tanstack/react-query"; import { Loader2 } from "lucide-react"; import { toast } from "sonner"; import { detailFromApiError } from "@/shared/api/client"; import { upsertAdminApplicationResult } from "@/lib/applicationAdminResultApi"; import { invalidateAfterAdminApplicationResultChange } from "@/components/admin/result/invalidateAdminApplicationResultQueries"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { type ApplicationMeritCategoryHint, formatApplicationSubgroupLabel, } from "@/components/admin/review/applicationMeritCategoryHint"; function MeritCategorySection({ hint }: { hint: ApplicationMeritCategoryHint }) { const subgroupLabel = formatApplicationSubgroupLabel(hint.subgroupCode); return (

Gợi ý theo nhóm Đơn

{subgroupLabel ? (

Mục Đơn: {subgroupLabel}

) : null} {hint.meritLevel ? (

Gợi ý mức xét: {hint.meritLevel}

) : null}

{hint.detail}

); } /** Full DOCX/kho completeness — chỉ hiển thị sau khi admin đã ✓/✗ ít nhất một minh chứng trên kho (từ nút mở kho minh chứng). */ function DocxTemplateCompletenessSection({ gaps }: { gaps: string[] }) { const complete = gaps.length === 0; if (complete) { return ( Mẫu DOCX / kho minh chứng Không phát hiện thiếu sót cơ bản theo Đơn và kho minh chứng — các trường cần cho mẫu đã được đối chiếu đủ. ); } return ( Các mục chưa đủ hoặc cần kiểm tra ); } function PendingEvidenceStaffReviewPrompt() { return ( Chưa mở khóa đối chiếu DOCX / kho minh chứng Đóng hộp thoại này, rồi mở kho minh chứng bằng nút ở chân khu xem mẫu — nút đó hiển thị nhãn tổng hợp{" "} Đạt, Không đạt hoặc{" "} Chưa xem (cùng quy tắc với tooltip « Mở kho minh chứng — … »). Trên trang kho, nhấn phê duyệt hoặc từ chối đối với ít nhất một dòng có tệp. Sau đó mở lại thao tác từ chối / duyệt để xem tóm tắt đầy đủ. ); } export type StaffReadonlyDialogVariant = "reject" | "approve"; export type AdminStaffReadonlyReviewDialogProps = { open: boolean; onOpenChange: (open: boolean) => void; /** Public application id — persisted with decision and feedback on confirm. */ applicationId: string; variant: StaffReadonlyDialogVariant; meritHint: ApplicationMeritCategoryHint; /** From {@link collectDocxTemplateCompletenessGaps} — Đơn + kho minh chứng. */ docxCompletenessGaps: string[]; /** Sau khi admin đã ✓/✗ minh chứng trên kho (mở qua nút kho minh chứng; cùng mã case). */ staffEvidenceReviewAcknowledged: boolean; }; const titles: Record = { reject: "Từ chối (xem trước)", approve: "Duyệt (xem trước)", }; /** * Hộp thoại giữa màn hình cho quản trị viên chỉ đọc: trạng thái mẫu DOCX, gợi ý mức xét, phản hồi. */ export function AdminStaffReadonlyReviewDialog({ open, onOpenChange, applicationId, variant, meritHint, docxCompletenessGaps, staffEvidenceReviewAcknowledged, }: AdminStaffReadonlyReviewDialogProps) { const queryClient = useQueryClient(); const [feedback, setFeedback] = useState(""); const [saving, setSaving] = useState(false); const handleOpenChange = (next: boolean) => { if (!next) setFeedback(""); onOpenChange(next); }; const confirm = async () => { const id = applicationId.trim(); if (!id) { toast.error("Thiếu mã hồ sơ — không thể lưu kết quả."); return; } const trimmed = feedback.trim(); const decision = variant === "approve" ? "approved" : "rejected"; setSaving(true); try { await upsertAdminApplicationResult(id, { decision, feedback: trimmed, rationale: null, }); await invalidateAfterAdminApplicationResultChange(queryClient, id); handleOpenChange(false); toast.success(trimmed ? "Đã lưu kết quả và phản hồi." : "Đã lưu kết quả.", { ...(trimmed ? { description: trimmed.length > 160 ? `${trimmed.slice(0, 157)}…` : trimmed } : {}), }); } catch (e) { toast.error(detailFromApiError(e, "Không lưu được kết quả.")); } finally { setSaving(false); } }; return ( {titles[variant]}
{staffEvidenceReviewAcknowledged ? ( ) : ( )}