"use client"; import { keepPreviousData, useQuery, useQueryClient } from "@tanstack/react-query"; import { useEffect, useState } from "react"; import { Loader2 } from "lucide-react"; import { http, toUserError } from "@/lib/api"; import type { CertificatePhysicalOrder, PhysicalCertSettings, PhysicalOrderStatus } from "@/lib/types"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { toast } from "@/components/providers"; import { formatFaNumber } from "@/lib/utils"; import { DEFAULT_PAGE_SIZE, ListPagination, buildPageQuery, } from "@/components/admin/list-pagination"; const STATUS_LABEL: Record = { requested: "درخواست‌شده", paid: "پرداخت‌شده", shipped: "ارسال‌شده", cancelled: "لغو", }; const NEXT: Partial> = { requested: "paid", paid: "shipped", }; export function PhysicalOrdersPanel() { const qc = useQueryClient(); const [statusFilter, setStatusFilter] = useState(""); const [page, setPage] = useState(1); const [notes, setNotes] = useState>({}); const [tracking, setTracking] = useState>({}); const [busy, setBusy] = useState(null); useEffect(() => { setPage(1); }, [statusFilter]); const { data, isLoading } = useQuery({ queryKey: ["admin", "physical-orders", statusFilter, page], queryFn: () => { const params = new URLSearchParams(buildPageQuery(page)); if (statusFilter) params.set("status", statusFilter); return http.get<{ orders: CertificatePhysicalOrder[]; physical: PhysicalCertSettings; total: number; page: number; pageSize: number; }>(`/api/admin/physical-orders?${params.toString()}`); }, placeholderData: keepPreviousData, }); const update = async (id: number, status: PhysicalOrderStatus) => { setBusy(id); try { await http.put(`/api/admin/physical-orders/${id}`, { status, note: notes[id] ?? "", trackingCode: tracking[id] ?? "", }); toast.success("وضعیت به‌روزرسانی شد — دانشجو مطلع می‌شود"); qc.invalidateQueries({ queryKey: ["admin", "physical-orders"] }); } catch (e) { toast.error(toUserError(e)); } finally { setBusy(null); } }; return (

پیگیری درخواست و ارسال گواهینامه فیزیکی.

{data?.physical && ( قیمت: {formatFaNumber(data.physical.priceIrr)} ریال · پنجره:{" "} {formatFaNumber(data.physical.windowDays)} روز )}
{isLoading && (
)} {(data?.orders ?? []).map((o) => (

{o.userName ?? `کاربر ${o.userId}`}

#{o.id} · cert {o.publicId}

مهلت پنجره: {new Date(o.windowEndsAt).toLocaleString("fa-IR")}

{(o.address || o.city) && (

{[o.recipientName, o.phone, o.city, o.postalCode].filter(Boolean).join(" · ")}
{o.address}

)} {o.trackingCode && (

tracking: {o.trackingCode}

)}
{STATUS_LABEL[o.status]}
{o.note &&

یادداشت: {o.note}

} setNotes((n) => ({ ...n, [o.id]: e.target.value }))} /> {(o.status === "paid" || o.status === "shipped") && ( setTracking((t) => ({ ...t, [o.id]: e.target.value }))} dir="ltr" /> )}
{NEXT[o.status] && ( )} {o.status !== "cancelled" && o.status !== "shipped" && ( )}
))} {!isLoading && (data?.orders ?? []).length === 0 && (

سفارشی نیست.

)}
); }