34 lines
1.4 KiB
TypeScript
34 lines
1.4 KiB
TypeScript
/**
|
|
* Konnektor → Sidebar-Zustand (R-P1c).
|
|
*
|
|
* Bildet eine Konnektor-Entscheidung (aus {@link tenantHasModule} / `resolveTenantProductAccess`)
|
|
* auf die drei Sidebar-Zustände ab, die das Walking-Skeleton exemplarisch demonstriert:
|
|
*
|
|
* - `active` — Tenant darf das Modul nutzen → Eintrag sichtbar + klickbar.
|
|
* - `locked` — Modul ist im Produkt-Blueprint, aber nicht im Abo des Tenants → sichtbar,
|
|
* aber `disabled` (Upsell-Hinweis).
|
|
* - `hidden` — Modul gilt für diesen Tenant/User gar nicht (nicht im Blueprint, Rolle fehlt,
|
|
* per Override abgeschaltet) → kein Eintrag (404 statt 403, Bauprinzip A.5.3).
|
|
*/
|
|
export type ConnectorNavState = "active" | "locked" | "hidden";
|
|
|
|
export interface ConnectorDecisionLike {
|
|
readonly allowed: boolean;
|
|
readonly reason?: string;
|
|
}
|
|
|
|
// Gründe, bei denen das Modul für diesen Tenant/User schlicht nicht existiert → ausblenden.
|
|
const HIDDEN_REASONS = new Set<string>(["blueprint-disabled", "tenant-role-missing", "tenant-override-disabled", "tenant-override-not-toggleable"]);
|
|
|
|
export function resolveConnectorNavState(decision: ConnectorDecisionLike): ConnectorNavState {
|
|
if (decision.allowed) {
|
|
return "active";
|
|
}
|
|
if (decision.reason && HIDDEN_REASONS.has(decision.reason)) {
|
|
return "hidden";
|
|
}
|
|
// Übrige Gründe (Entitlement nicht enthalten / Limit erreicht / kein Abo) = im Blueprint, aber
|
|
// nicht gebucht → gesperrt mit Upsell.
|
|
return "locked";
|
|
}
|