Files
gridpilot.gg/apps/website/lib/services/policy/PolicyService.ts
2026-01-16 01:00:03 +01:00

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;
}
}