The three admin endpoints shipped without anywhere to call them from, so the person who is supposed to maintain the national calendar could only do it with curl or a console command. That is not "the director can register the year's holidays". /admin/national-holidays is ROLE_ADMIN only and sits under the System group in the admin nav. The year lives in the query string, so back and refresh return to the year being edited. Editing takes only the title: `date` is the unique key, so moving a holiday is really deleting one and creating another, and the form says so rather than silently creating a duplicate. The date field is the shared Jalali picker, which speaks Gregorian, so the page converts before POSTing the jalali_date the API expects — and shows the converted value under the field so the user can see what will be stored. Deleting warns that the day leaves every clinic's calendar, because it does. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
62 lines
2.5 KiB
TypeScript
62 lines
2.5 KiB
TypeScript
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
import { toast } from 'sonner';
|
|
import { api, ApiError, type ApiResponse } from '../lib/api';
|
|
import type { NationalHoliday } from '../types';
|
|
|
|
/**
|
|
* تقویم تعطیلات رسمی از دید **مدیر سیستم** — تنها جایی که ساخته و حذف میشود.
|
|
*
|
|
* ⚠️ با `useHolidays` اشتباه نشود: آن مالِ یک محیط است و فقط «این روز برای ما باز
|
|
* است» را ثبت میکند (`holiday-overrides`). خودِ تعطیلی سراسری است و محیط ندارد.
|
|
*/
|
|
export function useNationalHolidays(year: number) {
|
|
const qc = useQueryClient();
|
|
const key = ['national-holidays', year];
|
|
|
|
const invalidate = () => {
|
|
qc.invalidateQueries({ queryKey: key });
|
|
// کارت تعطیلات در تب پزشک و منبع هم از همین سال میخواند.
|
|
qc.invalidateQueries({ queryKey: ['national-holidays'] });
|
|
};
|
|
|
|
const fail = (e: unknown, fallback: string) =>
|
|
toast.error(e instanceof ApiError ? e.message : fallback);
|
|
|
|
const query = useQuery({
|
|
queryKey: key,
|
|
queryFn: () =>
|
|
api.get<ApiResponse<{ year: number; holidays: NationalHoliday[] }>>(
|
|
`/api/v1/national-holidays?year=${year}`,
|
|
),
|
|
});
|
|
|
|
const create = useMutation({
|
|
mutationFn: (d: { jalali_date: string; title: string }) =>
|
|
api.post<ApiResponse<NationalHoliday>>('/api/v1/admin/national-holidays', d),
|
|
// سرور upsert میکند: همان روز دوباره یعنی تغییر عنوان، نه ردیف دوم.
|
|
onSuccess: () => { toast.success('تعطیلی ثبت شد'); invalidate(); },
|
|
onError: (e) => fail(e, 'ثبت تعطیلی ناموفق بود'),
|
|
});
|
|
|
|
const update = useMutation({
|
|
mutationFn: ({ uuid, title }: { uuid: string; title: string }) =>
|
|
api.patch<ApiResponse<NationalHoliday>>(`/api/v1/admin/national-holiday/${uuid}`, { title }),
|
|
onSuccess: () => { toast.success('عنوان بهروزرسانی شد'); invalidate(); },
|
|
onError: (e) => fail(e, 'بهروزرسانی ناموفق بود'),
|
|
});
|
|
|
|
const remove = useMutation({
|
|
mutationFn: (uuid: string) => api.delete<ApiResponse<null>>(`/api/v1/admin/national-holiday/${uuid}`),
|
|
onSuccess: () => { toast.success('تعطیلی حذف شد'); invalidate(); },
|
|
onError: (e) => fail(e, 'حذف تعطیلی ناموفق بود'),
|
|
});
|
|
|
|
return {
|
|
holidays: query.data?.data?.holidays ?? [],
|
|
loading: query.isLoading,
|
|
create,
|
|
update,
|
|
remove,
|
|
};
|
|
}
|