import React, { useMemo, useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { BanknotesIcon, ReceiptPercentIcon, ChatBubbleLeftRightIcon, CalculatorIcon, ArrowPathIcon, DocumentTextIcon, } from '@heroicons/react/24/outline'; import { api } from '../lib/api'; import type { ApiResponse, PaginatedResponse } from '../lib/api'; import { formatRial, formatNumber, formatDate } from '../lib/utils'; import Pagination from '../components/ui/Pagination'; interface FinanceRow { uuid: string; appointment_uuid: string | null; doctor_name: string | null; gross_rials: number; tax_rials: number; sms_fee_rials: number; commission_percent: number; representation_share_rials: number; created_at: string; } type RangeKey = 'today' | 'week' | 'month' | 'all'; function rangeFrom(key: RangeKey): number | null { const now = Math.floor(Date.now() / 1000); if (key === 'today') return Math.floor(new Date().setHours(0, 0, 0, 0) / 1000); if (key === 'week') return now - 7 * 86400; if (key === 'month') return now - 30 * 86400; return null; } const RANGES: { key: RangeKey; label: string }[] = [ { key: 'today', label: 'امروز' }, { key: 'week', label: '۷ روز اخیر' }, { key: 'month', label: '۳۰ روز اخیر' }, { key: 'all', label: 'همه' }, ]; export default function RepresentationFinancePage() { const [range, setRange] = useState('month'); const [page, setPage] = useState(1); const limit = 15; const { data, isLoading, isFetching, refetch } = useQuery({ queryKey: ['representation-finance', range, page], queryFn: () => { const params = new URLSearchParams({ page: String(page), limit: String(limit) }); const from = rangeFrom(range); if (from !== null) params.set('from', String(from)); return api.get>(`/api/v1/representation/finance/report?${params}`); }, }); const items: FinanceRow[] = data?.data ?? []; const total = data?.meta?.totalRecords ?? 0; // جمعِ ردیف‌های صفحه‌ی جاری (نمایش سریع؛ دقیق برای همین صفحه). const pageSums = useMemo(() => items.reduce( (acc, r) => { acc.share += r.representation_share_rials; acc.gross += r.gross_rials; acc.tax += r.tax_rials; acc.sms += r.sms_fee_rials; return acc; }, { share: 0, gross: 0, tax: 0, sms: 0 }, ), [items]); const cards = [ { label: 'سهم نماینده (این صفحه)', value: formatRial(pageSums.share), icon: BanknotesIcon, color: 'var(--primary)', bg: 'var(--primary-soft)' }, { label: 'مبلغ نوبت‌ها', value: formatRial(pageSums.gross), icon: CalculatorIcon, color: 'var(--info)', bg: 'var(--info-bg)' }, { label: 'مالیات', value: formatRial(pageSums.tax), icon: ReceiptPercentIcon, color: 'var(--warning)', bg: 'var(--warning-bg)' }, { label: 'هزینه پیامک', value: formatRial(pageSums.sms), icon: ChatBubbleLeftRightIcon, color: 'var(--violet)', bg: 'var(--violet-bg)' }, ]; return (

گزارش مالی

درآمد ثبت‌شده از پورسانت نوبت‌ها — تفکیک هر تراکنش
{/* فیلتر بازه — segmented */}
{RANGES.map(r => ( ))}
{/* کارت‌های خلاصه */}
{cards.map(c => (
{c.label}
{isLoading ? '—' : c.value}
))}
{/* جدول تراکنش‌ها */}

تراکنش‌ها

{!isLoading && {formatNumber(total)} ردیف}
{isLoading && Array.from({ length: 5 }).map((_, i) => ( {Array.from({ length: 7 }).map((__, j) => ( ))} ))} {!isLoading && items.length === 0 && ( )} {!isLoading && items.map(r => ( ))}
پزشک مبلغ نوبت مالیات هزینه پیامک درصد پورسانت سهم نماینده تاریخ
در این بازه درآمدی ثبت نشده است
با ثبت و پرداخت نوبت از دامنه‌ی شما، پورسانت اینجا نمایش داده می‌شود.
{r.doctor_name ?? '—'} {formatRial(r.gross_rials)} {formatRial(r.tax_rials)} {formatRial(r.sms_fee_rials)} {formatNumber(r.commission_percent)}٪ {formatRial(r.representation_share_rials)} {formatDate(r.created_at)}
); }