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>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { QueryClientProvider } from '@tanstack/react-query';
|
||||
import { MemoryRouter } from 'react-router';
|
||||
import { makeClient } from '../test/utils';
|
||||
import { useAuthStore } from '../stores/authStore';
|
||||
import SelectContextPage from './SelectContextPage';
|
||||
|
||||
vi.mock('react-router', async () => {
|
||||
const actual = await vi.importActual<typeof import('react-router')>('react-router');
|
||||
return { ...actual, useNavigate: () => vi.fn() };
|
||||
});
|
||||
|
||||
const initial = useAuthStore.getInitialState();
|
||||
|
||||
const CONTEXTS = [
|
||||
{ db_uuid: 'doc-1', db_key: 'k1', type: 'doctor', role: 'doctor', name: 'مطب شخصی' },
|
||||
{ db_uuid: 'clinic-1', db_key: 'k2', type: 'clinic', role: 'clinic', name: 'کلینیک تست' },
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
useAuthStore.setState(initial, true);
|
||||
useAuthStore.setState({ availableContexts: CONTEXTS as any, switchContext: vi.fn() as any });
|
||||
});
|
||||
|
||||
describe('SelectContextPage', () => {
|
||||
/**
|
||||
* هر پاسخِ cache شده متعلق به محیط قبلی است. اشتراک روی محیط مینشیند، پس بدون
|
||||
* پاک کردن cache، مطب شخصی پلن کلینیک را نشان میداد و برعکس.
|
||||
*/
|
||||
it('بعد از تعویض محیط، cache کوئریها را پاک میکند', async () => {
|
||||
const client = makeClient();
|
||||
client.setQueryData(['subscription-my', 'doc-1'], { stale: true });
|
||||
|
||||
render(<SelectContextPage />, {
|
||||
wrapper: ({ children }) => (
|
||||
<QueryClientProvider client={client}>
|
||||
<MemoryRouter>{children}</MemoryRouter>
|
||||
</QueryClientProvider>
|
||||
),
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByText('کلینیک تست'));
|
||||
|
||||
await waitFor(() => expect(client.getQueryData(['subscription-my', 'doc-1'])).toBeUndefined());
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useNavigate } from 'react-router';
|
||||
import { useState } from 'react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useAuthStore, ContextItem } from '../stores/authStore';
|
||||
|
||||
const ROLE_LABELS: Record<string, string> = {
|
||||
@@ -18,11 +19,15 @@ const TYPE_ICONS: Record<string, string> = {
|
||||
export default function SelectContextPage() {
|
||||
const { availableContexts, switchContext } = useAuthStore();
|
||||
const navigate = useNavigate();
|
||||
const qc = useQueryClient();
|
||||
const [loading, setLoading] = useState<string | null>(null);
|
||||
|
||||
const handleSelect = async (ctx: ContextItem) => {
|
||||
setLoading(ctx.db_uuid);
|
||||
await switchContext(ctx.db_uuid);
|
||||
// هر پاسخِ cacheشده متعلق به محیط قبلی است — از اشتراک و پلن گرفته تا بیماران و
|
||||
// نوبتها. بدون پاک کردن، محیط تازه داده و دسترسیهای محیط قبلی را نشان میدهد.
|
||||
qc.clear();
|
||||
navigate('/admin/dashboard', { replace: true });
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user