// Lit import { html, nothing } from "lit"; import { customElement, state } from "lit/decorators.js"; import { AiPriseLitElement } from "../utils/aiprise-element.js"; // Services import { createVerificationSession } from "../services/create-verification-session.js"; import { getVerificationSessionType } from "../services/get-verification-session-type.js"; // Typescript import { DetailedHTMLProps, HTMLAttributes } from "react"; import { AiPriseSessionEvent, AiPriseBusinessProfileEvent, AiPriseDataSavedEvent, } from "../types/aiprise-session-event.js"; import { AiPriseElementProps } from "../types/aiprise-element-props.js"; // Colors & Icons import assets from "../assets.js"; // Components import "./aiprise-spinner.js"; type PageStatus = "default" | "loading" | "success" | "error"; @customElement("aiprise-frame") export class AiPriseFrame extends AiPriseLitElement { // 1 - STATE @state() status: PageStatus = "default"; @state() iframeReady = false; @state() verificationURL = ""; @state() verificationSessionId = ""; // 2 - HELPER FUNCTIONS tryJSONParse = (jsonString: string | undefined) => { if (!jsonString) return; try { return JSON.parse(jsonString) as T; } catch {} }; handleIframeReady = () => { this.iframeReady = true; }; // 3 - SESSION EVENTS createNewSession = async () => { this.status = "loading"; // Show loading screen try { const data = await createVerificationSession({ mode: this.mode, template_id: this.templateId, callback_url: this.callbackUrl, events_callback_url: this.eventsCallbackUrl, client_reference_id: this.clientReferenceId, client_reference_data: this.tryJSONParse(this.clientReferenceData), user_profile_id: this.userProfileId, business_profile_id: this.businessProfileId, user_data: this.tryJSONParse(this.userData), business_data: this.tryJSONParse(this.businessData), additional_info: this.tryJSONParse(this.additionalInfo), ui_options: this.tryJSONParse(this.uiOptions), verification_options: this.tryJSONParse(this.verificationOptions), theme_options: this.tryJSONParse(this.theme), associated_email: this.associatedEmail, }); // Update data + status this.verificationURL = data.verification_url; this.verificationSessionId = data.verification_session_id; this.status = "success"; // Inform parent component this.dispatchStarted(data.verification_session_id); // Listen to events from the iframe this.attachIframeMessageListener(); } catch { this.status = "error"; // Show error screen this.dispatchError("SESSION_FAILED"); // Inform parent component } }; resumeExistingSession = async () => { if (!this.sessionIdFromProps) return; // Determine the type of session (user or business) for resuming this.status = "loading"; try { const data = await getVerificationSessionType({ mode: this.mode, verification_session_id: this.sessionIdFromProps, }); // Generate the URL + show iframe const baseUrl = this.mode === "PRODUCTION" ? "https://verify.aiprise.com/" : "https://verify-sandbox.aiprise.com/"; if (data.verification_session_type === "BUSINESS_ENTITY_TYPE") { this.verificationURL = baseUrl + "?business_onboarding_session_id=" + this.sessionIdFromProps; } else { this.verificationURL = baseUrl + "?verification_session_id=" + this.sessionIdFromProps; } this.verificationSessionId = this.sessionIdFromProps; this.status = "success"; // Inform parent component this.dispatchResumed(this.sessionIdFromProps); // Listen to events from the iframe this.attachIframeMessageListener(); } catch { this.status = "error"; // Show error screen this.dispatchError("RESUME_FAILED"); // Inform parent component } }; attachIframeMessageListener = () => { window.onmessage = (e) => { if (typeof e.data !== "string") return; // Business profile created if (e.data.startsWith("AiPriseVerification:BusinessProfileCreated:")) { const businessProfileId = e.data.split(":")[2]; this.dispatchBusinessProfileCreated(businessProfileId); } // Data saved (email associated with the session) else if (e.data.startsWith("AiPriseVerification:SessionDataSaved:")) { const emailAddress = e.data.split(":")[2]; this.dispatchDataSaved(emailAddress); } // Data restored (OTP verified) else if (e.data.startsWith("AiPriseVerification:SessionDataRestored")) { this.dispatchDataRestored(this.verificationSessionId); } // Verification form completed else if (e.data === "AiPriseVerification:Success") { this.dispatchSuccessful(this.verificationSessionId); } // Verification form completed AND user clicked "continue" else if (e.data === "AiPriseVerification:Complete") { this.dispatchContinue(this.verificationSessionId); this.dispatchCompleted(this.verificationSessionId); // DEPRECATED: Keeping for backward compatibility } // Verification has error (expired OR completed) else if (e.data.startsWith("AiPriseVerification:Error:")) { const errorCode = e.data.split(":")[2]; this.dispatchError(errorCode); } }; }; // 4 - LIFECYCLE METHODS connectedCallback() { super.connectedCallback(); if (this.sessionIdFromProps) { this.resumeExistingSession(); } else { this.createNewSession(); } } disconnectedCallback() { super.disconnectedCallback(); window.onmessage = null; // Clear iframe listener } // 4 - CSS & HTML render() { return html`
${this.status === "success" ? html` ` : nothing} ${this.status === "error" ? html`

Unable to create session.
Please try again.

` : nothing} ${this.status === "loading" || (this.status === "success" && !this.iframeReady) ? html`
` : nothing}
`; } } // Typescript declare global { interface HTMLElementTagNameMap { "aiprise-frame": AiPriseFrame; } interface HTMLElementEventMap { "aiprise:started": AiPriseSessionEvent; "aiprise:resumed": AiPriseSessionEvent; "aiprise:business-profile": AiPriseBusinessProfileEvent; "aiprise:data-saved": AiPriseDataSavedEvent; "aiprise:data-restored": AiPriseSessionEvent; "aiprise:successful": AiPriseSessionEvent; "aiprise:continue": AiPriseSessionEvent; "aiprise:completed": AiPriseSessionEvent; // DEPRECATED: Keeping for backward compatibility } // For React namespace JSX { interface IntrinsicElements { "aiprise-frame": DetailedHTMLProps, HTMLElement> & AiPriseElementProps; } } }