Add per-clinic payment methods (bank accounts + POS/card-reader devices)
under the "مدیریت پرداخت" settings tab at /admin/my-financial, ported from
clinic-pro-tauri's mock-only PaymentManagement tab into a real persisted
feature. These records are referenceable (by uuid) from patient invoices to
record which method a service payment was made with.
Backend (new src/PaymentMethod domain):
- BankAccount + Pos entities, repositories, PaymentMethodService (validation,
ownership scoping, create/update/toggle logic).
- Thin PaymentMethodController exposing /api/v1/my/payment-methods/{bank-accounts,pos}
(GET/POST/PUT + PATCH .../status), guarded to clinic/doctor/secretary/admin.
- Migration for bank_accounts + pos_devices tables.
- Functional tests (success + validation/404/403 + empty boundaries).
- docs/api/payment-method.md.
Frontend:
- Replace MyFinancialPage content with the payment-management UI (two tabs,
tables, add/edit modals, status toggle) using the admin design system.
- usePaymentMethods hook (TanStack Query) + presentational components.
- Update page test to cover tabs, data, empty state and the add modal.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
53 lines
1.7 KiB
TypeScript
53 lines
1.7 KiB
TypeScript
import React from 'react';
|
|
import { PlusIcon } from '@heroicons/react/24/outline';
|
|
|
|
export type PaymentTab = 'bank' | 'pos';
|
|
|
|
/**
|
|
* سربرگ صفحهٔ مدیریت پرداخت — پورت مبدأ PaymentManagement/Head.jsx.
|
|
* تیتر + سوییچ تب (حساب بانکی / کارت خوان) + دکمهٔ افزودن.
|
|
*/
|
|
export default function PaymentMethodHead({
|
|
activeTab,
|
|
onTabChange,
|
|
onAdd,
|
|
}: {
|
|
activeTab: PaymentTab;
|
|
onTabChange: (tab: PaymentTab) => void;
|
|
onAdd: () => void;
|
|
}) {
|
|
return (
|
|
<div style={{ marginBottom: 20 }}>
|
|
<h2 style={{ fontSize: 20, fontWeight: 700, color: 'var(--text)', margin: '0 0 16px' }}>
|
|
مدیریت پرداختها
|
|
</h2>
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
|
<div className="seg" role="tablist">
|
|
<button
|
|
type="button"
|
|
role="tab"
|
|
aria-selected={activeTab === 'bank'}
|
|
className={activeTab === 'bank' ? 'on' : ''}
|
|
onClick={() => onTabChange('bank')}
|
|
>
|
|
حساب بانکی
|
|
</button>
|
|
<button
|
|
type="button"
|
|
role="tab"
|
|
aria-selected={activeTab === 'pos'}
|
|
className={activeTab === 'pos' ? 'on' : ''}
|
|
onClick={() => onTabChange('pos')}
|
|
>
|
|
کارت خوان
|
|
</button>
|
|
</div>
|
|
<button className="btn primary" onClick={onAdd}>
|
|
<PlusIcon style={{ width: 16 }} />
|
|
{activeTab === 'bank' ? 'افزودن حساب بانکی' : 'افزودن کارت خوان'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|