- src/hooks/query-keys.ts - tests/e2e/registration.spec.ts - tests/e2e/subscription.spec.ts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
221 lines
7.3 KiB
TypeScript
221 lines
7.3 KiB
TypeScript
/**
|
|
* Centralized Query Keys for React Query / TanStack Query
|
|
* Provides consistent query key management across the application
|
|
*
|
|
* Benefits:
|
|
* - Single source of truth for all query keys
|
|
* - Easy invalidation and refetching
|
|
* - Type safety for query keys
|
|
* - Consistent naming conventions
|
|
*/
|
|
|
|
// Base query key factory
|
|
export const createQueryKey = (
|
|
entity: string,
|
|
params?: Record<string, any>,
|
|
) => {
|
|
return params ? [entity, params] : [entity];
|
|
};
|
|
|
|
// Entity-specific query keys
|
|
export const queryKeys = {
|
|
// Auth module
|
|
auth: {
|
|
all: () => createQueryKey('auth'),
|
|
session: () => createQueryKey('auth', { type: 'session' }),
|
|
user: (id?: string) => createQueryKey('auth', { type: 'user', id }),
|
|
permissions: () => createQueryKey('auth', { type: 'permissions' }),
|
|
oauthProviders: () => createQueryKey('auth', { type: 'oauth' }),
|
|
},
|
|
|
|
// Users module
|
|
users: {
|
|
all: (filters?: Record<string, any>) =>
|
|
createQueryKey('users', filters),
|
|
byId: (id: string) => createQueryKey('users', { id }),
|
|
profile: () => createQueryKey('users', { type: 'profile' }),
|
|
preferences: () => createQueryKey('users', { type: 'preferences' }),
|
|
invitations: (status?: string) =>
|
|
createQueryKey('users', { type: 'invitations', status }),
|
|
},
|
|
|
|
// Tenants module
|
|
tenants: {
|
|
all: () => createQueryKey('tenants'),
|
|
current: () => createQueryKey('tenants', { type: 'current' }),
|
|
byId: (id: string) => createQueryKey('tenants', { id }),
|
|
settings: (tenantId?: string) =>
|
|
createQueryKey('tenants', { type: 'settings', tenantId }),
|
|
usage: (tenantId?: string) =>
|
|
createQueryKey('tenants', { type: 'usage', tenantId }),
|
|
},
|
|
|
|
// Billing module
|
|
billing: {
|
|
subscriptions: {
|
|
all: (status?: string) =>
|
|
createQueryKey('billing', { type: 'subscriptions', status }),
|
|
current: () => createQueryKey('billing', { type: 'subscription', current: true }),
|
|
byId: (id: string) => createQueryKey('billing', { type: 'subscription', id }),
|
|
},
|
|
invoices: {
|
|
all: (filters?: Record<string, any>) =>
|
|
createQueryKey('billing', { type: 'invoices', ...filters }),
|
|
byId: (id: string) => createQueryKey('billing', { type: 'invoice', id }),
|
|
downloadUrl: (id: string) => createQueryKey('billing', { type: 'invoice', id, action: 'download' }),
|
|
},
|
|
payments: {
|
|
all: (filters?: Record<string, any>) =>
|
|
createQueryKey('billing', { type: 'payments', ...filters }),
|
|
byId: (id: string) => createQueryKey('billing', { type: 'payment', id }),
|
|
},
|
|
plans: {
|
|
all: () => createQueryKey('billing', { type: 'plans' }),
|
|
byId: (id: string) => createQueryKey('billing', { type: 'plan', id }),
|
|
features: () => createQueryKey('billing', { type: 'planFeatures' }),
|
|
},
|
|
},
|
|
|
|
// Notifications module
|
|
notifications: {
|
|
all: (filters?: Record<string, any>) =>
|
|
createQueryKey('notifications', filters),
|
|
unread: (count?: boolean) =>
|
|
createQueryKey('notifications', { unread: true, count }),
|
|
preferences: () => createQueryKey('notifications', { type: 'preferences' }),
|
|
devices: () => createQueryKey('notifications', { type: 'devices' }),
|
|
},
|
|
|
|
// Feature Flags module
|
|
featureFlags: {
|
|
all: () => createQueryKey('featureFlags'),
|
|
forUser: (userId: string) => createQueryKey('featureFlags', { userId }),
|
|
forTenant: (tenantId: string) => createQueryKey('featureFlags', { tenantId }),
|
|
evaluations: (params?: Record<string, any>) =>
|
|
createQueryKey('featureFlags', { type: 'evaluations', ...params }),
|
|
},
|
|
|
|
// Audit module
|
|
audit: {
|
|
logs: (filters?: Record<string, any>) =>
|
|
createQueryKey('audit', { type: 'logs', ...filters }),
|
|
activities: (filters?: Record<string, any>) =>
|
|
createQueryKey('audit', { type: 'activities', ...filters }),
|
|
summary: (period?: string) =>
|
|
createQueryKey('audit', { type: 'summary', period }),
|
|
},
|
|
|
|
// AI module
|
|
ai: {
|
|
configs: (tenantId?: string) =>
|
|
createQueryKey('ai', { type: 'configs', tenantId }),
|
|
usage: (filters?: Record<string, any>) =>
|
|
createQueryKey('ai', { type: 'usage', ...filters }),
|
|
models: () => createQueryKey('ai', { type: 'models' }),
|
|
},
|
|
|
|
// Storage module
|
|
storage: {
|
|
files: (filters?: Record<string, any>) =>
|
|
createQueryKey('storage', { type: 'files', ...filters }),
|
|
usage: () => createQueryKey('storage', { type: 'usage' }),
|
|
uploadUrl: (filename: string) =>
|
|
createQueryKey('storage', { type: 'uploadUrl', filename }),
|
|
},
|
|
|
|
// Webhooks module
|
|
webhooks: {
|
|
all: () => createQueryKey('webhooks'),
|
|
byId: (id: string) => createQueryKey('webhooks', { id }),
|
|
deliveries: (webhookId: string, filters?: Record<string, any>) =>
|
|
createQueryKey('webhooks', { type: 'deliveries', webhookId, ...filters }),
|
|
logs: (webhookId: string) =>
|
|
createQueryKey('webhooks', { type: 'logs', webhookId }),
|
|
},
|
|
|
|
// RBAC module
|
|
rbac: {
|
|
roles: {
|
|
all: () => createQueryKey('rbac', { type: 'roles' }),
|
|
byId: (id: string) => createQueryKey('rbac', { type: 'role', id }),
|
|
permissions: (roleId: string) =>
|
|
createQueryKey('rbac', { type: 'permissions', roleId }),
|
|
},
|
|
permissions: {
|
|
all: () => createQueryKey('rbac', { type: 'permissions' }),
|
|
byRole: (roleId: string) => createQueryKey('rbac', { type: 'permissions', roleId }),
|
|
},
|
|
userRoles: (userId?: string) =>
|
|
createQueryKey('rbac', { type: 'userRoles', userId }),
|
|
},
|
|
|
|
// WhatsApp module
|
|
whatsapp: {
|
|
configs: (tenantId?: string) =>
|
|
createQueryKey('whatsapp', { type: 'configs', tenantId }),
|
|
messages: (filters?: Record<string, any>) =>
|
|
createQueryKey('whatsapp', { type: 'messages', ...filters }),
|
|
templates: () => createQueryKey('whatsapp', { type: 'templates' }),
|
|
},
|
|
} as const;
|
|
|
|
// Type helpers for query keys
|
|
export type QueryKey = typeof queryKeys[keyof typeof queryKeys];
|
|
|
|
// Helper functions for common operations
|
|
export const queryKeyHelpers = {
|
|
/**
|
|
* Get all query keys for a module
|
|
*/
|
|
getModuleKeys: (module: keyof typeof queryKeys) => {
|
|
return Object.values(queryKeys[module]);
|
|
},
|
|
|
|
/**
|
|
* Check if a query key matches a pattern
|
|
*/
|
|
matches: (queryKey: any[], pattern: any[]): boolean => {
|
|
return JSON.stringify(queryKey.slice(0, pattern.length)) ===
|
|
JSON.stringify(pattern);
|
|
},
|
|
|
|
/**
|
|
* Extract parameters from a query key
|
|
*/
|
|
extractParams: (queryKey: any[]): Record<string, any> => {
|
|
const params: Record<string, any> = {};
|
|
|
|
if (queryKey.length > 1 && typeof queryKey[1] === 'object') {
|
|
Object.assign(params, queryKey[1]);
|
|
}
|
|
|
|
return params;
|
|
},
|
|
};
|
|
|
|
// Export commonly used combinations
|
|
export const commonQueryKeys = {
|
|
// User-specific data
|
|
userData: (userId: string) => [
|
|
...queryKeys.auth.user(userId),
|
|
...queryKeys.users.byId(userId),
|
|
...queryKeys.users.preferences(),
|
|
],
|
|
|
|
// Tenant-specific data
|
|
tenantData: (tenantId: string) => [
|
|
...queryKeys.tenants.byId(tenantId),
|
|
...queryKeys.tenants.settings(tenantId),
|
|
...queryKeys.billing.subscriptions.current(),
|
|
...queryKeys.featureFlags.forTenant(tenantId),
|
|
],
|
|
|
|
// Dashboard data
|
|
dashboard: () => [
|
|
...queryKeys.notifications.unread(true),
|
|
...queryKeys.audit.summary('7d'),
|
|
...queryKeys.billing.invoices.all({ limit: 5 }),
|
|
...queryKeys.storage.usage(),
|
|
],
|
|
};
|