feat: refactor ResourceExceptionsPanel and related hooks; remove unused availability logic and simplify resource detail management

This commit is contained in:
hamed
2026-08-03 10:36:13 +03:30
parent 00c275d618
commit 8509a04ae2
6 changed files with 99 additions and 221 deletions
+1 -14
View File
@@ -2,7 +2,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
import { api, ApiError, type ApiResponse } from '../lib/api';
import type {
HolidayOverride, NationalHoliday, ResourceAvailability,
HolidayOverride, NationalHoliday,
ResourceCalendarDays, ResourceException, WorkingHoursPayload,
} from '../types';
@@ -27,7 +27,6 @@ export function useResourceCalendar(resourceUuid: string | undefined) {
onSuccess: () => {
toast.success('شیفت‌ها ذخیره شد');
qc.invalidateQueries({ queryKey: key });
qc.invalidateQueries({ queryKey: ['resource-availability', resourceUuid] });
},
onError: (e) => fail(e, 'ذخیرهٔ شیفت‌ها ناموفق بود'),
});
@@ -41,7 +40,6 @@ export function useResourceExceptions(resourceUuid: string | undefined) {
const invalidate = () => {
qc.invalidateQueries({ queryKey: key });
qc.invalidateQueries({ queryKey: ['resource-availability', resourceUuid] });
};
const query = useQuery({
@@ -66,17 +64,6 @@ export function useResourceExceptions(resourceUuid: string | undefined) {
return { exceptions: query.data?.data ?? [], loading: query.isLoading, create, remove };
}
export function useResourceAvailability(resourceUuid: string | undefined, from: number, to: number) {
const query = useQuery({
queryKey: ['resource-availability', resourceUuid, from, to],
queryFn: () =>
api.get<ApiResponse<ResourceAvailability>>(`/api/v1/resource/${resourceUuid}/availability?from=${from}&to=${to}`),
enabled: !!resourceUuid,
});
return { availability: query.data?.data, loading: query.isLoading };
}
export function useHolidays(year: number) {
const qc = useQueryClient();
const key = ['national-holidays', year];
+14 -7
View File
@@ -10,6 +10,8 @@ import type {
* آدرس محل نوبت‌دهی است — پس فیلترها با `address_uuid` کار می‌کنند نه `branch_id`.
*/
const RESOURCES_KEY = 'resources';
/** کلیدِ کوئریِ صفحهٔ جزئیات — `useResourceDetail` هم از همین می‌سازد. */
const RESOURCE_DETAIL_KEY = 'resource-detail';
const TYPES_KEY = ['resource-types'];
const SKILLS_KEY = ['skills'];
const POOLS_KEY = ['resource-pools'];
@@ -36,7 +38,16 @@ function toQuery(filters: ResourceFilters): string {
export function useResources(filters: ResourceFilters = {}) {
const qc = useQueryClient();
const invalidate = () => qc.invalidateQueries({ queryKey: [RESOURCES_KEY] });
/**
* هر جهش روی یک منبع، هم فهرست را کهنه می‌کند هم صفحهٔ جزئیاتِ همان منبع را —
* دو کوئری با دو کلید جدا (`resources` و `resource-detail`). فقط باطل‌کردن فهرست
* یعنی صفحهٔ جزئیات تا رفرشِ دستی مقدار قدیمی را نشان می‌دهد.
*/
const invalidate = () => {
qc.invalidateQueries({ queryKey: [RESOURCES_KEY] });
qc.invalidateQueries({ queryKey: [RESOURCE_DETAIL_KEY] });
};
const query = useQuery({
queryKey: [RESOURCES_KEY, filters],
@@ -77,11 +88,7 @@ export function useResources(filters: ResourceFilters = {}) {
const setCategories = useMutation({
mutationFn: ({ uuid, categoryUuids }: { uuid: string; categoryUuids: string[] }) =>
api.put<ApiResponse<ClinicResource>>(`/api/v1/resource/${uuid}/categories`, { category_uuids: categoryUuids }),
onSuccess: () => {
toast.success('دسته‌بندی‌های منبع ذخیره شد');
invalidate();
qc.invalidateQueries({ queryKey: ['resource-detail'] });
},
onSuccess: () => { toast.success('دسته‌بندی‌های منبع ذخیره شد'); invalidate(); },
onError: (e) => fail(e, 'ذخیرهٔ دسته‌بندی‌ها ناموفق بود'),
});
@@ -234,7 +241,7 @@ export function useResourcePools() {
*/
export function useResourceDetail(uuid: string | undefined) {
const query = useQuery({
queryKey: ['resource-detail', uuid],
queryKey: [RESOURCE_DETAIL_KEY, uuid],
queryFn: () =>
api.get<ApiResponse<ClinicResource & { upcoming_appointments: number }>>(
`/api/v1/resource/${uuid}`,