import { useMemo } from 'react'; import { useQuery } from '@tanstack/react-query'; import { api } from '../lib/api'; import type { ApiResponse } from '../lib/api'; export interface CatalogAction { key: string; label: string; } export interface CatalogResource { key: string; label: string; /** فقط در محیط کلینیک معنا دارد — پزشک مستقل نباید ببیندش. */ clinic_only: boolean; actions: CatalogAction[]; } interface CatalogPayload { version: number; resources: CatalogResource[]; } /** * فهرستِ منابعِ قابل‌مجوزدهی — منبعِ واحدِ هر دو فرمِ مجوز (منشی و پزشکِ عضو کلینیک). * * تا پیش از این همین فهرست در سه فایل UI هاردکد بود و با بک‌اند واگرا می‌شد، پس * صفحهٔ تازه مجوزِ صفحهٔ دیگری را قرض می‌گرفت. حالا افزودن یک ردیف به * PermissionCatalog در بک‌اند کافی است. * * پاسخ به کاربر بستگی ندارد و تا وقتی رجیستری عوض نشود ثابت است. */ export function usePermissionCatalog() { const query = useQuery({ queryKey: ['permission-catalog'], queryFn: () => api.get>('/api/v1/permission-catalog'), staleTime: Infinity, }); // مرجعِ آرایه باید پایدار بماند: مصرف‌کننده‌ها آن را در وابستگیِ useEffect // می‌گذارند و یک `?? []` تازه در هر رندر، حلقهٔ بی‌پایان می‌سازد. const resources = useMemo( () => query.data?.data?.resources ?? [], [query.data], ); return { resources, version: query.data?.data?.version ?? 1, isLoading: query.isLoading, isError: query.isError, }; } /** شکلِ کاملِ کاتالوگ با همهٔ اکشن‌ها خاموش — مبنای فرمِ «هیچ دسترسی». */ export function blankPermissions(resources: CatalogResource[]): Record> { const out: Record> = {}; for (const resource of resources) { out[resource.key] = {}; for (const action of resource.actions) { out[resource.key][action.key] = false; } } return out; } /** * مقدارِ ذخیره‌شده را روی شکلِ کاتالوگ می‌نشاند. * * قرینهٔ PermissionCatalog::merge در بک‌اند: کلیدِ نبوده `false` می‌شود تا سوییچ * از uncontrolled به controlled نپرد، و کلیدِ خارج از کاتالوگ نمایش داده نمی‌شود. */ export function alignPermissions( stored: Record> | undefined | null, resources: CatalogResource[], ): Record> { const out: Record> = {}; for (const resource of resources) { out[resource.key] = {}; for (const action of resource.actions) { out[resource.key][action.key] = Boolean(stored?.[resource.key]?.[action.key]); } } return out; }