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
{gaps.map((g) => (
{g}
))}
);
}
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 (
);
}