import { environment } from '../environments/environment'; /** * Whether this bundle is running on a hosted Akashic origin rather than inside a WordPress page. * * Decided by the ABSENCE OF THE WORDPRESS PAYLOAD, not by the hostname. WordPress injects * `akasherePatientPortalData` before the bundle runs; nothing else does. Keying on the hostname would * mean a list of domains in the client, and a practice's own domain is exactly what we cannot enumerate. */ export const isHostedMount = (): boolean => !environment.wpData; // Public forms are embedded in a WordPress page, so a hosted client shows them but cannot act on them. export const PUBLIC_FORMS_NEED_WORDPRESS = 'Public forms are available through the Akashic WordPress plugin. Open your WordPress site to use this feature.'; /** * The subdomain label this page was served from, for the hostname resolve. * * Returns the first label only, and never assembles an address: the suffix is a per-environment * parameter on the server and every route that has one returns the real `hostname` and `url`. A client * that spells the address breaks silently in the first environment where the suffix differs. * * Undefined on a bare host with no subdomain, and on localhost, so the caller can say so rather than * resolving a label that was never claimed. */ export const hostedLabel = (hostname: string = window.location.hostname): string | undefined => { const labels = hostname.split('.'); if (labels.length < 2) return undefined; const first = labels[0]?.trim().toLowerCase(); return first ? first : undefined; }; /** * The root site this hosted address hangs off, read from the served hostname so no suffix is spelled * here. Unknown and reserved addresses both go there, so the redirect never confirms which exist. * Undefined when there is no parent domain. */ export const rootSiteUrl = (hostname: string = window.location.hostname): string | undefined => { const labels = hostname.split('.'); if (labels.length < 3) return undefined; return `https://${hostname.substring(hostname.indexOf('.') + 1)}/`; }; /** * Which experience a hosted path asks for. * * THE PATH DECIDES, NEVER THE RESOLVE RESPONSE. A hostname sets branding and presentation and nothing * else, so the response that carries branding must not also choose between the patient portal and the * staff portal - that would make it decide the most consequential thing on the page. * * The prefixes mirror the WordPress page slugs deliberately: the hosted portal is the same client on * another origin, so the same URL means the same screen on both. A second vocabulary here would be a * second thing to keep in step. * * `admin` is absent and stays absent - it names the wp-admin mount, which has no hosted equivalent. */ export const hostedMountContext = ( pathname: string = window.location.pathname, ): 'frontend' | 'staff' => ( /^\/staff-portal(\/|$)/.test(pathname) ? 'staff' : 'frontend' ); /** * The org-less patient portal, served on the reserved `patients` label. No practice owns it, so it is * never resolved as one: a patient signs in to their own record here. */ export const isOrglessPatientsHost = (hostname: string = window.location.hostname): boolean => isHostedMount() && hostedLabel(hostname) === 'patients'; // On the hosted mount the practice's own address is its portal, live from the moment it is claimed. export const hostedPortalUrl = ( type: 'patient' | 'staff', origin: string = window.location.origin, ): string | undefined => (isHostedMount() ? `${origin}${type === 'staff' ? '/staff-portal' : '/'}` : undefined);