Vitron-Front/app/routes/admin.ledger.sellers.tsx
Arda Samadi cedeef4746 feat(admin): ledger UI — overview/reconciliation, payouts, transactions, per-seller (slice 2a)
Ledger section with sub-tabs: overview (money held/owed, payouts by status, and
a reconciliation warning card), payouts + transactions lists, per-seller balances
list, and a per-seller detail showing recorded vs derived balance + discrepancy,
bank accounts and payout history. Enabled the Ledger nav item.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 12:28:11 +03:30

96 lines
2.5 KiB
TypeScript

import { useState } from "react";
import { Link } from "@remix-run/react";
import { ChevronLeft } from "lucide-react";
import {
useLedgerSellers,
type LedgerSellerRow,
} from "~/requestHandler/use-admin-hooks";
import {
AdminTable,
AdminPagination,
AdminToolbar,
AdminSearch,
faToman,
useDebouncedValue,
type Column,
} from "~/components/admin/DataTable";
const PAGE_SIZE = 25;
export default function LedgerSellers() {
const [page, setPage] = useState(1);
const [search, setSearch] = useState("");
const debouncedSearch = useDebouncedValue(search);
const { data, isLoading } = useLedgerSellers({
page,
page_size: PAGE_SIZE,
search: debouncedSearch,
});
const reset = (fn: () => void) => {
fn();
setPage(1);
};
const columns: Column<LedgerSellerRow>[] = [
{
header: "فروشگاه",
render: (s) => (
<div className="min-w-[140px]">
<p className="font-semibold">{s.storeName || "—"}</p>
<p className="text-GRAY text-[11px]" dir="ltr">@{s.username}</p>
</div>
),
},
{
header: "مانده",
render: (s) => (
<span className="tabular-nums font-semibold whitespace-nowrap">
{faToman(s.availableFunds)}
</span>
),
},
{
header: "برداشت‌شده",
render: (s) => <span className="tabular-nums whitespace-nowrap text-GRAY">{faToman(s.completedPayouts)}</span>,
},
{
header: "در انتظار برداشت",
render: (s) => <span className="tabular-nums whitespace-nowrap text-GRAY">{faToman(s.pendingPayouts)}</span>,
},
{
header: "",
className: "text-left w-10",
render: (s) => (
<Link
to={`/admin/ledger/sellers/${s.sellerId}`}
className="inline-grid h-8 w-8 place-items-center rounded-lg border border-WHITE3 text-BLACK2 hover:bg-WHITE2"
aria-label="جزئیات"
>
<ChevronLeft size={16} />
</Link>
),
},
];
return (
<div>
<AdminToolbar>
<AdminSearch
value={search}
onChange={(v) => reset(() => setSearch(v))}
placeholder="جستجوی فروشگاه…"
/>
</AdminToolbar>
<AdminTable
columns={columns}
rows={data?.results || []}
isLoading={isLoading}
getRowKey={(s) => s.sellerId}
/>
<AdminPagination page={page} pageSize={PAGE_SIZE} count={data?.count || 0} onPageChange={setPage} />
</div>
);
}