feat(subscription): implement resource quota management based on subscription plans
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { toast } from 'sonner';
|
||||
import { api, ApiError, type ApiResponse } from '../lib/api';
|
||||
import { useSubscription } from './useSubscription';
|
||||
import type {
|
||||
ClinicResource, ResourcePool, ResourcePayload, ResourceServiceOffering, ResourceType, Skill,
|
||||
} from '../types';
|
||||
@@ -99,6 +100,36 @@ export function useResources(filters: ResourceFilters = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* سهمیهٔ منابع محیط — سقفش از پلن اشتراک میآید و مصرفش از فهرست منابع.
|
||||
*
|
||||
* فهرست عمداً بیفیلتر خوانده میشود: سهمیه به کل محیط مربوط است و شمردنِ ردیفهای
|
||||
* فیلترشدهٔ صفحه، با هر فیلتر یک عدد متفاوت میداد. کوئری با کلیدِ `[resources, {}]`
|
||||
* همان کوئریِ حالتِ بیفیلترِ صفحه است، پس معمولاً رفتوبرگشت اضافهای نمیسازد.
|
||||
*
|
||||
* تصمیم نهایی با سرور است؛ این فقط دکمه را پیش از رفتن به فرم میبندد.
|
||||
*/
|
||||
export function useResourceQuota() {
|
||||
const { maxResources, planLoaded } = useSubscription();
|
||||
|
||||
const { data } = useQuery({
|
||||
queryKey: [RESOURCES_KEY, {}],
|
||||
queryFn: () => api.get<ApiResponse<ClinicResource[]>>('/api/v1/resources'),
|
||||
});
|
||||
|
||||
const used = data?.data?.length ?? 0;
|
||||
// سقفِ ناشناخته (نقش بیاشتراک، یا پاسخِ هنوز نرسیده) گیت نمیشود؛ سرور خودش
|
||||
// ۴۲۲ میدهد و بستنِ دکمه بر اساس حدس، بدتر از بستنش دیرتر است.
|
||||
const unlimited = !planLoaded || maxResources < 0;
|
||||
|
||||
return {
|
||||
used,
|
||||
limit: maxResources,
|
||||
unlimited,
|
||||
atLimit: !unlimited && used >= maxResources,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* سرویسهایی که یک منبع ارائه میدهد.
|
||||
*
|
||||
|
||||
@@ -19,12 +19,19 @@ export function useSubscription() {
|
||||
const effectivePlan = data?.data?.effective_plan ?? sub?.plan ?? null;
|
||||
const features: Record<string, boolean> = effectivePlan?.features ?? {};
|
||||
const maxSecretaries: number = effectivePlan?.max_secretaries ?? 1;
|
||||
// `-1` یعنی بینهایت.
|
||||
const maxResources: number = effectivePlan?.max_resources ?? 1;
|
||||
// نقشهایی که اشتراک ندارند (ادمین) و لحظهٔ پیش از رسیدن پاسخ: سقف ناشناخته است و
|
||||
// نباید با پیشفرضِ ۱ بهجای کاربر تصمیم گرفت — گیتکردن کارِ سرور است.
|
||||
const planLoaded = effectivePlan !== null;
|
||||
const hasPlan = sub !== null;
|
||||
|
||||
return {
|
||||
subscription: sub,
|
||||
hasFeature: (key: string) => features[key] ?? false,
|
||||
maxSecretaries,
|
||||
maxResources,
|
||||
planLoaded,
|
||||
hasPlan,
|
||||
isExpiringSoon: (sub?.days_remaining ?? 0) > 0 && (sub?.days_remaining ?? 0) <= 7,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user