mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-28 19:46:59 -05:00
397 lines
12 KiB
TypeScript
397 lines
12 KiB
TypeScript
/**
|
|
* 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 user profile cache
|
|
* Call this after profile updates
|
|
*/
|
|
invalidateUserProfile: (userId: string) => {
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.profile.detail(userId) });
|
|
},
|
|
|
|
/**
|
|
* Invalidate profile stats cache
|
|
* Call this after profile-related changes
|
|
*/
|
|
invalidateProfileStats: (userId: string) => {
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.profile.stats(userId) });
|
|
},
|
|
|
|
/**
|
|
* Invalidate profile activity cache
|
|
* Call this after activity changes
|
|
*/
|
|
invalidateProfileActivity: (userId: string) => {
|
|
queryClient.invalidateQueries({ queryKey: ['profile', 'activity', userId] });
|
|
},
|
|
|
|
/**
|
|
* Invalidate user search results
|
|
* Call this when display names change
|
|
*/
|
|
invalidateUserSearch: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['users', 'search'] });
|
|
},
|
|
|
|
/**
|
|
* Invalidate admin settings cache
|
|
* Call this after updating admin settings
|
|
*/
|
|
invalidateAdminSettings: () => {
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.admin.settings() });
|
|
},
|
|
|
|
/**
|
|
* Invalidate audit logs cache
|
|
* Call this after inserting audit log entries
|
|
*/
|
|
invalidateAuditLogs: (userId?: string) => {
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.admin.auditLogs(userId) });
|
|
},
|
|
|
|
/**
|
|
* Invalidate contact submissions cache
|
|
* Call this after updating contact submissions
|
|
*/
|
|
invalidateContactSubmissions: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['admin-contact-submissions'] });
|
|
},
|
|
|
|
/**
|
|
* Invalidate blog posts cache
|
|
* Call this after creating/updating/deleting blog posts
|
|
*/
|
|
invalidateBlogPosts: () => {
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.admin.blogPosts() });
|
|
},
|
|
|
|
/**
|
|
* 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']
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Invalidate company detail cache
|
|
* Call this after updating a company
|
|
*/
|
|
invalidateCompanyDetail: (slug: string, type: string) => {
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.companies.detail(slug, type) });
|
|
},
|
|
|
|
/**
|
|
* Invalidate company statistics cache
|
|
* Call this after changes affecting company stats
|
|
*/
|
|
invalidateCompanyStatistics: (id: string, type: string) => {
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.companies.statistics(id, type) });
|
|
},
|
|
|
|
/**
|
|
* Invalidate company parks cache
|
|
* Call this after park changes
|
|
*/
|
|
invalidateCompanyParks: (id: string, type: 'operator' | 'property_owner') => {
|
|
queryClient.invalidateQueries({ queryKey: ['companies', 'parks', id, type] });
|
|
},
|
|
|
|
/**
|
|
* Invalidate ride model detail cache
|
|
* Call this after updating a ride model
|
|
*/
|
|
invalidateRideModelDetail: (manufacturerSlug: string, modelSlug: string) => {
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.rideModels.detail(manufacturerSlug, modelSlug) });
|
|
},
|
|
|
|
/**
|
|
* Invalidate ride model statistics cache
|
|
* Call this after changes affecting model stats
|
|
*/
|
|
invalidateRideModelStatistics: (modelId: string) => {
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.rideModels.statistics(modelId) });
|
|
},
|
|
|
|
/**
|
|
* Invalidate model rides cache
|
|
* Call this after ride changes
|
|
*/
|
|
invalidateModelRides: (modelId: string, limit?: number) => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: queryKeys.rideModels.rides(modelId, limit),
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Invalidate entity name cache
|
|
* Call this after updating an entity's name
|
|
*/
|
|
invalidateEntityName: (entityType: string, entityId: string) => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: queryKeys.entities.name(entityType, entityId)
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Invalidate blog post cache
|
|
* Call this after updating a blog post
|
|
*/
|
|
invalidateBlogPost: (slug: string) => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: queryKeys.blog.post(slug)
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Invalidate coaster stats cache
|
|
* Call this after updating ride statistics
|
|
*/
|
|
invalidateCoasterStats: (rideId: string) => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: queryKeys.stats.coaster(rideId)
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Invalidate email change status cache
|
|
* Call this after email change operations
|
|
*/
|
|
invalidateEmailChangeStatus: () => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: queryKeys.security.emailChangeStatus()
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Invalidate sessions cache
|
|
* Call this after session operations (login, logout, revoke)
|
|
*/
|
|
invalidateSessions: () => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: queryKeys.security.sessions()
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Invalidate security queries
|
|
* Call this after security-related changes (email, sessions)
|
|
*/
|
|
invalidateSecurityQueries: () => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: queryKeys.security.emailChangeStatus()
|
|
});
|
|
queryClient.invalidateQueries({
|
|
queryKey: queryKeys.security.sessions()
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Smart invalidation for related entities
|
|
* Invalidates entity detail, photos, reviews, and name cache
|
|
* Call this after any entity update
|
|
*/
|
|
invalidateRelatedEntities: (entityType: string, entityId: string) => {
|
|
// Invalidate the entity itself
|
|
if (entityType === 'park') {
|
|
queryClient.invalidateQueries({
|
|
queryKey: queryKeys.parks.detail(entityId)
|
|
});
|
|
} else if (entityType === 'ride') {
|
|
queryClient.invalidateQueries({
|
|
queryKey: queryKeys.rides.detail('', entityId)
|
|
});
|
|
}
|
|
|
|
// Invalidate photos, reviews, and entity name
|
|
queryClient.invalidateQueries({
|
|
queryKey: queryKeys.photos.entity(entityType, entityId)
|
|
});
|
|
queryClient.invalidateQueries({
|
|
queryKey: queryKeys.reviews.entity(entityType as 'park' | 'ride', entityId)
|
|
});
|
|
queryClient.invalidateQueries({
|
|
queryKey: queryKeys.entities.name(entityType, entityId)
|
|
});
|
|
},
|
|
};
|
|
}
|