template-saas/apps/frontend/src/hooks/useFeatureFlags.ts
rckrdmrd 50a821a415
Some checks failed
CI / Backend CI (push) Has been cancelled
CI / Frontend CI (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / CI Summary (push) Has been cancelled
[SIMCO-V38] feat: Actualizar a SIMCO v3.8.0
- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8
- Actualizaciones de configuracion

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 08:53:08 -06:00

226 lines
6.8 KiB
TypeScript

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import {
featureFlagsApi,
CreateFlagRequest,
UpdateFlagRequest,
SetTenantFlagRequest,
SetUserFlagRequest,
FlagType,
FlagScope,
} from '@/services/api';
// Query keys
const flagKeys = {
all: ['feature-flags'] as const,
list: () => [...flagKeys.all, 'list'] as const,
detail: (id: string) => [...flagKeys.all, 'detail', id] as const,
tenantOverrides: () => [...flagKeys.all, 'tenant-overrides'] as const,
userOverrides: (userId: string) => [...flagKeys.all, 'user-overrides', userId] as const,
evaluation: () => [...flagKeys.all, 'evaluation'] as const,
evaluationKey: (key: string) => [...flagKeys.evaluation(), key] as const,
check: (key: string) => [...flagKeys.all, 'check', key] as const,
};
// ==================== Flag Management ====================
export function useFeatureFlags() {
return useQuery({
queryKey: flagKeys.list(),
queryFn: () => featureFlagsApi.list(),
});
}
export function useFeatureFlag(id: string) {
return useQuery({
queryKey: flagKeys.detail(id),
queryFn: () => featureFlagsApi.get(id),
enabled: !!id,
});
}
export function useCreateFeatureFlag() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreateFlagRequest) => featureFlagsApi.create(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: flagKeys.list() });
},
});
}
export function useUpdateFeatureFlag() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: string; data: UpdateFlagRequest }) =>
featureFlagsApi.update(id, data),
onSuccess: (_, { id }) => {
queryClient.invalidateQueries({ queryKey: flagKeys.list() });
queryClient.invalidateQueries({ queryKey: flagKeys.detail(id) });
queryClient.invalidateQueries({ queryKey: flagKeys.evaluation() });
},
});
}
export function useDeleteFeatureFlag() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => featureFlagsApi.delete(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: flagKeys.list() });
queryClient.invalidateQueries({ queryKey: flagKeys.evaluation() });
},
});
}
export function useToggleFeatureFlag() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, enabled }: { id: string; enabled: boolean }) =>
featureFlagsApi.toggle(id, enabled),
onSuccess: (_, { id }) => {
queryClient.invalidateQueries({ queryKey: flagKeys.list() });
queryClient.invalidateQueries({ queryKey: flagKeys.detail(id) });
queryClient.invalidateQueries({ queryKey: flagKeys.evaluation() });
},
});
}
// ==================== Tenant Flags ====================
export function useTenantFlagOverrides() {
return useQuery({
queryKey: flagKeys.tenantOverrides(),
queryFn: () => featureFlagsApi.getTenantOverrides(),
});
}
export function useSetTenantFlagOverride() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: SetTenantFlagRequest) => featureFlagsApi.setTenantOverride(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: flagKeys.tenantOverrides() });
queryClient.invalidateQueries({ queryKey: flagKeys.evaluation() });
},
});
}
export function useRemoveTenantFlagOverride() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (flagId: string) => featureFlagsApi.removeTenantOverride(flagId),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: flagKeys.tenantOverrides() });
queryClient.invalidateQueries({ queryKey: flagKeys.evaluation() });
},
});
}
// ==================== User Flags ====================
export function useUserFlagOverrides(userId: string) {
return useQuery({
queryKey: flagKeys.userOverrides(userId),
queryFn: () => featureFlagsApi.getUserOverrides(userId),
enabled: !!userId,
});
}
export function useSetUserFlagOverride() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: SetUserFlagRequest) => featureFlagsApi.setUserOverride(data),
onSuccess: (_, { user_id }) => {
queryClient.invalidateQueries({ queryKey: flagKeys.userOverrides(user_id) });
queryClient.invalidateQueries({ queryKey: flagKeys.evaluation() });
},
});
}
export function useRemoveUserFlagOverride() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ userId, flagId }: { userId: string; flagId: string }) =>
featureFlagsApi.removeUserOverride(userId, flagId),
onSuccess: (_, { userId }) => {
queryClient.invalidateQueries({ queryKey: flagKeys.userOverrides(userId) });
queryClient.invalidateQueries({ queryKey: flagKeys.evaluation() });
},
});
}
// ==================== Evaluation ====================
export function useFlagEvaluation(key: string) {
return useQuery({
queryKey: flagKeys.evaluationKey(key),
queryFn: () => featureFlagsApi.evaluate(key),
enabled: !!key,
});
}
export function useAllFlagEvaluations() {
return useQuery({
queryKey: flagKeys.evaluation(),
queryFn: () => featureFlagsApi.evaluateAll(),
});
}
export function useFlagCheck(key: string) {
return useQuery({
queryKey: flagKeys.check(key),
queryFn: () => featureFlagsApi.check(key),
enabled: !!key,
});
}
// ==================== Helper functions ====================
export function getFlagTypeLabel(type: FlagType): string {
const labels: Record<FlagType, string> = {
boolean: 'Boolean',
string: 'String',
number: 'Number',
json: 'JSON',
};
return labels[type] || type;
}
export function getFlagTypeColor(type: FlagType): string {
const colors: Record<FlagType, string> = {
boolean: 'bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-400',
string: 'bg-blue-100 text-blue-800 dark:bg-blue-900/20 dark:text-blue-400',
number: 'bg-purple-100 text-purple-800 dark:bg-purple-900/20 dark:text-purple-400',
json: 'bg-orange-100 text-orange-800 dark:bg-orange-900/20 dark:text-orange-400',
};
return colors[type] || 'bg-gray-100 text-gray-800';
}
export function getFlagScopeLabel(scope: FlagScope): string {
const labels: Record<FlagScope, string> = {
global: 'Global',
tenant: 'Tenant',
user: 'User',
plan: 'Plan',
};
return labels[scope] || scope;
}
export function getFlagScopeColor(scope: FlagScope): string {
const colors: Record<FlagScope, string> = {
global: 'bg-gray-100 text-gray-800 dark:bg-gray-900/20 dark:text-gray-400',
tenant: 'bg-blue-100 text-blue-800 dark:bg-blue-900/20 dark:text-blue-400',
user: 'bg-purple-100 text-purple-800 dark:bg-purple-900/20 dark:text-purple-400',
plan: 'bg-amber-100 text-amber-800 dark:bg-amber-900/20 dark:text-amber-400',
};
return colors[scope] || 'bg-gray-100 text-gray-800';
}