feat(admin): name the tab for what it shows, prefill the patient, paginate and search
The tab was called 'نوبتهای بعدی' but shows the whole course — finished sessions with their recorded readings as much as upcoming ones. It is 'دورههای درمان' now. Booking from a session still made the user search for a patient the page already had open. The plan response carries the patient's national code (from the profile, falling back to the user — the same COALESCE PatientController uses, because users.national_code is routinely empty), and the modal takes a patient prop that seeds the lookup and hides the search step. The old 'بیمار یافت شد' card is suppressed in that mode; saying it twice is noise. Sessions are now searchable and paged. A protocol allows up to 60 steps and a patient can hold several courses, so an unbounded list was only ever going to work for the small cases. Search filters on what the card actually shows — service, staff, status, session number, area names — and runs in the page, since /plan already returns the whole course and a round trip would add latency and nothing else. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -41,7 +41,7 @@ export interface BookingResource {
|
||||
*/
|
||||
export default function NewAppointmentModal({
|
||||
slot, onClose, onSuccess, serviceMode = false, services = [], date, clinicUuid = null, resource = null,
|
||||
treatmentSessionUuid = null,
|
||||
treatmentSessionUuid = null, patient = null,
|
||||
}: {
|
||||
slot: BookingSlot;
|
||||
onClose: () => void;
|
||||
@@ -57,11 +57,20 @@ export default function NewAppointmentModal({
|
||||
* اتصال از روی سرویس حدس زده میشود و سرویسِ اشتباه یک پروندهٔ موازی میسازد.
|
||||
*/
|
||||
treatmentSessionUuid?: string | null;
|
||||
/**
|
||||
* بیمارِ از پیش معلوم — وقتی مودال از پروندهٔ خودِ بیمار باز میشود.
|
||||
*
|
||||
* مرحلهٔ جستجو رد میشود: کسی که پروندهٔ بیمار را باز کرده نباید همان بیمار را
|
||||
* دوباره با کد ملی پیدا کند.
|
||||
*/
|
||||
patient?: { name: string | null; mobile: string; national_code: string | null } | null;
|
||||
}) {
|
||||
const [mobile, setMobile] = useState('');
|
||||
const [lookup, setLookup] = useState<PatientLookup | null>(null);
|
||||
const [patientName, setPatientName] = useState('');
|
||||
const [nationalCode, setNationalCode] = useState('');
|
||||
const [mobile, setMobile] = useState(patient?.mobile ?? '');
|
||||
const [lookup, setLookup] = useState<PatientLookup | null>(
|
||||
patient === null ? null : { found: true, name: patient.name, mobile: patient.mobile, national_code: patient.national_code },
|
||||
);
|
||||
const [patientName, setPatientName] = useState(patient?.name ?? '');
|
||||
const [nationalCode, setNationalCode] = useState(patient?.national_code ?? '');
|
||||
// معیار جستجوی بیمار: کد ملی (پیشفرض) یا موبایل.
|
||||
const [searchBy, setSearchBy] = useState<'mobile' | 'national'>('national');
|
||||
const [pick, setPick] = useState<ServicePick>({ serviceUuids: [], durations: {}, slot: null });
|
||||
@@ -329,7 +338,23 @@ export default function NewAppointmentModal({
|
||||
)}
|
||||
|
||||
<Step n={pickerMode ? 2 : null} title="بیمار">
|
||||
<div className="field-block" style={{ marginBottom: 14 }}>
|
||||
{/* بیمارِ از پیش معلوم: فقط تأیید میشود، جستجو لازم نیست. */}
|
||||
{patient !== null && (
|
||||
<div style={{
|
||||
marginBottom: 14, padding: '10px 14px', borderRadius: 'var(--r-sm)',
|
||||
background: 'var(--success-bg)', display: 'flex', alignItems: 'center', gap: 10, fontSize: 13,
|
||||
}}>
|
||||
<CheckCircleIcon style={{ width: 20, height: 20, color: 'var(--success)', flexShrink: 0 }} />
|
||||
<div style={{ minWidth: 0 }}>
|
||||
<div style={{ fontWeight: 700, color: 'var(--text)' }}>{patient.name || 'بدون نام'}</div>
|
||||
<div style={{ color: 'var(--text-2)', fontSize: 12, direction: 'ltr', textAlign: 'start' }}>
|
||||
{patient.mobile}{patient.national_code ? ` · ${patient.national_code}` : ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="field-block" style={{ marginBottom: 14, display: patient === null ? undefined : 'none' }}>
|
||||
<label htmlFor="appt-patient-search">جستجوی بیمار <span className="req">*</span></label>
|
||||
{/* انتخاب معیار جستجو: موبایل یا کد ملی */}
|
||||
<div className="seg" style={{ display: 'flex', marginBottom: 8 }}>
|
||||
@@ -391,7 +416,8 @@ export default function NewAppointmentModal({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{foundWithNationalCode && (
|
||||
{/* وقتی بیمار از قبل معلوم است، کارت بالا همین را میگوید؛ دو بار گفتنش نویز است. */}
|
||||
{patient === null && foundWithNationalCode && (
|
||||
<div style={{
|
||||
marginBottom: 16, padding: '10px 14px', borderRadius: 'var(--r-sm)',
|
||||
background: 'var(--success-bg)', fontSize: 13,
|
||||
|
||||
Reference in New Issue
Block a user