template-saas-frontend-v2/src/hooks/query-keys.ts
Adrian Flores Cortes f59bbfac64 [SYNC] feat: Add query-keys hook and e2e tests
- 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>
2026-01-24 18:12:21 -06:00

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(),
],
};