Fix demo mode showing real user data after logout
React Query cache was shared between /app (real API) and /demo/app (mock data) because query keys were identical. After login→logout→demo, stale real data served from cache. Two fixes: 1. Clear React Query cache on logout (auth store) 2. Namespace all query keys with basePath prefix so /app and /demo/app caches are completely isolated Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,7 @@ import {
|
||||
type DragEndEvent,
|
||||
} from "@dnd-kit/core";
|
||||
import { useMarkInProgress } from "@/lib/hooks/use-tasks";
|
||||
import { useDataProvider } from "@/lib/demo/data-provider-context";
|
||||
import { useDataProvider, useQueryKeyPrefix } from "@/lib/demo/data-provider-context";
|
||||
import { KanbanColumn } from "./kanban-column";
|
||||
import type { KanbanResponse, KanbanColumn as KanbanColumnType } from "@/lib/api/tasks";
|
||||
|
||||
@@ -24,6 +24,7 @@ export function KanbanBoard({ data }: KanbanBoardProps) {
|
||||
const router = useRouter();
|
||||
const queryClient = useQueryClient();
|
||||
const { basePath } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
const markInProgress = useMarkInProgress();
|
||||
|
||||
// Local columns state for instant optimistic updates
|
||||
@@ -88,7 +89,7 @@ export function KanbanBoard({ data }: KanbanBoardProps) {
|
||||
markInProgress.mutate(taskId, {
|
||||
onError: () => setColumns(data.columns),
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["tasks"] });
|
||||
queryClient.invalidateQueries({ queryKey: qk("tasks") });
|
||||
},
|
||||
});
|
||||
return;
|
||||
@@ -98,9 +99,9 @@ export function KanbanBoard({ data }: KanbanBoardProps) {
|
||||
// (no API endpoint for moving to overdue/due_soon/upcoming — those are computed server-side)
|
||||
moveTask(taskId, sourceCol.name, targetColumn);
|
||||
// Refetch to get correct server state
|
||||
queryClient.invalidateQueries({ queryKey: ["tasks"] });
|
||||
queryClient.invalidateQueries({ queryKey: qk("tasks") });
|
||||
},
|
||||
[columns, data.columns, moveTask, markInProgress, queryClient, router, basePath]
|
||||
[columns, data.columns, moveTask, markInProgress, queryClient, qk, router, basePath]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { createContext, useContext } from 'react';
|
||||
import { createContext, useContext, useMemo } from 'react';
|
||||
import type { DataProvider } from './data-provider';
|
||||
|
||||
const DataProviderContext = createContext<DataProvider | null>(null);
|
||||
@@ -13,6 +13,12 @@ export function useDataProvider(): DataProvider {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/** Returns a function that prefixes query keys with the current provider's basePath. */
|
||||
export function useQueryKeyPrefix(): (...key: unknown[]) => unknown[] {
|
||||
const { basePath } = useDataProvider();
|
||||
return useMemo(() => (...key: unknown[]) => [basePath, ...key], [basePath]);
|
||||
}
|
||||
|
||||
export function DataProviderProvider({
|
||||
value,
|
||||
children,
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useDataProvider } from '@/lib/demo/data-provider-context';
|
||||
import { useDataProvider, useQueryKeyPrefix } from '@/lib/demo/data-provider-context';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
export function useCurrentUser() {
|
||||
const { auth } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['auth', 'user'],
|
||||
queryKey: qk('auth', 'user'),
|
||||
queryFn: () => auth.getCurrentUser(),
|
||||
retry: false,
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useDataProvider } from '@/lib/demo/data-provider-context';
|
||||
import { useDataProvider, useQueryKeyPrefix } from '@/lib/demo/data-provider-context';
|
||||
import type { CreateContractorRequest, UpdateContractorRequest } from '@/lib/api/contractors';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -10,8 +10,9 @@ import type { CreateContractorRequest, UpdateContractorRequest } from '@/lib/api
|
||||
|
||||
export function useContractors() {
|
||||
const { contractors } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['contractors'],
|
||||
queryKey: qk('contractors'),
|
||||
queryFn: () => contractors.list(),
|
||||
select: (data) => (Array.isArray(data) ? data : []),
|
||||
});
|
||||
@@ -19,8 +20,9 @@ export function useContractors() {
|
||||
|
||||
export function useContractor(id: number) {
|
||||
const { contractors } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['contractors', id],
|
||||
queryKey: qk('contractors', id),
|
||||
queryFn: () => contractors.get(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
@@ -28,8 +30,9 @@ export function useContractor(id: number) {
|
||||
|
||||
export function useContractorTasks(id: number) {
|
||||
const { contractors } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['contractors', id, 'tasks'],
|
||||
queryKey: qk('contractors', id, 'tasks'),
|
||||
queryFn: () => contractors.getTasks(id),
|
||||
enabled: !!id,
|
||||
select: (data) => (Array.isArray(data) ? data : []),
|
||||
@@ -43,11 +46,12 @@ export function useContractorTasks(id: number) {
|
||||
export function useCreateContractor() {
|
||||
const queryClient = useQueryClient();
|
||||
const { contractors } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (data: CreateContractorRequest) =>
|
||||
contractors.create(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['contractors'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('contractors') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -55,12 +59,13 @@ export function useCreateContractor() {
|
||||
export function useUpdateContractor(id: number) {
|
||||
const queryClient = useQueryClient();
|
||||
const { contractors } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (data: UpdateContractorRequest) =>
|
||||
contractors.update(id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['contractors'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['contractors', id] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('contractors') });
|
||||
queryClient.invalidateQueries({ queryKey: qk('contractors', id) });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -68,10 +73,11 @@ export function useUpdateContractor(id: number) {
|
||||
export function useDeleteContractor() {
|
||||
const queryClient = useQueryClient();
|
||||
const { contractors } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => contractors.delete(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['contractors'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('contractors') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -79,10 +85,11 @@ export function useDeleteContractor() {
|
||||
export function useToggleFavorite() {
|
||||
const queryClient = useQueryClient();
|
||||
const { contractors } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => contractors.toggleFavorite(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['contractors'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('contractors') });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useDataProvider } from '@/lib/demo/data-provider-context';
|
||||
import { useDataProvider, useQueryKeyPrefix } from '@/lib/demo/data-provider-context';
|
||||
import type { DocumentListParams, CreateDocumentRequest, UpdateDocumentRequest } from '@/lib/api/documents';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -10,8 +10,9 @@ import type { DocumentListParams, CreateDocumentRequest, UpdateDocumentRequest }
|
||||
|
||||
export function useDocuments(params?: DocumentListParams) {
|
||||
const { documents } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['documents', params],
|
||||
queryKey: qk('documents', params),
|
||||
queryFn: () => documents.list(params),
|
||||
select: (data) => (Array.isArray(data) ? data : []),
|
||||
});
|
||||
@@ -19,8 +20,9 @@ export function useDocuments(params?: DocumentListParams) {
|
||||
|
||||
export function useWarranties() {
|
||||
const { documents } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['documents', 'warranties'],
|
||||
queryKey: qk('documents', 'warranties'),
|
||||
queryFn: () => documents.listWarranties(),
|
||||
select: (data) => (Array.isArray(data) ? data : []),
|
||||
});
|
||||
@@ -28,7 +30,8 @@ export function useWarranties() {
|
||||
|
||||
export function useDocument(id: number) {
|
||||
const { documents } = useDataProvider();
|
||||
return useQuery({ queryKey: ['documents', id], queryFn: () => documents.get(id), enabled: !!id });
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({ queryKey: qk('documents', id), queryFn: () => documents.get(id), enabled: !!id });
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -38,6 +41,7 @@ export function useDocument(id: number) {
|
||||
export function useCreateDocument() {
|
||||
const queryClient = useQueryClient();
|
||||
const { documents } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: ({ data, file }: { data: CreateDocumentRequest; file?: File }) => {
|
||||
if (file) {
|
||||
@@ -46,7 +50,7 @@ export function useCreateDocument() {
|
||||
return documents.create(data);
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['documents'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('documents') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -54,12 +58,13 @@ export function useCreateDocument() {
|
||||
export function useUpdateDocument(id: number) {
|
||||
const queryClient = useQueryClient();
|
||||
const { documents } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (data: UpdateDocumentRequest) =>
|
||||
documents.update(id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['documents'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['documents', id] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('documents') });
|
||||
queryClient.invalidateQueries({ queryKey: qk('documents', id) });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -67,10 +72,11 @@ export function useUpdateDocument(id: number) {
|
||||
export function useDeleteDocument() {
|
||||
const queryClient = useQueryClient();
|
||||
const { documents } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => documents.delete(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['documents'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('documents') });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useDataProvider } from '@/lib/demo/data-provider-context';
|
||||
import { useDataProvider, useQueryKeyPrefix } from '@/lib/demo/data-provider-context';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Main hook — fetches all static data in a single request
|
||||
@@ -9,8 +9,9 @@ import { useDataProvider } from '@/lib/demo/data-provider-context';
|
||||
|
||||
export function useLookups() {
|
||||
const { lookups } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['lookups', 'static-data'],
|
||||
queryKey: qk('lookups', 'static-data'),
|
||||
queryFn: () => lookups.getStaticData(),
|
||||
staleTime: Infinity, // ETag-based; never auto-refetch
|
||||
});
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useDataProvider } from '@/lib/demo/data-provider-context';
|
||||
import { useDataProvider, useQueryKeyPrefix } from '@/lib/demo/data-provider-context';
|
||||
import type { UpdatePreferencesRequest } from '@/lib/api/notifications';
|
||||
|
||||
export function useNotifications(limit?: number) {
|
||||
const { notifications } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['notifications', limit],
|
||||
queryKey: qk('notifications', limit),
|
||||
queryFn: () => notifications.list(limit),
|
||||
});
|
||||
}
|
||||
|
||||
export function useUnreadCount() {
|
||||
const { notifications } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['notifications', 'unread-count'],
|
||||
queryKey: qk('notifications', 'unread-count'),
|
||||
queryFn: () => notifications.getUnreadCount(),
|
||||
refetchInterval: 60_000,
|
||||
});
|
||||
@@ -23,8 +25,9 @@ export function useUnreadCount() {
|
||||
|
||||
export function useNotificationPreferences() {
|
||||
const { notifications } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['notifications', 'preferences'],
|
||||
queryKey: qk('notifications', 'preferences'),
|
||||
queryFn: () => notifications.getPreferences(),
|
||||
});
|
||||
}
|
||||
@@ -32,10 +35,11 @@ export function useNotificationPreferences() {
|
||||
export function useUpdatePreferences() {
|
||||
const queryClient = useQueryClient();
|
||||
const { notifications } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (data: UpdatePreferencesRequest) => notifications.updatePreferences(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['notifications', 'preferences'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('notifications', 'preferences') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -43,11 +47,12 @@ export function useUpdatePreferences() {
|
||||
export function useMarkAsRead() {
|
||||
const queryClient = useQueryClient();
|
||||
const { notifications } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => notifications.markAsRead(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['notifications'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['notifications', 'unread-count'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('notifications') });
|
||||
queryClient.invalidateQueries({ queryKey: qk('notifications', 'unread-count') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -55,11 +60,12 @@ export function useMarkAsRead() {
|
||||
export function useMarkAllAsRead() {
|
||||
const queryClient = useQueryClient();
|
||||
const { notifications } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: () => notifications.markAllAsRead(),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['notifications'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['notifications', 'unread-count'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('notifications') });
|
||||
queryClient.invalidateQueries({ queryKey: qk('notifications', 'unread-count') });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useDataProvider } from '@/lib/demo/data-provider-context';
|
||||
import { useDataProvider, useQueryKeyPrefix } from '@/lib/demo/data-provider-context';
|
||||
import type { CreateResidenceRequest, UpdateResidenceRequest } from '@/lib/api/residences';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -10,8 +10,9 @@ import type { CreateResidenceRequest, UpdateResidenceRequest } from '@/lib/api/r
|
||||
|
||||
export function useResidences() {
|
||||
const { residences } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['residences'],
|
||||
queryKey: qk('residences'),
|
||||
queryFn: () => residences.getMyResidences(),
|
||||
select: (data) => (Array.isArray(data) ? data : []),
|
||||
});
|
||||
@@ -19,8 +20,9 @@ export function useResidences() {
|
||||
|
||||
export function useResidence(id: number) {
|
||||
const { residences } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['residences', id],
|
||||
queryKey: qk('residences', id),
|
||||
queryFn: () => residences.get(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
@@ -33,11 +35,12 @@ export function useResidence(id: number) {
|
||||
export function useCreateResidence() {
|
||||
const queryClient = useQueryClient();
|
||||
const { residences } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (data: CreateResidenceRequest) =>
|
||||
residences.create(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['residences'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('residences') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -45,12 +48,13 @@ export function useCreateResidence() {
|
||||
export function useUpdateResidence(id: number) {
|
||||
const queryClient = useQueryClient();
|
||||
const { residences } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (data: UpdateResidenceRequest) =>
|
||||
residences.update(id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['residences'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['residences', id] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('residences') });
|
||||
queryClient.invalidateQueries({ queryKey: qk('residences', id) });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -58,10 +62,11 @@ export function useUpdateResidence(id: number) {
|
||||
export function useDeleteResidence() {
|
||||
const queryClient = useQueryClient();
|
||||
const { residences } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => residences.delete(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['residences'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('residences') });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useDataProvider } from '@/lib/demo/data-provider-context';
|
||||
import { useDataProvider, useQueryKeyPrefix } from '@/lib/demo/data-provider-context';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Query hooks
|
||||
@@ -9,8 +9,9 @@ import { useDataProvider } from '@/lib/demo/data-provider-context';
|
||||
|
||||
export function useShareCode(residenceId: number) {
|
||||
const { sharing } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['residences', residenceId, 'share-code'],
|
||||
queryKey: qk('residences', residenceId, 'share-code'),
|
||||
queryFn: () => sharing.getShareCode(residenceId),
|
||||
enabled: !!residenceId,
|
||||
});
|
||||
@@ -18,8 +19,9 @@ export function useShareCode(residenceId: number) {
|
||||
|
||||
export function useResidenceUsers(residenceId: number) {
|
||||
const { sharing } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['residences', residenceId, 'users'],
|
||||
queryKey: qk('residences', residenceId, 'users'),
|
||||
queryFn: () => sharing.getResidenceUsers(residenceId),
|
||||
enabled: !!residenceId,
|
||||
});
|
||||
@@ -32,10 +34,11 @@ export function useResidenceUsers(residenceId: number) {
|
||||
export function useGenerateShareCode(residenceId: number) {
|
||||
const queryClient = useQueryClient();
|
||||
const { sharing } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: () => sharing.generateShareCode(residenceId),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['residences', residenceId, 'share-code'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('residences', residenceId, 'share-code') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -43,10 +46,11 @@ export function useGenerateShareCode(residenceId: number) {
|
||||
export function useRemoveResidenceUser(residenceId: number) {
|
||||
const queryClient = useQueryClient();
|
||||
const { sharing } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (userId: number) => sharing.removeUser(residenceId, userId),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['residences', residenceId, 'users'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('residences', residenceId, 'users') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -54,10 +58,11 @@ export function useRemoveResidenceUser(residenceId: number) {
|
||||
export function useJoinResidence() {
|
||||
const queryClient = useQueryClient();
|
||||
const { sharing } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (code: string) => sharing.joinWithCode({ code }),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['residences'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('residences') });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
"use client";
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useDataProvider } from '@/lib/demo/data-provider-context';
|
||||
import { useDataProvider, useQueryKeyPrefix } from '@/lib/demo/data-provider-context';
|
||||
|
||||
export function useSubscriptionStatus() {
|
||||
const { subscription } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['subscription', 'status'],
|
||||
queryKey: qk('subscription', 'status'),
|
||||
queryFn: () => subscription.getStatus(),
|
||||
});
|
||||
}
|
||||
|
||||
export function useFeatureBenefits() {
|
||||
const { subscription } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['subscription', 'features'],
|
||||
queryKey: qk('subscription', 'features'),
|
||||
queryFn: () => subscription.getFeatureBenefits(),
|
||||
staleTime: Infinity,
|
||||
});
|
||||
@@ -22,8 +24,9 @@ export function useFeatureBenefits() {
|
||||
|
||||
export function useUpgradeTriggers() {
|
||||
const { subscription } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['subscription', 'upgrade-triggers'],
|
||||
queryKey: qk('subscription', 'upgrade-triggers'),
|
||||
queryFn: () => subscription.getUpgradeTriggers(),
|
||||
staleTime: Infinity,
|
||||
});
|
||||
|
||||
+30
-18
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useDataProvider } from '@/lib/demo/data-provider-context';
|
||||
import { useDataProvider, useQueryKeyPrefix } from '@/lib/demo/data-provider-context';
|
||||
import type { CreateTaskRequest, UpdateTaskRequest, CreateCompletionRequest } from '@/lib/api/tasks';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -10,16 +10,18 @@ import type { CreateTaskRequest, UpdateTaskRequest, CreateCompletionRequest } fr
|
||||
|
||||
export function useTasks() {
|
||||
const { tasks } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['tasks'],
|
||||
queryKey: qk('tasks'),
|
||||
queryFn: () => tasks.list(),
|
||||
});
|
||||
}
|
||||
|
||||
export function useTasksByResidence(residenceId: number) {
|
||||
const { tasks } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['tasks', 'by-residence', residenceId],
|
||||
queryKey: qk('tasks', 'by-residence', residenceId),
|
||||
queryFn: () => tasks.getByResidence(residenceId),
|
||||
enabled: !!residenceId,
|
||||
});
|
||||
@@ -27,8 +29,9 @@ export function useTasksByResidence(residenceId: number) {
|
||||
|
||||
export function useTask(id: number) {
|
||||
const { tasks } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['tasks', id],
|
||||
queryKey: qk('tasks', id),
|
||||
queryFn: () => tasks.get(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
@@ -36,8 +39,9 @@ export function useTask(id: number) {
|
||||
|
||||
export function useKanbanBoard(residenceId: number) {
|
||||
const { tasks } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['tasks', 'kanban', residenceId],
|
||||
queryKey: qk('tasks', 'kanban', residenceId),
|
||||
queryFn: () => tasks.getByResidence(residenceId),
|
||||
enabled: !!residenceId,
|
||||
});
|
||||
@@ -45,8 +49,9 @@ export function useKanbanBoard(residenceId: number) {
|
||||
|
||||
export function useTaskCompletions(taskId: number) {
|
||||
const { tasks } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useQuery({
|
||||
queryKey: ['tasks', taskId, 'completions'],
|
||||
queryKey: qk('tasks', taskId, 'completions'),
|
||||
queryFn: () => tasks.getCompletions(taskId),
|
||||
enabled: !!taskId,
|
||||
});
|
||||
@@ -59,11 +64,12 @@ export function useTaskCompletions(taskId: number) {
|
||||
export function useCreateTask() {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (data: CreateTaskRequest) => tasks.create(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['residences'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('tasks') });
|
||||
queryClient.invalidateQueries({ queryKey: qk('residences') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -71,12 +77,13 @@ export function useCreateTask() {
|
||||
export function useUpdateTask(id: number) {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (data: UpdateTaskRequest) => tasks.update(id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks', id] });
|
||||
queryClient.invalidateQueries({ queryKey: ['residences'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('tasks') });
|
||||
queryClient.invalidateQueries({ queryKey: qk('tasks', id) });
|
||||
queryClient.invalidateQueries({ queryKey: qk('residences') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -84,11 +91,12 @@ export function useUpdateTask(id: number) {
|
||||
export function useDeleteTask() {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => tasks.delete(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['residences'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('tasks') });
|
||||
queryClient.invalidateQueries({ queryKey: qk('residences') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -96,10 +104,11 @@ export function useDeleteTask() {
|
||||
export function useMarkInProgress() {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => tasks.markInProgress(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('tasks') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -107,10 +116,11 @@ export function useMarkInProgress() {
|
||||
export function useCancelTask() {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => tasks.cancel(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('tasks') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -118,10 +128,11 @@ export function useCancelTask() {
|
||||
export function useArchiveTask() {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => tasks.archive(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('tasks') });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -129,6 +140,7 @@ export function useArchiveTask() {
|
||||
export function useCreateCompletion() {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
const qk = useQueryKeyPrefix();
|
||||
return useMutation({
|
||||
mutationFn: ({
|
||||
data,
|
||||
@@ -151,8 +163,8 @@ export function useCreateCompletion() {
|
||||
return tasks.createCompletion(data);
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['residences'] });
|
||||
queryClient.invalidateQueries({ queryKey: qk('tasks') });
|
||||
queryClient.invalidateQueries({ queryKey: qk('residences') });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { create } from 'zustand';
|
||||
import * as authApi from '@/lib/api/auth';
|
||||
import { getQueryClient } from '@/lib/query/query-client';
|
||||
import type { UserResponse } from '@/lib/api/auth';
|
||||
|
||||
interface AuthState {
|
||||
@@ -62,6 +63,8 @@ export const useAuthStore = create<AuthState>()((set) => ({
|
||||
} catch {
|
||||
// Even if logout fails server-side, clear local state
|
||||
} finally {
|
||||
// Clear React Query cache to prevent stale data leaking into demo mode
|
||||
getQueryClient().clear();
|
||||
set({
|
||||
user: null,
|
||||
isAuthenticated: false,
|
||||
|
||||
Reference in New Issue
Block a user