feat(patient): complete "اطلاعات پرونده" demographic form
Backend:
- Add profile columns field_of_study, province_id, city_id, postal_code,
referral_source (UserProfile + migration).
- Extend PATCH /api/v1/patient/{uuid} to persist all demographic fields
and return them in the patient profile payload.
- Support editable mobile (login identifier): validation, uniqueness,
User.setMobileNumber, new ERR_PROFILE_002.
- Update docs/api/patient.md.
Frontend:
- New reusable Input, Field, and PatientRecordInfoForm (RHF + Zod).
- usePatient/useUpdatePatient hooks and patientForm mapping helpers.
- Extend the existing "info" tab in MyPatientsPage to the full field set
via the shared form (province/city/insurance options, Jalali date).
Tests: Patient entity + PATCH integration (PHPUnit); form, hooks, and
mapping helpers (Vitest).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import PatientRecordInfoForm, {
|
||||
type PatientFormValues,
|
||||
type PatientFormOptions,
|
||||
} from '@/components/PatientRecordInfoForm';
|
||||
|
||||
const options: PatientFormOptions = {
|
||||
gender: [{ value: 'female', label: 'زن' }, { value: 'male', label: 'مرد' }],
|
||||
marital: [{ value: 'single', label: 'مجرد' }],
|
||||
education: [{ value: 'bachelor', label: 'کارشناسی' }],
|
||||
insurance: [{ value: 3, label: 'تأمین اجتماعی' }],
|
||||
province: [{ value: 8, label: 'یزد' }],
|
||||
city: [{ value: 42, label: 'یزد' }],
|
||||
referral: [{ value: 'instagram', label: 'اینستاگرام' }],
|
||||
};
|
||||
|
||||
const baseValues: PatientFormValues = {
|
||||
name: 'ساغر صابری نژاد',
|
||||
mobile: '',
|
||||
national_code: '',
|
||||
gender: null,
|
||||
birth_date: '',
|
||||
fathers_name: '',
|
||||
marital_status: null,
|
||||
basic_insurance_id: null,
|
||||
field_of_study: '',
|
||||
education: null,
|
||||
job: '',
|
||||
province_id: null,
|
||||
city_id: null,
|
||||
home_phone: '',
|
||||
address: '',
|
||||
postal_code: '',
|
||||
referral_source: null,
|
||||
description: '',
|
||||
};
|
||||
|
||||
function setup(overrides: Partial<PatientFormValues> = {}) {
|
||||
const onSubmit = vi.fn();
|
||||
render(
|
||||
<PatientRecordInfoForm
|
||||
defaultValues={{ ...baseValues, ...overrides }}
|
||||
recordNumber="123456789"
|
||||
options={options}
|
||||
onSubmit={onSubmit}
|
||||
/>,
|
||||
);
|
||||
return { onSubmit };
|
||||
}
|
||||
|
||||
describe('PatientRecordInfoForm', () => {
|
||||
it('برچسبهای اصلی و شماره پروندهٔ read-only را رندر میکند', () => {
|
||||
setup();
|
||||
expect(screen.getByText('نام و نام خانوادگی مراجعه کننده')).toBeInTheDocument();
|
||||
expect(screen.getByText('نحوه آشنایی')).toBeInTheDocument();
|
||||
expect((screen.getByDisplayValue('123456789') as HTMLInputElement).readOnly).toBe(true);
|
||||
});
|
||||
|
||||
it('نام خالی → خطای الزامی و onSubmit صدا نمیخورد', async () => {
|
||||
const { onSubmit } = setup({ name: '' });
|
||||
await userEvent.click(screen.getByRole('button', { name: /ثبت اطلاعات/ }));
|
||||
expect(await screen.findByText('نام و نام خانوادگی الزامی است')).toBeInTheDocument();
|
||||
expect(onSubmit).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('کدملی نامعتبر → خطای ۱۰ رقم', async () => {
|
||||
setup({ national_code: '123' });
|
||||
await userEvent.click(screen.getByRole('button', { name: /ثبت اطلاعات/ }));
|
||||
expect(await screen.findByText('کد ملی باید ۱۰ رقم باشد')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('ورودی معتبر → onSubmit با مقادیر فرم', async () => {
|
||||
const { onSubmit } = setup({ national_code: '0012345678' });
|
||||
await userEvent.click(screen.getByRole('button', { name: /ثبت اطلاعات/ }));
|
||||
await waitFor(() => expect(onSubmit).toHaveBeenCalledTimes(1));
|
||||
expect(onSubmit.mock.calls[0][0]).toMatchObject({
|
||||
name: 'ساغر صابری نژاد',
|
||||
national_code: '0012345678',
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user