feat(forms): add isolated Form A consultation testing

This commit is contained in:
DeCentN2Madness committed 2026-10-29 10:21:45 -07:00
1 parent 6a5e54e130
commit ff80ee516f
25 files changed
+1046 -253

No files matched your search

+25 -4
View File
@@ -1,20 +1,41 @@
---
import Button from './Button.astro';
import ContactObfuscation from './ContactObfuscation.astro';
import JotformIframe from './JotformIframe.astro';
import { formMessages } from '../utils/form-messages';
import { formModeForRuntime, resolveFormMode, resolveMockFormResult, type LogicalForm } from '../utils/form-integration';
const { lang = 'en', showBackground = false } = Astro.props;
import { formModeForRuntime, resolveFormAIframe, resolveFormMode, resolveMockFormResult, type LogicalForm } from '../utils/form-integration';
const { lang = 'en', showBackground = false, route = '' } = Astro.props;
const text = formMessages(lang);
const title = Astro.props.title ?? text.heading;
const logicalForm: LogicalForm = Astro.props.logicalForm ?? (Astro.props.title === 'Physician & Insurer Referrals' ? 'referral' : 'service');
const config = resolveFormMode(import.meta.env.PUBLIC_AIA_FORMS_MODE, import.meta.env.PUBLIC_AIA_FORMS_LIVE_APPROVED);
const mode = formModeForRuntime(config);
const mockResult = resolveMockFormResult(import.meta.env.PUBLIC_AIA_FORMS_MOCK_RESULT);
const formAIframe = logicalForm === 'service'
? resolveFormAIframe({
rawMode: import.meta.env.PUBLIC_AIA_FORMS_MODE,
liveApproved: import.meta.env.PUBLIC_AIA_FORMS_LIVE_APPROVED,
isolatedTestApproved: import.meta.env.PUBLIC_AIA_FORMS_ISOLATED_TEST_APPROVED,
consultationTestApproved: import.meta.env.PUBLIC_AIA_FORMS_CONSULTATION_TEST_APPROVED,
productionApproved: import.meta.env.PUBLIC_AIA_FORM_A_PRODUCTION_APPROVED,
environmentRole: import.meta.env.PUBLIC_AIA_FORMS_ENVIRONMENT,
allowIndexing: import.meta.env.PUBLIC_ALLOW_INDEXING,
route,
locale: lang,
})
: undefined;
const consultationIframeEnabled = formAIframe?.enabled && formAIframe.context === 'consultation';
const consultationHeading = lang === 'es' ? 'Comience una conversación' : 'Start a conversation';
const consultationDescription = lang === 'es'
? 'Use este formulario para solicitar una conversación. Un defensor de clientes de AIA puede explicarle los próximos pasos.'
: 'Use this form to request a conversation. An AIA client advocate can explain the next steps.';
---
<section class:list={['form-section', { 'form-section-background': showBackground }]} aria-labelledby="form-title">
<div class="container form-grid">
<div><p class="eyebrow">{text.eyebrow}</p><h2 id="form-title">{title}</h2><p>{text.intro}</p></div>
<div class="form" role="group" data-aia-form data-form-mode={mode} data-form-mode-reason={config.reason} data-logical-form={logicalForm} data-mock-result={mockResult} data-mock-success={text.mockSuccess} data-mock-failed={text.mockFailed} data-mock-unavailable={text.mockUnavailable}>
{formAIframe && consultationIframeEnabled
? <JotformIframe config={formAIframe} heading={consultationHeading} description={consultationDescription} />
: <div class="form" role="group" data-aia-form data-form-mode={mode} data-form-mode-reason={config.reason} data-logical-form={logicalForm} data-mock-result={mockResult} data-mock-success={text.mockSuccess} data-mock-failed={text.mockFailed} data-mock-unavailable={text.mockUnavailable}>
<label>{text.name}<input name="name" autocomplete="name" disabled={mode === 'off'} /></label>
<label>{text.email}<input type="email" name="email" autocomplete="email" disabled={mode === 'off'} /></label>
<label>{text.phone}<input type="tel" name="phone" autocomplete="tel" disabled={mode === 'off'} /></label>
@@ -22,7 +43,7 @@ const mockResult = resolveMockFormResult(import.meta.env.PUBLIC_AIA_FORMS_MOCK_R
<label>{text.message}<textarea name="message" rows="5" disabled={mode === 'off'}></textarea></label>
<Button type="button" data-mock-submit disabled={mode === 'off'} aria-describedby="form-note">{text.submit}</Button>
<p id="form-note" class="form-note" data-form-status>{mode === 'mock' ? text.mock : <>{text.disabled} <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />.</>}</p>
</div>
</div>}
</div>
</section>
+58 -11
View File
@@ -5,32 +5,40 @@ interface Props {
config: FormAIframeConfig;
heading: string;
description?: string;
variant?: 'standalone' | 'embedded';
variant?: 'standalone' | 'embedded' | 'drawer';
deferUntilActivated?: boolean;
hideHeading?: boolean;
}
const { config, heading, description, variant = 'standalone' } = Astro.props;
const { config, heading, description, variant = 'standalone', deferUntilActivated = false, hideHeading = false } = Astro.props;
if (!config.enabled || !config.url || !config.title || !config.fallbackText || !config.fallbackLinkText) {
throw new Error('JotformIframe requires an enabled, fully validated Form A iframe configuration.');
}
const idBase = `jotform-form-a-${config.route.replaceAll('/', '-').replaceAll(/^-+|-+$/g, '')}-${config.context}`;
const headingId = `${idBase}-heading`;
---
<section
class:list={['jotform-iframe', { 'jotform-iframe--embedded': variant === 'embedded' }]}
class:list={['jotform-iframe', { 'jotform-iframe--embedded': variant === 'embedded', 'jotform-iframe--drawer': variant === 'drawer' }]}
role="group"
aria-labelledby="jotform-iframe-heading"
aria-labelledby={hideHeading ? undefined : headingId}
aria-label={hideHeading ? config.title : undefined}
data-jotform-form-a
data-form-mode={config.mode}
data-form-environment={config.environmentRole}
data-logical-form="general"
data-logical-form={config.context === 'consultation' ? 'service' : 'general'}
data-form-context={config.context}
data-jotform-source="approved-form-a"
data-jotform-deferred={deferUntilActivated ? 'true' : undefined}
>
<h3 id="jotform-iframe-heading" class="jotform-iframe__heading">{heading}</h3>
{!hideHeading && <h3 id={headingId} class="jotform-iframe__heading">{heading}</h3>}
{description && <p class="jotform-iframe__description">{description}</p>}
<iframe
class="jotform-iframe__frame"
src={config.url}
src={deferUntilActivated ? undefined : config.url}
data-jotform-iframe-url={deferUntilActivated ? config.url : undefined}
title={config.title}
loading="eager"
referrerpolicy="no-referrer"
@@ -65,6 +73,7 @@ if (!config.enabled || !config.url || !config.title || !config.fallbackText || !
fallback.hidden = true;
let disposed = false;
let activated = false;
const hideFallback = () => {
fallback.hidden = true;
container.dataset.jotformFallback = 'hidden';
@@ -74,20 +83,37 @@ if (!config.enabled || !config.url || !config.title || !config.fallbackText || !
fallback.hidden = false;
container.dataset.jotformFallback = 'visible';
};
const timer = window.setTimeout(showFallback, fallbackTimeoutMs);
let timer;
const onLoad = () => {
window.clearTimeout(timer);
if (timer) window.clearTimeout(timer);
// A late frame load supersedes the transport timeout. It is still not
// treated as a success, conversion, or cross-origin health signal.
hideFallback();
};
const dispose = () => {
disposed = true;
window.clearTimeout(timer);
if (timer) window.clearTimeout(timer);
frame.removeEventListener('load', onLoad);
container.removeEventListener('aia:jotform-activate', activate);
};
frame.addEventListener('load', onLoad, { once: true });
const activate = () => {
if (disposed || activated) return;
const deferred = container.dataset.jotformDeferred === 'true';
const approvedUrl = frame.dataset.jotformIframeUrl;
if (deferred && !approvedUrl) return;
activated = true;
frame.addEventListener('load', onLoad, { once: true });
timer = window.setTimeout(showFallback, fallbackTimeoutMs);
if (deferred) frame.src = approvedUrl;
container.dataset.jotformIframeActivated = 'true';
};
if (container.dataset.jotformDeferred === 'true') {
container.addEventListener('aia:jotform-activate', activate, { once: true });
} else {
activate();
}
window.addEventListener('pagehide', dispose, { once: true });
document.addEventListener('astro:before-swap', dispose, { once: true });
};
@@ -184,6 +210,22 @@ if (!config.enabled || !config.url || !config.title || !config.fallbackText || !
text-align: left;
}
.jotform-iframe--drawer {
--jotform-frame-height: 72rem;
background: transparent;
border-radius: 0;
box-shadow: none;
overflow: visible;
padding: 0;
}
.jotform-iframe--drawer .jotform-iframe__heading {
border: 0;
margin: 0 0 1rem;
padding: 0;
text-align: left;
}
@media (max-width: 640px) {
.jotform-iframe__frame {
height: 68rem;
@@ -194,5 +236,10 @@ if (!config.enabled || !config.url || !config.title || !config.fallbackText || !
height: 50rem;
min-height: 50rem;
}
.jotform-iframe--drawer .jotform-iframe__frame {
height: 82rem;
min-height: 82rem;
}
}
</style>
+325 -158
View File
@@ -1,189 +1,299 @@
---
import ContactObfuscation from './ContactObfuscation.astro';
import { formModeForRuntime, resolveFormMode, resolveMockFormResult } from '../utils/form-integration';
import JotformIframe from './JotformIframe.astro';
import {
formModeForRuntime,
resolveFormAIframe,
resolveFormMode,
resolveMockFormResult,
} from '../utils/form-integration';
type ServiceKey = 'aba-therapy' | 'autism-evaluations' | 'learner-social-club';
type SupportedLocale = 'en' | 'es';
interface Props {
service: ServiceKey;
lang: SupportedLocale;
route: string;
}
const serviceCopy: Record<ServiceKey, {
heading: string[];
serviceName: string;
statusLead: string;
status: string;
prompt: string;
}> = {
'aba-therapy': {
heading: ['No WAITLIST!'],
serviceName: 'ABA Therapy',
statusLead: 'is',
status: 'currently accepting new patients',
prompt: "To help guarantee your child's admission to our program, please provide their information."
const serviceNames: Record<SupportedLocale, Record<ServiceKey, string>> = {
en: {
'aba-therapy': 'ABA Therapy',
'autism-evaluations': 'Autism Evaluations',
'learner-social-club': 'Learner Social Club',
},
'autism-evaluations': {
heading: ['Enrollment', 'Now Open'],
serviceName: 'Autism Evaluations',
statusLead: 'are',
status: 'now open for enrollment',
prompt: "To help guarantee your child's admission into one of our upcoming programs, please provide their information."
es: {
'aba-therapy': 'Terapia ABA',
'autism-evaluations': 'Evaluaciones de autismo',
'learner-social-club': 'Learner Social Club',
},
'learner-social-club': {
heading: ['Enrollment', 'Now Open'],
serviceName: 'Learner Social Club',
statusLead: 'is',
status: 'now open for enrollment',
prompt: "To help guarantee your child's spot in one of our upcoming group enrichment programs, please provide their information."
}
};
const { service } = Astro.props;
const copy = serviceCopy[service];
const drawerId = `service-inquiry-${service}`;
const drawerCopy: Record<SupportedLocale, {
open: (service: string) => string;
heading: (service: string) => string;
introduction: string;
privacy: string;
close: string;
noScript: string;
hostedLink: string;
legacyStatus: string;
legacyPrompt: string;
firstName: string;
lastName: string;
phone: string;
email: string;
childFirstName: string;
childLastName: string;
childBirthDate: string;
location: string;
service: string;
payment: string;
referral: string;
comments: string;
select: string;
submit: string;
disabled: string;
mock: string;
}> = {
en: {
open: (service) => `Talk with AIA about ${service}`,
heading: (service) => `Talk with AIA about ${service}`,
introduction: 'Use this form to request a conversation. An AIA client advocate can explain the next steps.',
privacy: 'Please use this form only for general contact information. AIA can discuss any needed details during follow-up.',
close: 'Close consultation form',
noScript: 'To request a conversation,',
hostedLink: 'open the consultation form in a new tab.',
legacyStatus: 'An AIA client advocate can discuss this service and possible next steps.',
legacyPrompt: 'Online submission is not yet connected. Please call AIA to begin a conversation.',
firstName: 'First name',
lastName: 'Last name',
phone: 'Phone number',
email: 'Email',
childFirstName: 'Child first name',
childLastName: 'Child last name',
childBirthDate: 'Child birth date',
location: 'Location interest',
service: 'Service interest',
payment: 'Insurance and payment options',
referral: 'How did you hear about us?',
comments: 'Additional information or comments',
select: 'Please select',
submit: 'Submit',
disabled: 'Online submission is not yet connected. Please call',
mock: 'Demo only: this local fixture never sends information.',
},
es: {
open: (service) => `Hable con AIA sobre ${service}`,
heading: (service) => `Hable con AIA sobre ${service}`,
introduction: 'Use este formulario para solicitar una conversación. Un defensor de clientes de AIA puede explicarle los próximos pasos.',
privacy: 'Use este formulario solo para información general de contacto. AIA puede hablar sobre los detalles necesarios durante el seguimiento.',
close: 'Cerrar el formulario de consulta',
noScript: 'Para solicitar una conversación,',
hostedLink: 'abra el formulario de consulta en una pestaña nueva.',
legacyStatus: 'Un defensor de clientes de AIA puede hablar sobre este servicio y los próximos pasos posibles.',
legacyPrompt: 'El envío en línea aún no está habilitado. Llame a AIA para iniciar una conversación.',
firstName: 'Nombre',
lastName: 'Apellido',
phone: 'Número de teléfono',
email: 'Correo electrónico',
childFirstName: 'Nombre del niño o la niña',
childLastName: 'Apellido del niño o la niña',
childBirthDate: 'Fecha de nacimiento del niño o la niña',
location: 'Ubicación de interés',
service: 'Servicio de interés',
payment: 'Opciones de seguro y pago',
referral: '¿Cómo se enteró de nosotros?',
comments: 'Información adicional o comentarios',
select: 'Seleccione una opción',
submit: 'Enviar',
disabled: 'El envío en línea aún no está habilitado. Llame al',
mock: 'Solo demostración: esta prueba local nunca envía información.',
},
};
const { service, lang, route } = Astro.props;
const copy = drawerCopy[lang];
const serviceName = serviceNames[lang][service];
const drawerId = `service-inquiry-${lang}-${service}`;
const titleId = `${drawerId}-title`;
const noteId = `${drawerId}-note`;
const config = resolveFormMode(import.meta.env.PUBLIC_AIA_FORMS_MODE, import.meta.env.PUBLIC_AIA_FORMS_LIVE_APPROVED);
const mode = formModeForRuntime(config);
const mockResult = resolveMockFormResult(import.meta.env.PUBLIC_AIA_FORMS_MOCK_RESULT);
const formAIframe = resolveFormAIframe({
rawMode: import.meta.env.PUBLIC_AIA_FORMS_MODE,
liveApproved: import.meta.env.PUBLIC_AIA_FORMS_LIVE_APPROVED,
isolatedTestApproved: import.meta.env.PUBLIC_AIA_FORMS_ISOLATED_TEST_APPROVED,
consultationTestApproved: import.meta.env.PUBLIC_AIA_FORMS_CONSULTATION_TEST_APPROVED,
productionApproved: import.meta.env.PUBLIC_AIA_FORM_A_PRODUCTION_APPROVED,
environmentRole: import.meta.env.PUBLIC_AIA_FORMS_ENVIRONMENT,
allowIndexing: import.meta.env.PUBLIC_ALLOW_INDEXING,
route,
locale: lang,
});
const consultationTestEnabled = formAIframe.enabled && formAIframe.context === 'consultation';
---
{consultationTestEnabled && formAIframe.url && <>
<button
class="service-inquiry-drawer__open"
type="button"
data-service-inquiry-open
aria-controls={drawerId}
aria-haspopup="dialog"
>
{copy.open(serviceName)}
</button>
<noscript>
<p class="service-inquiry-drawer__noscript">
{copy.noScript} <a href={formAIframe.url} target="_blank" rel="noopener noreferrer">{copy.hostedLink}</a>
</p>
</noscript>
</>}
<dialog
id={drawerId}
class="service-inquiry-drawer"
data-service-inquiry-drawer
data-dismiss-key={`aia-service-inquiry-dismissed:${service}`}
data-explicit-activation={consultationTestEnabled ? 'true' : undefined}
data-dismiss-key={consultationTestEnabled ? undefined : `aia-service-inquiry-dismissed:${lang}:${service}`}
aria-labelledby={titleId}
>
<button class="service-inquiry-drawer__close" type="button" data-service-inquiry-close aria-label="Close inquiry form">
<button class="service-inquiry-drawer__close" type="button" data-service-inquiry-close aria-label={copy.close}>
<svg aria-hidden="true" viewBox="0 0 32 32" width="18" height="18">
<path d="M4 4 28 28M28 4 4 28" fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="3" />
</svg>
</button>
<header class="service-inquiry-drawer__intro">
<h2 id={titleId} data-service-inquiry-title tabindex="-1">
{copy.heading.map((line, index) => <Fragment>{index > 0 && <br />}{line}</Fragment>)}
</h2>
<p>
Arizona Institute for Autism's<br />
<strong>{copy.serviceName}</strong><br />
{copy.statusLead} <em>{copy.status}</em>.
</p>
<p>{copy.prompt}</p>
<h2 id={titleId} data-service-inquiry-title tabindex="-1">{consultationTestEnabled ? copy.heading(serviceName) : serviceName}</h2>
<p>{consultationTestEnabled ? copy.introduction : copy.legacyStatus}</p>
{consultationTestEnabled && <p class="service-inquiry-drawer__privacy">{copy.privacy}</p>}
</header>
<div class="service-inquiry-form" role="group" data-aia-form data-form-mode={mode} data-form-mode-reason={config.reason} data-logical-form="service" data-mock-result={mockResult} data-mock-success="Demo only: the local fixture completed without sending anything." data-mock-failed="Demo only: the local fixture simulated a failed submission." data-mock-unavailable="Demo only: the local fixture simulated an unavailable service.">
<div class="service-inquiry-form__grid">
<label>
<span>First Name<span class="required-mark" aria-hidden="true">*</span></span>
<input name="first_name" autocomplete="given-name" required disabled={mode === 'off'} />
</label>
<label>
<span>Last Name<span class="required-mark" aria-hidden="true">*</span></span>
<input name="last_name" autocomplete="family-name" required disabled={mode === 'off'} />
</label>
<label>
<span>Phone Number<span class="required-mark" aria-hidden="true">*</span></span>
<span class="service-inquiry-form__phone">
<span class="service-inquiry-form__country">
<span aria-hidden="true">🇺🇸</span>
<span class="service-inquiry-form__country-caret" aria-hidden="true"></span>
<span class="visually-hidden">United States country code</span>
{consultationTestEnabled
? <div class="service-inquiry-drawer__iframe">
<JotformIframe config={formAIframe} heading={copy.heading(serviceName)} variant="drawer" deferUntilActivated hideHeading />
</div>
: <div class="service-inquiry-form" role="group" data-aia-form data-form-mode={mode} data-form-mode-reason={config.reason} data-logical-form="service" data-mock-result={mockResult} data-mock-success="Demo only: the local fixture completed without sending anything." data-mock-failed="Demo only: the local fixture simulated a failed submission." data-mock-unavailable="Demo only: the local fixture simulated an unavailable service.">
<div class="service-inquiry-form__grid">
<label>
<span>{copy.firstName}<span class="required-mark" aria-hidden="true">*</span></span>
<input name="first_name" autocomplete="given-name" required disabled={mode === 'off'} />
</label>
<label>
<span>{copy.lastName}<span class="required-mark" aria-hidden="true">*</span></span>
<input name="last_name" autocomplete="family-name" required disabled={mode === 'off'} />
</label>
<label>
<span>{copy.phone}<span class="required-mark" aria-hidden="true">*</span></span>
<span class="service-inquiry-form__phone">
<span class="service-inquiry-form__country">
<span aria-hidden="true">🇺🇸</span>
<span class="service-inquiry-form__country-caret" aria-hidden="true"></span>
<span class="visually-hidden">United States country code</span>
</span>
<span class="service-inquiry-form__phone-number">
<span aria-hidden="true">+1</span>
<input type="tel" name="phone" autocomplete="tel-national" required disabled={mode === 'off'} />
</span>
</span>
<span class="service-inquiry-form__phone-number">
<span aria-hidden="true">+1</span>
<input type="tel" name="phone" autocomplete="tel-national" required disabled={mode === 'off'} />
</span>
</span>
</label>
<label>
<span>Email<span class="required-mark" aria-hidden="true">*</span></span>
<input type="email" name="email" autocomplete="email" required disabled={mode === 'off'} />
</label>
<label>
<span>Child First Name</span>
<input name="child_first_name" autocomplete="off" disabled={mode === 'off'} />
</label>
<label>
<span>Child Last Name</span>
<input name="child_last_name" autocomplete="off" disabled={mode === 'off'} />
</label>
<label class="service-inquiry-form__wide">
<span>Child Birth Date</span>
<input name="child_birth_date" inputmode="numeric" autocomplete="bday" placeholder="MM - DD - YYYY" disabled={mode === 'off'} />
</label>
<label>
<span>Location Interest</span>
<select name="location_interest" disabled={mode === 'off'}>
<option value="" selected>Please Select</option>
<option value="aia_scottsdale">AIA Scottsdale</option>
<option value="aia_glendale">AIA Glendale</option>
<option value="other_none">Other/None</option>
</select>
</label>
<label>
<span>Service Interest</span>
<select name="service_interest" disabled={mode === 'off'}>
<option value="" selected>Please Select</option>
<option value="behavioral">Behavioral - ABA Therapy Service</option>
<option value="psychological">Psychological - Autism Evaluation Service</option>
<option value="sociological">Sociological - Learners Social Club Service</option>
<option value="other_none">Other/None</option>
</select>
</label>
<label>
<span>Insurance &amp; Payment Options</span>
<select name="payment_options" disabled={mode === 'off'}>
<option value="" selected>Please select</option>
<option>United Healthcare AHCCCS</option>
<option>BCBS AZ</option>
<option>United Healthcare</option>
<option>Optum</option>
<option>Tricare</option>
<option>Care Credit</option>
<option>Private Pay</option>
<option value="Other">Other (please describe in comment)</option>
</select>
</label>
<label>
<span>How did you hear about us?</span>
<select name="referred_by" disabled={mode === 'off'}>
<option value="" selected>Please select</option>
<option>Facebook</option>
<option>Google</option>
<option>Primary Doctor</option>
<option value="Specialist">Specialist (e.g., Developmental Psychologist)</option>
<option>Client Referral</option>
<option>Community Event</option>
<option value="Other">Other (please describe in comment)</option>
</select>
</label>
<label class="service-inquiry-form__wide">
<span>Additional Information/Comments</span>
<textarea name="comment" rows="2" disabled={mode === 'off'}></textarea>
</label>
</div>
</label>
<label>
<span>{copy.email}<span class="required-mark" aria-hidden="true">*</span></span>
<input type="email" name="email" autocomplete="email" required disabled={mode === 'off'} />
</label>
<label>
<span>{copy.childFirstName}</span>
<input name="child_first_name" autocomplete="off" disabled={mode === 'off'} />
</label>
<label>
<span>{copy.childLastName}</span>
<input name="child_last_name" autocomplete="off" disabled={mode === 'off'} />
</label>
<label class="service-inquiry-form__wide">
<span>{copy.childBirthDate}</span>
<input name="child_birth_date" inputmode="numeric" autocomplete="bday" placeholder="MM - DD - YYYY" disabled={mode === 'off'} />
</label>
<label>
<span>{copy.location}</span>
<select name="location_interest" disabled={mode === 'off'}>
<option value="" selected>{copy.select}</option>
<option value="aia_scottsdale">AIA Scottsdale</option>
<option value="aia_glendale">AIA Glendale</option>
<option value="other_none">Other/None</option>
</select>
</label>
<label>
<span>{copy.service}</span>
<select name="service_interest" disabled={mode === 'off'}>
<option value="" selected>{copy.select}</option>
<option value="behavioral">Behavioral - ABA Therapy Service</option>
<option value="psychological">Psychological - Autism Evaluation Service</option>
<option value="sociological">Sociological - Learners Social Club Service</option>
<option value="other_none">Other/None</option>
</select>
</label>
<label>
<span>{copy.payment}</span>
<select name="payment_options" disabled={mode === 'off'}>
<option value="" selected>{copy.select}</option>
<option>United Healthcare AHCCCS</option>
<option>BCBS AZ</option>
<option>United Healthcare</option>
<option>Optum</option>
<option>Tricare</option>
<option>Care Credit</option>
<option>Private Pay</option>
<option value="Other">Other (please describe in comment)</option>
</select>
</label>
<label>
<span>{copy.referral}</span>
<select name="referred_by" disabled={mode === 'off'}>
<option value="" selected>{copy.select}</option>
<option>Facebook</option>
<option>Google</option>
<option>Primary Doctor</option>
<option value="Specialist">Specialist (e.g., Developmental Psychologist)</option>
<option>Client Referral</option>
<option>Community Event</option>
<option value="Other">Other (please describe in comment)</option>
</select>
</label>
<label class="service-inquiry-form__wide">
<span>{copy.comments}</span>
<textarea name="comment" rows="2" disabled={mode === 'off'}></textarea>
</label>
</div>
<div class="service-inquiry-form__footer">
<p id={noteId} data-form-status>{mode === 'mock' ? 'Demo only: this local fixture never sends information.' : <>Online submission is not yet connected. Please call <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />.</>}</p>
<button type="button" data-mock-submit disabled={mode === 'off'} aria-describedby={noteId}>Submit</button>
</div>
</div>
<div class="service-inquiry-form__footer">
<p id={noteId} data-form-status>{mode === 'mock' ? copy.mock : <>{copy.disabled} <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />.</>}</p>
<button type="button" data-mock-submit disabled={mode === 'off'} aria-describedby={noteId}>{copy.submit}</button>
</div>
</div>}
</dialog>
<script>
import { bindMockForms } from '../scripts/mock-form';
bindMockForms();
const initializeServiceInquiryDrawers = () => {
document.querySelectorAll('[data-service-inquiry-drawer]').forEach((element) => {
if (!(element instanceof HTMLDialogElement) || element.dataset.initialized === 'true') return;
element.dataset.initialized = 'true';
const explicitActivation = element.dataset.explicitActivation === 'true';
const closeButton = element.querySelector('[data-service-inquiry-close]');
const title = element.querySelector('[data-service-inquiry-title]');
const frameAdapter = element.querySelector('[data-jotform-form-a]');
const triggers = Array.from(document.querySelectorAll(`[data-service-inquiry-open][aria-controls="${element.id}"]`));
const dismissKey = element.dataset.dismissKey;
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
let closeTimer: number | undefined;
let trigger: HTMLElement | undefined;
const wasDismissed = () => {
try {
@@ -208,7 +318,7 @@ const mockResult = resolveMockFormResult(import.meta.env.PUBLIC_AIA_FORMS_MOCK_R
const closeDrawer = () => {
if (!element.open) return;
rememberDismissal();
if (!explicitActivation) rememberDismissal();
element.classList.remove('is-open');
window.clearTimeout(closeTimer);
@@ -220,17 +330,23 @@ const mockResult = resolveMockFormResult(import.meta.env.PUBLIC_AIA_FORMS_MOCK_R
closeTimer = window.setTimeout(finishClose, 500);
};
const openDrawer = () => {
if (element.open || wasDismissed()) return;
const openDrawer = (openedBy?: EventTarget | null) => {
if (element.open || (!explicitActivation && wasDismissed())) return;
trigger = openedBy instanceof HTMLElement ? openedBy : undefined;
element.showModal();
document.documentElement.classList.add('service-inquiry-open');
if (explicitActivation && frameAdapter instanceof HTMLElement) {
frameAdapter.dispatchEvent(new Event('aia:jotform-activate'));
}
requestAnimationFrame(() => requestAnimationFrame(() => {
element.classList.add('is-open');
if (title instanceof HTMLElement) title.focus({ preventScroll: true });
if (closeButton instanceof HTMLElement) closeButton.focus({ preventScroll: true });
else if (title instanceof HTMLElement) title.focus({ preventScroll: true });
}));
};
closeButton?.addEventListener('click', closeDrawer);
triggers.forEach((openButton) => openButton.addEventListener('click', () => openDrawer(openButton)));
element.addEventListener('cancel', (event) => {
event.preventDefault();
closeDrawer();
@@ -241,9 +357,13 @@ const mockResult = resolveMockFormResult(import.meta.env.PUBLIC_AIA_FORMS_MOCK_R
element.addEventListener('close', () => {
element.classList.remove('is-open');
document.documentElement.classList.remove('service-inquiry-open');
if (trigger instanceof HTMLElement) {
trigger.focus({ preventScroll: true });
trigger = undefined;
}
});
window.setTimeout(openDrawer, 10_000);
if (!explicitActivation) window.setTimeout(() => openDrawer(undefined), 10_000);
});
};
@@ -255,6 +375,41 @@ const mockResult = resolveMockFormResult(import.meta.env.PUBLIC_AIA_FORMS_MOCK_R
overflow: hidden;
}
.service-inquiry-drawer__open {
background: var(--color-accent, #ffbd59);
border: 2px solid var(--color-accent, #ffbd59);
border-radius: 4px;
color: var(--color-primary);
cursor: pointer;
font: inherit;
font-weight: 700;
margin: 1.5rem auto 0;
padding: .75rem 1rem;
}
.service-inquiry-drawer__open:hover,
.service-inquiry-drawer__open:focus-visible {
background: transparent;
border-color: var(--color-accent-strong, #ff914d);
}
.service-inquiry-drawer__open:focus-visible {
outline: 3px solid var(--color-focus, #115bbd);
outline-offset: 3px;
}
.service-inquiry-drawer__noscript {
margin: 1.5rem auto 0;
max-width: 42rem;
text-align: center;
}
.service-inquiry-drawer__noscript a {
color: inherit;
text-decoration: underline;
text-underline-offset: .15em;
}
.service-inquiry-drawer {
background: white;
border: 0;
@@ -271,7 +426,7 @@ const mockResult = resolveMockFormResult(import.meta.env.PUBLIC_AIA_FORMS_MOCK_R
padding: 0;
transform: translateX(calc(100% + 20px));
transition: opacity 300ms ease, transform 500ms ease;
width: 608px;
width: min(760px, calc(100vw - 20px));
}
.service-inquiry-drawer.is-open {
@@ -301,11 +456,11 @@ const mockResult = resolveMockFormResult(import.meta.env.PUBLIC_AIA_FORMS_MOCK_R
position: absolute;
right: 10px;
top: 10px;
z-index: 1;
z-index: 2;
}
.service-inquiry-drawer__close:focus-visible {
outline: 2px solid var(--color-primary);
outline: 3px solid var(--color-focus, #115bbd);
outline-offset: 2px;
}
@@ -317,18 +472,24 @@ const mockResult = resolveMockFormResult(import.meta.env.PUBLIC_AIA_FORMS_MOCK_R
.service-inquiry-drawer__intro h2 {
font-family: var(--font-body);
font-size: 1.625rem;
line-height: 1.05;
line-height: 1.1;
margin: 10px 0 16px;
outline: none;
}
.service-inquiry-drawer__intro p {
line-height: 1.2;
margin: 0 0 16px;
line-height: 1.45;
margin: 0 auto 16px;
max-width: 42rem;
}
.service-inquiry-drawer__intro p:last-child {
margin-bottom: 0;
.service-inquiry-drawer__privacy {
color: var(--color-muted);
font-size: .9rem;
}
.service-inquiry-drawer__iframe {
padding: 2rem 3.75rem 3.75rem;
}
.service-inquiry-form {
@@ -477,8 +638,21 @@ const mockResult = resolveMockFormResult(import.meta.env.PUBLIC_AIA_FORMS_MOCK_R
}
@media (max-width: 500px) {
.service-inquiry-drawer__intro {
padding-top: 20px;
.service-inquiry-drawer {
inset: 0;
max-height: 100dvh;
max-width: 100vw;
width: 100vw;
}
.service-inquiry-drawer__intro,
.service-inquiry-drawer__iframe,
.service-inquiry-form {
padding-inline: 1.25rem;
}
.service-inquiry-drawer__iframe {
padding-block: 1.5rem 2.5rem;
}
.service-inquiry-form__grid {
@@ -499,13 +673,6 @@ const mockResult = resolveMockFormResult(import.meta.env.PUBLIC_AIA_FORMS_MOCK_R
}
}
@media (max-width: 360px) {
.service-inquiry-drawer__intro,
.service-inquiry-form {
padding-inline: 32px;
}
}
@media (prefers-reduced-motion: reduce) {
.service-inquiry-drawer,
.service-inquiry-drawer::backdrop {
@@ -26,6 +26,7 @@ const formAIframe = resolveFormAIframe({
rawMode: import.meta.env.PUBLIC_AIA_FORMS_MODE,
liveApproved: import.meta.env.PUBLIC_AIA_FORMS_LIVE_APPROVED,
isolatedTestApproved: import.meta.env.PUBLIC_AIA_FORMS_ISOLATED_TEST_APPROVED,
consultationTestApproved: import.meta.env.PUBLIC_AIA_FORMS_CONSULTATION_TEST_APPROVED,
productionApproved: import.meta.env.PUBLIC_AIA_FORM_A_PRODUCTION_APPROVED,
environmentRole: import.meta.env.PUBLIC_AIA_FORMS_ENVIRONMENT,
allowIndexing: import.meta.env.PUBLIC_ALLOW_INDEXING,
@@ -6,6 +6,7 @@ const formAIframe = resolveFormAIframe({
rawMode: import.meta.env.PUBLIC_AIA_FORMS_MODE,
liveApproved: import.meta.env.PUBLIC_AIA_FORMS_LIVE_APPROVED,
isolatedTestApproved: import.meta.env.PUBLIC_AIA_FORMS_ISOLATED_TEST_APPROVED,
consultationTestApproved: import.meta.env.PUBLIC_AIA_FORMS_CONSULTATION_TEST_APPROVED,
productionApproved: import.meta.env.PUBLIC_AIA_FORM_A_PRODUCTION_APPROVED,
environmentRole: import.meta.env.PUBLIC_AIA_FORMS_ENVIRONMENT,
allowIndexing: import.meta.env.PUBLIC_ALLOW_INDEXING,
@@ -19,6 +19,7 @@ const formAIframe = resolveFormAIframe({
rawMode: import.meta.env.PUBLIC_AIA_FORMS_MODE,
liveApproved: import.meta.env.PUBLIC_AIA_FORMS_LIVE_APPROVED,
isolatedTestApproved: import.meta.env.PUBLIC_AIA_FORMS_ISOLATED_TEST_APPROVED,
consultationTestApproved: import.meta.env.PUBLIC_AIA_FORMS_CONSULTATION_TEST_APPROVED,
productionApproved: import.meta.env.PUBLIC_AIA_FORM_A_PRODUCTION_APPROVED,
environmentRole: import.meta.env.PUBLIC_AIA_FORMS_ENVIRONMENT,
allowIndexing: import.meta.env.PUBLIC_ALLOW_INDEXING,