feat: Enhance appointment management by decoupling online booking toggle for admin context
- Introduced management mode for appointment slots, allowing doctors, admins, and clinic managers to view and book slots regardless of the online booking status. - Updated SlotCalculatorService to accept a management context parameter, bypassing online booking restrictions. - Modified appointment-related endpoints to handle management context and ensure proper authorization checks. - Added tests to verify that management users can access slots even when online booking is disabled, while public users are still restricted. - Improved documentation for API endpoints to reflect new management parameters and behaviors.
This commit is contained in:
@@ -500,6 +500,28 @@ function SessionEditor({ session, onChange, onRemove, addresses, serviceMode = f
|
||||
const withClinic = (url: string, clinicUuid?: string | null): string =>
|
||||
clinicUuid ? `${url}${url.includes('?') ? '&' : '?'}clinic_uuid=${encodeURIComponent(clinicUuid)}` : url;
|
||||
|
||||
/**
|
||||
* وقتی محیط انتخابشده مکانِ نوبت فعالی ندارد. متن به محیط بستگی دارد: پزشک عضو
|
||||
* کلینیک آدرس مستقل ثبت نمیکند، پس در محیط کلینیک نباید «ابتدا آدرس مطب را ثبت
|
||||
* کنید» ببیند — آدرس از تنظیمات همان کلینیک میآید.
|
||||
*/
|
||||
function NoLocationsNotice({ clinicUuid }: { clinicUuid?: string | null }) {
|
||||
const [title, hint] = clinicUuid
|
||||
? ['این کلینیک هنوز مکان نوبتدهی فعال ندارد', 'ابتدا در تنظیمات کلینیک یک آدرس فعال ثبت شود']
|
||||
: ['ابتدا آدرس مطب را ثبت کنید', 'برنامه کاری نیاز به حداقل یک مکان نوبت دارد'];
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center gap-3 py-12 text-center">
|
||||
<div className="w-12 h-12 rounded-full bg-amber-50 dark:bg-amber-500/10 border border-amber-200 dark:border-amber-500/30 flex items-center justify-center">
|
||||
<MapPinIcon className="w-6 h-6 text-amber-500" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-slate-700 dark:text-slate-200">{title}</p>
|
||||
<p className="text-xs text-slate-400 dark:text-slate-500 mt-1">{hint}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function WeeklyScheduleTab({ doctorUuid, clinicUuid, addresses, readOnly = false }: { doctorUuid: string; clinicUuid?: string | null; addresses: AddressData[]; readOnly?: boolean }) {
|
||||
const qc = useQueryClient();
|
||||
const [scheduleMap, setScheduleMap] = useState<NewScheduleMap>(EMPTY_NEW_SCHEDULE);
|
||||
@@ -595,17 +617,7 @@ export function WeeklyScheduleTab({ doctorUuid, clinicUuid, addresses, readOnly
|
||||
<div className="space-y-3">{Array.from({ length: 4 }).map((_, i) => <div key={i} className="h-12 rounded-xl skeleton" />)}</div>
|
||||
);
|
||||
|
||||
if (addresses.length === 0) return (
|
||||
<div className="flex flex-col items-center justify-center gap-3 py-12 text-center">
|
||||
<div className="w-12 h-12 rounded-full bg-amber-50 dark:bg-amber-500/10 border border-amber-200 dark:border-amber-500/30 flex items-center justify-center">
|
||||
<MapPinIcon className="w-6 h-6 text-amber-500" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-slate-700 dark:text-slate-200">ابتدا آدرس مطب را ثبت کنید</p>
|
||||
<p className="text-xs text-slate-400 dark:text-slate-500 mt-1">برنامه کاری نیاز به حداقل یک مکان نوبت دارد</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
if (addresses.length === 0) return <NoLocationsNotice clinicUuid={clinicUuid} />;
|
||||
|
||||
// نمای فقطخواندنی برای نماینده: برنامهی هفتگی بهصورت متن، بدون فرم.
|
||||
if (readOnly) {
|
||||
@@ -1047,17 +1059,7 @@ function DateOverridesTab({ doctorUuid, clinicUuid, addresses, readOnly = false
|
||||
<div className="space-y-2">{Array.from({ length: 3 }).map((_, i) => <div key={i} className="h-14 rounded-xl skeleton" />)}</div>
|
||||
);
|
||||
|
||||
if (addresses.length === 0) return (
|
||||
<div className="flex flex-col items-center justify-center gap-3 py-12 text-center">
|
||||
<div className="w-12 h-12 rounded-full bg-amber-50 dark:bg-amber-500/10 border border-amber-200 dark:border-amber-500/30 flex items-center justify-center">
|
||||
<MapPinIcon className="w-6 h-6 text-amber-500" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-slate-700 dark:text-slate-200">ابتدا آدرس مطب را ثبت کنید</p>
|
||||
<p className="text-xs text-slate-400 dark:text-slate-500 mt-1">برنامه کاری نیاز به حداقل یک مکان نوبت دارد</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
if (addresses.length === 0) return <NoLocationsNotice clinicUuid={clinicUuid} />;
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
|
||||
Reference in New Issue
Block a user