import { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { Link, useNavigate } from 'react-router-dom'; import { PlusIcon, PencilIcon, EyeIcon, MagnifyingGlassIcon, AdjustmentsHorizontalIcon, Squares2X2Icon, TableCellsIcon, ExclamationCircleIcon, IdentificationIcon, } from '@heroicons/react/24/outline'; import { api } from '../lib/api'; import type { ApiResponse } from '../lib/api'; import type { PatientRecord } from '../types'; import { formatNumber, toDate } from '../lib/utils'; import Pagination from '../components/ui/Pagination'; import PatientTagsCell from '../components/PatientTagsCell'; import PatientsFilterModal, { type PatientFilters } from '../components/PatientsFilterModal'; const LIMIT = 20; const EMPTY: PatientRecord[] = []; /** unix start-of-day for `from`, end-of-day for `to`, from a gregorian Y-m-d. */ function dayBound(value: string | undefined, end: boolean): number | undefined { if (!value) return 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; } /** Number of filters currently applied (for the button badge). */ function countFilters(f: PatientFilters): number { return [f.gender, f.insurance_id, f.admitted_from, f.admitted_to, f.service_status, f.has_debt || undefined, f.tags?.length ? '1' : undefined] .filter(Boolean).length; } /** پرونده‌ها — patient records list (table + card views) matching the Figma design. */ export default function PatientsListPage() { const navigate = useNavigate(); const [page, setPage] = useState(1); const [search, setSearch] = useState(''); const [view, setView] = useState<'table' | 'card'>('table'); const [filterOpen, setFilterOpen] = useState(false); const [filters, setFilters] = useState({}); const qs = new URLSearchParams({ page: String(page), limit: String(LIMIT) }); if (search) qs.set('search', search); if (filters.gender) qs.set('gender', filters.gender); if (filters.insurance_id) qs.set('insurance_id', filters.insurance_id); if (filters.service_status) qs.set('service_status', filters.service_status); if (filters.has_debt) qs.set('has_debt', '1'); if (filters.tags?.length) qs.set('tags', filters.tags.join(',')); const af = dayBound(filters.admitted_from, false); const at = dayBound(filters.admitted_to, true); if (af) qs.set('admitted_from', String(af)); if (at) qs.set('admitted_to', String(at)); const { data, isLoading } = useQuery & { meta?: { totalRecords: number } }>({ queryKey: ['patients', qs.toString()], queryFn: () => api.get(`/api/v1/patients?${qs.toString()}`), }); const activeFilters = countFilters(filters); const records = data?.data ?? EMPTY; const total = data?.meta?.totalRecords ?? 0; const editHref = (r: PatientRecord) => `/admin/patients/${r.uuid}/edit`; const viewHref = (r: PatientRecord) => `/admin/patients/${r.uuid}`; return (
{/* Header */}

پرونده‌ها

{ setSearch(e.target.value); setPage(1); }} style={{ width: 320, maxWidth: '60vw', height: 40, paddingInlineStart: 34 }} />
{/* view toggle */}
{isLoading ? (
در حال بارگذاری...
) : records.length === 0 ? (
پرونده‌ای یافت نشد.
) : view === 'table' ? (
{['ردیف', 'مراجعه کننده', 'برچسب ها', 'شماره پرونده', 'شماره تماس', 'کد ملی', 'عملیات'].map((h) => ( ))} {records.map((r, i) => ( ))}
{h}
{formatNumber((page - 1) * LIMIT + i + 1)} {r.user_name || '—'} {!r.user_national_code && } {r.record_number || '—'} {r.user_mobile || '—'} {r.user_national_code || '—'}
) : (
{records.map((r) => (
{r.user_name || '—'}
شماره پرونده: {r.record_number || '—'} تماس: {r.user_mobile || '—'} کد ملی: {r.user_national_code || '—'}
مشاهده ویرایش
))}
)}
setFilterOpen(false)} onApply={(f) => { setFilters(f); setPage(1); setFilterOpen(false); }} />
); }