"use client"; // SMS settings data layer. Serves EITHER the local mock (Shell not configured — the demo keeps // working) OR the live be-crm data door (crm.settings.sms.*), behind one interface. // // Live contract (be-crm → IIOS BYO credential store): // query crm.settings.sms.status {} -> { configured, enabled?, hints? } // cmd crm.settings.sms.configure { accountSid, authToken, fromNumber } -> masked status // The auth token is write-only: it is sealed in IIOS and NEVER returned — status carries only // non-secret hints (from-number + SID last-4). import { useCallback, useState } from "react"; import { useAppShell, useQuery } from "@abe-kap/appshell-sdk/react"; import { isShellConfigured } from "./appshell"; export interface SmsCredentials { accountSid: string; authToken: string; fromNumber: string } export interface SmsStatus { configured: boolean; enabled: boolean; fromNumber?: string; sidLast4?: string; } export interface SmsSettingsData { live: boolean; loading: boolean; error: string | null; status: SmsStatus; configure: (input: SmsCredentials) => Promise; refetch: () => void; } interface StatusDTO { configured: boolean; enabled?: boolean; hints?: { fromNumber?: string; sidLast4?: string } } function toStatus(dto?: StatusDTO | null): SmsStatus { return { configured: !!dto?.configured, enabled: dto?.enabled ?? false, fromNumber: dto?.hints?.fromNumber, sidLast4: dto?.hints?.sidLast4, }; } /* ---- Mock (demo mode) — stores only the non-secret hints, mirroring the masked live status ---- */ function useMockSms(): SmsSettingsData { const [status, setStatus] = useState({ configured: false, enabled: false }); const configure = useCallback(async ({ accountSid, fromNumber }: SmsCredentials) => { setStatus({ configured: true, enabled: true, fromNumber, sidLast4: accountSid.slice(-4) }); }, []); return { live: false, loading: false, error: null, status, configure, refetch: () => {} }; } /* ---- Live (be-crm data door) ---- */ function useLiveSms(): SmsSettingsData { const { sdk } = useAppShell(); const q = useQuery("crm.settings.sms.status", {}); const configure = useCallback(async (input: SmsCredentials) => { await sdk.command("crm.settings.sms.configure", { ...input }); q.refetch(); }, [sdk, q]); return { live: true, loading: q.loading, error: q.error ? String(q.error) : null, status: toStatus(q.data), configure, refetch: q.refetch, }; } const SHELL = isShellConfigured(); export function useSmsSettings(): SmsSettingsData { // SHELL is constant for the bundle's life (NEXT_PUBLIC_* is build-time), so the same hook path // runs every render — Rules-of-Hooks safe. return SHELL ? useLiveSms() : useMockSms(); }