keystone-design-bootstrap 1.0.87 → 1.0.88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/design_system/sections/index.d.ts +1 -2
  2. package/dist/index.d.ts +24 -5
  3. package/dist/lib/server-api.d.ts +1 -2
  4. package/dist/lib/server-api.js +1 -1
  5. package/dist/lib/server-api.js.map +1 -1
  6. package/dist/package-DeHKpQp7.d.ts +121 -0
  7. package/dist/types/index.d.ts +68 -6
  8. package/package.json +28 -28
  9. package/src/design_system/portal/PortalPage.tsx +2 -3
  10. package/src/lib/server-api.ts +1 -2
  11. package/dist/company-information-C1pP-SvU.d.ts +0 -50
  12. package/dist/config-C_XBZixg.d.ts +0 -21
  13. package/dist/consumer-BWjQawiO.d.ts +0 -48
  14. package/dist/design_system/portal/index.d.ts +0 -52
  15. package/dist/design_system/portal/index.js +0 -3113
  16. package/dist/design_system/portal/index.js.map +0 -1
  17. package/dist/lib/consumer-session.d.ts +0 -16
  18. package/dist/lib/consumer-session.js +0 -85
  19. package/dist/lib/consumer-session.js.map +0 -1
  20. package/dist/lib/cta-urls.d.ts +0 -34
  21. package/dist/lib/cta-urls.js +0 -33
  22. package/dist/lib/cta-urls.js.map +0 -1
  23. package/dist/next/contexts/form-definitions.d.ts +0 -17
  24. package/dist/next/contexts/form-definitions.js +0 -21
  25. package/dist/next/contexts/form-definitions.js.map +0 -1
  26. package/dist/next/gallery/design-gallery.d.ts +0 -103
  27. package/dist/next/gallery/design-gallery.js +0 -19301
  28. package/dist/next/gallery/design-gallery.js.map +0 -1
  29. package/dist/next/layouts/root-layout.d.ts +0 -55
  30. package/dist/next/layouts/root-layout.js +0 -19713
  31. package/dist/next/layouts/root-layout.js.map +0 -1
  32. package/dist/next/legal/privacy-policy.d.ts +0 -7
  33. package/dist/next/legal/privacy-policy.js +0 -18949
  34. package/dist/next/legal/privacy-policy.js.map +0 -1
  35. package/dist/next/legal/terms-of-service.d.ts +0 -7
  36. package/dist/next/legal/terms-of-service.js +0 -18949
  37. package/dist/next/legal/terms-of-service.js.map +0 -1
  38. package/dist/next/providers/ssr-provider.d.ts +0 -12
  39. package/dist/next/providers/ssr-provider.js +0 -12
  40. package/dist/next/providers/ssr-provider.js.map +0 -1
  41. package/dist/next/routes/chat.d.ts +0 -26
  42. package/dist/next/routes/chat.js +0 -160
  43. package/dist/next/routes/chat.js.map +0 -1
  44. package/dist/next/routes/consumer-auth.d.ts +0 -33
  45. package/dist/next/routes/consumer-auth.js +0 -254
  46. package/dist/next/routes/consumer-auth.js.map +0 -1
  47. package/dist/next/routes/form.d.ts +0 -37
  48. package/dist/next/routes/form.js +0 -97
  49. package/dist/next/routes/form.js.map +0 -1
  50. package/dist/package-IU_GpDA0.d.ts +0 -74
  51. package/src/types/rails-actioncable.d.ts +0 -16
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/design_system/portal/PortalPage.tsx","../../../src/utils/cx.ts","../../../src/design_system/logo/keystone-logo-minimal.tsx","../../../src/design_system/logo/keystone-wordmark.tsx","../../../src/design_system/logo/keystone-brand-lockup.tsx","../../../src/design_system/portal/LogoutButton.tsx","../../../src/design_system/portal/LoginModalController.tsx","../../../src/design_system/elements/modal/modal.tsx","../../../src/design_system/portal/LoginForm.tsx","../../../src/utils/countries.tsx","../../../src/utils/phone-helpers.ts","../../../src/tracking/firePixelEvent.ts","../../../src/tracking/captureEvent.ts","../../../src/design_system/portal/MessageComposer.tsx","../../../src/design_system/chat/useRealtimeReplyOrchestrator.ts","../../../src/design_system/portal/RowThumbnail.tsx","../../../src/lib/hooks/use-image-cycle.ts","../../../src/design_system/portal/PortalTabTracker.tsx","../../../src/design_system/portal/BookIframePanel.tsx","../../../src/lib/consumer-session.ts","../../../src/lib/server-api.ts"],"sourcesContent":["import React from 'react';\nimport Link from 'next/link';\nimport { cookies } from 'next/headers';\nimport { KeystoneBrandLockup } from '../logo/keystone-brand-lockup';\nimport { KEYSTONE_APP_URL } from '../logo/keystone-logo-minimal';\nimport { LogoutButton } from './LogoutButton';\nimport { LoginModalController } from './LoginModalController';\nimport { MessageComposer } from './MessageComposer';\nimport { RowThumbnail } from './RowThumbnail';\nimport { PortalTabTracker } from './PortalTabTracker';\nimport { BookIframePanel } from './BookIframePanel';\nimport {\n CONSUMER_TOKEN_COOKIE,\n fetchConsumerMe,\n fetchConsumerConversations,\n fetchConsumerMessages,\n} from '../../lib/consumer-session';\nimport {\n getServices,\n getPackages,\n getCompanyInformation,\n} from '../../lib/server-api';\nimport type { Message, ContactSummary } from '../../types/api/consumer';\nimport type { Service, ServiceItem } from '../../types/api/service';\nimport type { Package } from '../../types/api/package';\nimport type { OfferPublic } from '../../types/api/offer';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ninterface SpecialItem {\n id: number;\n name: string;\n value_terms: string | null | undefined;\n expires_at: string | null | undefined;\n parentName: string;\n parentType: 'service' | 'package';\n photoAttachments: OfferPublic['photo_attachments'];\n}\n\nconst ALL_TABS = ['services', 'packages', 'specials', 'messages', 'book'] as const;\ntype Tab = (typeof ALL_TABS)[number];\nconst DEFAULT_TABS: Tab[] = ['book', 'services', 'packages', 'specials', 'messages'];\n\nexport interface PortalPageProps {\n searchParams?: Promise<Record<string, string>> | Record<string, string>;\n portalHref?: string;\n bookingHref?: string | null;\n bookingLabel?: string;\n /**\n * Controls which tabs are rendered in the portal header.\n * Default: ['book', 'services', 'packages', 'specials', 'messages']\n */\n enabledTabs?: Tab[];\n /**\n * Optional per-tab label overrides, e.g. { messages: 'Chat with Us' }.\n */\n tabLabels?: Partial<Record<Tab, string>>;\n /**\n * When true, always opens booking in a new tab even if the URL supports iframes.\n * Useful when the booking page's iframe experience is broken or undesirable.\n */\n forceExternalBooking?: boolean;\n /**\n * Path to the site's contact page, shown when no booking URL is configured.\n * Defaults to \"/contact\".\n */\n contactHref?: string;\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\n/** HEAD-request the booking URL and inspect framing headers to decide whether to embed in an iframe. */\nasync function checkIframeAllowed(url: string): Promise<boolean> {\n try {\n const fetchOptions: RequestInit & { next?: { revalidate?: number } } = {\n method: 'HEAD',\n redirect: 'follow',\n // Cache for 1 hour — booking platforms rarely change their embedding policy.\n next: { revalidate: 3600 },\n };\n const res = await fetch(url, fetchOptions);\n\n const xfo = res.headers.get('x-frame-options')?.toUpperCase();\n if (xfo === 'DENY' || xfo === 'SAMEORIGIN') return false;\n\n const csp = res.headers.get('content-security-policy');\n if (csp) {\n const match = csp.match(/frame-ancestors\\s+([^;]+)/i);\n if (match) {\n const policy = match[1].trim();\n if (policy === \"'none'\") return false;\n }\n }\n\n return true;\n } catch {\n return false;\n }\n}\n\nfunction formatCents(cents: number): string {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n minimumFractionDigits: 0,\n }).format(cents / 100);\n}\n\nfunction formatTime(iso: string): string {\n return new Date(iso).toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' });\n}\n\nfunction getInitials(str: string): string {\n return str.split(' ').map((w) => w[0]).join('').slice(0, 2).toUpperCase();\n}\n\nfunction aggregateSpecials(services: Service[], packages: Package[]): SpecialItem[] {\n const seen = new Set<number>();\n const specials: SpecialItem[] = [];\n\n for (const service of services) {\n for (const item of service.service_items ?? []) {\n for (const offer of item.offers ?? []) {\n if (offer.active === false || offer.expired) continue;\n if (seen.has(offer.id)) continue;\n seen.add(offer.id);\n specials.push({\n id: offer.id,\n name: offer.name,\n value_terms: offer.value_terms,\n expires_at: offer.expires_at,\n parentName: item.name,\n parentType: 'service',\n photoAttachments: item.photo_attachments,\n });\n }\n }\n }\n\n for (const pkg of packages) {\n for (const offer of pkg.offers ?? []) {\n if (offer.active === false || offer.expired) continue;\n if (seen.has(offer.id)) continue;\n seen.add(offer.id);\n specials.push({\n id: offer.id,\n name: offer.name,\n value_terms: offer.value_terms,\n expires_at: offer.expires_at,\n parentName: pkg.name,\n parentType: 'package',\n photoAttachments: pkg.photo_attachments,\n });\n }\n }\n\n return specials;\n}\n\n// ─── Shared sub-components ────────────────────────────────────────────────────\n\nfunction LockButton({ label = 'View price' }: { label?: string }) {\n return (\n <button\n data-open-login-modal\n className=\"cursor-pointer rounded px-1.5 py-0.5 text-xs text-quaternary underline underline-offset-2 transition-colors hover:text-secondary\"\n >\n {label}\n </button>\n );\n}\n\nfunction LoginWall({ message, cta }: { message: string; cta: string }) {\n return (\n <div className=\"flex flex-col items-center justify-center py-20 text-center\">\n <div className=\"mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-secondary\">\n <svg className=\"size-5 text-quaternary\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z\" />\n </svg>\n </div>\n <p className=\"text-sm font-medium text-primary\">{message}</p>\n <button\n data-open-login-modal\n className=\"mt-4 cursor-pointer rounded-interactive bg-brand-solid px-5 py-2 text-sm font-semibold text-white transition-colors hover:bg-brand-solid_hover\"\n >\n {cta}\n </button>\n </div>\n );\n}\n\nfunction EmptyState({ message }: { message: string }) {\n return (\n <div className=\"rounded-component border border-secondary bg-secondary py-16 text-center\">\n <p className=\"text-sm text-tertiary\">{message}</p>\n </div>\n );\n}\n\n// ─── Services Panel ───────────────────────────────────────────────────────────\n\nfunction ServiceItemRow({\n item,\n isLoggedIn,\n specialsEnabled,\n specialsHref,\n}: {\n item: ServiceItem;\n isLoggedIn: boolean;\n specialsEnabled: boolean;\n specialsHref: string;\n}) {\n const activeOffers = (item.offers ?? []).filter((o) => o.active !== false && !o.expired);\n return (\n <div className=\"group flex items-center gap-3 px-4 py-3\">\n <RowThumbnail\n photoAttachments={item.photo_attachments}\n seed={`item-${item.id}`}\n alt={item.name}\n />\n <div className=\"flex-1 min-w-0 flex items-center justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"text-base font-medium text-primary\">{item.name}</p>\n {item.summary && <p className=\"mt-0.5 text-sm text-tertiary\">{item.summary}</p>}\n {item.duration_minutes != null && item.duration_minutes > 0 && (\n <p className=\"mt-0.5 text-xs text-quaternary\">{item.duration_minutes} min</p>\n )}\n {specialsEnabled && activeOffers.length > 0 && (\n <div className=\"mt-1.5 flex flex-wrap gap-1\">\n {activeOffers.map((offer) =>\n isLoggedIn ? (\n <Link\n key={offer.id}\n href={specialsHref}\n className=\"inline-flex items-center rounded-badge bg-secondary border border-brand px-2 py-0.5 text-xs font-medium text-brand-secondary hover:bg-secondary_hover transition-colors\"\n >\n Special: {offer.name}\n </Link>\n ) : (\n <button\n key={offer.id}\n data-open-login-modal\n data-login-redirect={specialsHref}\n className=\"inline-flex items-center rounded-badge bg-secondary border border-brand px-2 py-0.5 text-xs font-medium text-brand-secondary hover:bg-secondary_hover transition-colors cursor-pointer\"\n >\n Special: {offer.name}\n </button>\n )\n )}\n </div>\n )}\n </div>\n <div className=\"shrink-0 text-right\">\n {isLoggedIn ? (\n item.price_cents != null ? (\n <span className=\"text-sm font-semibold text-primary\">{formatCents(item.price_cents)}</span>\n ) : item.pricing_info ? (\n <span className=\"text-sm text-secondary\">{item.pricing_info}</span>\n ) : null\n ) : (item.price_cents != null || item.pricing_info) ? (\n <LockButton />\n ) : null}\n </div>\n </div>\n </div>\n );\n}\n\nfunction ServicesPanel({\n services,\n isLoggedIn,\n specialsEnabled,\n portalHref,\n}: {\n services: Service[];\n isLoggedIn: boolean;\n specialsEnabled: boolean;\n portalHref: string;\n}) {\n const activeServices = services.filter((s) => (s.service_items?.length ?? 0) > 0);\n const specialsHref = `${portalHref}?tab=specials`;\n\n if (activeServices.length === 0) {\n return <EmptyState message=\"No services listed yet.\" />;\n }\n\n return (\n <>\n <PortalTabTracker event=\"ViewContent\" params={{ contentName: 'Services', contentCategory: 'Services' }} tab=\"services\" />\n <div className=\"divide-y divide-tertiary rounded-component border border-secondary bg-primary overflow-hidden\">\n {activeServices.map((service) => (\n <details key={service.id} className=\"group\" open>\n <summary className=\"flex cursor-pointer list-none items-center justify-between px-5 py-4 hover:bg-secondary transition-colors\">\n <div>\n <span className=\"font-medium text-primary\">{service.name}</span>\n {service.summary && (\n <p className=\"mt-0.5 text-sm text-tertiary\">{service.summary}</p>\n )}\n </div>\n <div className=\"ml-4 flex items-center gap-2 shrink-0\">\n <span className=\"text-xs text-quaternary\">{service.service_items?.length ?? 0} items</span>\n <svg className=\"size-4 text-quaternary transition-transform group-open:rotate-180\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </div>\n </summary>\n {service.service_items && service.service_items.length > 0 && (\n <div className=\"border-t border-tertiary bg-secondary divide-y divide-tertiary\">\n {service.service_items.map((item) => (\n <ServiceItemRow\n key={item.id}\n item={item}\n isLoggedIn={isLoggedIn}\n specialsEnabled={specialsEnabled}\n specialsHref={specialsHref}\n />\n ))}\n </div>\n )}\n </details>\n ))}\n </div>\n </>\n );\n}\n\n// ─── Packages Panel ───────────────────────────────────────────────────────────\n\nfunction PackagesPanel({\n packages,\n isLoggedIn,\n specialsEnabled,\n portalHref,\n}: {\n packages: Package[];\n isLoggedIn: boolean;\n specialsEnabled: boolean;\n portalHref: string;\n}) {\n const specialsHref = `${portalHref}?tab=specials`;\n\n if (packages.length === 0) return <EmptyState message=\"No packages available yet.\" />;\n\n return (\n <>\n <PortalTabTracker event=\"ViewContent\" params={{ contentName: 'Packages', contentCategory: 'Packages' }} tab=\"packages\" />\n <div className=\"grid gap-4 sm:grid-cols-2\">\n {packages.map((pkg) => {\n const activeOffers = (pkg.offers ?? []).filter((o) => o.active !== false && !o.expired);\n return (\n <div key={pkg.id} className=\"group rounded-component border border-secondary bg-primary p-4 flex flex-col gap-3\">\n <div className=\"flex items-start gap-3\">\n <RowThumbnail\n photoAttachments={pkg.photo_attachments}\n seed={`pkg-${pkg.id}`}\n alt={pkg.name}\n sizeClassName=\"w-16 h-16\"\n />\n <div className=\"flex-1 min-w-0 flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <h4 className=\"font-semibold text-primary\">{pkg.name}</h4>\n {pkg.summary && <p className=\"mt-0.5 text-sm text-tertiary\">{pkg.summary}</p>}\n </div>\n <div className=\"shrink-0 text-right\">\n {isLoggedIn ? (\n pkg.price_cents != null ? (\n <span className=\"text-xl font-bold text-primary\">{formatCents(pkg.price_cents)}</span>\n ) : pkg.pricing_info ? (\n <span className=\"text-sm font-medium text-secondary\">{pkg.pricing_info}</span>\n ) : null\n ) : (pkg.price_cents != null || pkg.pricing_info) ? (\n <LockButton />\n ) : null}\n </div>\n </div>\n </div>\n\n {pkg.package_items && pkg.package_items.length > 0 && (\n <ul className=\"space-y-1.5\">\n {pkg.package_items.map((item, idx) => (\n <li key={idx} className=\"flex items-center gap-2 text-sm text-secondary\">\n <span className=\"size-1.5 rounded-full bg-quaternary shrink-0\" />\n {item.quantity > 1 && <span className=\"font-medium text-primary\">{item.quantity}×</span>}\n {item.service_item?.name ?? '—'}\n </li>\n ))}\n </ul>\n )}\n\n {specialsEnabled && activeOffers.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\">\n {activeOffers.map((offer) =>\n isLoggedIn ? (\n <Link\n key={offer.id}\n href={specialsHref}\n className=\"inline-flex items-center rounded-badge bg-secondary border border-brand px-2.5 py-0.5 text-xs font-medium text-brand-secondary hover:bg-secondary_hover transition-colors\"\n >\n Special: {offer.name}\n </Link>\n ) : (\n <button\n key={offer.id}\n data-open-login-modal\n data-login-redirect={specialsHref}\n className=\"inline-flex items-center rounded-badge bg-secondary border border-brand px-2.5 py-0.5 text-xs font-medium text-brand-secondary hover:bg-secondary_hover transition-colors cursor-pointer\"\n >\n Special: {offer.name}\n </button>\n )\n )}\n </div>\n )}\n </div>\n );\n })}\n </div>\n </>\n );\n}\n\n// ─── Specials Panel ───────────────────────────────────────────────────────────\n\nfunction SpecialsPanel({ specials }: { specials: SpecialItem[] }) {\n if (specials.length === 0) {\n return <EmptyState message=\"No active specials right now. Check back soon.\" />;\n }\n\n return (\n <>\n <PortalTabTracker event=\"ViewContent\" params={{ contentName: 'Specials', contentCategory: 'Specials' }} tab=\"specials\" />\n <div className=\"space-y-3\">\n {specials.map((special) => (\n <div key={special.id} className=\"group flex items-start gap-3 rounded-component border border-secondary bg-primary px-4 py-4\">\n <RowThumbnail\n photoAttachments={special.photoAttachments}\n seed={`special-${special.id}`}\n alt={special.parentName}\n />\n <div className=\"flex-1 min-w-0\">\n <p className=\"font-semibold text-primary\">{special.name}</p>\n {special.value_terms && (\n <p className=\"mt-0.5 text-sm text-secondary\">{special.value_terms}</p>\n )}\n <p className=\"mt-1 text-xs text-quaternary\">\n {special.parentType === 'service' ? 'Service' : 'Package'}: {special.parentName}\n </p>\n {special.expires_at && (\n <p className=\"mt-0.5 text-xs text-quaternary\">\n Expires {new Date(special.expires_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}\n </p>\n )}\n </div>\n </div>\n ))}\n </div>\n </>\n );\n}\n\n// ─── Messages Panel ───────────────────────────────────────────────────────────\n\nfunction MessagesPanel({\n messages,\n contactSummary,\n contactId,\n businessName,\n}: {\n messages: Message[];\n contactSummary: ContactSummary | null;\n contactId: number | null;\n businessName: string;\n}) {\n const threadBusiness =\n contactSummary?.business?.company_name ||\n contactSummary?.business?.name ||\n businessName;\n\n return (\n <div className=\"flex flex-col rounded-component border border-secondary bg-primary overflow-hidden\">\n {/* Thread header */}\n <div className=\"flex items-center gap-2.5 border-b border-secondary px-4 py-3 shrink-0\">\n <div className=\"flex h-7 w-7 items-center justify-center rounded-full bg-brand-solid text-xs font-semibold text-white shrink-0\">\n {getInitials(threadBusiness)}\n </div>\n <span className=\"text-sm font-semibold text-primary\">{threadBusiness}</span>\n </div>\n\n {/* Scrollable message list */}\n <div className=\"overflow-y-auto px-4 py-4 space-y-3\" style={{ height: '70vh' }}>\n {messages.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center h-full py-16 text-center\">\n <div className=\"mb-3 flex h-10 w-10 items-center justify-center rounded-full bg-secondary\">\n <svg className=\"size-5 text-quaternary\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8.625 12a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H8.25m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H12m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0h-.375M21 12c0 4.556-4.03 8.25-9 8.25a9.764 9.764 0 01-2.555-.337A5.972 5.972 0 015.41 20.97a5.969 5.969 0 01-.474-.065 4.48 4.48 0 00.978-2.025c.09-.457-.133-.901-.467-1.226C3.93 16.178 3 14.189 3 12c0-4.556 4.03-8.25 9-8.25s9 3.694 9 8.25z\" />\n </svg>\n </div>\n <p className=\"text-sm font-medium text-primary\">No messages yet</p>\n <p className=\"mt-1 text-xs text-tertiary\">Send a message to start the conversation.</p>\n </div>\n ) : (\n messages.map((m) => {\n const isOutbound = m.direction === 'outbound';\n return (\n <div key={m.id} className={`flex ${isOutbound ? 'justify-start' : 'justify-end'}`}>\n <div className={`max-w-[80%] rounded-component px-4 py-2.5 text-sm ${\n isOutbound ? 'bg-secondary text-primary' : 'bg-brand-solid text-white'\n }`}>\n {m.sender_display_name && (\n <p className=\"mb-0.5 text-xs font-medium opacity-60\">{m.sender_display_name}</p>\n )}\n <p className=\"whitespace-pre-wrap leading-relaxed\">{m.body || '—'}</p>\n <p className=\"mt-1 text-right text-[10px] opacity-50\">{formatTime(m.created_at)}</p>\n </div>\n </div>\n );\n })\n )}\n </div>\n\n {/* Composer — fixed to bottom of panel */}\n {contactId && <MessageComposer contactId={contactId} />}\n </div>\n );\n}\n\n// ─── Book Panel ───────────────────────────────────────────────────────────────\n\nfunction BookPanel({\n bookingHref,\n bookingLabel,\n bookingAllowsIframe,\n isLoggedIn,\n businessName,\n}: {\n bookingHref: string;\n bookingLabel: string;\n bookingAllowsIframe: boolean;\n isLoggedIn: boolean;\n businessName: string;\n}) {\n if (!isLoggedIn) {\n return <LoginWall message=\"Continue to view booking options.\" cta=\"View Booking Options\" />;\n }\n\n if (bookingAllowsIframe) {\n return (\n <>\n <PortalTabTracker event=\"InitiateCheckout\" tab=\"booking\" />\n <BookIframePanel bookingHref={bookingHref} businessName={businessName} />\n </>\n );\n }\n\n return (\n <>\n <PortalTabTracker event=\"InitiateCheckout\" tab=\"booking\" />\n <div className=\"flex flex-col items-center justify-center py-20 text-center\">\n <div className=\"mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-secondary\">\n <svg className=\"size-5 text-quaternary\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 9v7.5\" />\n </svg>\n </div>\n <p className=\"text-sm font-medium text-primary\">Ready to book?</p>\n <p className=\"mt-1 text-sm text-tertiary\">You&apos;ll be taken to our booking system.</p>\n <a\n href={bookingHref}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mt-5 inline-flex items-center gap-2 rounded-interactive bg-brand-solid px-6 py-2.5 text-sm font-semibold text-white transition-colors hover:bg-brand-solid_hover\"\n >\n {bookingLabel}\n <svg className=\"size-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25\" />\n </svg>\n </a>\n </div>\n </>\n );\n}\n\n// ─── Main Portal Page (Self-Contained Async Server Component) ─────────────────\n\nexport async function PortalPage({\n searchParams,\n portalHref = '/portal',\n bookingHref,\n bookingLabel = 'Book Now',\n enabledTabs,\n tabLabels,\n forceExternalBooking = false,\n contactHref = '/contact',\n}: PortalPageProps) {\n const params = await searchParams ?? {};\n const contactIdParsed = params.contact ? parseInt(params.contact, 10) : NaN;\n const contactId = Number.isFinite(contactIdParsed) ? contactIdParsed : null;\n\n const cookieStore = await cookies();\n const token = cookieStore.get(CONSUMER_TOKEN_COOKIE)?.value ?? null;\n\n // Fetch public data + consumer in parallel.\n // Conversations are always fetched when logged in — needed for display name and messages.\n const [services, packages, companyInformation, consumer, conversations] = await Promise.all([\n getServices(),\n getPackages(),\n getCompanyInformation(),\n token ? fetchConsumerMe(token) : Promise.resolve(null),\n token ? fetchConsumerConversations(token) : Promise.resolve([]),\n ]);\n\n const resolvedBookingHref =\n bookingHref ?? companyInformation?.external_management_url ?? null;\n\n const hasCustomTabOrder = Array.isArray(enabledTabs) && enabledTabs.length > 0;\n const requestedTabs = (enabledTabs ?? DEFAULT_TABS).filter((tab, index, arr): tab is Tab => (\n ALL_TABS.includes(tab) && arr.indexOf(tab) === index\n ));\n const normalizedTabs: Tab[] = requestedTabs.length > 0 ? requestedTabs : DEFAULT_TABS;\n const nonBookTabs = normalizedTabs.filter((tab) => tab !== 'book');\n const includesBookTab = normalizedTabs.includes('book');\n\n const labelForTab = (tab: Tab): string => {\n if (tab === 'book') return tabLabels?.book ?? bookingLabel;\n if (tab === 'services') return tabLabels?.services ?? 'Services';\n if (tab === 'packages') return tabLabels?.packages ?? 'Packages';\n if (tab === 'specials') return tabLabels?.specials ?? 'Specials';\n return tabLabels?.messages ?? 'Messages';\n };\n\n // Keep existing behavior: when booking is configured, \"Book Now\" appears first; otherwise last.\n const tabs: Array<{ id: Tab; label: string }> = hasCustomTabOrder\n ? normalizedTabs.map((tab) => ({ id: tab, label: labelForTab(tab) }))\n : [\n ...(includesBookTab && resolvedBookingHref ? [{ id: 'book' as Tab, label: labelForTab('book') }] : []),\n ...nonBookTabs.map((tab) => ({ id: tab, label: labelForTab(tab) })),\n ...(includesBookTab && !resolvedBookingHref ? [{ id: 'book' as Tab, label: labelForTab('book') }] : []),\n ];\n const selectableTabIds = tabs.map((tab) => tab.id);\n const tabParam = selectableTabIds.includes(params.tab as Tab) ? (params.tab as Tab) : null;\n\n // Default to the first tab so tab order and default selection are always in sync.\n const tab: Tab = tabParam ?? tabs[0].id;\n\n // Auto-detect iframe support by inspecting the booking URL's framing headers.\n // Only runs when the book tab is active to avoid unnecessary requests.\n // Skipped entirely when forceExternalBooking is set.\n const bookingAllowsIframe =\n !forceExternalBooking && tab === 'book' && resolvedBookingHref\n ? await checkIframeAllowed(resolvedBookingHref)\n : false;\n\n const businessName =\n companyInformation?.company_name ||\n 'Member Portal';\n\n const isLoggedIn = !!consumer;\n\n // Use the first conversation's contact_id to identify this business's contact —\n // conversations are filtered server-side via API key, so they're always scoped correctly.\n const resolvedContactId = contactId ?? conversations[0]?.contact_id ?? null;\n\n // Find display name from the contact linked to this business's conversation thread,\n // falling back to any known identifier on the consumer record.\n const businessContact = consumer?.contacts?.find((c) => c.id === resolvedContactId);\n const consumerDisplayName =\n businessContact?.display_name ||\n consumer?.contacts?.[0]?.display_name ||\n consumer?.primary_identifier ||\n consumer?.email ||\n consumer?.phone ||\n null;\n\n const messageData =\n token && tab === 'messages' && resolvedContactId\n ? await fetchConsumerMessages(token, resolvedContactId)\n : { messages: [], contact: null };\n\n const serviceList = services ?? [];\n const packageList = packages ?? [];\n const specials = aggregateSpecials(serviceList, packageList);\n const specialsEnabled = selectableTabIds.includes('specials');\n\n return (\n <div className=\"min-h-screen bg-primary\">\n {/* Portal Header */}\n <div className=\"border-b border-secondary bg-primary sticky top-0 z-40 shrink-0\">\n <div className=\"mx-auto max-w-4xl px-4 py-4\">\n <div className=\"flex items-center justify-between gap-4\">\n <div>\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-quaternary\">\n Member Portal\n </p>\n <h1 className=\"text-xl font-bold text-primary leading-tight\">{businessName}</h1>\n </div>\n\n <div className=\"flex items-center gap-3\">\n {isLoggedIn ? (\n <div className=\"flex items-center gap-3\">\n {consumerDisplayName && (\n <div className=\"hidden sm:flex items-center gap-2 rounded-full border border-secondary bg-secondary px-3 py-1.5\">\n <div className=\"flex h-5 w-5 items-center justify-center rounded-full bg-brand-solid text-[9px] font-bold text-white shrink-0\">\n {getInitials(consumerDisplayName)}\n </div>\n <span className=\"text-xs font-medium text-secondary max-w-[120px] truncate\">\n {consumerDisplayName}\n </span>\n </div>\n )}\n <LogoutButton />\n </div>\n ) : (\n <button\n data-open-login-modal\n className=\"cursor-pointer rounded-interactive border border-secondary px-3 py-1.5 text-xs font-medium text-secondary hover:bg-secondary transition-colors\"\n >\n Sign in\n </button>\n )}\n\n <div className=\"border-l border-tertiary pl-3\">\n <a\n href={KEYSTONE_APP_URL}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label=\"Visit Keystone website\"\n >\n <KeystoneBrandLockup\n className=\"gap-2\"\n iconClassName=\"h-3.5\"\n wordmarkClassName=\"hidden sm:block h-2.5\"\n />\n </a>\n </div>\n </div>\n </div>\n\n {/* Tabs — scrollable on mobile; fade on right edge hints at overflow */}\n <div className=\"relative mt-4\">\n <div className=\"flex gap-1 overflow-x-auto pb-px scrollbar-none\">\n {tabs.map((t) => {\n const isActive = tab === t.id;\n const isGated = !isLoggedIn && (t.id === 'specials' || t.id === 'messages' || t.id === 'book');\n const href = `${portalHref}?tab=${t.id}`;\n const className = `shrink-0 rounded-interactive px-4 py-2 text-sm font-medium transition-colors whitespace-nowrap ${\n isActive ? 'bg-brand-solid text-white' : 'text-secondary hover:bg-secondary hover:text-primary'\n }`;\n if (isGated) {\n return (\n <button\n key={t.id}\n data-open-login-modal\n data-login-redirect={href}\n className={className}\n >\n {t.label}\n </button>\n );\n }\n return (\n <Link key={t.id} href={href} className={className}>\n {t.label}\n </Link>\n );\n })}\n </div>\n {/* Right-edge fade: visible on small screens only, hints that tabs are scrollable */}\n <div className=\"pointer-events-none absolute inset-y-0 right-0 w-8 bg-gradient-to-l from-primary to-transparent md:hidden\" />\n </div>\n </div>\n </div>\n\n {/* Tab Content */}\n <div className=\"mx-auto max-w-4xl px-4 py-8\">\n {tab === 'services' && (\n <ServicesPanel\n services={serviceList}\n isLoggedIn={isLoggedIn}\n specialsEnabled={specialsEnabled}\n portalHref={portalHref}\n />\n )}\n {tab === 'packages' && (\n <PackagesPanel\n packages={packageList}\n isLoggedIn={isLoggedIn}\n specialsEnabled={specialsEnabled}\n portalHref={portalHref}\n />\n )}\n {tab === 'specials' && (\n isLoggedIn ? (\n <SpecialsPanel specials={specials} />\n ) : (\n <LoginWall message=\"Continue to view specials.\" cta=\"View Specials\" />\n )\n )}\n {tab === 'messages' && (\n isLoggedIn ? (\n <MessagesPanel\n messages={messageData.messages}\n contactSummary={messageData.contact}\n contactId={resolvedContactId}\n businessName={businessName}\n />\n ) : (\n <LoginWall message=\"Continue to view your messages.\" cta=\"View Messages\" />\n )\n )}\n {tab === 'book' && (\n resolvedBookingHref ? (\n <BookPanel\n bookingHref={resolvedBookingHref}\n bookingLabel={bookingLabel}\n bookingAllowsIframe={bookingAllowsIframe}\n isLoggedIn={isLoggedIn}\n businessName={businessName}\n />\n ) : (\n <div className=\"flex flex-col items-center justify-center py-20 text-center\">\n <div className=\"mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-secondary\">\n <svg className=\"size-5 text-quaternary\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 9v7.5\" />\n </svg>\n </div>\n <p className=\"text-sm font-medium text-primary\">Ready to book?</p>\n <p className=\"mt-1 text-sm text-tertiary max-w-xs\">\n Give us a call or submit a request on our{' '}\n <a href={contactHref} className=\"underline underline-offset-2 hover:text-primary transition-colors\">contact page</a>\n {' '}and we&apos;ll get you scheduled.\n </p>\n </div>\n )\n )}\n </div>\n\n {/* Single login modal controller — listens for [data-open-login-modal] clicks */}\n <LoginModalController />\n </div>\n );\n}\n","import { extendTailwindMerge } from \"tailwind-merge\";\n\nconst twMerge = extendTailwindMerge({\n extend: {\n theme: {\n text: [\"display-xs\", \"display-sm\", \"display-md\", \"display-lg\", \"display-xl\", \"display-2xl\"],\n },\n },\n});\n\n/**\n * This function is a wrapper around the twMerge function.\n * It is used to merge the classes inside style objects.\n */\nexport const cx = twMerge;\n\n/**\n * This function does nothing besides helping us to be able to\n * sort the classes inside style objects which is not supported\n * by the Tailwind IntelliSense by default.\n */\nexport function sortCx<T extends Record<string, string | number | Record<string, string | number | Record<string, string | number>>>>(classes: T): T {\n return classes;\n}\n\n","\"use client\";\n\nimport type { SVGProps } from \"react\";\nimport { cx } from \"../../utils/cx\";\n\nexport const KEYSTONE_BRAND_COLOR = \"#6ECC8B\";\nexport const KEYSTONE_APP_URL = \"https://www.keystone.app\";\n\nexport const KeystoneLogoMinimal = (props: SVGProps<SVGSVGElement>) => {\n return (\n <svg\n viewBox=\"0 0 36 41\"\n fill=\"none\"\n aria-hidden=\"true\"\n {...props}\n className={cx(\"text-[#6ECC8B]\", props.className)}\n >\n <path\n d=\"M36 13.6677L24.0031 20.4999L36 27.3321V40.9966L11.998 27.3288V13.671L36 0.0032959V13.6677Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M11.9971 27.3288V40.9958L0 34.1644V20.4973L11.9971 27.3288Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M11.9971 13.671L0.00476074 20.4999L0 20.4973V6.83551L11.9971 0.00402832V13.671Z\"\n fill=\"currentColor\"\n />\n </svg>\n );\n};\n","\"use client\";\n\nimport type { SVGProps } from \"react\";\nimport { cx } from \"../../utils/cx\";\n\nexport const KeystoneWordmark = (props: SVGProps<SVGSVGElement>) => {\n return (\n <svg\n viewBox=\"0 0 104 20\"\n fill=\"none\"\n aria-hidden=\"true\"\n {...props}\n className={cx(\"text-[#6ECC8B]\", props.className)}\n >\n <path\n d=\"M3.14032 0L3.1612 8.23754H3.82871L9.47236 2.94575H13.0328V3.34299L6.45695 9.52024L13.2946 16.1684V16.5656H9.53903L3.8267 11.0811H3.15919V16.5584H0V0H3.14032Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M18.4299 2.62219C22.4643 2.62219 24.8242 5.10147 24.8242 9.20756V10.6049H14.6121C14.6635 12.8878 16.0848 14.486 18.4167 14.486C20.7485 14.486 21.6835 13.2718 21.8892 12.243H24.5535V12.6403C24.1957 14.422 22.5534 16.8876 18.4552 16.8876C14.357 16.8876 11.7031 14.4462 11.7031 9.7505C11.7031 5.05478 14.3675 2.62662 18.4295 2.62662L18.4299 2.62219ZM21.9647 8.28025C21.939 6.42119 20.7365 4.9932 18.3914 4.9932C16.0463 4.9932 14.8181 6.45903 14.6506 8.28025H21.9667H21.9647Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M27.5146 2.93809L31.2554 12.994H31.459L35.1865 2.93809H38.2369V3.33534L31.565 19.9996H28.5147V19.6024L29.7417 16.5942L24.3848 3.33292V2.93567H27.5142L27.5146 2.93809Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M44.1191 2.63538C47.759 2.63538 49.8832 4.19177 50.1017 6.73947V7.13671H47.3345C47.2445 5.53847 45.965 4.98667 44.1319 4.98667C42.2989 4.98667 41.3129 5.54088 41.3129 6.5982C41.3129 7.65551 42.1338 7.9956 43.3002 8.18115L45.8103 8.57839C48.4747 9.0022 50.2796 10.1214 50.2796 12.6027C50.2796 15.084 48.3591 16.8767 44.4898 16.8767C40.6205 16.8767 38.3782 15.082 38.1855 12.6667V12.2695H41.0045C41.133 13.8677 42.5692 14.5258 44.4898 14.5258C46.4104 14.5258 47.3859 13.8391 47.3859 12.7706C47.3859 11.702 46.5521 11.2782 45.1332 11.0552L42.623 10.658C40.1129 10.2607 38.4324 9.12818 38.4324 6.66219C38.4324 4.1962 40.4944 2.6378 44.1215 2.6378H44.1195L44.1191 2.63538Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M54.2257 2.93729V0H57.2632V2.93729H62.247V5.35257H57.2632V13.7724L57.4668 13.9821H62.1679V16.5673H57.8765C55.5828 16.5673 54.2237 15.353 54.2237 13.0327V5.35217H50.2773V2.93689L54.2257 2.93729Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M69.219 2.62219C73.3325 2.62219 76.2025 5.13004 76.2025 9.74608C76.2025 14.3621 73.3325 16.8832 69.219 16.8832C65.1056 16.8832 62.25 14.3754 62.25 9.74608C62.25 5.11676 65.1052 2.62219 69.219 2.62219ZM69.219 14.4442C71.6003 14.4442 73.1265 12.7687 73.1265 9.74648C73.1265 6.72426 71.6023 5.06202 69.219 5.06202C66.8358 5.06202 65.3241 6.73754 65.3241 9.74648C65.3241 12.7554 66.8482 14.4442 69.219 14.4442Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M80.2535 2.94007V4.45661H80.4568C81.3785 3.16304 82.8641 2.64868 84.6606 2.64868C87.7989 2.64868 89.7472 4.29763 89.7472 7.66236V16.5681H86.7097V7.93846C86.7097 6.03755 85.698 5.15451 83.8907 5.15451C81.9315 5.15451 80.3539 6.30238 80.3539 8.95392V16.566H77.3164V2.94007H80.2535Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M97.6065 2.62219C101.64 2.62219 104 5.10147 104 9.20756V10.6049H93.7886C93.838 12.8878 95.261 14.486 97.5933 14.486C99.9255 14.486 100.859 13.2718 101.065 12.243H103.729V12.6403C103.371 14.422 101.73 16.8876 97.6314 16.8876C93.5328 16.8876 90.8789 14.4462 90.8789 9.7505C90.8789 5.05478 93.5437 2.62662 97.6057 2.62662L97.6065 2.62219ZM101.141 8.28025C101.115 6.42119 99.9127 4.9932 97.568 4.9932C95.2233 4.9932 93.9943 6.45903 93.8272 8.28025H101.143H101.141Z\"\n fill=\"currentColor\"\n />\n </svg>\n );\n};\n","\"use client\";\n\nimport type { HTMLAttributes } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { KeystoneLogoMinimal } from \"./keystone-logo-minimal\";\nimport { KeystoneWordmark } from \"./keystone-wordmark\";\n\ntype KeystoneBrandLockupProps = HTMLAttributes<HTMLDivElement> & {\n iconClassName?: string;\n wordmarkClassName?: string;\n};\n\nexport function KeystoneBrandLockup({\n className,\n iconClassName,\n wordmarkClassName,\n ...props\n}: KeystoneBrandLockupProps) {\n return (\n <div {...props} className={cx(\"flex flex-col items-start gap-2\", className)}>\n <KeystoneLogoMinimal className={cx(\"h-4 w-auto shrink-0\", iconClassName)} />\n <KeystoneWordmark className={cx(\"h-4 w-auto shrink-0\", wordmarkClassName)} />\n </div>\n );\n}\n","'use client';\n\nimport { useRouter } from 'next/navigation';\n\nexport function LogoutButton() {\n const router = useRouter();\n\n const handleLogout = async () => {\n await fetch('/api/consumer/logout', { method: 'POST' });\n router.refresh();\n };\n\n return (\n <button\n type=\"button\"\n onClick={handleLogout}\n className=\"text-xs text-tertiary hover:text-primary transition-colors\"\n >\n Sign out\n </button>\n );\n}\n","'use client';\n\nimport React, { useState, useEffect, useTransition } from 'react';\nimport { useRouter } from 'next/navigation';\nimport { Modal } from '../elements/modal/modal';\nimport { LoginForm } from './LoginForm';\nimport { KEYSTONE_APP_URL, KeystoneLogoMinimal } from '../logo/keystone-logo-minimal';\n\nconst keystoneFooter = (\n <div className=\"px-6 py-4 bg-secondary flex flex-col items-center gap-1\">\n <a href={KEYSTONE_APP_URL} target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"Visit Keystone website\">\n <KeystoneLogoMinimal className=\"h-5 w-auto shrink-0\" />\n </a>\n <a\n href={KEYSTONE_APP_URL}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-xs text-quaternary hover:text-secondary transition-colors\"\n >\n Powered by Keystone Universal Login\n </a>\n </div>\n);\n\n/**\n * Renders a single login modal for the entire portal.\n * Any server-rendered element with `data-open-login-modal` will open it on click.\n *\n * After successful auth, the modal switches to a loading state and stays open\n * until the router transition (router.refresh / router.push) has fully completed\n * and the server component has re-rendered with the new session. This prevents\n * the brief flash of logged-out content that would otherwise appear.\n */\nexport function LoginModalController() {\n const [open, setOpen] = useState(false);\n const [redirectUrl, setRedirectUrl] = useState<string | null>(null);\n const [refreshing, setRefreshing] = useState(false);\n const [isPending, startTransition] = useTransition();\n const router = useRouter();\n\n useEffect(() => {\n const handleClick = (e: MouseEvent) => {\n const trigger = (e.target as HTMLElement).closest('[data-open-login-modal]');\n if (trigger) {\n e.preventDefault();\n setRedirectUrl(trigger.getAttribute('data-login-redirect'));\n setOpen(true);\n }\n };\n document.addEventListener('click', handleClick);\n return () => document.removeEventListener('click', handleClick);\n }, []);\n\n const handleSuccess = () => {\n setRefreshing(true);\n startTransition(() => {\n if (redirectUrl) {\n router.push(redirectUrl);\n setRedirectUrl(null);\n } else {\n router.refresh();\n }\n });\n };\n\n // Close the modal once the router transition has fully completed and the\n // server component has re-rendered with the new authenticated state.\n useEffect(() => {\n if (!(refreshing && !isPending)) return;\n const timeout = window.setTimeout(() => {\n setOpen(false);\n setRefreshing(false);\n }, 0);\n return () => window.clearTimeout(timeout);\n }, [refreshing, isPending]);\n\n return (\n <Modal\n isOpen={open}\n onClose={refreshing ? () => {} : () => setOpen(false)}\n hideHeader\n ariaLabel=\"Sign in or create account\"\n footer={refreshing ? undefined : keystoneFooter}\n >\n {refreshing ? (\n <div className=\"flex flex-col items-center justify-center py-12 gap-3\">\n <div className=\"h-6 w-6 animate-spin rounded-full border-2 border-brand border-t-transparent\" />\n <p className=\"text-sm text-tertiary\">Signing you in…</p>\n </div>\n ) : (\n <LoginForm onSuccess={handleSuccess} onClose={() => setOpen(false)} />\n )}\n </Modal>\n );\n}\n","'use client';\n\nimport React, { useEffect, useRef } from 'react';\n\nexport interface ModalProps {\n /** Whether the modal is open */\n isOpen: boolean;\n /** Called when the user requests close (button, Escape, or overlay click) */\n onClose: () => void;\n /** Optional title for the dialog (used for aria-labelledby) */\n title?: string;\n /** Optional id for the title element (must be set if title is set for a11y) */\n titleId?: string;\n /** Dialog content */\n children: React.ReactNode;\n /** Optional footer rendered below scrollable content (e.g. branding or action bars). */\n footer?: React.ReactNode;\n /**\n * Hide the built-in header bar and close button. Use when the content provides its own\n * title and close affordance (e.g. a form with its own header). Escape and overlay click\n * still close the dialog.\n */\n hideHeader?: boolean;\n /** Accessible name for the dialog when no visible title is rendered (i.e. when hideHeader is true). */\n ariaLabel?: string;\n /** Optional className for the overlay (backdrop) */\n overlayClassName?: string;\n /** Optional className for the dialog panel */\n panelClassName?: string;\n /** Optional max width class for the panel (default: max-w-md). Use max-w-lg, max-w-2xl, etc. */\n maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl';\n}\n\nconst MAX_WIDTH_CLASSES: Record<NonNullable<ModalProps['maxWidth']>, string> = {\n sm: 'max-w-sm',\n md: 'max-w-md',\n lg: 'max-w-lg',\n xl: 'max-w-xl',\n '2xl': 'max-w-2xl',\n '3xl': 'max-w-3xl',\n '4xl': 'max-w-4xl',\n '5xl': 'max-w-5xl',\n};\n\n/**\n * Shared modal (dialog) component. Escape to close, aria-modal, overlay click to close, scroll lock, focus return on close.\n * Use for detail views, confirmations, and other overlay content. Renders in place (use a portal from the consumer if needed).\n * When `hideHeader` is true, provide an `aria-label` via `panelClassName` or ensure children supply a visible heading.\n */\nexport function Modal({\n isOpen,\n onClose,\n title,\n titleId = 'modal-title',\n children,\n footer,\n hideHeader = false,\n ariaLabel,\n overlayClassName,\n panelClassName,\n maxWidth = 'md',\n}: ModalProps) {\n const overlayRef = useRef<HTMLDivElement>(null);\n const closeButtonRef = useRef<HTMLButtonElement>(null);\n\n useEffect(() => {\n if (!isOpen) return;\n const previouslyFocused = document.activeElement as HTMLElement | null;\n // When hideHeader is true there is no close button ref; autoFocus on content handles focus.\n closeButtonRef.current?.focus();\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n document.addEventListener('keydown', handleEscape);\n document.body.style.overflow = 'hidden';\n return () => {\n document.removeEventListener('keydown', handleEscape);\n document.body.style.overflow = '';\n previouslyFocused?.focus();\n };\n }, [isOpen, onClose]);\n\n if (!isOpen) return null;\n\n const maxWidthClass = MAX_WIDTH_CLASSES[maxWidth];\n\n return (\n <div\n ref={overlayRef}\n className={\n overlayClassName ??\n 'fixed inset-0 z-[200] flex items-center justify-center p-4 bg-black/50'\n }\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel}\n aria-labelledby={!ariaLabel && title && !hideHeader ? titleId : undefined}\n onClick={(e) => e.target === overlayRef.current && onClose()}\n >\n <div\n className={\n panelClassName ??\n `bg-primary border border-secondary rounded-lg shadow-xl w-full overflow-hidden ${maxWidthClass} max-h-[90vh] flex flex-col`\n }\n onClick={(e) => e.stopPropagation()}\n >\n {!hideHeader && (\n <div className=\"flex items-start justify-between gap-4 p-4 md:p-6 border-b border-secondary flex-shrink-0\">\n {title ? (\n <h2\n id={titleId}\n className=\"font-display text-lg font-normal text-fg-primary md:text-xl flex-1 min-w-0\"\n >\n {title}\n </h2>\n ) : (\n <span className=\"flex-1\" aria-hidden />\n )}\n <button\n ref={closeButtonRef}\n type=\"button\"\n onClick={onClose}\n className=\"shrink-0 p-1 text-fg-primary hover:text-brand-accent rounded focus:outline-none focus:ring-2 focus:ring-brand-accent\"\n aria-label=\"Close\"\n >\n <svg\n className=\"w-5 h-5\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n aria-hidden\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n )}\n <div className=\"overflow-y-auto flex-1 p-4 md:p-6\">{children}</div>\n {footer && <div className=\"flex-shrink-0 border-t border-secondary\">{footer}</div>}\n </div>\n </div>\n );\n}\n","'use client';\n\nimport React, { useEffect, useMemo, useState } from 'react';\nimport { useRouter } from 'next/navigation';\nimport { countries } from '../../utils/countries';\nimport { getNationalMask, formatDigitsToMask } from '../../utils/phone-helpers';\nimport { firePixelEvent, setPixelUserData } from '../../tracking/firePixelEvent';\nimport { captureEvent } from '../../tracking/captureEvent';\n\ntype Step = 'identifier' | 'verify' | 'profile';\ntype FunnelStep = 'identifier' | 'signin' | 'signup';\n\ninterface LoginFormProps {\n onSuccess?: () => void;\n onClose?: () => void;\n}\n\nconst inputClass =\n 'block w-full rounded-input border border-primary bg-primary px-3 py-2.5 text-base text-primary placeholder-quaternary focus:border-brand focus:outline-none focus:ring-1 focus:ring-brand transition-colors';\nconst labelClass = 'block text-sm text-secondary mb-1';\n\nexport function LoginForm({ onSuccess, onClose }: LoginFormProps) {\n const router = useRouter();\n const [step, setStep] = useState<Step>('identifier');\n\n const [phoneValue, setPhoneValue] = useState('');\n const [selectedCountry, setSelectedCountry] = useState('US');\n const [verificationCode, setVerificationCode] = useState('');\n const [verificationToken, setVerificationToken] = useState<string | null>(null);\n\n const [firstName, setFirstName] = useState('');\n const [lastName, setLastName] = useState('');\n const [email, setEmail] = useState('');\n\n const [resendAvailableAt, setResendAvailableAt] = useState<number | null>(null);\n const [secondsUntilResend, setSecondsUntilResend] = useState(0);\n\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n\n useEffect(() => {\n captureEvent('portal_login_started');\n }, []);\n\n useEffect(() => {\n const funnelStep: FunnelStep = step === 'identifier' ? 'identifier' : step === 'verify' ? 'signin' : 'signup';\n captureEvent('portal_login_step_viewed', { step: funnelStep });\n }, [step]);\n\n const country = useMemo(() => countries.find((c) => c.code === selectedCountry), [selectedCountry]);\n const phoneCode = country ? (country.phoneCode.startsWith('+') ? country.phoneCode : `+${country.phoneCode}`) : '+1';\n const nationalMask = useMemo(() => getNationalMask(country), [country]);\n const nationalPlaceholder = nationalMask ? nationalMask.replace(/#/g, '0') : '(555) 000-0000';\n const countryOptions = useMemo(\n () => countries.map((c) => ({ label: c.phoneCode.startsWith('+') ? c.phoneCode : `+${c.phoneCode}`, value: c.code })),\n []\n );\n const phoneDigits = phoneValue.replace(/\\D/g, '');\n const fullPhone = phoneDigits.length > 0 ? `${phoneCode}${phoneDigits}` : null;\n\n useEffect(() => {\n if (!resendAvailableAt) {\n setSecondsUntilResend(0);\n return;\n }\n const tick = () => {\n const remaining = Math.max(0, Math.ceil((resendAvailableAt - Date.now()) / 1000));\n setSecondsUntilResend(remaining);\n };\n tick();\n const interval = window.setInterval(tick, 1000);\n return () => window.clearInterval(interval);\n }, [resendAvailableAt]);\n\n const phoneInput = (value: string, onChange: (v: string) => void, required = false) => (\n <div className=\"flex rounded-input border border-primary overflow-hidden focus-within:border-brand focus-within:ring-1 focus-within:ring-brand transition-colors\">\n <select\n value={selectedCountry}\n onChange={(e) => { setSelectedCountry(e.target.value); onChange(''); }}\n className=\"border-r border-secondary bg-secondary px-2 py-2.5 text-base text-secondary focus:outline-none\"\n aria-label=\"Country code\"\n >\n {countryOptions.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n <input\n type=\"tel\"\n value={value}\n onChange={(e) => {\n const digits = e.target.value.replace(/\\D/g, '');\n onChange(nationalMask ? formatDigitsToMask(digits, nationalMask) : digits);\n }}\n placeholder={nationalPlaceholder}\n className=\"flex-1 px-3 py-2.5 text-base text-primary placeholder-quaternary bg-transparent focus:outline-none\"\n autoComplete=\"tel\"\n required={required}\n />\n </div>\n );\n\n const finishPasswordlessAuth = async ({\n token,\n firstNameValue,\n lastNameValue,\n emailValue,\n }: {\n token: string;\n firstNameValue: string;\n lastNameValue: string;\n emailValue: string;\n }): Promise<boolean> => {\n const res = await fetch('/api/consumer/passwordless_auth', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({\n phone: fullPhone,\n verification_token: token,\n first_name: firstNameValue.trim(),\n last_name: lastNameValue.trim(),\n email: emailValue.trim(),\n }),\n });\n const result = await res.json().catch(() => ({}));\n if (!res.ok) {\n setError(result.error || 'Authentication failed. Please try again.');\n captureEvent('portal_login_failed', { step: 'signup', reason: result.error || 'passwordless_auth_failed' });\n return false;\n }\n\n firePixelEvent('Lead');\n captureEvent('portal_login_step_advanced', { from_step: 'signup', to_step: 'authenticated', reason: 'passwordless_auth_success' });\n captureEvent('portal_login_completed', { flow: 'signup' });\n setResendAvailableAt(null);\n setSecondsUntilResend(0);\n if (onSuccess) onSuccess(); else router.refresh();\n return true;\n };\n\n const handleSendCode = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!fullPhone) {\n setError('Enter your phone number to continue.');\n captureEvent('portal_login_failed', { step: 'identifier', reason: 'validation_missing_phone' });\n return;\n }\n\n setLoading(true);\n setError(null);\n captureEvent('portal_login_step_submitted', { step: 'identifier' });\n try {\n const res = await fetch('/api/consumer/send_code', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ phone: fullPhone }),\n });\n const result = await res.json().catch(() => ({}));\n if (!res.ok) {\n if (result.code === 'cooldown_active' && typeof result.retry_in_seconds === 'number') {\n setResendAvailableAt(Date.now() + result.retry_in_seconds * 1000);\n }\n setError(result.error || 'Could not send verification code.');\n return;\n }\n\n await setPixelUserData({ phone: fullPhone });\n firePixelEvent('Lead');\n\n setResendAvailableAt(result.resend_available_at ? new Date(result.resend_available_at).getTime() : Date.now() + 5 * 60 * 1000);\n setStep('verify');\n captureEvent('portal_login_step_advanced', { from_step: 'identifier', to_step: 'signin', reason: 'verification_code_sent' });\n } catch {\n setError('Could not send verification code.');\n captureEvent('portal_login_failed', { step: 'identifier', reason: 'network_error' });\n } finally {\n setLoading(false);\n }\n };\n\n const handleVerifyCode = async (e: React.FormEvent) => {\n e.preventDefault();\n const code = verificationCode.replace(/\\D/g, '');\n if (!fullPhone || code.length !== 4) {\n setError('Enter the 4-digit code sent to your phone.');\n captureEvent('portal_login_failed', { step: 'signin', reason: 'validation_invalid_code' });\n return;\n }\n\n setLoading(true);\n setError(null);\n captureEvent('portal_login_step_submitted', { step: 'signin' });\n try {\n const res = await fetch('/api/consumer/verify_code', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ phone: fullPhone, code }),\n });\n const result = await res.json().catch(() => ({}));\n if (!res.ok || !result.verification_token) {\n setError(result.error || 'That code is invalid or expired.');\n captureEvent('portal_login_failed', { step: 'signin', reason: result.code || 'verification_failed' });\n return;\n }\n\n setVerificationToken(result.verification_token);\n setFirstName(result.first_name || '');\n setLastName(result.last_name || '');\n setEmail(result.email || '');\n\n const hasCompleteExistingProfile =\n typeof result.first_name === 'string' && result.first_name.trim().length > 0 &&\n typeof result.last_name === 'string' && result.last_name.trim().length > 0 &&\n typeof result.email === 'string' && result.email.trim().length > 0;\n\n if (hasCompleteExistingProfile) {\n captureEvent('portal_login_step_advanced', {\n from_step: 'signin',\n to_step: 'authenticated',\n reason: 'verification_success_profile_complete',\n });\n await finishPasswordlessAuth({\n token: result.verification_token,\n firstNameValue: result.first_name,\n lastNameValue: result.last_name,\n emailValue: result.email,\n });\n return;\n }\n\n setStep('profile');\n captureEvent('portal_login_step_advanced', { from_step: 'signin', to_step: 'signup', reason: 'verification_success' });\n } catch {\n setError('That code is invalid or expired.');\n captureEvent('portal_login_failed', { step: 'signin', reason: 'network_error' });\n } finally {\n setLoading(false);\n }\n };\n\n const handleResendCode = async () => {\n if (!fullPhone || loading || secondsUntilResend > 0) return;\n setLoading(true);\n setError(null);\n try {\n const res = await fetch('/api/consumer/send_code', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ phone: fullPhone }),\n });\n const result = await res.json().catch(() => ({}));\n if (!res.ok) {\n if (result.code === 'cooldown_active' && typeof result.retry_in_seconds === 'number') {\n setResendAvailableAt(Date.now() + result.retry_in_seconds * 1000);\n }\n setError(result.error || 'Could not request a new code yet.');\n return;\n }\n\n setVerificationCode('');\n setResendAvailableAt(result.resend_available_at ? new Date(result.resend_available_at).getTime() : Date.now() + 5 * 60 * 1000);\n } catch {\n setError('Could not request a new code yet.');\n } finally {\n setLoading(false);\n }\n };\n\n const handleProfileSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!fullPhone || !verificationToken) {\n setError('Verification expired. Please request a new code.');\n setStep('identifier');\n return;\n }\n if (!firstName.trim() || !lastName.trim() || !email.trim()) {\n setError('Please enter your first name, last name, and email.');\n return;\n }\n\n setLoading(true);\n setError(null);\n captureEvent('portal_login_step_submitted', { step: 'signup' });\n try {\n await finishPasswordlessAuth({\n token: verificationToken,\n firstNameValue: firstName,\n lastNameValue: lastName,\n emailValue: email,\n });\n } catch {\n setError('Authentication failed. Please try again.');\n captureEvent('portal_login_failed', { step: 'signup', reason: 'network_error' });\n } finally {\n setLoading(false);\n }\n };\n\n const goBackToPhone = () => {\n setStep('identifier');\n setVerificationCode('');\n setVerificationToken(null);\n setFirstName('');\n setLastName('');\n setEmail('');\n setResendAvailableAt(null);\n setError(null);\n };\n\n const formatCountdown = (totalSeconds: number) => {\n const mins = Math.floor(totalSeconds / 60);\n const secs = totalSeconds % 60;\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n };\n\n const headerTitle = step === 'identifier' ? 'Welcome' : step === 'verify' ? 'Verify your phone' : 'Last step';\n const headerSubtitle =\n step === 'identifier'\n ? 'Enter your phone number to get started.'\n : step === 'verify'\n ? 'We sent a 4-digit verification code by text.'\n : 'Enter your first name, last name, and email.';\n\n return (\n <div>\n <div className=\"flex items-start justify-between gap-4 mb-5\">\n <div>\n <h3 className=\"text-lg font-normal text-primary\">{headerTitle}</h3>\n <p className=\"mt-0.5 text-sm text-tertiary\">{headerSubtitle}</p>\n </div>\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"shrink-0 p-1 text-tertiary hover:text-primary transition-colors\"\n aria-label=\"Close\"\n >\n <svg className=\"size-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n )}\n </div>\n\n {error && (\n <div className=\"mb-4 rounded-input border border-error bg-error-primary px-3 py-2 text-sm text-error-primary\">\n {error}\n </div>\n )}\n\n <div className=\"relative overflow-hidden transition-all duration-300 ease-out\">\n {step === 'identifier' && (\n <form onSubmit={handleSendCode} className=\"space-y-3\">\n <div>\n <label className={labelClass}>Phone number</label>\n {phoneInput(phoneValue, setPhoneValue, true)}\n </div>\n <div className=\"pt-1\">\n <button\n type=\"submit\"\n disabled={loading}\n className=\"w-full rounded-interactive bg-brand-solid px-4 py-2.5 text-sm font-medium text-white hover:bg-brand-solid_hover transition-colors disabled:opacity-50\"\n >\n {loading ? 'Sending code…' : 'Continue'}\n </button>\n </div>\n </form>\n )}\n\n {step === 'verify' && (\n <form onSubmit={handleVerifyCode} className=\"space-y-3\">\n <div>\n <label className={labelClass}>Verification code</label>\n <input\n type=\"text\"\n value={verificationCode}\n onChange={(e) => setVerificationCode(e.target.value.replace(/\\D/g, '').slice(0, 4))}\n placeholder=\"0000\"\n className={inputClass}\n autoComplete=\"one-time-code\"\n inputMode=\"numeric\"\n required\n />\n </div>\n <div className=\"pt-1\">\n <button\n type=\"submit\"\n disabled={loading}\n className=\"w-full rounded-interactive bg-brand-solid px-4 py-2.5 text-sm font-medium text-white hover:bg-brand-solid_hover transition-colors disabled:opacity-50\"\n >\n {loading ? 'Verifying…' : 'Verify code'}\n </button>\n </div>\n <button\n type=\"button\"\n onClick={handleResendCode}\n disabled={loading || secondsUntilResend > 0}\n className=\"w-full text-center text-sm text-tertiary hover:text-primary transition-colors disabled:opacity-50\"\n >\n {secondsUntilResend > 0 ? `Request new code in ${formatCountdown(secondsUntilResend)}` : 'Request new code'}\n </button>\n <button\n type=\"button\"\n onClick={goBackToPhone}\n className=\"w-full text-center text-sm text-tertiary hover:text-primary transition-colors\"\n >\n ← Use a different phone number\n </button>\n </form>\n )}\n\n {step === 'profile' && (\n <form onSubmit={handleProfileSubmit} className=\"space-y-3\">\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label className={labelClass}>First name</label>\n <input\n type=\"text\"\n value={firstName}\n onChange={(e) => setFirstName(e.target.value)}\n placeholder=\"Jane\"\n className={inputClass}\n autoComplete=\"given-name\"\n required\n />\n </div>\n <div>\n <label className={labelClass}>Last name</label>\n <input\n type=\"text\"\n value={lastName}\n onChange={(e) => setLastName(e.target.value)}\n placeholder=\"Smith\"\n className={inputClass}\n autoComplete=\"family-name\"\n required\n />\n </div>\n </div>\n <div>\n <label className={labelClass}>Email address</label>\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"you@example.com\"\n className={inputClass}\n autoComplete=\"email\"\n required\n />\n </div>\n <div className=\"pt-1\">\n <button\n type=\"submit\"\n disabled={loading}\n className=\"w-full rounded-interactive bg-brand-solid px-4 py-2.5 text-sm font-medium text-white hover:bg-brand-solid_hover transition-colors disabled:opacity-50\"\n >\n {loading ? 'Finishing…' : 'Continue'}\n </button>\n </div>\n <button\n type=\"button\"\n onClick={goBackToPhone}\n className=\"w-full text-center text-sm text-tertiary hover:text-primary transition-colors\"\n >\n ← Use a different phone number\n </button>\n </form>\n )}\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport type { HTMLAttributes } from \"react\";\nimport Image from \"next/image\";\nimport type { SelectItemType } from '../design_system/elements/select/select';\n\n/**\n * List of countries with their respective country code, flag, phone code, and phone mask.\n */\nexport const countries = [\n {\n name: \"Afghanistan\",\n code: \"AF\",\n flag: \"https://www.untitledui.com/images/flags/AF.svg\",\n phoneCode: \"93\",\n phoneMask: \"+93-##-###-####\",\n },\n {\n name: \"Albania\",\n code: \"AL\",\n flag: \"https://www.untitledui.com/images/flags/AL.svg\",\n phoneCode: \"355\",\n phoneMask: \"+355 (###) ###-###\",\n },\n {\n name: \"Algeria\",\n code: \"DZ\",\n flag: \"https://www.untitledui.com/images/flags/DZ.svg\",\n phoneCode: \"213\",\n phoneMask: \"+213-##-###-####\",\n },\n {\n name: \"Andorra\",\n code: \"AD\",\n flag: \"https://www.untitledui.com/images/flags/AD.svg\",\n phoneCode: \"376\",\n phoneMask: \"+376-###-###\",\n },\n {\n name: \"Angola\",\n code: \"AO\",\n flag: \"https://www.untitledui.com/images/flags/AO.svg\",\n phoneCode: \"244\",\n phoneMask: \"+244 (###) ###-###\",\n },\n {\n name: \"Antigua and Barbuda\",\n code: \"AG\",\n flag: \"https://www.untitledui.com/images/flags/AG.svg\",\n phoneCode: \"+1-268\",\n phoneMask: \"+1 (268) ###-####\",\n },\n {\n name: \"Argentina\",\n code: \"AR\",\n flag: \"https://www.untitledui.com/images/flags/AR.svg\",\n phoneCode: \"54\",\n phoneMask: \"+54 (###) ###-####\",\n },\n {\n name: \"Armenia\",\n code: \"AM\",\n flag: \"https://www.untitledui.com/images/flags/AM.svg\",\n phoneCode: \"374\",\n phoneMask: \"+374-##-###-###\",\n },\n {\n name: \"Australia\",\n code: \"AU\",\n flag: \"https://www.untitledui.com/images/flags/AU.svg\",\n phoneCode: \"61\",\n phoneMask: \"+61-#-####-####\",\n },\n {\n name: \"Austria\",\n code: \"AT\",\n flag: \"https://www.untitledui.com/images/flags/AT.svg\",\n phoneCode: \"43\",\n phoneMask: \"+43 (###) ###-####\",\n },\n {\n name: \"Azerbaijan\",\n code: \"AZ\",\n flag: \"https://www.untitledui.com/images/flags/AZ.svg\",\n phoneCode: \"994\",\n phoneMask: \"+994-##-###-##-##\",\n },\n {\n name: \"Bahamas\",\n code: \"BS\",\n flag: \"https://www.untitledui.com/images/flags/BS.svg\",\n phoneCode: \"+1-242\",\n phoneMask: \"+1 (242) ###-####\",\n },\n {\n name: \"Bahrain\",\n code: \"BH\",\n flag: \"https://www.untitledui.com/images/flags/BH.svg\",\n phoneCode: \"973\",\n phoneMask: \"+973-####-####\",\n },\n {\n name: \"Bangladesh\",\n code: \"BD\",\n flag: \"https://www.untitledui.com/images/flags/BD.svg\",\n phoneCode: \"880\",\n phoneMask: \"+880-##-###-###\",\n },\n {\n name: \"Barbados\",\n code: \"BB\",\n flag: \"https://www.untitledui.com/images/flags/BB.svg\",\n phoneCode: \"+1-246\",\n phoneMask: \"+1 (246) ###-####\",\n },\n {\n name: \"Belarus\",\n code: \"BY\",\n flag: \"https://www.untitledui.com/images/flags/BY.svg\",\n phoneCode: \"375\",\n phoneMask: \"+375 (##) ###-##-##\",\n },\n {\n name: \"Belgium\",\n code: \"BE\",\n flag: \"https://www.untitledui.com/images/flags/BE.svg\",\n phoneCode: \"32\",\n phoneMask: \"+32 (###) ###-###\",\n },\n {\n name: \"Belize\",\n code: \"BZ\",\n flag: \"https://www.untitledui.com/images/flags/BZ.svg\",\n phoneCode: \"501\",\n phoneMask: \"+501-###-####\",\n },\n {\n name: \"Benin\",\n code: \"BJ\",\n flag: \"https://www.untitledui.com/images/flags/BJ.svg\",\n phoneCode: \"229\",\n phoneMask: \"+229-##-##-####\",\n },\n {\n name: \"Bhutan\",\n code: \"BT\",\n flag: \"https://www.untitledui.com/images/flags/BT.svg\",\n phoneCode: \"975\",\n phoneMask: \"+975-#-###-###\",\n },\n {\n name: \"Bolivia\",\n code: \"BO\",\n flag: \"https://www.untitledui.com/images/flags/BO.svg\",\n phoneCode: \"591\",\n phoneMask: \"+591-#-###-####\",\n },\n {\n name: \"Bosnia and Herzegovina\",\n code: \"BA\",\n flag: \"https://www.untitledui.com/images/flags/BA.svg\",\n phoneCode: \"387\",\n phoneMask: \"+387-##-####\",\n },\n {\n name: \"Botswana\",\n code: \"BW\",\n flag: \"https://www.untitledui.com/images/flags/BW.svg\",\n phoneCode: \"267\",\n phoneMask: \"+267-##-###-###\",\n },\n {\n name: \"Brazil\",\n code: \"BR\",\n flag: \"https://www.untitledui.com/images/flags/BR.svg\",\n phoneCode: \"55\",\n phoneMask: \"+55 (##) 9####-####\",\n },\n {\n name: \"Brunei\",\n code: \"BN\",\n flag: \"https://www.untitledui.com/images/flags/BN.svg\",\n phoneCode: \"673\",\n phoneMask: \"+673-###-####\",\n },\n {\n name: \"Bulgaria\",\n code: \"BG\",\n flag: \"https://www.untitledui.com/images/flags/BG.svg\",\n phoneCode: \"359\",\n phoneMask: \"+359 (###) ###-###\",\n },\n {\n name: \"Burkina Faso\",\n code: \"BF\",\n flag: \"https://www.untitledui.com/images/flags/BF.svg\",\n phoneCode: \"226\",\n phoneMask: \"+226-##-##-####\",\n },\n {\n name: \"Burundi\",\n code: \"BI\",\n flag: \"https://www.untitledui.com/images/flags/BI.svg\",\n phoneCode: \"257\",\n phoneMask: \"+257-##-##-####\",\n },\n {\n name: \"Cambodia\",\n code: \"KH\",\n flag: \"https://www.untitledui.com/images/flags/KH.svg\",\n phoneCode: \"855\",\n phoneMask: \"+855-##-###-###\",\n },\n {\n name: \"Cameroon\",\n code: \"CM\",\n flag: \"https://www.untitledui.com/images/flags/CM.svg\",\n phoneCode: \"237\",\n phoneMask: \"+237-####-####\",\n },\n {\n name: \"Canada\",\n code: \"CA\",\n flag: \"https://www.untitledui.com/images/flags/CA.svg\",\n phoneCode: \"1\",\n phoneMask: \"+1 (###) ###-####\",\n },\n {\n name: \"Central African Republic\",\n code: \"CF\",\n flag: \"https://www.untitledui.com/images/flags/CF.svg\",\n phoneCode: \"236\",\n phoneMask: \"+236-##-##-####\",\n },\n {\n name: \"Chad\",\n code: \"TD\",\n flag: \"https://www.untitledui.com/images/flags/TD.svg\",\n phoneCode: \"235\",\n phoneMask: \"+235-##-##-##-##\",\n },\n {\n name: \"Chile\",\n code: \"CL\",\n flag: \"https://www.untitledui.com/images/flags/CL.svg\",\n phoneCode: \"56\",\n phoneMask: \"+56-#-####-####\",\n },\n {\n name: \"China\",\n code: \"CN\",\n flag: \"https://www.untitledui.com/images/flags/CN.svg\",\n phoneCode: \"86\",\n phoneMask: \"+86-##-#####-#####\",\n },\n {\n name: \"Colombia\",\n code: \"CO\",\n flag: \"https://www.untitledui.com/images/flags/CO.svg\",\n phoneCode: \"57\",\n phoneMask: \"+57 (###) ###-####\",\n },\n {\n name: \"Comoros\",\n code: \"KM\",\n flag: \"https://www.untitledui.com/images/flags/KM.svg\",\n phoneCode: \"269\",\n phoneMask: \"+269-##-#####\",\n },\n {\n name: \"Costa Rica\",\n code: \"CR\",\n flag: \"https://www.untitledui.com/images/flags/CR.svg\",\n phoneCode: \"506\",\n phoneMask: \"+506-####-####\",\n },\n {\n name: \"Croatia\",\n code: \"HR\",\n flag: \"https://www.untitledui.com/images/flags/HR.svg\",\n phoneCode: \"385\",\n phoneMask: \"+385-##-###-###\",\n },\n {\n name: \"Cuba\",\n code: \"CU\",\n flag: \"https://www.untitledui.com/images/flags/CU.svg\",\n phoneCode: \"53\",\n phoneMask: \"+53-#-###-####\",\n },\n {\n name: \"Cyprus\",\n code: \"CY\",\n flag: \"https://www.untitledui.com/images/flags/CY.svg\",\n phoneCode: \"357\",\n phoneMask: \"+357-##-###-###\",\n },\n {\n name: \"Czech Republic\",\n code: \"CZ\",\n flag: \"https://www.untitledui.com/images/flags/CZ.svg\",\n phoneCode: \"420\",\n phoneMask: \"+420 (###) ###-###\",\n },\n {\n name: \"Democratic Republic of the Congo\",\n code: \"CD\",\n flag: \"https://www.untitledui.com/images/flags/CD.svg\",\n phoneCode: \"243\",\n phoneMask: \"+243 (###) ###-###\",\n },\n {\n name: \"Denmark\",\n code: \"DK\",\n flag: \"https://www.untitledui.com/images/flags/DK.svg\",\n phoneCode: \"45\",\n phoneMask: \"+45-##-##-##-##\",\n },\n {\n name: \"Djibouti\",\n code: \"DJ\",\n flag: \"https://www.untitledui.com/images/flags/DJ.svg\",\n phoneCode: \"253\",\n phoneMask: \"+253-##-##-##-##\",\n },\n {\n name: \"Dominica\",\n code: \"DM\",\n flag: \"https://www.untitledui.com/images/flags/DM.svg\",\n phoneCode: \"+1-767\",\n phoneMask: \"+1 (767) ###-####\",\n },\n {\n name: \"Dominican Republic\",\n code: \"DO\",\n flag: \"https://www.untitledui.com/images/flags/DO.svg\",\n phoneCode: \"+1-809\",\n phoneMask: \"+1 (809) ###-####\",\n },\n {\n name: \"East Timor\",\n code: \"TL\",\n flag: \"https://www.untitledui.com/images/flags/TL.svg\",\n phoneCode: \"670\",\n phoneMask: \"+670-78#-#####\",\n },\n {\n name: \"Ecuador\",\n code: \"EC\",\n flag: \"https://www.untitledui.com/images/flags/EC.svg\",\n phoneCode: \"593\",\n phoneMask: \"+593-#-###-####\",\n },\n {\n name: \"Egypt\",\n code: \"EG\",\n flag: \"https://www.untitledui.com/images/flags/EG.svg\",\n phoneCode: \"20\",\n phoneMask: \"+20 (###) ###-####\",\n },\n {\n name: \"El Salvador\",\n code: \"SV\",\n flag: \"https://www.untitledui.com/images/flags/SV.svg\",\n phoneCode: \"503\",\n phoneMask: \"+503-##-##-####\",\n },\n {\n name: \"Equatorial Guinea\",\n code: \"GQ\",\n flag: \"https://www.untitledui.com/images/flags/GQ.svg\",\n phoneCode: \"240\",\n phoneMask: \"+240-##-###-####\",\n },\n {\n name: \"Eritrea\",\n code: \"ER\",\n flag: \"https://www.untitledui.com/images/flags/ER.svg\",\n phoneCode: \"291\",\n phoneMask: \"+291-#-###-###\",\n },\n {\n name: \"Estonia\",\n code: \"EE\",\n flag: \"https://www.untitledui.com/images/flags/EE.svg\",\n phoneCode: \"372\",\n phoneMask: \"+372-###-####\",\n },\n {\n name: \"Eswatini\",\n code: \"SZ\",\n flag: \"https://www.untitledui.com/images/flags/SZ.svg\",\n phoneCode: \"268\",\n phoneMask: \"+268-##-##-####\",\n },\n {\n name: \"Ethiopia\",\n code: \"ET\",\n flag: \"https://www.untitledui.com/images/flags/ET.svg\",\n phoneCode: \"251\",\n phoneMask: \"+251-##-###-####\",\n },\n {\n name: \"Fiji\",\n code: \"FJ\",\n flag: \"https://www.untitledui.com/images/flags/FJ.svg\",\n phoneCode: \"679\",\n phoneMask: \"+679-##-#####\",\n },\n {\n name: \"Finland\",\n code: \"FI\",\n flag: \"https://www.untitledui.com/images/flags/FI.svg\",\n phoneCode: \"358\",\n phoneMask: \"+358 (###) ###-##-##\",\n },\n {\n name: \"France\",\n code: \"FR\",\n flag: \"https://www.untitledui.com/images/flags/FR.svg\",\n phoneCode: \"33\",\n phoneMask: \"+590 (###) ###-###\",\n },\n {\n name: \"Gabon\",\n code: \"GA\",\n flag: \"https://www.untitledui.com/images/flags/GA.svg\",\n phoneCode: \"241\",\n phoneMask: \"+241-#-##-##-##\",\n },\n {\n name: \"Gambia\",\n code: \"GM\",\n flag: \"https://www.untitledui.com/images/flags/GM.svg\",\n phoneCode: \"220\",\n phoneMask: \"+220 (###) ##-##\",\n },\n {\n name: \"Georgia\",\n code: \"GE\",\n flag: \"https://www.untitledui.com/images/flags/GE.svg\",\n phoneCode: \"995\",\n phoneMask: \"+995 (###) ###-###\",\n },\n {\n name: \"Germany\",\n code: \"DE\",\n flag: \"https://www.untitledui.com/images/flags/DE.svg\",\n phoneCode: \"49\",\n phoneMask: \"+49-###-###\",\n },\n {\n name: \"Ghana\",\n code: \"GH\",\n flag: \"https://www.untitledui.com/images/flags/GH.svg\",\n phoneCode: \"233\",\n phoneMask: \"+233 (###) ###-###\",\n },\n {\n name: \"Greece\",\n code: \"GR\",\n flag: \"https://www.untitledui.com/images/flags/GR.svg\",\n phoneCode: \"30\",\n phoneMask: \"+30 (###) ###-####\",\n },\n {\n name: \"Grenada\",\n code: \"GD\",\n flag: \"https://www.untitledui.com/images/flags/GD.svg\",\n phoneCode: \"+1-473\",\n phoneMask: \"+1 (473) ###-####\",\n },\n {\n name: \"Guatemala\",\n code: \"GT\",\n flag: \"https://www.untitledui.com/images/flags/GT.svg\",\n phoneCode: \"502\",\n phoneMask: \"+502-#-###-####\",\n },\n {\n name: \"Guinea\",\n code: \"GN\",\n flag: \"https://www.untitledui.com/images/flags/GN.svg\",\n phoneCode: \"224\",\n phoneMask: \"+224-##-###-###\",\n },\n {\n name: \"Guinea-Bissau\",\n code: \"GW\",\n flag: \"https://www.untitledui.com/images/flags/GW.svg\",\n phoneCode: \"245\",\n phoneMask: \"+245-#-######\",\n },\n {\n name: \"Guyana\",\n code: \"GY\",\n flag: \"https://www.untitledui.com/images/flags/GY.svg\",\n phoneCode: \"592\",\n phoneMask: \"+592-###-####\",\n },\n {\n name: \"Haiti\",\n code: \"HT\",\n flag: \"https://www.untitledui.com/images/flags/HT.svg\",\n phoneCode: \"509\",\n phoneMask: \"+509-##-##-####\",\n },\n {\n name: \"Honduras\",\n code: \"HN\",\n flag: \"https://www.untitledui.com/images/flags/HN.svg\",\n phoneCode: \"504\",\n phoneMask: \"+504-####-####\",\n },\n {\n name: \"Hungary\",\n code: \"HU\",\n flag: \"https://www.untitledui.com/images/flags/HU.svg\",\n phoneCode: \"36\",\n phoneMask: \"+36 (###) ###-###\",\n },\n {\n name: \"Iceland\",\n code: \"IS\",\n flag: \"https://www.untitledui.com/images/flags/IS.svg\",\n phoneCode: \"354\",\n phoneMask: \"+354-###-####\",\n },\n {\n name: \"India\",\n code: \"IN\",\n flag: \"https://www.untitledui.com/images/flags/IN.svg\",\n phoneCode: \"91\",\n phoneMask: \"+91 (####) ###-###\",\n },\n {\n name: \"Indonesia\",\n code: \"ID\",\n flag: \"https://www.untitledui.com/images/flags/ID.svg\",\n phoneCode: \"62\",\n phoneMask: \"+62 (8##) ###-##-###\",\n },\n {\n name: \"Iran\",\n code: \"IR\",\n flag: \"https://www.untitledui.com/images/flags/IR.svg\",\n phoneCode: \"98\",\n phoneMask: \"+98 (###) ###-####\",\n },\n {\n name: \"Iraq\",\n code: \"IQ\",\n flag: \"https://www.untitledui.com/images/flags/IQ.svg\",\n phoneCode: \"964\",\n phoneMask: \"+964 (###) ###-####\",\n },\n {\n name: \"Ireland\",\n code: \"IE\",\n flag: \"https://www.untitledui.com/images/flags/IE.svg\",\n phoneCode: \"353\",\n phoneMask: \"+353 (###) ###-###\",\n },\n {\n name: \"Israel\",\n code: \"IL\",\n flag: \"https://www.untitledui.com/images/flags/IL.svg\",\n phoneCode: \"972\",\n phoneMask: \"+972-#-###-####\",\n },\n {\n name: \"Italy\",\n code: \"IT\",\n flag: \"https://www.untitledui.com/images/flags/IT.svg\",\n phoneCode: \"39\",\n phoneMask: \"+39 (###) ####-###\",\n },\n {\n name: \"Jamaica\",\n code: \"JM\",\n flag: \"https://www.untitledui.com/images/flags/JM.svg\",\n phoneCode: \"+1-876\",\n phoneMask: \"+1 (876) ###-####\",\n },\n {\n name: \"Japan\",\n code: \"JP\",\n flag: \"https://www.untitledui.com/images/flags/JP.svg\",\n phoneCode: \"81\",\n phoneMask: \"+81 (###) ###-###\",\n },\n {\n name: \"Jordan\",\n code: \"JO\",\n flag: \"https://www.untitledui.com/images/flags/JO.svg\",\n phoneCode: \"962\",\n phoneMask: \"+962-#-####-####\",\n },\n {\n name: \"Kazakhstan\",\n code: \"KZ\",\n flag: \"https://www.untitledui.com/images/flags/KZ.svg\",\n phoneCode: \"7\",\n phoneMask: \"+7 (7##) ###-##-##\",\n },\n {\n name: \"Kenya\",\n code: \"KE\",\n flag: \"https://www.untitledui.com/images/flags/KE.svg\",\n phoneCode: \"254\",\n phoneMask: \"+254-###-######\",\n },\n {\n name: \"Kiribati\",\n code: \"KI\",\n flag: \"https://www.untitledui.com/images/flags/KI.svg\",\n phoneCode: \"686\",\n phoneMask: \"+686-##-###\",\n },\n {\n name: \"Kuwait\",\n code: \"KW\",\n flag: \"https://www.untitledui.com/images/flags/KW.svg\",\n phoneCode: \"965\",\n phoneMask: \"+965-####-####\",\n },\n {\n name: \"Kyrgyzstan\",\n code: \"KG\",\n flag: \"https://www.untitledui.com/images/flags/KG.svg\",\n phoneCode: \"996\",\n phoneMask: \"+996 (###) ###-###\",\n },\n {\n name: \"Laos\",\n code: \"LA\",\n flag: \"https://www.untitledui.com/images/flags/LA.svg\",\n phoneCode: \"856\",\n phoneMask: \"+856-##-###-###\",\n },\n {\n name: \"Latvia\",\n code: \"LV\",\n flag: \"https://www.untitledui.com/images/flags/LV.svg\",\n phoneCode: \"371\",\n phoneMask: \"+371-##-###-###\",\n },\n {\n name: \"Lebanon\",\n code: \"LB\",\n flag: \"https://www.untitledui.com/images/flags/LB.svg\",\n phoneCode: \"961\",\n phoneMask: \"+961-#-###-###\",\n },\n {\n name: \"Lesotho\",\n code: \"LS\",\n flag: \"https://www.untitledui.com/images/flags/LS.svg\",\n phoneCode: \"266\",\n phoneMask: \"+266-#-###-####\",\n },\n {\n name: \"Liberia\",\n code: \"LR\",\n flag: \"https://www.untitledui.com/images/flags/LR.svg\",\n phoneCode: \"231\",\n phoneMask: \"+231-##-###-###\",\n },\n {\n name: \"Libya\",\n code: \"LY\",\n flag: \"https://www.untitledui.com/images/flags/LY.svg\",\n phoneCode: \"218\",\n phoneMask: \"+218-21-###-####\",\n },\n {\n name: \"Liechtenstein\",\n code: \"LI\",\n flag: \"https://www.untitledui.com/images/flags/LI.svg\",\n phoneCode: \"423\",\n phoneMask: \"+423 (###) ###-####\",\n },\n {\n name: \"Lithuania\",\n code: \"LT\",\n flag: \"https://www.untitledui.com/images/flags/LT.svg\",\n phoneCode: \"370\",\n phoneMask: \"+370 (###) ##-###\",\n },\n {\n name: \"Luxembourg\",\n code: \"LU\",\n flag: \"https://www.untitledui.com/images/flags/LU.svg\",\n phoneCode: \"352\",\n phoneMask: \"+352 (###) ###-###\",\n },\n {\n name: \"Madagascar\",\n code: \"MG\",\n flag: \"https://www.untitledui.com/images/flags/MG.svg\",\n phoneCode: \"261\",\n phoneMask: \"+261-##-##-#####\",\n },\n {\n name: \"Malawi\",\n code: \"MW\",\n flag: \"https://www.untitledui.com/images/flags/MW.svg\",\n phoneCode: \"265\",\n phoneMask: \"+265-#-####-####\",\n },\n {\n name: \"Malaysia\",\n code: \"MY\",\n flag: \"https://www.untitledui.com/images/flags/MY.svg\",\n phoneCode: \"60\",\n phoneMask: \"+60-#-###-###\",\n },\n {\n name: \"Maldives\",\n code: \"MV\",\n flag: \"https://www.untitledui.com/images/flags/MV.svg\",\n phoneCode: \"960\",\n phoneMask: \"+960-###-####\",\n },\n {\n name: \"Mali\",\n code: \"ML\",\n flag: \"https://www.untitledui.com/images/flags/ML.svg\",\n phoneCode: \"223\",\n phoneMask: \"+223-##-##-####\",\n },\n {\n name: \"Malta\",\n code: \"MT\",\n flag: \"https://www.untitledui.com/images/flags/MT.svg\",\n phoneCode: \"356\",\n phoneMask: \"+356-####-####\",\n },\n {\n name: \"Marshall Islands\",\n code: \"MH\",\n flag: \"https://www.untitledui.com/images/flags/MH.svg\",\n phoneCode: \"692\",\n phoneMask: \"+692-###-####\",\n },\n {\n name: \"Mauritania\",\n code: \"MR\",\n flag: \"https://www.untitledui.com/images/flags/MR.svg\",\n phoneCode: \"222\",\n phoneMask: \"+222-##-##-####\",\n },\n {\n name: \"Mauritius\",\n code: \"MU\",\n flag: \"https://www.untitledui.com/images/flags/MU.svg\",\n phoneCode: \"230\",\n phoneMask: \"+230-###-####\",\n },\n {\n name: \"Mexico\",\n code: \"MX\",\n flag: \"https://www.untitledui.com/images/flags/MX.svg\",\n phoneCode: \"52\",\n phoneMask: \"+52-##-##-####\",\n },\n {\n name: \"Micronesia\",\n code: \"FM\",\n flag: \"https://www.untitledui.com/images/flags/FM.svg\",\n phoneCode: \"691\",\n phoneMask: \"+691-###-####\",\n },\n {\n name: \"Moldova\",\n code: \"MD\",\n flag: \"https://www.untitledui.com/images/flags/MD.svg\",\n phoneCode: \"373\",\n phoneMask: \"+373-####-####\",\n },\n {\n name: \"Monaco\",\n code: \"MC\",\n flag: \"https://www.untitledui.com/images/flags/MC.svg\",\n phoneCode: \"377\",\n phoneMask: \"+377-##-###-###\",\n },\n {\n name: \"Mongolia\",\n code: \"MN\",\n flag: \"https://www.untitledui.com/images/flags/MN.svg\",\n phoneCode: \"976\",\n phoneMask: \"+976-##-##-####\",\n },\n {\n name: \"Montenegro\",\n code: \"ME\",\n flag: \"https://www.untitledui.com/images/flags/ME.svg\",\n phoneCode: \"382\",\n phoneMask: \"+382-##-###-###\",\n },\n {\n name: \"Morocco\",\n code: \"MA\",\n flag: \"https://www.untitledui.com/images/flags/MA.svg\",\n phoneCode: \"212\",\n phoneMask: \"+212-##-####-###\",\n },\n {\n name: \"Mozambique\",\n code: \"MZ\",\n flag: \"https://www.untitledui.com/images/flags/MZ.svg\",\n phoneCode: \"258\",\n phoneMask: \"+258-##-###-###\",\n },\n {\n name: \"Myanmar\",\n code: \"MM\",\n flag: \"https://www.untitledui.com/images/flags/MM.svg\",\n phoneCode: \"95\",\n phoneMask: \"+95-###-###\",\n },\n {\n name: \"Namibia\",\n code: \"NA\",\n flag: \"https://www.untitledui.com/images/flags/NA.svg\",\n phoneCode: \"264\",\n phoneMask: \"+264-##-###-####\",\n },\n {\n name: \"Nauru\",\n code: \"NR\",\n flag: \"https://www.untitledui.com/images/flags/NR.svg\",\n phoneCode: \"674\",\n phoneMask: \"+674-###-####\",\n },\n {\n name: \"Nepal\",\n code: \"NP\",\n flag: \"https://www.untitledui.com/images/flags/NP.svg\",\n phoneCode: \"977\",\n phoneMask: \"+977-##-###-###\",\n },\n {\n name: \"Netherlands\",\n code: \"NL\",\n flag: \"https://www.untitledui.com/images/flags/NL.svg\",\n phoneCode: \"31\",\n phoneMask: \"+31-##-###-####\",\n },\n {\n name: \"New Zealand\",\n code: \"NZ\",\n flag: \"https://www.untitledui.com/images/flags/NZ.svg\",\n phoneCode: \"64\",\n phoneMask: \"+64 (###) ###-####\",\n },\n {\n name: \"Nicaragua\",\n code: \"NI\",\n flag: \"https://www.untitledui.com/images/flags/NI.svg\",\n phoneCode: \"505\",\n phoneMask: \"+505-####-####\",\n },\n {\n name: \"Niger\",\n code: \"NE\",\n flag: \"https://www.untitledui.com/images/flags/NE.svg\",\n phoneCode: \"227\",\n phoneMask: \"+227-##-##-####\",\n },\n {\n name: \"Nigeria\",\n code: \"NG\",\n flag: \"https://www.untitledui.com/images/flags/NG.svg\",\n phoneCode: \"234\",\n phoneMask: \"+234 (###) ###-####\",\n },\n {\n name: \"North Korea\",\n code: \"KP\",\n flag: \"https://www.untitledui.com/images/flags/KP.svg\",\n phoneCode: \"850\",\n phoneMask: \"+850-####-#############\",\n },\n {\n name: \"North Macedonia\",\n code: \"MK\",\n flag: \"https://www.untitledui.com/images/flags/MK.svg\",\n phoneCode: \"389\",\n phoneMask: \"+389-##-###-###\",\n },\n {\n name: \"Norway\",\n code: \"NO\",\n flag: \"https://www.untitledui.com/images/flags/NO.svg\",\n phoneCode: \"47\",\n phoneMask: \"+47 (###) ##-###\",\n },\n {\n name: \"Oman\",\n code: \"OM\",\n flag: \"https://www.untitledui.com/images/flags/OM.svg\",\n phoneCode: \"968\",\n phoneMask: \"+968-##-###-###\",\n },\n {\n name: \"Pakistan\",\n code: \"PK\",\n flag: \"https://www.untitledui.com/images/flags/PK.svg\",\n phoneCode: \"92\",\n phoneMask: \"+92 (###) ###-####\",\n },\n {\n name: \"Palau\",\n code: \"PW\",\n flag: \"https://www.untitledui.com/images/flags/PW.svg\",\n phoneCode: \"680\",\n phoneMask: \"+680-###-####\",\n },\n {\n name: \"Panama\",\n code: \"PA\",\n flag: \"https://www.untitledui.com/images/flags/PA.svg\",\n phoneCode: \"507\",\n phoneMask: \"+507-###-####\",\n },\n {\n name: \"Papua New Guinea\",\n code: \"PG\",\n flag: \"https://www.untitledui.com/images/flags/PG.svg\",\n phoneCode: \"675\",\n phoneMask: \"+675 (###) ##-###\",\n },\n {\n name: \"Paraguay\",\n code: \"PY\",\n flag: \"https://www.untitledui.com/images/flags/PY.svg\",\n phoneCode: \"595\",\n phoneMask: \"+595 (###) ###-###\",\n },\n {\n name: \"Peru\",\n code: \"PE\",\n flag: \"https://www.untitledui.com/images/flags/PE.svg\",\n phoneCode: \"51\",\n phoneMask: \"+51 (###) ###-###\",\n },\n {\n name: \"Philippines\",\n code: \"PH\",\n flag: \"https://www.untitledui.com/images/flags/PH.svg\",\n phoneCode: \"63\",\n phoneMask: \"+63 (###) ###-####\",\n },\n {\n name: \"Poland\",\n code: \"PL\",\n flag: \"https://www.untitledui.com/images/flags/PL.svg\",\n phoneCode: \"48\",\n phoneMask: \"+48 (###) ###-###\",\n },\n {\n name: \"Portugal\",\n code: \"PT\",\n flag: \"https://www.untitledui.com/images/flags/PT.svg\",\n phoneCode: \"351\",\n phoneMask: \"+351-##-###-####\",\n },\n {\n name: \"Qatar\",\n code: \"QA\",\n flag: \"https://www.untitledui.com/images/flags/QA.svg\",\n phoneCode: \"974\",\n phoneMask: \"+974-####-####\",\n },\n {\n name: \"Romania\",\n code: \"RO\",\n flag: \"https://www.untitledui.com/images/flags/RO.svg\",\n phoneCode: \"40\",\n phoneMask: \"+40-##-###-####\",\n },\n {\n name: \"Russia\",\n code: \"RU\",\n flag: \"https://www.untitledui.com/images/flags/RU.svg\",\n phoneCode: \"7\",\n phoneMask: \"+7 (###) ###-##-##\",\n },\n {\n name: \"Rwanda\",\n code: \"RW\",\n flag: \"https://www.untitledui.com/images/flags/RW.svg\",\n phoneCode: \"250\",\n phoneMask: \"+250 (###) ###-###\",\n },\n {\n name: \"Saint Kitts and Nevis\",\n code: \"KN\",\n flag: \"https://www.untitledui.com/images/flags/KN.svg\",\n phoneCode: \"+1-869\",\n phoneMask: \"+1 (869) ###-####\",\n },\n {\n name: \"Saint Lucia\",\n code: \"LC\",\n flag: \"https://www.untitledui.com/images/flags/LC.svg\",\n phoneCode: \"+1-758\",\n phoneMask: \"+1 (758) ###-####\",\n },\n {\n name: \"Saint Vincent and the Grenadines\",\n code: \"VC\",\n flag: \"https://www.untitledui.com/images/flags/VC.svg\",\n phoneCode: \"+1-784\",\n phoneMask: \"+1 (784) ###-####\",\n },\n {\n name: \"Samoa\",\n code: \"WS\",\n flag: \"https://www.untitledui.com/images/flags/WS.svg\",\n phoneCode: \"685\",\n phoneMask: \"+685-##-####\",\n },\n {\n name: \"San Marino\",\n code: \"SM\",\n flag: \"https://www.untitledui.com/images/flags/SM.svg\",\n phoneCode: \"378\",\n phoneMask: \"+378-####-######\",\n },\n {\n name: \"Sao Tome and Principe\",\n code: \"ST\",\n flag: \"https://www.untitledui.com/images/flags/ST.svg\",\n phoneCode: \"239\",\n phoneMask: \"+239-##-#####\",\n },\n {\n name: \"Saudi Arabia\",\n code: \"SA\",\n flag: \"https://www.untitledui.com/images/flags/SA.svg\",\n phoneCode: \"966\",\n phoneMask: \"+966-#-###-####\",\n },\n {\n name: \"Senegal\",\n code: \"SN\",\n flag: \"https://www.untitledui.com/images/flags/SN.svg\",\n phoneCode: \"221\",\n phoneMask: \"+221-##-###-####\",\n },\n {\n name: \"Serbia\",\n code: \"RS\",\n flag: \"https://www.untitledui.com/images/flags/RS.svg\",\n phoneCode: \"381\",\n phoneMask: \"+381-##-###-####\",\n },\n {\n name: \"Seychelles\",\n code: \"SC\",\n flag: \"https://www.untitledui.com/images/flags/SC.svg\",\n phoneCode: \"248\",\n phoneMask: \"+248-#-###-###\",\n },\n {\n name: \"Sierra Leone\",\n code: \"SL\",\n flag: \"https://www.untitledui.com/images/flags/SL.svg\",\n phoneCode: \"232\",\n phoneMask: \"+232-##-######\",\n },\n {\n name: \"Singapore\",\n code: \"SG\",\n flag: \"https://www.untitledui.com/images/flags/SG.svg\",\n phoneCode: \"65\",\n phoneMask: \"+65-####-####\",\n },\n {\n name: \"Slovakia\",\n code: \"SK\",\n flag: \"https://www.untitledui.com/images/flags/SK.svg\",\n phoneCode: \"421\",\n phoneMask: \"+421 (###) ###-###\",\n },\n {\n name: \"Slovenia\",\n code: \"SI\",\n flag: \"https://www.untitledui.com/images/flags/SI.svg\",\n phoneCode: \"386\",\n phoneMask: \"+386-##-###-###\",\n },\n {\n name: \"Solomon Islands\",\n code: \"SB\",\n flag: \"https://www.untitledui.com/images/flags/SB.svg\",\n phoneCode: \"677\",\n phoneMask: \"+677-#####\",\n },\n {\n name: \"Somalia\",\n code: \"SO\",\n flag: \"https://www.untitledui.com/images/flags/SO.svg\",\n phoneCode: \"252\",\n phoneMask: \"+252-#-###-###\",\n },\n {\n name: \"South Africa\",\n code: \"ZA\",\n flag: \"https://www.untitledui.com/images/flags/ZA.svg\",\n phoneCode: \"27\",\n phoneMask: \"+27-##-###-####\",\n },\n {\n name: \"South Korea\",\n code: \"KR\",\n flag: \"https://www.untitledui.com/images/flags/KR.svg\",\n phoneCode: \"82\",\n phoneMask: \"+82-##-###-####\",\n },\n {\n name: \"South Sudan\",\n code: \"SS\",\n flag: \"https://www.untitledui.com/images/flags/SS.svg\",\n phoneCode: \"211\",\n phoneMask: \"+211-##-###-####\",\n },\n {\n name: \"Spain\",\n code: \"ES\",\n flag: \"https://www.untitledui.com/images/flags/ES.svg\",\n phoneCode: \"34\",\n phoneMask: \"+34 (###) ###-###\",\n },\n {\n name: \"Sri Lanka\",\n code: \"LK\",\n flag: \"https://www.untitledui.com/images/flags/LK.svg\",\n phoneCode: \"94\",\n phoneMask: \"+94-##-###-####\",\n },\n {\n name: \"Suriname\",\n code: \"SR\",\n flag: \"https://www.untitledui.com/images/flags/SR.svg\",\n phoneCode: \"597\",\n phoneMask: \"+597-###-###\",\n },\n {\n name: \"Sweden\",\n code: \"SE\",\n flag: \"https://www.untitledui.com/images/flags/SE.svg\",\n phoneCode: \"46\",\n phoneMask: \"+46-##-###-####\",\n },\n {\n name: \"Switzerland\",\n code: \"CH\",\n flag: \"https://www.untitledui.com/images/flags/CH.svg\",\n phoneCode: \"41\",\n phoneMask: \"+41-##-###-####\",\n },\n {\n name: \"Syria\",\n code: \"SY\",\n flag: \"https://www.untitledui.com/images/flags/SY.svg\",\n phoneCode: \"963\",\n phoneMask: \"+963-##-####-###\",\n },\n {\n name: \"Tajikistan\",\n code: \"TJ\",\n flag: \"https://www.untitledui.com/images/flags/TJ.svg\",\n phoneCode: \"992\",\n phoneMask: \"+992-##-###-####\",\n },\n {\n name: \"Tanzania\",\n code: \"TZ\",\n flag: \"https://www.untitledui.com/images/flags/TZ.svg\",\n phoneCode: \"255\",\n phoneMask: \"+255-##-###-####\",\n },\n {\n name: \"Thailand\",\n code: \"TH\",\n flag: \"https://www.untitledui.com/images/flags/TH.svg\",\n phoneCode: \"66\",\n phoneMask: \"+66-##-###-###\",\n },\n {\n name: \"Togo\",\n code: \"TG\",\n flag: \"https://www.untitledui.com/images/flags/TG.svg\",\n phoneCode: \"228\",\n phoneMask: \"+228-##-###-###\",\n },\n {\n name: \"Tonga\",\n code: \"TO\",\n flag: \"https://www.untitledui.com/images/flags/TO.svg\",\n phoneCode: \"676\",\n phoneMask: \"+676-#####\",\n },\n {\n name: \"Trinidad and Tobago\",\n code: \"TT\",\n flag: \"https://www.untitledui.com/images/flags/TT.svg\",\n phoneCode: \"+1-868\",\n phoneMask: \"+1 (868) ###-####\",\n },\n {\n name: \"Tunisia\",\n code: \"TN\",\n flag: \"https://www.untitledui.com/images/flags/TN.svg\",\n phoneCode: \"216\",\n phoneMask: \"+216-##-###-###\",\n },\n {\n name: \"Turkey\",\n code: \"TR\",\n flag: \"https://www.untitledui.com/images/flags/TR.svg\",\n phoneCode: \"90\",\n phoneMask: \"+90 (###) ###-####\",\n },\n {\n name: \"Turkmenistan\",\n code: \"TM\",\n flag: \"https://www.untitledui.com/images/flags/TM.svg\",\n phoneCode: \"993\",\n phoneMask: \"+993-#-###-####\",\n },\n {\n name: \"Tuvalu\",\n code: \"TV\",\n flag: \"https://www.untitledui.com/images/flags/TV.svg\",\n phoneCode: \"688\",\n phoneMask: \"+688-2####\",\n },\n {\n name: \"Uganda\",\n code: \"UG\",\n flag: \"https://www.untitledui.com/images/flags/UG.svg\",\n phoneCode: \"256\",\n phoneMask: \"+256 (###) ###-###\",\n },\n {\n name: \"Ukraine\",\n code: \"UA\",\n flag: \"https://www.untitledui.com/images/flags/UA.svg\",\n phoneCode: \"380\",\n phoneMask: \"+380 (##) ###-##-##\",\n },\n {\n name: \"United Arab Emirates\",\n code: \"AE\",\n flag: \"https://www.untitledui.com/images/flags/AE.svg\",\n phoneCode: \"971\",\n phoneMask: \"+971-#-###-####\",\n },\n {\n name: \"United Kingdom\",\n code: \"GB\",\n flag: \"https://www.untitledui.com/images/flags/GB.svg\",\n phoneCode: \"44\",\n },\n {\n name: \"United States\",\n code: \"US\",\n flag: \"https://www.untitledui.com/images/flags/US.svg\",\n phoneCode: \"1\",\n phoneMask: \"+1 (###) ###-####\",\n },\n {\n name: \"Uruguay\",\n code: \"UY\",\n flag: \"https://www.untitledui.com/images/flags/UY.svg\",\n phoneCode: \"598\",\n phoneMask: \"+598-#-###-##-##\",\n },\n {\n name: \"Uzbekistan\",\n code: \"UZ\",\n flag: \"https://www.untitledui.com/images/flags/UZ.svg\",\n phoneCode: \"998\",\n phoneMask: \"+998-##-###-####\",\n },\n {\n name: \"Vanuatu\",\n code: \"VU\",\n flag: \"https://www.untitledui.com/images/flags/VU.svg\",\n phoneCode: \"678\",\n phoneMask: \"+678-#####\",\n },\n {\n name: \"Venezuela\",\n code: \"VE\",\n flag: \"https://www.untitledui.com/images/flags/VE.svg\",\n phoneCode: \"58\",\n phoneMask: \"+58 (###) ###-####\",\n },\n {\n name: \"Vietnam\",\n code: \"VN\",\n flag: \"https://www.untitledui.com/images/flags/VN.svg\",\n phoneCode: \"84\",\n phoneMask: \"+84 (###) ####-###\",\n },\n {\n name: \"Yemen\",\n code: \"YE\",\n flag: \"https://www.untitledui.com/images/flags/YE.svg\",\n phoneCode: \"967\",\n phoneMask: \"+967-##-###-###\",\n },\n {\n name: \"Zambia\",\n code: \"ZM\",\n flag: \"https://www.untitledui.com/images/flags/ZM.svg\",\n phoneCode: \"260\",\n phoneMask: \"+260-##-###-####\",\n },\n {\n name: \"Zimbabwe\",\n code: \"ZW\",\n flag: \"https://www.untitledui.com/images/flags/ZW.svg\",\n phoneCode: \"263\",\n phoneMask: \"+263-#-######\",\n },\n];\n\n/**\n * Phone code options for the select component.\n */\nexport const phoneCodeOptions: SelectItemType[] = countries.map((country) => ({\n id: country.code,\n label: country.code,\n}));\n\n/**\n * Country options for the select component.\n */\nexport const countriesOptions: SelectItemType[] = countries.map((country) => ({\n id: country.code,\n label: country.name,\n icon: (props: HTMLAttributes<HTMLImageElement>) => {\n const { ...restProps } = props;\n return <Image {...restProps} src={country.flag} alt={`${country.name} flag`} width={20} height={15} />;\n },\n}));\n\nexport default countries;\n","import type countries from './countries';\n\ntype Country = (typeof countries)[0];\n\n/** Get national-format mask from country by stripping the country code prefix (e.g. \"+1 (###) ###-####\" → \"(###) ###-####\"). */\nexport function getNationalMask(country: Country | undefined): string {\n if (!country?.phoneMask) return '';\n const code = country.phoneCode.startsWith('+') ? country.phoneCode : `+${country.phoneCode}`;\n const escaped = code.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return country.phoneMask.replace(new RegExp(`^\\\\s*${escaped}[\\\\s-]*`), '').trim();\n}\n\n/** Format a raw digit string into a mask pattern where '#' represents one digit. No trailing literals so backspace works naturally. */\nexport function formatDigitsToMask(digits: string, mask: string): string {\n if (digits.length === 0) return '';\n let i = 0;\n let out = '';\n for (const c of mask) {\n if (c === '#') {\n if (i < digits.length) out += digits[i++];\n else break;\n } else if (i < digits.length) {\n out += c;\n }\n }\n return out;\n}\n","type FbqFn = (method: string, ...args: unknown[]) => void;\n\nexport type PixelEvent = 'PageView' | 'ViewContent' | 'InitiateCheckout' | 'Lead';\n\nexport interface PixelEventParams {\n contentName?: string;\n contentCategory?: string;\n}\n\n/** Raw (unhashed) user identifiers for advanced matching. */\nexport interface PixelUserData {\n email?: string | null;\n phone?: string | null;\n}\n\n// Hashed user data stored in sessionStorage for the duration of the browsing session.\n// Keyed by a short namespace to avoid collisions.\nconst STORAGE_KEY = 'ks_pud';\n\nasync function sha256Hex(str: string): Promise<string> {\n const buffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str));\n return Array.from(new Uint8Array(buffer))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\nfunction getFbq(): FbqFn | undefined {\n if (typeof window === 'undefined') return undefined;\n return (window as Window & { fbq?: FbqFn }).fbq;\n}\n\n/** Read the pixel IDs registered by MetaPixel via the inline init script. */\nfunction getRegisteredPixelIds(): string[] {\n return (window as Window & { __ks_pixel_ids?: string[] }).__ks_pixel_ids ?? [];\n}\n\n/** Apply stored hashed user data to every configured Meta Pixel. */\nfunction applyStoredUserData(fbq: FbqFn): void {\n try {\n const raw = sessionStorage.getItem(STORAGE_KEY);\n if (!raw) return;\n const hashed = JSON.parse(raw) as Record<string, string>;\n if (Object.keys(hashed).length === 0) return;\n getRegisteredPixelIds().forEach((id) => fbq('init', id, hashed));\n } catch {\n // sessionStorage unavailable or JSON malformed — safe to ignore\n }\n}\n\n/**\n * Hash and store user identifiers so they are automatically included in all\n * subsequent pixel events for this browser session. Call this as soon as\n * identity is known (e.g. contact form submission, portal login step 1).\n */\nexport async function setPixelUserData(userData: PixelUserData): Promise<void> {\n const hashed: Record<string, string> = {};\n\n if (userData.email) {\n hashed.em = await sha256Hex(userData.email.trim().toLowerCase());\n }\n if (userData.phone) {\n const digits = userData.phone.replace(/\\D/g, '');\n if (digits) hashed.ph = await sha256Hex(digits);\n }\n\n if (Object.keys(hashed).length === 0) return;\n\n try {\n sessionStorage.setItem(STORAGE_KEY, JSON.stringify(hashed));\n } catch {\n // sessionStorage unavailable — still apply to fbq for this page load\n }\n\n const fbq = getFbq();\n if (fbq) {\n getRegisteredPixelIds().forEach((id) => fbq('init', id, hashed));\n }\n}\n\n/**\n * Single entry point for all client-side Meta Pixel event fires.\n * Automatically applies any stored user identity before firing so that Meta\n * can match events to known users across the entire session.\n * Silently no-ops if fbq is not loaded (pixel not configured for this site).\n *\n * @param eventId - Optional server-side event ID for browser/server deduplication.\n * Pass the `eventId` returned by the form submission API so Meta can match and\n * deduplicate the browser Lead event against the server-side CAPI Lead event.\n * Format: fbq('track', event, params, { eventID: eventId })\n */\nexport function firePixelEvent(event: PixelEvent, params?: PixelEventParams, eventId?: string): void {\n const fbq = getFbq();\n if (!fbq) {\n console.debug('[MetaPixel] skipped — fbq not loaded', { event });\n return;\n }\n\n // Re-apply stored identity before every event so user data is included\n // even on events that fire after a client-side navigation (PageView, ViewContent, etc.)\n applyStoredUserData(fbq);\n\n const normalized: Record<string, string> = {};\n if (params?.contentName) normalized.content_name = params.contentName;\n if (params?.contentCategory) normalized.content_category = params.contentCategory;\n\n const customData = Object.keys(normalized).length > 0 ? normalized : undefined;\n const eventData = eventId ? { eventID: eventId } : undefined;\n\n console.debug('[MetaPixel]', event, normalized, eventId ? { eventID: eventId } : '');\n fbq('track', event, customData, eventData);\n}\n","/**\n * PostHog event capture — Keystone customer sites.\n *\n * ## Naming convention\n * All events use snake_case `object_action` format.\n * Properties use snake_case as well.\n *\n * ## Event taxonomy\n * Add new events here: define the name in `KsEventName` and its required\n * properties in `KsEventProperties`. Every callsite is then type-checked.\n *\n * ## Usage\n *\n * import { captureEvent } from 'keystone-design-bootstrap/tracking';\n *\n * captureEvent('form_submitted', { form_type: 'lead' });\n * captureEvent('booking_cta_clicked', { source_path: '/services/massage', booking_url: url });\n *\n * All calls are safe no-ops when PostHog has not been initialised (e.g. no\n * POSTHOG_API_KEY configured on the server).\n *\n * ## Super properties\n * account_id, account_name, and site_domain are registered as super properties\n * by PostHogProvider and are automatically attached to every event — you do not\n * need to include them in individual captureEvent calls.\n */\n\nimport posthog from 'posthog-js';\n\n// ---------------------------------------------------------------------------\n// Event taxonomy\n// ---------------------------------------------------------------------------\n\nexport type KsEventName =\n // Booking / conversion\n | 'booking_cta_clicked'\n // Forms\n | 'form_submitted'\n | 'form_failed'\n // Chat widget\n | 'chat_opened'\n | 'chat_message_sent'\n | 'chat_message_failed'\n // Member portal — tab navigation\n | 'portal_tab_viewed'\n // Member portal — authentication flow\n | 'portal_login_started'\n | 'portal_login_step_viewed'\n | 'portal_login_step_submitted'\n | 'portal_login_step_advanced'\n | 'portal_login_back_clicked'\n | 'portal_login_identified'\n | 'portal_login_completed'\n | 'portal_login_failed';\n\nexport type KsEventProperties = {\n /** Fired when a visitor clicks any CTA that links to the external booking URL. */\n booking_cta_clicked: {\n source_path: string;\n booking_url: string;\n };\n\n /** Fired when a Keystone form is successfully submitted. */\n form_submitted: {\n /** One of: lead | job_application | marketing_list_signup */\n form_type: string;\n /** Server-generated event ID for CAPI deduplication (when present). */\n event_id?: string;\n };\n\n /** Fired when a form submission fails (validation error or network error). */\n form_failed: {\n form_type: string;\n error: string;\n };\n\n /** Fired when the chat widget is first opened by the visitor. */\n chat_opened: Record<string, never>;\n\n /** Fired when a chat message is successfully sent. */\n chat_message_sent: {\n /** Whether the visitor is authenticated (contactId present). */\n is_authenticated: boolean;\n };\n\n /** Fired when a chat message fails to send. */\n chat_message_failed: {\n error: string;\n };\n\n /** Fired when a member portal tab is opened. */\n portal_tab_viewed: {\n tab: string;\n };\n\n /** Fired when the portal login modal is opened / login flow starts. */\n portal_login_started: Record<string, never>;\n\n /** Fired whenever a login step becomes visible to the user. */\n portal_login_step_viewed: {\n step: 'identifier' | 'signin' | 'signup';\n };\n\n /** Fired when the user submits a specific login step. */\n portal_login_step_submitted: {\n step: 'identifier' | 'signin' | 'signup';\n };\n\n /** Fired when the flow transitions from one step to another state. */\n portal_login_step_advanced: {\n from_step: 'identifier' | 'signin' | 'signup';\n to_step: 'signin' | 'signup' | 'authenticated';\n reason: string;\n };\n\n /** Fired when the user explicitly navigates back to the identifier step. */\n portal_login_back_clicked: {\n from_step: 'signin' | 'signup';\n to_step: 'identifier';\n };\n\n /**\n * Fired after the identifier step resolves — we know whether the user\n * already has an account.\n */\n portal_login_identified: {\n method: 'email' | 'phone' | 'email_and_phone';\n user_exists: boolean;\n };\n\n /** Fired after the user successfully signs in or creates an account. */\n portal_login_completed: {\n flow: 'signin' | 'signup';\n };\n\n /** Fired when any step of the login flow returns an error. */\n portal_login_failed: {\n step: 'identifier' | 'signin' | 'signup';\n reason: string;\n };\n};\n\n// ---------------------------------------------------------------------------\n// Capture helper\n// ---------------------------------------------------------------------------\n\n/**\n * Captures a typed Keystone analytics event via PostHog.\n * Safe no-op when PostHog has not been initialised.\n */\nexport function captureEvent<E extends KsEventName>(\n event: E,\n ...args: KsEventProperties[E] extends Record<string, never>\n ? []\n : [properties: KsEventProperties[E]]\n): void {\n posthog.capture(event, args[0] as Record<string, unknown>);\n}\n","'use client';\n\nimport React, { useState, useTransition, useRef, useEffect, useCallback } from 'react';\nimport { useRouter } from 'next/navigation';\nimport { useRealtimeReplyOrchestrator, type RealtimeSubscriptionData } from '../chat/useRealtimeReplyOrchestrator';\n\nexport function MessageComposer({ contactId }: { contactId: number }) {\n const [body, setBody] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [isPending, startTransition] = useTransition();\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const router = useRouter();\n\n const hasAgentReplyWithBody = useCallback(async () => {\n const response = await fetch(`/api/chat/?contact_id=${encodeURIComponent(contactId)}`);\n if (!response.ok) return false;\n const result = await response.json();\n const messages = (result?.data || []) as Array<{ sender_type?: string; body?: string | null }>;\n const latest = messages[messages.length - 1];\n return (\n latest?.sender_type === 'agent' &&\n latest?.body != null &&\n String(latest.body).trim() !== ''\n );\n }, [contactId]);\n\n const fetchRealtimeData = useCallback(async (): Promise<RealtimeSubscriptionData | null> => {\n const response = await fetch(`/api/chat/?action=realtime_token&contact_id=${encodeURIComponent(contactId)}`);\n if (!response.ok) return null;\n const result = await response.json();\n const token = result?.data?.token as string | undefined;\n const streamContactId = result?.data?.contact_id as number | undefined;\n const cableUrl = result?.data?.cable_url as string | undefined;\n if (!token || !streamContactId || !cableUrl) return null;\n return { token, contact_id: streamContactId, cable_url: cableUrl };\n }, [contactId]);\n\n const {\n beginReplyWait,\n ensureRealtimeSubscription,\n } = useRealtimeReplyOrchestrator({\n debugLabel: 'MessageComposer',\n fetchRealtimeData,\n loadLatestHasReply: hasAgentReplyWithBody,\n onReplyResolved: () => {\n router.refresh();\n },\n });\n\n // Auto-resize textarea\n useEffect(() => {\n const el = textareaRef.current;\n if (!el) return;\n el.style.height = 'auto';\n el.style.height = `${Math.min(el.scrollHeight, 120)}px`;\n }, [body]);\n\n useEffect(() => {\n void ensureRealtimeSubscription();\n }, [ensureRealtimeSubscription]);\n\n function submit() {\n if (!body.trim() || isPending) return;\n setError(null);\n startTransition(async () => {\n try {\n const res = await fetch('/api/chat', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ contact_id: contactId, body: body.trim() }),\n });\n const result = await res.json().catch(() => ({}));\n if (!res.ok) {\n setError(result.error || 'Failed to send message.');\n } else {\n setBody('');\n router.refresh();\n const hasBackgroundReplyJob = Boolean(result?.data?.job_id);\n if (hasBackgroundReplyJob) {\n const realtimeFromSend = result?.data?.realtime_token && result?.data?.contact_id && result?.data?.cable_url\n ? {\n token: result.data.realtime_token,\n contact_id: result.data.contact_id,\n cable_url: result.data.cable_url,\n }\n : null;\n beginReplyWait({ realtimeData: realtimeFromSend });\n }\n }\n } catch {\n setError('Failed to send message.');\n }\n });\n }\n\n function handleSubmit(e: React.FormEvent) {\n e.preventDefault();\n submit();\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLTextAreaElement>) {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n submit();\n }\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"border-t border-secondary px-4 py-3\">\n {error && (\n <p className=\"mb-2 text-xs text-red-600\">{error}</p>\n )}\n <div className=\"flex items-end gap-2\">\n <textarea\n ref={textareaRef}\n value={body}\n onChange={(e) => setBody(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Type a message… (Enter to send)\"\n rows={1}\n disabled={isPending}\n className=\"flex-1 resize-none rounded-input border border-primary bg-primary px-3 py-2 text-sm text-primary placeholder-quaternary focus:border-brand focus:outline-none focus:ring-1 focus:ring-brand transition-colors disabled:opacity-50\"\n />\n <button\n type=\"submit\"\n disabled={!body.trim() || isPending}\n className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-interactive bg-brand-solid text-white transition-colors hover:bg-brand-solid_hover disabled:opacity-40 disabled:cursor-not-allowed\"\n aria-label=\"Send message\"\n >\n {isPending ? (\n <svg className=\"size-4 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\" />\n </svg>\n ) : (\n <svg className=\"size-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.269 20.876L5.999 12zm0 0h7.5\" />\n </svg>\n )}\n </button>\n </div>\n </form>\n );\n}\n","'use client';\n\nimport { useCallback, useEffect, useRef } from 'react';\nimport { createConsumer } from '@rails/actioncable';\n\nexport interface RealtimeSubscriptionData {\n token: string;\n contact_id: number;\n cable_url: string;\n}\n\ninterface UseRealtimeReplyOrchestratorOptions {\n debugLabel: string;\n fetchRealtimeData: () => Promise<RealtimeSubscriptionData | null>;\n loadLatestHasReply: () => Promise<boolean>;\n onReplyResolved: () => void;\n onAgentThinking?: () => void;\n}\n\nexport function useRealtimeReplyOrchestrator({\n debugLabel,\n fetchRealtimeData,\n loadLatestHasReply,\n onReplyResolved,\n onAgentThinking,\n}: UseRealtimeReplyOrchestratorOptions) {\n const cableRef = useRef<ReturnType<typeof createConsumer> | null>(null);\n const subscriptionRef = useRef<{ unsubscribe: () => void } | null>(null);\n const subscribedContactRef = useRef<number | null>(null);\n\n const clearRealtime = useCallback(() => {\n if (subscriptionRef.current) {\n subscriptionRef.current.unsubscribe();\n subscriptionRef.current = null;\n }\n if (cableRef.current) {\n cableRef.current.disconnect();\n cableRef.current = null;\n }\n subscribedContactRef.current = null;\n }, []);\n\n const resolveReply = useCallback(() => {\n onReplyResolved();\n }, [onReplyResolved]);\n\n const subscribeRealtime = useCallback((realtime: RealtimeSubscriptionData) => {\n const token = realtime.token;\n const contactIdForStream = realtime.contact_id;\n const cableUrl = realtime.cable_url;\n if (!token || !contactIdForStream || !cableUrl) return;\n\n if (\n subscribedContactRef.current === contactIdForStream &&\n subscriptionRef.current &&\n cableRef.current\n ) {\n return;\n }\n\n clearRealtime();\n\n const cable = createConsumer(`${cableUrl}?token=${encodeURIComponent(token)}`);\n cableRef.current = cable;\n subscribedContactRef.current = contactIdForStream;\n subscriptionRef.current = cable.subscriptions.create(\n { channel: 'ContactCommunicationsChannel', contact_id: String(contactIdForStream) },\n {\n connected: () => {\n console.info(`[${debugLabel}] realtime connected contact_id=${contactIdForStream}`);\n },\n disconnected: () => {\n console.warn(`[${debugLabel}] realtime disconnected contact_id=${contactIdForStream}`);\n },\n rejected: () => {\n console.warn(`[${debugLabel}] realtime rejected contact_id=${contactIdForStream}`);\n },\n received: async (data: { type?: string }) => {\n console.info(`[${debugLabel}] realtime received type=${data?.type ?? 'unknown'} contact_id=${contactIdForStream}`);\n if (data?.type === 'agent_thinking') {\n onAgentThinking?.();\n return;\n }\n if (data?.type !== 'new_communication') return;\n try {\n const hasReply = await loadLatestHasReply();\n if (hasReply) {\n resolveReply();\n }\n } catch (error) {\n console.error(`[${debugLabel}] realtime receive handling error`, error);\n }\n },\n }\n );\n }, [clearRealtime, debugLabel, loadLatestHasReply, onAgentThinking, resolveReply]);\n\n const ensureRealtimeSubscription = useCallback(async () => {\n try {\n const realtime = await fetchRealtimeData();\n if (!realtime) return;\n subscribeRealtime(realtime);\n } catch {\n // Realtime is best-effort; UI remains in waiting state until connection succeeds.\n }\n }, [fetchRealtimeData, subscribeRealtime]);\n\n const beginReplyWait = useCallback((options?: { realtimeData?: RealtimeSubscriptionData | null }) => {\n if (options?.realtimeData) {\n subscribeRealtime(options.realtimeData);\n } else {\n void ensureRealtimeSubscription();\n }\n }, [ensureRealtimeSubscription, subscribeRealtime]);\n\n useEffect(() => {\n return () => {\n clearRealtime();\n };\n }, [clearRealtime]);\n\n return {\n ensureRealtimeSubscription,\n subscribeRealtime,\n beginReplyWait,\n };\n}\n","'use client';\n\nimport React from 'react';\nimport type { PhotoAttachment } from '../../types/api/photos';\nimport { useImageCycle, CROSSFADE_DURATION_MS } from '../../lib/hooks/use-image-cycle';\n\nconst CROSSFADE_STYLE = { transitionDuration: `${CROSSFADE_DURATION_MS}ms` };\n\ninterface RowThumbnailProps {\n photoAttachments?: PhotoAttachment[];\n seed: string;\n alt: string;\n /** Tailwind size classes. Defaults to w-14 h-14. */\n sizeClassName?: string;\n}\n\nexport function RowThumbnail({\n photoAttachments,\n seed,\n alt,\n sizeClassName = 'w-14 h-14',\n}: RowThumbnailProps) {\n const { list, currentIndex, nextIndex, transitioning } = useImageCycle(photoAttachments, seed);\n\n const displayAlt = list[currentIndex]?.alt || alt;\n\n if (list.length === 0) {\n return (\n <div className={`${sizeClassName} shrink-0 rounded-component bg-secondary border border-tertiary flex items-center justify-center`}>\n <svg className=\"size-5 text-quaternary\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z\" />\n </svg>\n </div>\n );\n }\n\n if (list.length === 1) {\n return (\n <div className={`${sizeClassName} shrink-0 rounded-component overflow-hidden`}>\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img\n src={list[0]!.url}\n alt={list[0]!.alt || alt}\n className=\"w-full h-full object-cover transition-transform duration-300 group-hover:scale-105\"\n />\n </div>\n );\n }\n\n return (\n <div className={`${sizeClassName} shrink-0 rounded-component overflow-hidden relative`}>\n <div\n className={`absolute inset-0 ${transitioning ? 'transition-opacity ease-in-out' : 'transition-none'}`}\n style={{ opacity: transitioning ? 0 : 1, ...(transitioning ? CROSSFADE_STYLE : {}) }}\n >\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img\n src={list[currentIndex]!.url}\n alt={list[currentIndex]?.alt ?? displayAlt}\n className=\"w-full h-full object-cover transition-transform duration-300 group-hover:scale-105\"\n />\n </div>\n <div\n className={`absolute inset-0 ${transitioning ? 'transition-opacity ease-in-out' : 'transition-none'}`}\n style={{ opacity: transitioning ? 1 : 0, ...(transitioning ? CROSSFADE_STYLE : {}) }}\n >\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img\n src={list[nextIndex]!.url}\n alt={list[nextIndex]?.alt ?? displayAlt}\n className=\"w-full h-full object-cover transition-transform duration-300 group-hover:scale-105\"\n />\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { useState, useEffect, useMemo } from 'react';\nimport type { PhotoAttachment } from '../../types/api/photos';\n\nconst CYCLE_INTERVAL_MIN_MS = 6000;\nconst CYCLE_INTERVAL_MAX_MS = 8000;\nexport const CROSSFADE_DURATION_MS = 600;\n\nexport interface CycledImage {\n url: string;\n alt: string;\n}\n\nexport interface UseImageCycleResult {\n list: CycledImage[];\n currentIndex: number;\n nextIndex: number;\n transitioning: boolean;\n}\n\n/** Stable value in [0, 1) derived from seed string (FNV-1a hash). Same seed always produces same value. */\nfunction seedToUnit(seed: string): number {\n let h = 2166136261 >>> 0;\n for (let i = 0; i < seed.length; i++) {\n h ^= seed.charCodeAt(i);\n h = (Math.imul(h, 16777619) >>> 0) >>> 0;\n }\n return (h >>> 0) / 4294967296;\n}\n\n/** Seeded Fisher-Yates shuffle. Same seed produces same order (SSR-safe). */\nfunction shuffleWithSeed<T>(array: T[], seed: string): T[] {\n if (array.length <= 1) return array;\n const arr = [...array];\n let h = 2166136261 >>> 0;\n for (let i = 0; i < seed.length; i++) {\n h ^= seed.charCodeAt(i);\n h = (Math.imul(h, 16777619) >>> 0) >>> 0;\n }\n const next = (step: number) => {\n h = (Math.imul(1664525, (h + step) >>> 0) + 1013904223) >>> 0;\n return (h >>> 0) / 4294967296;\n };\n for (let i = arr.length - 1; i > 0; i--) {\n const j = Math.floor(next(i) * (i + 1));\n [arr[i], arr[j]] = [arr[j], arr[i]];\n }\n return arr;\n}\n\nfunction photoUrlFromAttachment(pa: PhotoAttachment): string | undefined {\n return pa.photo?.large_url || pa.photo?.medium_url || pa.photo?.thumbnail_url;\n}\n\nfunction photoAltFromAttachment(pa: PhotoAttachment): string {\n return pa.photo?.alt_text || pa.photo?.title || '';\n}\n\n/**\n * Cycles through a list of photo attachments with a seeded shuffle and crossfade transitions.\n *\n * Each card uses a unique seed so intervals are staggered — cards don't all transition in sync.\n * The shuffle is deterministic (SSR-safe) and the timer only activates when there are 2+ images.\n */\nexport function useImageCycle(\n photoAttachments: PhotoAttachment[] | undefined,\n seed: string\n): UseImageCycleResult {\n const list = useMemo<CycledImage[]>(() => {\n const arr = Array.isArray(photoAttachments) && photoAttachments.length > 0 ? photoAttachments : [];\n if (arr.length === 0) return [];\n return shuffleWithSeed(arr, seed)\n .map((pa) => ({ url: photoUrlFromAttachment(pa) ?? '', alt: photoAltFromAttachment(pa) }))\n .filter((x) => x.url);\n }, [photoAttachments, seed]);\n\n const [currentIndex, setCurrentIndex] = useState(0);\n const [transitioning, setTransitioning] = useState(false);\n\n // Per-card random interval (6–8 s) so cards don't all transition in sync\n const intervalMs = useMemo(\n () => CYCLE_INTERVAL_MIN_MS + Math.floor(seedToUnit(seed) * (CYCLE_INTERVAL_MAX_MS - CYCLE_INTERVAL_MIN_MS + 1)),\n [seed]\n );\n\n useEffect(() => {\n if (list.length <= 1) return;\n const id = setInterval(() => setTransitioning(true), intervalMs);\n return () => clearInterval(id);\n }, [list.length, intervalMs]);\n\n useEffect(() => {\n if (!transitioning || list.length <= 1) return;\n const t = setTimeout(() => {\n setCurrentIndex((i) => (i + 1) % list.length);\n setTransitioning(false);\n }, CROSSFADE_DURATION_MS);\n return () => clearTimeout(t);\n }, [transitioning, list.length]);\n\n const nextIndex = list.length > 1 ? (currentIndex + 1) % list.length : 0;\n\n return { list, currentIndex, nextIndex, transitioning };\n}\n","'use client';\n\nimport { useEffect } from 'react';\nimport { firePixelEvent } from '../../tracking/firePixelEvent';\nimport { captureEvent } from '../../tracking/captureEvent';\nimport type { PixelEvent, PixelEventParams } from '../../tracking/firePixelEvent';\n\ninterface Props {\n event: PixelEvent;\n params?: PixelEventParams;\n /** Human-readable tab name for PostHog (e.g. 'booking', 'appointments', 'membership'). */\n tab: string;\n}\n\n/**\n * Fires tracking events once when a portal tab mounts.\n * Placed at the root of each tab panel so it fires on both direct navigation\n * and post-login redirect to that tab.\n *\n * Fires:\n * - Meta Pixel: the provided `event` (e.g. ViewContent, InitiateCheckout)\n * - PostHog: portal_tab_viewed with the tab name\n */\nexport function PortalTabTracker({ event, params, tab }: Props) {\n useEffect(() => {\n firePixelEvent(event, params);\n captureEvent('portal_tab_viewed', { tab });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return null;\n}\n","'use client';\n\nimport React, { useState, useEffect, useRef } from 'react';\n\ninterface BookIframePanelProps {\n bookingHref: string;\n businessName: string;\n}\n\nexport function BookIframePanel({ bookingHref, businessName }: BookIframePanelProps) {\n const [hasOpened, setHasOpened] = useState(false);\n const [modalOpen, setModalOpen] = useState(false);\n const [isVisible, setIsVisible] = useState(false);\n const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const openModal = () => {\n setHasOpened(true);\n setModalOpen(true);\n };\n\n const closeModal = () => {\n setIsVisible(false);\n closeTimerRef.current = setTimeout(() => setModalOpen(false), 300);\n };\n\n // Clear any pending close timer on unmount.\n useEffect(() => {\n return () => {\n if (closeTimerRef.current) clearTimeout(closeTimerRef.current);\n };\n }, []);\n\n // Animate in after mount — double rAF ensures the transition fires after the\n // element is painted rather than immediately on insertion.\n useEffect(() => {\n if (!modalOpen) return;\n let cancelled = false;\n const id = requestAnimationFrame(() =>\n requestAnimationFrame(() => {\n if (!cancelled) setIsVisible(true);\n })\n );\n return () => {\n cancelled = true;\n cancelAnimationFrame(id);\n };\n }, [modalOpen]);\n\n // Prevent body scroll while modal is open.\n useEffect(() => {\n document.body.style.overflow = modalOpen ? 'hidden' : '';\n return () => { document.body.style.overflow = ''; };\n }, [modalOpen]);\n\n return (\n <>\n {/* Blurred iframe preview with overlay message */}\n <div className=\"relative rounded-component border border-secondary overflow-hidden\" style={{ height: '70vh' }}>\n {/* iframe — purely visual, non-interactive */}\n <iframe\n src={bookingHref}\n className=\"w-full h-full pointer-events-none select-none\"\n title=\"Booking preview\"\n tabIndex={-1}\n aria-hidden=\"true\"\n />\n\n {/* Backdrop blur + message overlay */}\n <div className=\"absolute inset-0 flex flex-col items-center justify-center px-6 py-8 backdrop-blur-[3.9px] bg-primary/70\">\n <div className=\"w-full max-w-sm rounded-component border border-secondary bg-primary px-6 py-6 text-center shadow-sm\">\n <p className=\"text-xl font-bold text-primary\">Booking Instructions</p>\n <p className=\"mt-5 text-sm text-secondary leading-relaxed\">\n We use a separate platform that may ask for an additional sign in or intake details to fully create your profile and collect your appointment information.\n </p>\n <div className=\"mt-5 flex flex-wrap items-center justify-center gap-3\">\n <button\n onClick={openModal}\n className=\"inline-flex items-center gap-2 rounded-interactive bg-brand-solid px-5 py-2.5 text-sm font-semibold text-white transition-colors hover:bg-brand-solid_hover\"\n >\n Start Booking\n </button>\n <a\n href={bookingHref}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1.5 rounded-interactive border border-secondary bg-secondary px-5 py-2.5 text-sm font-semibold text-primary transition-colors hover:bg-secondary_hover\"\n >\n Open in New Tab\n <svg className=\"size-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25\" />\n </svg>\n </a>\n </div>\n </div>\n </div>\n </div>\n\n {/* Full-screen modal — kept mounted after first open so the iframe session persists on close/reopen */}\n {hasOpened && (\n <div\n className={`fixed inset-0 z-50 flex flex-col bg-primary transition-[opacity,transform] duration-300 ease-out ${\n modalOpen && isVisible\n ? 'opacity-100 translate-y-0'\n : 'opacity-0 translate-y-3 pointer-events-none'\n }`}\n >\n {/* Modal header */}\n <div className=\"flex shrink-0 items-center justify-between border-b border-secondary bg-primary px-4 py-3\">\n <span className=\"text-sm font-semibold text-primary\">{businessName} Booking</span>\n <button\n onClick={closeModal}\n className=\"inline-flex items-center gap-2 rounded-interactive bg-brand-solid px-4 py-1.5 text-sm font-semibold text-white transition-colors hover:bg-brand-solid_hover\"\n >\n <svg className=\"size-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n Close\n </button>\n </div>\n\n {/* iframe fills the rest of the screen */}\n <iframe\n src={bookingHref}\n className=\"min-h-0 flex-1 w-full\"\n title=\"Book appointment\"\n allow=\"payment\"\n />\n </div>\n )}\n </>\n );\n}\n","/**\n * Server-side consumer session helpers.\n * Runs on the server only — accepts the JWT token read from cookies by the page component.\n */\n\nexport const CONSUMER_TOKEN_COOKIE = 'ks_consumer_token';\n\nimport type { Consumer, ConversationSummary, Message, ContactSummary } from '../types/api/consumer';\nexport type { Consumer, ConversationSummary, Message, ContactSummary };\n\nfunction getApiUrl(): string {\n return process.env.API_URL || 'http://localhost:3000/api/v1';\n}\n\nasync function consumerFetch<T>(path: string, token: string): Promise<T | null> {\n try {\n const res = await fetch(`${getApiUrl()}${path}`, {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n cache: 'no-store',\n });\n if (!res.ok) return null;\n const json = await res.json();\n return (json.data ?? json) as T;\n } catch {\n return null;\n }\n}\n\nexport async function fetchConsumerMe(token: string): Promise<Consumer | null> {\n return consumerFetch<Consumer>('/consumer/me', token);\n}\n\nexport async function fetchConsumerConversations(token: string): Promise<ConversationSummary[]> {\n const apiKey = process.env.API_KEY;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n ...(apiKey ? { 'X-API-Key': apiKey } : {}),\n };\n try {\n const res = await fetch(`${getApiUrl()}/consumer/me/conversations`, { headers, cache: 'no-store' });\n if (!res.ok) return [];\n const json = await res.json();\n return (json.data ?? []) as ConversationSummary[];\n } catch {\n return [];\n }\n}\n\nexport async function fetchConsumerMessages(\n token: string,\n contactId: number\n): Promise<{ messages: Message[]; contact: ContactSummary | null }> {\n try {\n const res = await fetch(\n `${getApiUrl()}/consumer/me/contacts/${contactId}/messages?per_page=100`,\n {\n headers: { Authorization: `Bearer ${token}` },\n cache: 'no-store',\n }\n );\n if (!res.ok) return { messages: [], contact: null };\n const json = await res.json();\n return {\n messages: (json.data ?? []) as Message[],\n contact: (json.contact ?? null) as ContactSummary | null,\n };\n } catch {\n return { messages: [], contact: null };\n }\n}\n","/**\n * Server-side API client for SSR\n * API key is stored securely on the server - never exposed to browser\n */\n\nimport type { CompanyInformation } from '../types/api/company-information';\nimport type { Service } from '../types/api/service';\nimport type { Package } from '../types/api/package';\nimport type { WebsitePhotos } from '../types/api/website-photos';\n\nconst API_URL = process.env.API_URL || 'http://localhost:3000/api/v1';\nconst API_KEY = process.env.API_KEY || '';\n\ninterface FetchOptions {\n cache?: RequestCache;\n revalidate?: number;\n}\n\nasync function serverFetch<T>(endpoint: string, options: FetchOptions = {}): Promise<T | null> {\n const url = `${API_URL}${endpoint}`;\n \n try {\n const fetchOptions: RequestInit & { next?: { revalidate?: number } } = {\n headers: {\n 'X-API-Key': API_KEY,\n 'Content-Type': 'application/json',\n },\n cache: options.cache,\n };\n \n if (options.revalidate) {\n fetchOptions.next = { revalidate: options.revalidate };\n }\n \n const response = await fetch(url, fetchOptions);\n\n if (!response.ok) {\n console.error(`[Server API] Error ${response.status} for ${endpoint}`);\n return null;\n }\n\n const json = await response.json();\n \n // Rails API returns { data: [...], meta: {...} }\n return json.data ?? json;\n } catch (error) {\n console.error(`[Server API] Failed to fetch ${endpoint}:`, error);\n return null;\n }\n}\n\n/**\n * Generic serverApi object for flexible endpoint access\n */\nexport const serverApi = {\n get: <T = unknown>(endpoint: string, options?: FetchOptions): Promise<T | null> => {\n return serverFetch<T>(endpoint, options || { revalidate: 60 });\n }\n};\n\n// Revalidate data every 60 seconds (ISR)\nconst defaultOptions: FetchOptions = { revalidate: 60 };\n\nexport async function getCompanyInformation(): Promise<CompanyInformation | null> {\n return serverFetch<CompanyInformation>('/public/company_information', defaultOptions);\n}\n\n/** Ads config (e.g. Meta Pixel). Returns { meta_pixel_id?: string } or {}. Only present when account has connected Meta Ads. */\nexport async function getAdsConfig(): Promise<{ meta_pixel_id?: string } | null> {\n const data = await serverFetch<{ meta_pixel_id?: string }>('/public/ads_config', defaultOptions);\n return data ?? null;\n}\n\n/** Extract Meta Pixel ID from ads config for use with <MetaPixel pixelId={...} />. Only returns a value when present and valid (numeric). */\nexport function getMetaPixelId(adsConfig: { meta_pixel_id?: string } | null | undefined): string | null {\n const id = adsConfig && typeof adsConfig === 'object' && 'meta_pixel_id' in adsConfig && adsConfig.meta_pixel_id;\n const str = id != null && id !== '' ? String(id).trim() : '';\n return str !== '' && str !== 'null' && /^\\d+$/.test(str) ? str : null;\n}\n\nexport type AnalyticsConfig = {\n /** PostHog project API key — platform-wide, from POSTHOG_API_KEY env var on the Rails server. */\n posthog_api_key?: string;\n /** Per-site GTM container ID (e.g. GTM-ABC123), provisioned by Keystone. */\n gtm_container_public_id?: string;\n /**\n * Environment identifier from KEYSTONE_ENV on the Rails server (e.g. \"production\", \"staging\",\n * \"development\"). Registered as a PostHog super property on every event so the sync job can\n * filter by environment and avoid cross-environment data contamination.\n */\n environment?: string;\n};\n\n/** Analytics config for customer sites. Returns platform-wide analytics keys (e.g. PostHog). */\nexport async function getAnalyticsConfig(): Promise<AnalyticsConfig | null> {\n const data = await serverFetch<AnalyticsConfig>('/public/analytics_config', defaultOptions);\n return data ?? null;\n}\n\n/** Extract PostHog API key from analytics config for use with <PostHogProvider apiKey={...} />. */\nexport function getPostHogApiKey(analyticsConfig: AnalyticsConfig | null | undefined): string | null {\n const key = analyticsConfig?.posthog_api_key;\n const str = key != null && key !== '' ? String(key).trim() : '';\n return str !== '' && str !== 'null' ? str : null;\n}\n\n/** Extract GTM container ID from analytics config for use with <GoogleTagManager containerId={...} />. */\nexport function getGtmContainerPublicId(analyticsConfig: AnalyticsConfig | null | undefined): string | null {\n const value = analyticsConfig?.gtm_container_public_id;\n const str = value != null && value !== '' ? String(value).trim() : '';\n return str !== '' && str !== 'null' && /^GTM-[A-Z0-9]+$/i.test(str) ? str : null;\n}\n\n/** Extract environment string from analytics config for use with <PostHogProvider environment={...} />. */\nexport function getKeystoneEnvironment(analyticsConfig: AnalyticsConfig | null | undefined): string {\n return analyticsConfig?.environment?.trim() || 'development';\n}\n\nexport async function getServices(): Promise<Service[] | null> {\n return serverFetch<Service[]>('/public/services', defaultOptions);\n}\n\nexport async function getService(slug: string): Promise<Service | null> {\n return serverFetch<Service>(`/public/services/by_slug/${slug}`, defaultOptions);\n}\n\nexport async function getLocations() {\n return serverFetch('/public/locations', defaultOptions);\n}\n\nexport async function getLocation(slug: string) {\n return serverFetch(`/public/locations/by_slug/${slug}`, defaultOptions);\n}\n\nexport async function getReviews() {\n return serverFetch('/public/reviews', defaultOptions);\n}\n\nexport async function getFAQs() {\n return serverFetch('/public/faq_questions', defaultOptions);\n}\n\nexport async function getBlogPosts() {\n return serverFetch('/public/blog_posts', defaultOptions);\n}\n\nexport async function getBlogPost(slug: string) {\n return serverFetch(`/public/blog_posts/by_slug/${slug}`, defaultOptions);\n}\n\nexport async function getTeamMembers() {\n return serverFetch('/public/team_members', defaultOptions);\n}\n\nexport async function getWebsitePhotos(): Promise<WebsitePhotos | null> {\n return serverFetch<WebsitePhotos>('/public/website_photos', defaultOptions);\n}\n\nexport async function getJobPostings() {\n return serverFetch('/public/job_postings', defaultOptions);\n}\n\nexport async function getJobPosting(slug: string) {\n return serverFetch(`/public/job_postings/by_slug/${slug}`, defaultOptions);\n}\n\nexport async function getSocialPosts() {\n // Social payloads can exceed Next's data-cache item size; avoid noisy build warnings.\n return serverFetch('/public/social_posts', { cache: 'no-store' });\n}\n\n/** Packages (bundles of service items). */\nexport async function getPackages(): Promise<Package[] | null> {\n return serverFetch<Package[]>('/public/packages', defaultOptions);\n}\n\nexport async function getPackage(slug: string): Promise<Package | null> {\n return serverFetch<Package>(`/public/packages/by_slug/${encodeURIComponent(slug)}`, defaultOptions);\n}\n\n// Alias for testimonials (API uses \"reviews\")\nexport async function getTestimonials() {\n return getReviews();\n}\n\n/** Form definition for dynamic form rendering, fetched by form_type. */\nexport async function getForm(formType: string) {\n type FormDefinition = import('../types/api/form').FormDefinition;\n return serverFetch<FormDefinition>(`/public/forms/${encodeURIComponent(formType)}`, defaultOptions);\n}\n\n/** Form definition for dynamic form rendering, fetched by numeric ID. */\nexport async function getFormById(id: number | string) {\n type FormDefinition = import('../types/api/form').FormDefinition;\n return serverFetch<FormDefinition>(`/public/form_by_id/${encodeURIComponent(id)}`, defaultOptions);\n}\n\n"],"mappings":"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,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,EACf;AAAA,EACA;AAAA,IACI,MAAM;AAAA,IACN,MAAM;AAAA,IACN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","names":["React","React","useState","useEffect","useRouter","React","React","useEffect","useRouter","useRouter","useEffect","React","e","React","useState","useRouter","useEffect","React","useState","useTransition","useRef","useEffect","useCallback","useRouter","useEffect","useRef","useState","useTransition","useRef","useRouter","useCallback","useEffect","React","React","useState","useEffect","useMemo","React","useEffect","useEffect","React","useState","useEffect","useRef","React","_a","tab","_b","_c","_d","_e"]}
@@ -1,16 +0,0 @@
1
- import { C as ConversationSummary, a as Consumer, M as Message, b as ContactSummary } from '../consumer-BWjQawiO.js';
2
-
3
- /**
4
- * Server-side consumer session helpers.
5
- * Runs on the server only — accepts the JWT token read from cookies by the page component.
6
- */
7
- declare const CONSUMER_TOKEN_COOKIE = "ks_consumer_token";
8
-
9
- declare function fetchConsumerMe(token: string): Promise<Consumer | null>;
10
- declare function fetchConsumerConversations(token: string): Promise<ConversationSummary[]>;
11
- declare function fetchConsumerMessages(token: string, contactId: number): Promise<{
12
- messages: Message[];
13
- contact: ContactSummary | null;
14
- }>;
15
-
16
- export { CONSUMER_TOKEN_COOKIE, Consumer, ContactSummary, ConversationSummary, Message, fetchConsumerConversations, fetchConsumerMe, fetchConsumerMessages };