import { useNavigate, useSearchParams } from 'react-router-dom';
import { ArrowPathIcon } from '@heroicons/react/24/outline';
import PageHeader from '../components/ui/PageHeader';
import Pagination from '../components/ui/Pagination';
import PersianDatePicker from '../components/ui/PersianDatePicker';
import SearchableSelect from '../components/ui/SearchableSelect';
import StatCard from '../components/ui/StatCard';
import StatusBadge from '../components/ui/StatusBadge';
import DataTable, { type Column } from '../components/ui/DataTable';
import { formatRial, formatDate, formatNumber, toDate } from '../lib/utils';
import {
usePayments,
usePaymentsSummary,
MY_PAYMENTS_LIMIT,
type PaymentRow,
} from '../hooks/useMyPayments';
const STATUS_OPTIONS = [
{ value: '', label: 'همه وضعیتها' },
{ value: 'paid', label: 'پرداخت شده' },
{ value: 'partial', label: 'پرداخت ناقص' },
{ value: 'unsettled', label: 'تسویه نشده' },
];
const isoNDaysAgo = (days: number): string => {
const d = new Date();
d.setDate(d.getDate() - days);
return d.toISOString().slice(0, 10);
};
const todayIso = (): string => new Date().toISOString().slice(0, 10);
/** HH:MM (Persian digits) from a unix timestamp. */
function formatTime(unix: number): string {
return new Intl.DateTimeFormat('fa-IR', { hour: '2-digit', minute: '2-digit' }).format(new Date(unix * 1000));
}
/** unix start-of-day for `from`, end-of-day for `to`, from a gregorian Y-m-d. */
function dayBound(value: string, end: boolean): number | undefined {
const d = toDate(value);
if (!d) return undefined;
const secs = Math.floor(d.setHours(0, 0, 0, 0) / 1000);
return end ? secs + 86399 : secs;
}
function Avatar({ name }: { name: string | null }) {
return (
{(name ?? '؟').charAt(0)}
);
}
/**
* لیست پرداختها — فهرست تخت صورتحسابهای ثبتشدهی tenant.
* فیلترها در query string زندگی میکنند تا رفرش و اشتراک لینک، نما را حفظ کند.
*/
export default function MyPaymentsPage() {
const navigate = useNavigate();
const [params, setParams] = useSearchParams();
const search = params.get('search') ?? '';
const status = params.get('status') ?? '';
const from = params.get('from') ?? '';
const to = params.get('to') ?? '';
const page = Math.max(1, Number(params.get('page') ?? 1));
const hasFilters = !!(search || status || from || to);
/** تغییر فیلتر همیشه به صفحهی اول برمیگردد؛ ماندن روی صفحه ۵ با نتیجهی جدید بیمعناست. */
const setParam = (patch: Record) => {
const next = new URLSearchParams(params);
Object.entries(patch).forEach(([k, v]) => (v ? next.set(k, v) : next.delete(k)));
if (!('page' in patch)) next.delete('page');
setParams(next, { replace: true });
};
const filters = {
national_code: search || undefined,
status: status || undefined,
from: from ? dayBound(from, false) : undefined,
to: to ? dayBound(to, true) : undefined,
};
const listQuery = usePayments({ page, ...filters });
const summaryQuery = usePaymentsSummary(filters);
const rows = listQuery.data?.data ?? [];
const total = listQuery.data?.meta?.totalRecords ?? 0;
const summary = summaryQuery.data?.data;
const columns: Column[] = [
{
key: 'patient_name',
header: 'بیمار',
render: (r) => (
),
},
{ key: 'national_code', header: 'کد ملی', render: (r) => {r.national_code ?? '—'} },
{
key: 'issued_at',
header: 'تاریخ',
render: (r) => {formatDate(r.issued_at)} - {formatTime(r.issued_at)},
},
{
key: 'amount_rials',
header: 'مبلغ',
render: (r) => (
{formatRial(r.amount_rials)}
{r.status === 'partial' && (
پرداختشده: {formatRial(r.paid_rials)}
)}
),
},
{ key: 'status', header: 'وضعیت', render: (r) => },
];
return (
<>
setParam({ status: v ? String(v) : '' })}
placeholder="همه وضعیتها"
height={38}
/>
setParam({ from: v })} height={38} />
setParam({ to: v })} height={38} />
{hasFilters && (
)}
setParam({ search: v.replace(/\D/g, '') })}
searchPlaceholder="کد ملی بیمار"
emptyMessage="پرداختی ثبت نشده است."
actions={(row) => (
)}
/>
{total > MY_PAYMENTS_LIMIT && (
setParam({ page: String(p) })} />
)}
>
);
}