100 lines
3.0 KiB
TypeScript
100 lines
3.0 KiB
TypeScript
import { PolicyApiClient, type FeatureState, type PolicySnapshotDto } from '@/lib/api/policy/PolicyApiClient';
|
|
import { Result } from '@/lib/contracts/Result';
|
|
import { DomainError, Service } from '@/lib/contracts/services/Service';
|
|
import { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';
|
|
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
|
|
import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';
|
|
|
|
export interface CapabilityEvaluationResult {
|
|
isLoading: boolean;
|
|
isError: boolean;
|
|
capabilityState: FeatureState | null;
|
|
shouldShowChildren: boolean;
|
|
shouldShowComingSoon: boolean;
|
|
}
|
|
|
|
export class PolicyService implements Service {
|
|
private readonly apiClient: PolicyApiClient;
|
|
|
|
constructor() {
|
|
const baseUrl = getWebsiteApiBaseUrl();
|
|
const logger = new ConsoleLogger();
|
|
const errorReporter = new EnhancedErrorReporter(logger);
|
|
this.apiClient = new PolicyApiClient(baseUrl, errorReporter, logger);
|
|
}
|
|
|
|
async getSnapshot(): Promise<Result<PolicySnapshotDto, DomainError>> {
|
|
try {
|
|
const data = await this.apiClient.getSnapshot();
|
|
return Result.ok(data);
|
|
} catch (error: any) {
|
|
return Result.err({ type: 'serverError', message: error.message || 'Failed to get policy snapshot' });
|
|
}
|
|
}
|
|
|
|
getCapabilityState(snapshot: PolicySnapshotDto, capabilityKey: string): FeatureState {
|
|
return snapshot.capabilities[capabilityKey] ?? 'hidden';
|
|
}
|
|
|
|
isCapabilityEnabled(snapshot: PolicySnapshotDto, capabilityKey: string): boolean {
|
|
return this.getCapabilityState(snapshot, capabilityKey) === 'enabled';
|
|
}
|
|
|
|
/**
|
|
* Evaluate capability state and determine what should be rendered
|
|
* Centralizes the logic for capability-based UI rendering
|
|
*/
|
|
evaluateCapability(
|
|
snapshot: PolicySnapshotDto | null,
|
|
capabilityKey: string,
|
|
isLoading: boolean,
|
|
isError: boolean
|
|
): CapabilityEvaluationResult {
|
|
if (isLoading || isError || !snapshot) {
|
|
return {
|
|
isLoading,
|
|
isError,
|
|
capabilityState: null,
|
|
shouldShowChildren: false,
|
|
shouldShowComingSoon: false,
|
|
};
|
|
}
|
|
|
|
const capabilityState = this.getCapabilityState(snapshot, capabilityKey);
|
|
|
|
return {
|
|
isLoading,
|
|
isError,
|
|
capabilityState,
|
|
shouldShowChildren: capabilityState === 'enabled',
|
|
shouldShowComingSoon: capabilityState === 'coming_soon',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get the appropriate content based on capability state
|
|
* Handles fallback and coming soon logic
|
|
*/
|
|
getCapabilityContent(
|
|
snapshot: PolicySnapshotDto | null,
|
|
capabilityKey: string,
|
|
isLoading: boolean,
|
|
isError: boolean,
|
|
children: React.ReactNode,
|
|
fallback: React.ReactNode = null,
|
|
comingSoon: React.ReactNode = null
|
|
): React.ReactNode {
|
|
const evaluation = this.evaluateCapability(snapshot, capabilityKey, isLoading, isError);
|
|
|
|
if (evaluation.shouldShowChildren) {
|
|
return children;
|
|
}
|
|
|
|
if (evaluation.shouldShowComingSoon) {
|
|
return comingSoon ?? fallback;
|
|
}
|
|
|
|
return fallback;
|
|
}
|
|
}
|