import { useState } from "react"; import { Plus, Pencil, Trash2, X } from "lucide-react"; import { useAdminDiscounts, useAdminDiscountCreate, useAdminDiscountUpdate, useAdminDiscountDelete, type AdminDiscountRow, } from "~/requestHandler/use-admin-hooks"; import { AdminTable, AdminPagination, AdminToolbar, AdminSearch, AdminSelect, AdminPageTitle, StatusBadge, faNum, faDate, useDebouncedValue, type Column, } from "~/components/admin/DataTable"; const PAGE_SIZE = 25; const TYPE: Record = { user_based: "کاربر-محور", count_based: "تعداد-محور", value_based: "مبلغ-محور", }; type FormState = { name: string; code: string; discountType: string; value: string; minPurchaseAmount: string; maxDiscountAmount: string; validFrom: string; validTo: string; maxCount: string; isActive: boolean; }; const EMPTY: FormState = { name: "", code: "", discountType: "value_based", value: "", minPurchaseAmount: "", maxDiscountAmount: "", validFrom: "", validTo: "", maxCount: "", isActive: true, }; const toLocal = (iso: string | null) => (iso ? iso.slice(0, 16) : ""); function fromRow(r: AdminDiscountRow): FormState { return { name: r.name, code: String(r.code), discountType: r.discountType, value: String(r.value), minPurchaseAmount: r.minPurchaseAmount != null ? String(r.minPurchaseAmount) : "", maxDiscountAmount: r.maxDiscountAmount != null ? String(r.maxDiscountAmount) : "", validFrom: toLocal(r.validFrom), validTo: toLocal(r.validTo), maxCount: r.maxCount != null ? String(r.maxCount) : "", isActive: r.isActive, }; } export default function AdminDiscounts() { const [page, setPage] = useState(1); const [search, setSearch] = useState(""); const [active, setActive] = useState(""); const [editing, setEditing] = useState(null); const [creating, setCreating] = useState(false); const debouncedSearch = useDebouncedValue(search); const { data, isLoading } = useAdminDiscounts({ page, page_size: PAGE_SIZE, search: debouncedSearch, is_active: active, }); const del = useAdminDiscountDelete(); const reset = (fn: () => void) => { fn(); setPage(1); }; const onDelete = (r: AdminDiscountRow) => { if (confirm(`حذف تخفیف «${r.name}»؟`)) del.mutate(r.id); }; const columns: Column[] = [ { header: "نام", render: (r) => (

{r.name}

#{faNum(r.code)}

), }, { header: "نوع", render: (r) => {TYPE[r.discountType] || r.discountType} }, { header: "مقدار", render: (r) => {faNum(r.value)}, }, { header: "اعتبار", render: (r) => ( {faDate(r.validFrom)} — {faDate(r.validTo)} ), }, { header: "وضعیت", render: (r) => r.isValid ? ( ) : r.isActive ? ( ) : ( ), }, { header: "", render: (r) => (
), }, ]; return (
تخفیف‌ها
reset(() => setSearch(v))} placeholder="جستجوی نام تخفیف…" /> reset(() => setActive(v))} options={[ { value: "", label: "همه" }, { value: "true", label: "فعال" }, { value: "false", label: "غیرفعال" }, ]} /> r.id} emptyText="تخفیفی ثبت نشده است" /> {(creating || editing) && ( { setCreating(false); setEditing(null); }} /> )}
); } function DiscountModal({ row, onClose }: { row: AdminDiscountRow | null; onClose: () => void }) { const [form, setForm] = useState(row ? fromRow(row) : EMPTY); const [error, setError] = useState(""); const create = useAdminDiscountCreate(); const update = useAdminDiscountUpdate(); const busy = create.isPending || update.isPending; const set = (k: K, v: FormState[K]) => setForm((f) => ({ ...f, [k]: v })); const submit = () => { setError(""); if (!form.name || !form.code || !form.value || !form.validFrom || !form.validTo) { setError("نام، کد، مقدار و بازه اعتبار الزامی است."); return; } const payload = { name: form.name, code: Number(form.code), discountType: form.discountType, value: Number(form.value), minPurchaseAmount: form.minPurchaseAmount ? Number(form.minPurchaseAmount) : null, maxDiscountAmount: form.maxDiscountAmount ? Number(form.maxDiscountAmount) : null, validFrom: form.validFrom, validTo: form.validTo, maxCount: form.maxCount ? Number(form.maxCount) : null, isActive: form.isActive, }; const onErr = (e: unknown) => setError(e instanceof Error ? e.message : "خطا در ذخیره"); if (row) { update.mutate({ id: row.id, data: payload }, { onSuccess: onClose, onError: onErr }); } else { create.mutate(payload, { onSuccess: onClose, onError: onErr }); } }; return (
e.stopPropagation()} >

{row ? "ویرایش تخفیف" : "تخفیف جدید"}

set("name", e.target.value)} /> set("code", e.target.value)} dir="ltr" /> set("value", e.target.value)} dir="ltr" /> set("maxCount", e.target.value)} dir="ltr" /> set("minPurchaseAmount", e.target.value)} dir="ltr" /> set("maxDiscountAmount", e.target.value)} dir="ltr" /> set("validFrom", e.target.value)} dir="ltr" /> set("validTo", e.target.value)} dir="ltr" /> {error &&

{error}

}
); } const inputCls = "w-full rounded-xl border border-WHITE3 bg-WHITE px-3 py-2 text-[13.5px] focus:outline-none focus:border-GRAY"; function Field({ label, children, className, }: { label: string; children: React.ReactNode; className?: string; }) { return (
{children}
); }