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 = { boolean: 'Boolean', string: 'String', number: 'Number', json: 'JSON', }; return labels[type] || type; } export function getFlagTypeColor(type: FlagType): string { const colors: Record = { 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 = { global: 'Global', tenant: 'Tenant', user: 'User', plan: 'Plan', }; return labels[scope] || scope; } export function getFlagScopeColor(scope: FlagScope): string { const colors: Record = { 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'; }