feat(migrations): add national_code_verified flag to users and normalize bank_account representation
- Added a new column `national_code_verified` to the `users` table. - Normalized the `bank_account` field in the `representations` table from a single object to an array of IBANs with a default `verified` status of false. feat(ApiIrService): implement identity verification client for api.ir - Created `ApiIrService` to handle identity verification via api.ir. - Implemented methods for matching national code with mobile and IBAN with national code and birth date. - Added error handling and logging for external API requests.
This commit is contained in:
@@ -78,7 +78,7 @@ export default function SettlementDetailPage() {
|
||||
onError: (e: Error) => toast.error(e.message),
|
||||
});
|
||||
|
||||
// آپلود رسید → سپس ثبت پرداخت نهایی (paid). مبلغ قبلاً هنگام درخواست از کیفپول کسر شده.
|
||||
// آپلود رسید (بدون نهاییسازی). نهاییسازی با دکمهی جداگانهی «تکمیل» انجام میشود.
|
||||
const handleReceiptUpload = async (file: File) => {
|
||||
setPaying(true);
|
||||
try {
|
||||
@@ -94,15 +94,26 @@ export default function SettlementDetailPage() {
|
||||
const json = await res.json();
|
||||
const url = json?.data?.url;
|
||||
if (!url) throw new Error('آپلود رسید ناموفق بود');
|
||||
await api.post<ApiResponse<null>>(`/api/v1/settlement/${uuid}/paid`, { receipt: url });
|
||||
toast.success('پرداخت ثبت شد');
|
||||
// رسید را در همان رکورد ذخیره میکنیم تا دکمهی «تکمیل» فعال شود (وضعیت همچنان approved).
|
||||
await api.post<ApiResponse<null>>(`/api/v1/settlement/${uuid}/receipt`, { receipt: url });
|
||||
toast.success('رسید آپلود شد');
|
||||
qc.invalidateQueries({ queryKey: ['settlement-detail', uuid] });
|
||||
qc.invalidateQueries({ queryKey: ['settlements'] });
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (e: any) { toast.error(e?.message ?? 'خطا در ثبت پرداخت'); }
|
||||
} catch (e: any) { toast.error(e?.message ?? 'خطا در آپلود رسید'); }
|
||||
finally { setPaying(false); }
|
||||
};
|
||||
|
||||
// تکمیل: نهاییسازی پرداخت (وضعیت → paid). مبلغ قبلاً هنگام درخواست از کیفپول کسر شده.
|
||||
const completeMut = useMutation({
|
||||
mutationFn: () => api.post<ApiResponse<null>>(`/api/v1/settlement/${uuid}/paid`, { receipt: s?.receipt }),
|
||||
onSuccess: () => {
|
||||
toast.success('تسویه تکمیل شد');
|
||||
qc.invalidateQueries({ queryKey: ['settlement-detail', uuid] });
|
||||
qc.invalidateQueries({ queryKey: ['settlements'] });
|
||||
},
|
||||
onError: (e: Error) => toast.error(e.message),
|
||||
});
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="fade-in">
|
||||
@@ -186,16 +197,27 @@ export default function SettlementDetailPage() {
|
||||
)}
|
||||
|
||||
{s.status === 'approved' && (
|
||||
<div style={{ marginTop: 14 }}>
|
||||
<div style={{ marginTop: 14, display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
|
||||
<input ref={receiptInputRef} type="file" accept="image/*" style={{ display: 'none' }}
|
||||
onChange={e => e.target.files?.[0] && handleReceiptUpload(e.target.files[0])} />
|
||||
<button className="btn primary sm" disabled={paying}
|
||||
<button className="btn ghost sm" disabled={paying}
|
||||
onClick={() => receiptInputRef.current?.click()}>
|
||||
<ArrowUpTrayIcon style={{ width: 15, height: 15 }} />
|
||||
{paying ? 'در حال ثبت...' : 'آپلود رسید و ثبت پرداخت'}
|
||||
{paying ? 'در حال آپلود...' : (s.receipt ? 'تغییر رسید' : 'آپلود رسید')}
|
||||
</button>
|
||||
<p className="muted" style={{ fontSize: 12, marginTop: 8 }}>
|
||||
با آپلود رسید، وضعیت به «پرداخت شده» تغییر میکند. مبلغ هنگام ثبت درخواست از کیفپول کسر شده است.
|
||||
|
||||
{/* دکمهی تکمیل فقط بعد از آپلود رسید فعال میشود */}
|
||||
<button className="btn primary sm" disabled={!s.receipt || completeMut.isPending}
|
||||
onClick={() => completeMut.mutate()}
|
||||
title={!s.receipt ? 'ابتدا رسید را آپلود کنید' : undefined}>
|
||||
<CheckIcon style={{ width: 15, height: 15 }} />
|
||||
{completeMut.isPending ? 'در حال تکمیل...' : 'تکمیل'}
|
||||
</button>
|
||||
|
||||
<p className="muted" style={{ fontSize: 12, width: '100%' }}>
|
||||
{s.receipt
|
||||
? 'با زدن «تکمیل»، وضعیت به «پرداخت شده» تغییر میکند. مبلغ هنگام ثبت درخواست از کیفپول کسر شده است.'
|
||||
: 'ابتدا رسید پرداخت را آپلود کنید، سپس دکمهی «تکمیل» فعال میشود.'}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user