Replace all native <select> elements in the admin panel with SearchableSelect for a consistent UI experience. This change enhances accessibility, supports RTL and dark mode, and improves the overall design by utilizing a common component. The updates include adjustments to state management and event handling to ensure seamless integration with existing functionality across various pages and components.
This commit is contained in:
@@ -7,6 +7,7 @@ import type { ApiResponse } from '../lib/api';
|
||||
import Modal from './ui/Modal';
|
||||
import PersianDateInput from './ui/PersianDateInput';
|
||||
import PriceInput from './ui/PriceInput';
|
||||
import SearchableSelect from './ui/SearchableSelect';
|
||||
import { WalletChargeLink } from './AppointmentActions';
|
||||
import { tehranWallClockToUnix } from '../lib/utils';
|
||||
|
||||
@@ -153,7 +154,6 @@ export default function NewAppointmentDrawer({ doctorUuid, defaultDate, queryKey
|
||||
});
|
||||
|
||||
const label = { fontSize: 12.5, color: 'var(--text-3)' } as const;
|
||||
const sel = { width: '100%', height: 38, borderRadius: 'var(--r-sm)', border: '1px solid var(--border)', background: 'var(--surface)', fontSize: 13, fontFamily: 'inherit', padding: '0 10px' } as const;
|
||||
const patients = useMemo(() => patientsQ.data?.data ?? [], [patientsQ.data]);
|
||||
|
||||
return (
|
||||
@@ -205,33 +205,41 @@ export default function NewAppointmentDrawer({ doctorUuid, defaultDate, queryKey
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginBottom: 10 }}>
|
||||
<div>
|
||||
<label style={label}>بخش</label>
|
||||
<select aria-label="بخش" style={{ ...sel, marginTop: 6 }} value={sectionUuid} onChange={e => { setSectionUuid(e.target.value); setItemUuid(''); }}>
|
||||
<option value="">انتخاب بخش</option>
|
||||
{(sectionsQ.data?.data ?? []).map(o => <option key={o.uuid} value={o.uuid}>{o.name}</option>)}
|
||||
</select>
|
||||
<div style={{ marginTop: 6 }}>
|
||||
<SearchableSelect
|
||||
options={(sectionsQ.data?.data ?? []).map(o => ({ value: o.uuid, label: o.name ?? '' }))}
|
||||
value={sectionUuid || null}
|
||||
onChange={v => { setSectionUuid(v ? String(v) : ''); setItemUuid(''); }}
|
||||
placeholder="انتخاب بخش"
|
||||
isLoading={sectionsQ.isLoading}
|
||||
isClearable
|
||||
height={38}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label style={label}>سرویس{serviceMode ? ' (یک یا چند)' : ''}</label>
|
||||
<select
|
||||
aria-label="سرویس"
|
||||
style={{ ...sel, marginTop: 6 }}
|
||||
value={serviceMode ? '' : itemUuid}
|
||||
disabled={!sectionUuid}
|
||||
onChange={e => {
|
||||
const uuid = e.target.value;
|
||||
if (!uuid) return;
|
||||
if (serviceMode) {
|
||||
const name = (itemsQ.data?.data ?? []).find(o => o.uuid === uuid)?.name ?? '';
|
||||
setServiceUuids(prev => prev.includes(uuid) ? prev : [...prev, uuid]);
|
||||
setSvcNames(prev => ({ ...prev, [uuid]: name }));
|
||||
} else {
|
||||
setItemUuid(uuid);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<option value="">{serviceMode ? 'افزودن سرویس' : 'انتخاب سرویس'}</option>
|
||||
{(itemsQ.data?.data ?? []).map(o => <option key={o.uuid} value={o.uuid}>{o.name}</option>)}
|
||||
</select>
|
||||
<div style={{ marginTop: 6 }}>
|
||||
<SearchableSelect
|
||||
options={(itemsQ.data?.data ?? []).map(o => ({ value: o.uuid, label: o.name ?? '' }))}
|
||||
value={serviceMode ? null : (itemUuid || null)}
|
||||
isDisabled={!sectionUuid}
|
||||
isLoading={itemsQ.isLoading}
|
||||
placeholder={serviceMode ? 'افزودن سرویس' : 'انتخاب سرویس'}
|
||||
onChange={v => {
|
||||
const uuid = v ? String(v) : '';
|
||||
if (!uuid) { if (!serviceMode) setItemUuid(''); return; }
|
||||
if (serviceMode) {
|
||||
const name = (itemsQ.data?.data ?? []).find(o => o.uuid === uuid)?.name ?? '';
|
||||
setServiceUuids(prev => prev.includes(uuid) ? prev : [...prev, uuid]);
|
||||
setSvcNames(prev => ({ ...prev, [uuid]: name }));
|
||||
} else {
|
||||
setItemUuid(uuid);
|
||||
}
|
||||
}}
|
||||
height={38}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{serviceMode && serviceUuids.length > 0 && (
|
||||
@@ -247,10 +255,17 @@ export default function NewAppointmentDrawer({ doctorUuid, defaultDate, queryKey
|
||||
</div>
|
||||
)}
|
||||
<label style={label}>انتخاب پرسنل</label>
|
||||
<select aria-label="پرسنل" style={{ ...sel, margin: '6px 0 12px' }} value={staffUuid} onChange={e => setStaffUuid(e.target.value)}>
|
||||
<option value="">انتخاب...</option>
|
||||
{(staffQ.data?.data ?? []).map(o => <option key={o.uuid} value={o.uuid}>{o.full_name}</option>)}
|
||||
</select>
|
||||
<div style={{ margin: '6px 0 12px' }}>
|
||||
<SearchableSelect
|
||||
options={(staffQ.data?.data ?? []).map(o => ({ value: o.uuid, label: o.full_name ?? '' }))}
|
||||
value={staffUuid || null}
|
||||
onChange={v => setStaffUuid(v ? String(v) : '')}
|
||||
placeholder="انتخاب..."
|
||||
isLoading={staffQ.isLoading}
|
||||
isClearable
|
||||
height={38}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ fontSize: 13.5, fontWeight: 700, margin: '6px 0 10px' }}>زمان نوبت:</div>
|
||||
<label style={label}>انتخاب تاریخ</label>
|
||||
@@ -326,10 +341,15 @@ export default function NewAppointmentDrawer({ doctorUuid, defaultDate, queryKey
|
||||
)}
|
||||
|
||||
<label style={label}>انتخاب وضعیت</label>
|
||||
<select aria-label="وضعیت" style={{ ...sel, margin: '6px 0 12px' }} value={status} onChange={e => setStatus(e.target.value)}>
|
||||
<option value="pending">ثبت شده</option>
|
||||
<option value="confirmed">قطعی شده</option>
|
||||
</select>
|
||||
<div style={{ margin: '6px 0 12px' }}>
|
||||
<SearchableSelect
|
||||
options={[{ value: 'pending', label: 'ثبت شده' }, { value: 'confirmed', label: 'قطعی شده' }]}
|
||||
value={status || null}
|
||||
onChange={v => setStatus(v ? String(v) : '')}
|
||||
placeholder="انتخاب وضعیت"
|
||||
height={38}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="field" style={{ height: 'auto', marginBottom: 16 }}>
|
||||
<textarea value={note} onChange={e => setNote(e.target.value)} rows={3} placeholder="توضیحات..."
|
||||
|
||||
Reference in New Issue
Block a user