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:
hamed
2026-07-16 08:56:59 +03:30
parent 7b8a5c2775
commit b1b99903ec
21 changed files with 571 additions and 288 deletions
+44 -67
View File
@@ -26,6 +26,7 @@ import AppointmentStatusDropdown from "./ui/AppointmentStatusDropdown";
import Modal from "./ui/Modal";
import PersianDateInput from "./ui/PersianDateInput";
import PriceInput from "./ui/PriceInput";
import SearchableSelect from "./ui/SearchableSelect";
/** Row actions for the appointments table (Figma عملیات menu). */
type ModalKind = null | "info" | "move" | "transfer" | "replace";
@@ -732,16 +733,6 @@ export function ReplaceAppointmentModal({
});
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 lockedField = { margin: "6px 0 12px", opacity: 0.6 } as const;
const patients = patientsQ.data?.data ?? [];
@@ -847,39 +838,32 @@ export function ReplaceAppointmentModal({
>
<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}>سرویس</label>
<select
aria-label="سرویس"
style={{ ...sel, marginTop: 6 }}
value={itemUuid}
onChange={(e) => setItemUuid(e.target.value)}
disabled={!sectionUuid}
>
<option value="">انتخاب زیر بخش</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={itemUuid || null}
onChange={(v) => setItemUuid(v ? String(v) : "")}
placeholder="انتخاب زیر بخش"
isDisabled={!sectionUuid}
isLoading={itemsQ.isLoading}
isClearable
height={38}
/>
</div>
</div>
</div>
@@ -958,35 +942,28 @@ export function ReplaceAppointmentModal({
</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>
<label style={label}>انتخاب وضعیت</label>
<select
aria-label="وضعیت"
style={{ ...sel, margin: "6px 0 12px" }}
value={status}
onChange={(e) =>
setStatus(e.target.value as Appointment["status"])
}
>
{statusOptions.map(([v, l]) => (
<option key={v} value={v}>
{l}
</option>
))}
</select>
<div style={{ margin: "6px 0 12px" }}>
<SearchableSelect
options={statusOptions.map(([v, l]) => ({ value: v, label: l }))}
value={status || null}
onChange={(v) => setStatus((v ? String(v) : "") as Appointment["status"])}
placeholder="انتخاب وضعیت"
height={38}
/>
</div>
<label style={label}>توضیحات</label>
<div