/** * Tenant context switcher dropdown with logo display. */ import { showAsyncFlash } from './app-async-flash.js'; import { warnOnce, resolveHost } from '../core/app-dom.js'; import { postForm } from '../core/app-http.js'; const SWITCHER_ROOT_SELECTOR = '[data-tenant-switcher]'; const TENANT_LINK_SELECTOR = '[data-switch-tenant]'; const setPending = (link, pending) => { link.style.pointerEvents = pending ? 'none' : ''; link.style.opacity = pending ? '0.5' : ''; if (pending) { link.setAttribute('aria-busy', 'true'); } else { link.removeAttribute('aria-busy'); } }; const switchTenant = async (link) => { const tenantId = link.dataset.switchTenant; const csrfKey = link.dataset.csrfKey; const csrfToken = link.dataset.csrfToken; const errorMessage = link.dataset.errorMessage || 'Failed to switch tenant'; if (!tenantId || !csrfKey || !csrfToken) { warnOnce('UI_DATA_MISSING', 'Missing tenant ID or CSRF token', { module: 'tenant-switcher' }); return; } // Disable link during request setPending(link, true); try { const data = await postForm('admin/users/switch-tenant', { tenant_id: tenantId, [csrfKey]: csrfToken }); if (data && data.ok) { if (data.theme) { document.documentElement.dataset.theme = data.theme; } window.location.reload(); } else { warnOnce('FETCH_FAILED', 'Tenant switch failed', { module: 'tenant-switcher', error: data?.error ?? '' }); showAsyncFlash('error', errorMessage); setPending(link, false); } } catch (error) { warnOnce('FETCH_ERROR', 'Tenant switch request failed', { module: 'tenant-switcher', error, status: error?.status }); showAsyncFlash('error', errorMessage); setPending(link, false); } }; export const initTenantSwitcher = (root = document, options = {}) => { const host = resolveHost(root); const switcherSelector = String(options.rootSelector || SWITCHER_ROOT_SELECTOR).trim() || SWITCHER_ROOT_SELECTOR; const tenantLinkSelector = String(options.linkSelector || TENANT_LINK_SELECTOR).trim() || TENANT_LINK_SELECTOR; const switcherRoot = host.matches?.(switcherSelector) ? host : host.querySelector(switcherSelector); if (!switcherRoot) { // Single-tenant users do not render a switcher; this is expected. return { destroy: () => {} }; } const tenantLinks = Array.from(switcherRoot.querySelectorAll(tenantLinkSelector)); if (!tenantLinks.length) { warnOnce('UI_EL_MISSING', 'Tenant switcher root exists but contains no switch links', { module: 'tenant-switcher' }); return { destroy: () => {} }; } const cleanupFns = []; tenantLinks.forEach(link => { const onClick = (e) => { e.preventDefault(); switchTenant(link); }; link.addEventListener('click', onClick); cleanupFns.push(() => link.removeEventListener('click', onClick)); }); return { destroy: () => { cleanupFns.forEach((cleanup) => cleanup()); }, }; };