codalware-auth
Version:
Complete authentication system with enterprise security, attack protection, team workspaces, waitlist, billing, UI components, 2FA, and account recovery - production-ready in 5 minutes. Enhanced CLI with verification, rollback, and App Router scaffolding.
135 lines (115 loc) • 3.77 kB
text/typescript
import { useState, useEffect, useCallback } from 'react';
import { useAuth } from './useAuth';
interface FeatureConfig {
featureKey: string;
isEnabled: boolean;
config?: Record<string, unknown>;
}
interface UseFeatureFlagsReturn {
isFeatureEnabled: (featureKey: string) => boolean;
getFeatureConfig: (featureKey: string) => Record<string, unknown> | null;
features: FeatureConfig[];
loading: boolean;
error: string | null;
refetch: () => Promise<void>;
}
/**
* Hook to check feature flags for the current tenant
* @returns Feature flag utilities and state
*/
export function useFeatureFlags(): UseFeatureFlagsReturn {
const { user } = useAuth();
const [features, setFeatures] = useState<FeatureConfig[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const fetchFeatures = useCallback(async () => {
if (!user?.tenantId) {
setFeatures([]);
setLoading(false);
return;
}
try {
setLoading(true);
setError(null);
const response = await fetch('/api/tenant/features');
if (!response.ok) {
throw new Error('Failed to fetch features');
}
const data = await response.json();
// Transform to simple feature config format
const featureConfigs: FeatureConfig[] = (data.features || [])
.filter((f: { isEnabledGlobally: boolean }) => f.isEnabledGlobally)
.map((f: {
featureKey: string;
tenantEnabled?: boolean;
tenantConfig?: Record<string, unknown>;
}) => ({
featureKey: f.featureKey,
isEnabled: f.tenantEnabled ?? true,
config: f.tenantConfig,
}));
setFeatures(featureConfigs);
} catch (err) {
setError(err instanceof Error ? err.message : 'An error occurred');
setFeatures([]);
} finally {
setLoading(false);
}
}, [user?.tenantId]);
useEffect(() => {
void fetchFeatures();
}, [fetchFeatures]);
/**
* Check if a feature is enabled
* @param featureKey - The feature key to check (e.g., "auth.2fa")
* @returns true if the feature is enabled, false otherwise
*/
const isFeatureEnabled = (featureKey: string): boolean => {
const feature = features.find(f => f.featureKey === featureKey);
return feature?.isEnabled ?? false;
};
/**
* Get configuration for a feature
* @param featureKey - The feature key to get config for
* @returns The feature configuration object or null
*/
const getFeatureConfig = (featureKey: string): Record<string, unknown> | null => {
const feature = features.find(f => f.featureKey === featureKey);
return feature?.config ?? null;
};
return {
isFeatureEnabled,
getFeatureConfig,
features,
loading,
error,
refetch: fetchFeatures,
};
}
/**
* Hook to check a specific feature
* @param featureKey - The feature key to check
* @returns Object with enabled status and config
*/
export function useFeature(featureKey: string) {
const { isFeatureEnabled, getFeatureConfig, loading, error } = useFeatureFlags();
return {
isEnabled: isFeatureEnabled(featureKey),
config: getFeatureConfig(featureKey),
loading,
error,
};
}
// Specific feature hooks for common features
export function use2FAFeature() {
return useFeature('auth.2fa');
}
export function useMagicLinkFeature() {
return useFeature('auth.magic_link');
}
export function useMultiTenantFeature() {
return useFeature('org.multi_tenant');
}
export function useRBACFeature() {
return useFeature('auth.rbac');
}