feat(patients): phase B5 — wire service creation into the detail page
Reuse the existing NewSessionPage (service section/item + insurance coverage +
payment flow → POST /patient/{recordUuid}/session) from the new patient detail:
add a patients-scoped route /admin/patients/:recordUuid/session/new and a
"سرویس جدید" action on the services tab. The multi-step visual restyle and the
standalone invoice-issuance screen remain a follow-up (the underlying
session/billing endpoints already exist).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -197,6 +197,7 @@ export default function App() {
|
||||
<Route path="patients/new" element={<RoleRoute roles={['doctor', 'secretary', 'clinic']} blockClinicScope><PatientRecordFormPage /></RoleRoute>} />
|
||||
<Route path="patients/:uuid/edit" element={<RoleRoute roles={['doctor', 'secretary', 'clinic']} blockClinicScope><PatientRecordFormPage /></RoleRoute>} />
|
||||
<Route path="patients/:uuid" element={<RoleRoute roles={['doctor', 'secretary', 'clinic']} blockClinicScope><PatientDetailPage /></RoleRoute>} />
|
||||
<Route path="patients/:recordUuid/session/new" element={<RoleRoute roles={['doctor', 'secretary', 'clinic']} blockClinicScope><NewSessionPage /></RoleRoute>} />
|
||||
<Route path="my-patients/:recordUuid/session/new" element={<RoleRoute roles={['doctor', 'secretary', 'clinic']} blockClinicScope><NewSessionPage /></RoleRoute>} />
|
||||
<Route path="insurance-pricing" element={<RoleRoute roles={['doctor', 'clinic']} blockClinicScope><InsurancePricingPage /></RoleRoute>} />
|
||||
<Route path="claims" element={<RoleRoute roles={['doctor', 'clinic']} blockClinicScope><ClaimsPage /></RoleRoute>} />
|
||||
|
||||
@@ -76,6 +76,13 @@ describe('PatientDetailPage (پرونده تبدار)', () => {
|
||||
expect(await screen.findByPlaceholderText('مثلاً: معاینه اولیه')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('links "سرویس جدید" on the services tab to the new-session route', async () => {
|
||||
renderDetail();
|
||||
await screen.findByText('ساغر صابری'); // services is the default tab
|
||||
const link = await screen.findByRole('link', { name: /سرویس جدید/ });
|
||||
expect(link).toHaveAttribute('href', '/admin/patients/r1/session/new');
|
||||
});
|
||||
|
||||
it('renders the messages tab with a send box', async () => {
|
||||
renderDetail();
|
||||
await screen.findByText('ساغر صابری');
|
||||
|
||||
@@ -122,8 +122,13 @@ export default function PatientDetailPage() {
|
||||
<InfoRow label="توضیحات" value={profile.description} />
|
||||
</div>
|
||||
) : tab === 'services' ? (
|
||||
<TabList q={sessionsQ} emptyLabel="سرویسی ثبت نشده است"
|
||||
row={(s) => ({ title: s.section_name || s.name || 'سرویس', meta: s.created_at ? formatDate(s.created_at) : '', badge: s.status })} />
|
||||
<div>
|
||||
<div style={{ marginBottom: 14 }}>
|
||||
<Link to={`/admin/patients/${uuid}/session/new`} className="btn primary"><PlusIcon style={{ width: 16 }} /> سرویس جدید</Link>
|
||||
</div>
|
||||
<TabList q={sessionsQ} emptyLabel="سرویسی ثبت نشده است"
|
||||
row={(s) => ({ title: s.section_name || s.name || 'سرویس', meta: s.created_at ? formatDate(s.created_at) : '', badge: s.status })} />
|
||||
</div>
|
||||
) : tab === 'appointments' ? (
|
||||
<TabList q={appointmentsQ} emptyLabel="نوبتی ثبت نشده است"
|
||||
row={(a) => ({ title: a.service_name || a.doctor_name || 'نوبت', meta: a.date ? formatDate(a.date) : (a.starts_at ? formatDate(a.starts_at) : ''), badge: a.status_label || a.status })} />
|
||||
|
||||
Reference in New Issue
Block a user