1import { call } from "frappe-ui";
2import type { RouteLocationNormalized, RouteLocationRaw } from "vue-router";
3
4const PERSONA_DONE_KEY = "opendesk_persona_captured";
5
6let personaChecked = false;
7
8// Minimal auth contract, so this module doesn't import the auth store (cycle).
9interface PersonaAuth {
10 isLoggedIn: boolean;
11 hasDeskAccess: boolean;
12 isAdmin: boolean;
13 personaCaptured: boolean;
14}
15
16function isPersonaCaptured(auth: PersonaAuth): boolean {
17 try {
18 if (localStorage.getItem(PERSONA_DONE_KEY)) return true;
19 } catch {
20 // storage blocked — fall through to the server flag
21 }
22 return !!auth.personaCaptured;
23}
24
25// window.telemetry is a boot value injected by www/opendesk, so this is
26// synchronous and guard-safe.
27export function telemetryEnabled(): boolean {
28 return !!window.telemetry?.enabled;
29}
30
31// Gate for the route's beforeEnter: only an uncaptured desk admin may view
32// the wizard, even via URL.
33export function canViewPersona(auth: PersonaAuth): boolean {
34 return (
35 auth.isLoggedIn &&
36 auth.hasDeskAccess &&
37 auth.isAdmin &&
38 !isPersonaCaptured(auth)
39 );
40}
41
42// Interrupt the first eligible admin navigation, once per session, only if
43// telemetry is on. Returns where to redirect, or undefined to continue.
44export function personaInterrupt(
45 to: RouteLocationNormalized,
46 auth: PersonaAuth
47): RouteLocationRaw | undefined {
48 if (to.name === "Persona" || personaChecked) return;
49 if (!(auth.isLoggedIn && auth.hasDeskAccess && auth.isAdmin)) return;
50 personaChecked = true;
51 if (telemetryEnabled() && canViewPersona(auth)) return { name: "Persona" };
52}
53
54export async function markPersonaCaptured(brandName?: string): Promise<void> {
55 localStorage.setItem(PERSONA_DONE_KEY, "1");
56 await call("opendesk.api.onboarding.mark_persona_captured", {
57 brand_name: brandName,
58 });
59}
60