/** * Query invalidation helpers for TanStack Query * * Use these helpers to invalidate cached queries when data changes. * This ensures UI stays in sync with backend state. */ import { useQueryClient } from '@tanstack/react-query'; import { queryKeys } from './queryKeys'; /** * Hook providing query invalidation helpers */ export function useQueryInvalidation() { const queryClient = useQueryClient(); return { /** * Invalidate user roles cache * Call this after assigning/revoking roles */ invalidateUserRoles: (userId?: string) => { if (userId) { queryClient.invalidateQueries({ queryKey: queryKeys.userRoles(userId) }); } else { queryClient.invalidateQueries({ queryKey: ['user-roles'] }); } }, /** * Invalidate user permissions cache * Call this after role changes that affect permissions */ invalidateUserPermissions: (userId?: string) => { if (userId) { queryClient.invalidateQueries({ queryKey: queryKeys.userPermissions(userId) }); } else { queryClient.invalidateQueries({ queryKey: ['user-permissions'] }); } }, /** * Invalidate both roles and permissions for a user * Use this as a convenience method after role updates */ invalidateUserAuth: (userId?: string) => { if (userId) { queryClient.invalidateQueries({ queryKey: queryKeys.userRoles(userId) }); queryClient.invalidateQueries({ queryKey: queryKeys.userPermissions(userId) }); } else { queryClient.invalidateQueries({ queryKey: ['user-roles'] }); queryClient.invalidateQueries({ queryKey: ['user-permissions'] }); } }, /** * Invalidate moderation queue * Call this after moderation actions */ invalidateModerationQueue: () => { queryClient.invalidateQueries({ queryKey: ['moderation-queue'] }); }, /** * Invalidate moderation stats * Call this after queue changes */ invalidateModerationStats: () => { queryClient.invalidateQueries({ queryKey: queryKeys.moderationStats() }); }, /** * Invalidate homepage data * Call this after creating/updating parks or rides */ invalidateHomepageData: (entityType?: 'parks' | 'rides' | 'all') => { if (!entityType || entityType === 'all') { queryClient.invalidateQueries({ queryKey: ['homepage'] }); } else if (entityType === 'parks') { queryClient.invalidateQueries({ queryKey: ['homepage'], predicate: (query) => { const key = query.queryKey[1] as string; return typeof key === 'string' && key.includes('parks'); } }); } else if (entityType === 'rides') { queryClient.invalidateQueries({ queryKey: ['homepage'], predicate: (query) => { const key = query.queryKey[1] as string; return typeof key === 'string' && key.includes('rides'); } }); } }, /** * Invalidate parks listing cache * Call this after creating/updating/deleting parks */ invalidateParks: () => { queryClient.invalidateQueries({ queryKey: ['parks'] }); }, /** * Invalidate rides listing cache * Call this after creating/updating/deleting rides */ invalidateRides: () => { queryClient.invalidateQueries({ queryKey: ['rides'] }); }, /** * Invalidate park detail cache * Call this after updating a park */ invalidateParkDetail: (slug: string) => { queryClient.invalidateQueries({ queryKey: queryKeys.parks.detail(slug) }); }, /** * Invalidate ride detail cache * Call this after updating a ride */ invalidateRideDetail: (parkSlug: string, rideSlug: string) => { queryClient.invalidateQueries({ queryKey: queryKeys.rides.detail(parkSlug, rideSlug) }); }, /** * Invalidate entity reviews * Call this after adding/updating/deleting reviews */ invalidateEntityReviews: (entityType: 'park' | 'ride', entityId: string) => { queryClient.invalidateQueries({ queryKey: queryKeys.reviews.entity(entityType, entityId) }); }, /** * Invalidate user reviews * Call this after a user adds/updates/deletes their reviews */ invalidateUserReviews: (userId: string) => { queryClient.invalidateQueries({ queryKey: ['reviews', 'user', userId] }); }, /** * Invalidate entity photos * Call this after uploading/deleting photos */ invalidateEntityPhotos: (entityType: string, entityId: string) => { queryClient.invalidateQueries({ queryKey: queryKeys.photos.entity(entityType, entityId) }); }, /** * Invalidate photo count * Call this after photo changes */ invalidatePhotoCount: (entityType: string, entityId: string) => { queryClient.invalidateQueries({ queryKey: queryKeys.photos.count(entityType, entityId) }); }, /** * Invalidate search results * Call this after major data changes */ invalidateSearchResults: () => { queryClient.invalidateQueries({ queryKey: ['search'] }); }, /** * Invalidate similar rides * Call this after ride updates */ invalidateSimilarRides: (parkId: string, category: string) => { queryClient.invalidateQueries({ queryKey: ['rides', 'similar', parkId, category] }); }, /** * Invalidate featured parks * Call this after park updates that affect featured status */ invalidateFeaturedParks: () => { queryClient.invalidateQueries({ queryKey: ['homepage', 'featured-parks'] }); }, }; }