import React, { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; import { EyeIcon, TrashIcon, PlusIcon } from '@heroicons/react/24/outline'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { toast } from 'sonner'; import { api } from '../lib/api'; import type { ApiResponse, PaginatedResponse } from '../lib/api'; import type { Representation } from '../types'; import { formatDate, formatRial, formatNumber } from '../lib/utils'; import PageHeader from '../components/ui/PageHeader'; import DataTable, { Column } from '../components/ui/DataTable'; import { ActiveBadge } from '../components/ui/StatusBadge'; import Pagination from '../components/ui/Pagination'; import ConfirmDialog from '../components/ui/ConfirmDialog'; import Modal from '../components/ui/Modal'; const schema = z.object({ domain: z.string().min(3, 'دامنه معتبر نیست'), city: z.string().min(2, 'شهر را وارد کنید'), commission_percent: z.coerce.number().min(0).max(100), }); type FormData = z.infer; export default function RepresentationsPage() { const navigate = useNavigate(); const qc = useQueryClient(); const [page, setPage] = useState(1); const [search, setSearch] = useState(''); const [addOpen, setAddOpen] = useState(false); const [deleteTarget, setDeleteTarget] = useState(null); const limit = 15; const { data, isLoading } = useQuery({ queryKey: ['representations', page, search], queryFn: () => { const params = new URLSearchParams({ page: String(page), limit: String(limit) }); if (search) params.set('search', search); return api.get>(`/api/v1/admin/representations?${params}`); }, }); const { register, handleSubmit, reset, formState: { errors, isSubmitting } } = useForm({ resolver: zodResolver(schema), defaultValues: { commission_percent: 10 }, }); const createMutation = useMutation({ mutationFn: (d: FormData) => api.post>('/api/v1/representation', d), onSuccess: () => { toast.success('نماینده اضافه شد'); setAddOpen(false); reset(); qc.invalidateQueries({ queryKey: ['representations'] }); }, onError: (err: Error) => toast.error(err.message), }); const deleteMutation = useMutation({ mutationFn: (r: Representation) => api.delete>(`/api/v1/representation/${r.uuid}`), onSuccess: () => { toast.success('نماینده حذف شد'); setDeleteTarget(null); qc.invalidateQueries({ queryKey: ['representations'] }); }, onError: (err: Error) => toast.error(err.message), }); const columns: Column[] = [ { key: 'domain', header: 'دامنه', render: (r) => {r.domain} }, { key: 'city', header: 'شهر' }, { key: 'commission_percent', header: 'کمیسیون', render: (r) => `${formatNumber(r.commission_percent)}٪`, }, { key: 'wallet_balance', header: 'موجودی کیف‌پول', render: (r) => formatRial(r.wallet_balance ?? 0), }, { key: 'is_active', header: 'وضعیت', render: (r) => }, { key: 'created_at', header: 'تاریخ ثبت', render: (r) => formatDate(r.created_at) }, ]; const items = data?.data ?? []; const total = data?.meta?.totalRecords ?? 0; return (
setAddOpen(true)} className="flex items-center gap-2 px-4 py-2 bg-primary-600 text-white text-sm rounded-[10px] hover:bg-primary-700 transition-colors"> افزودن نماینده } />
columns={columns} data={items} loading={isLoading} searchValue={search} onSearchChange={(v) => { setSearch(v); setPage(1); }} searchPlaceholder="جستجو بر اساس دامنه یا شهر..." emptyMessage="هیچ نماینده‌ای یافت نشد" actions={(rep) => ( <> )} />
setAddOpen(false)} footer={ <> } >
createMutation.mutate(d))} className="space-y-4">
{errors.domain &&

{errors.domain.message}

}
{errors.city &&

{errors.city.message}

}
{errors.commission_percent &&

{errors.commission_percent.message}

}
deleteTarget && deleteMutation.mutate(deleteTarget)} onCancel={() => setDeleteTarget(null)} />
); }