Files
clinicpro/assets/admin/hooks/useSubscription.ts
T
hamedandClaude Opus 5 1ce9957538 fix(admin): drop cached environment data when switching context
A doctor who also owns a clinic runs two environments, and a subscription
belongs to an environment, not to the user. The panel treated it as the
user's: the subscription query was keyed ['subscription-my'] with no
context, and switching environments never touched the react-query cache. So
upgrading the clinic left the personal practice showing the clinic's plan
with its feature-gated menu items unlocked, and vice versa.

The query key now carries the active dbUuid, and the context switch clears
the whole cache — every cached response belongs to the environment it was
fetched in, not just this one.

The API was already correct: DualEnvironmentSubscriptionTest pins that
granting one environment leaves the other on free.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 22:15:56 +03:30

43 lines
2.0 KiB
TypeScript

import { useQuery } from '@tanstack/react-query';
import { api } from '../lib/api';
import type { ApiResponse } from '../lib/api';
import { useAuthStore } from '../stores/authStore';
import type { MySubscriptionData } from '../types';
export function useSubscription() {
const primaryRole = useAuthStore((s) => s.primaryRole);
const dbUuid = useAuthStore((s) => s.dbUuid);
const enabled = primaryRole === 'doctor' || primaryRole === 'clinic' || primaryRole === 'secretary';
// کلید شامل محیط فعال است: اشتراک روی محیط می‌نشیند، نه روی کاربر. پزشکی که هم
// مطب شخصی دارد و هم کلینیک، با کلیدِ بدون محیط پلنِ محیط قبلی را می‌دید و هر دو
// محیط ارتقایافته به‌نظر می‌رسیدند.
const { data } = useQuery<ApiResponse<MySubscriptionData>>({
queryKey: ['subscription-my', dbUuid],
queryFn: () => api.get('/api/v1/subscription/my'),
enabled,
staleTime: 2 * 60 * 1000,
});
const sub = data?.data?.subscription ?? null;
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,
};
}