/* Application flows. Submissions go to a Google Form (see ax-config.js) by posting a hidden form into a hidden iframe — no backend, no keys, no cross-origin read. Google returns an opaque response, so a completed load is treated as delivered; with no form configured the flow validates and shows the received state without sending. */ const AX_GFORM = window.AURAXIS_GFORM || {}; const AX_EMAIL = window.AURAXIS_EMAIL || ""; function axGformBase(kind) { const cfg = AX_GFORM[kind]; return cfg && cfg.formId ? "https://docs.google.com/forms/d/e/" + encodeURIComponent(cfg.formId) : null; } /* Prefilled form URL — the guaranteed fallback when the in-page post cannot be confirmed. */ function axGformPrefill(kind, data) { const base = axGformBase(kind); if (!base) return null; const entries = (AX_GFORM[kind] || {}).entries || {}; const q = ["usp=pp_url"]; Object.keys(entries).forEach(key => { const id = entries[key], v = data[key]; if (!id || v === undefined || v === null || v === "") return; q.push(encodeURIComponent(id) + "=" + encodeURIComponent(typeof v === "boolean" ? (v ? "Yes" : "No") : String(v))); }); return base + "/viewform?" + q.join("&"); } /* Posts a hidden form into a hidden iframe, then verifies that the navigation actually left this origin. A blocked navigation leaves the sink on about:blank and readable, so it is reported as "blocked" rather than assumed delivered. */ function axGformPost(kind, data) { const base = axGformBase(kind); if (!base) return Promise.resolve("unconfigured"); const entries = (AX_GFORM[kind] || {}).entries || {}; return new Promise(resolve => { let sink = document.getElementById("ax-gf-sink"); if (!sink) { sink = document.createElement("iframe"); sink.id = "ax-gf-sink"; sink.name = "ax-gf-sink"; sink.setAttribute("aria-hidden", "true"); sink.tabIndex = -1; sink.style.display = "none"; document.body.appendChild(sink); } const form = document.createElement("form"); form.action = base + "/formResponse"; form.method = "POST"; form.target = "ax-gf-sink"; form.style.display = "none"; Object.keys(entries).forEach(key => { const id = entries[key], v = data[key]; if (!id || v === undefined || v === null || v === "") return; const input = document.createElement("input"); input.type = "hidden"; input.name = id; input.value = typeof v === "boolean" ? (v ? "Yes" : "No") : String(v); form.appendChild(input); }); document.body.appendChild(form); let blocked = false; const onViolation = e => { const d = e.effectiveDirective || e.violatedDirective || ""; if (d === "form-action" || d === "frame-src" || d === "child-src") blocked = true; }; document.addEventListener("securitypolicyviolation", onViolation); let settled = false; const finish = () => { if (settled) return; settled = true; sink.removeEventListener("load", finish); document.removeEventListener("securitypolicyviolation", onViolation); form.remove(); let left = false; try { const href = sink.contentWindow && sink.contentWindow.location.href; left = !!href && href !== "about:blank"; } catch (_) { left = true; // cross-origin and unreadable: the navigation genuinely reached Google } resolve(!blocked && left ? "sent" : "blocked"); }; sink.addEventListener("load", finish); setTimeout(finish, 6000); form.submit(); }); } function Field({ f, value, onChange, error }) { const common = { value: value || "", onChange: e => onChange(f.name, e.target.value) }; if (f.type === "select") return (
{error ? {error} : f.hint ? {f.hint} : null} ); if (f.type === "check") return onChange(f.name, e.target.checked)} />; return ; } function StepStrip({ steps, i }) { return (
{steps.map((s, k) => (
{String(k + 1).padStart(2, "0")} · {s.title.toUpperCase()}
))}
); } /* Generic staged flow used by both the Engine application and the consultancy booking. */ function useFlow(steps, kind) { const [i, setI] = useState(0); const [data, setData] = useState({}); const [errs, setErrs] = useState({}); const [state, setState] = useState("editing"); // editing | sending | done | failed const set = useCallback((k, v) => { setData(d => ({ ...d, [k]: v })); setErrs(e => e[k] ? { ...e, [k]: null } : e); }, []); const validate = () => { const e = {}; steps[i].fields.forEach(f => { const v = data[f.name]; if (f.required && (!v || String(v).trim() === "")) e[f.name] = "Required."; else if (f.type === "email" && v && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(v)) e[f.name] = "Address not recognised."; }); setErrs(e); return Object.keys(e).length === 0; }; const next = async () => { if (!validate()) return; if (i < steps.length - 1) { setI(i + 1); return; } setState("sending"); let outcome = "blocked"; try { outcome = await axGformPost(kind, data); } catch (_) { outcome = "blocked"; } setState(outcome === "sent" ? "done" : "failed"); }; return { i, setI, data, set, errs, state, next, setState }; } function FlowBody({ flow, steps }) { const { i, data, set, errs } = flow; const s = steps[i]; return (
{s.heading}
{s.note ?

{s.note}

: null}
{s.fields.map(f => (
))}
); } /* Delivery could not be confirmed: never claim receipt. Offer the real form and the desk address. */ function SubmitFallback({ kind, data }) { const url = axGformPrefill(kind, data); return (
Not submitted

This submission has not been recorded. Your answers are still in the form below.{url ? " Open the application form to send them, or write to the desk directly." : " Write to the desk directly and we will take it from there."}

{url ? : null}
); } function Received({ title, lines, code }) { return (
Received
{title}
{lines.map(l =>

{l}

)}
); } const REF = "AX-" + Math.random().toString(36).slice(2, 7).toUpperCase(); const APPLY_STEPS = [ { title: "Identity", heading: "Who is applying", note: "Firm-issued addresses are reviewed first.", fields: [ { name: "name", label: "Full name", required: true, wide: false }, { name: "email", label: "Email", type: "email", required: true }, { name: "org", label: "Organisation", placeholder: "Independent, if none" }, { name: "type", label: "Applicant type", type: "select", options: ["Individual", "Institution", "Broker", "Introducing broker"], required: true }, ] }, { title: "Mandate", heading: "Scale and current position", note: "Used to size the allocation model, not to rank applicants.", fields: [ { name: "capital", label: "Approximate capital under management", mono: true, suffix: "USD", placeholder: "250,000", required: true }, { name: "horizon", label: "Intended deployment", type: "select", options: ["Immediate", "Within one quarter", "Evaluating only"] }, { name: "situation", label: "Current trading situation", type: "textarea", rows: 4, wide: true, required: true, placeholder: "Instruments traded, execution venue, what is working and what is not.", hint: "Two or three sentences is enough." }, ] }, { title: "Objectives", heading: "What the Engine is being asked to do", fields: [ { name: "objectives", label: "Objectives", type: "textarea", rows: 4, wide: true, required: true, placeholder: "Return targets, drawdown tolerance, reporting requirements." }, { name: "notes", label: "Additional information", type: "textarea", rows: 3, wide: true, placeholder: "Existing infrastructure, jurisdiction, constraints." }, { name: "ack", label: "I understand AURAXIS supplies research and execution technology, not investment advice, and that trading carries substantial risk of loss.", type: "check", wide: true, required: true }, ] }, ]; const CONSULT_STEPS = [ { title: "Contact", heading: "How to reach you", fields: [ { name: "name", label: "Full name", required: true }, { name: "email", label: "Email", type: "email", required: true }, { name: "country", label: "Country / time zone", placeholder: "e.g. UAE · GST" }, { name: "experience", label: "Years trading", type: "select", options: ["Under one year", "One to three years", "Three to seven years", "Over seven years"], required: true }, ] }, { title: "Position", heading: "Where the account stands now", note: "Answer plainly. The review is only useful if it is accurate.", fields: [ { name: "instruments", label: "Instruments traded", placeholder: "Gold, indices, FX" }, { name: "size", label: "Account size", mono: true, suffix: "USD", placeholder: "25,000" }, { name: "problem", label: "Primary difficulty", type: "select", wide: true, options: ["Inconsistent results", "Repeated stop-losses", "Strategy selection", "Portfolio structure and sizing", "Discipline and execution", "Something else"], required: true }, { name: "detail", label: "Describe the pattern you keep running into", type: "textarea", rows: 4, wide: true, required: true, placeholder: "When it happens, what you do next, and what you have already tried." }, ] }, { title: "Program", heading: "Scope of the engagement", fields: [ { name: "goal", label: "What a successful quarter looks like", type: "textarea", rows: 3, wide: true, required: true }, { name: "bundle", label: "Consider me for the current limited intake bundle, subject to the consultation call.", type: "check", wide: true }, { name: "ack", label: "I understand this is a technology and structure review, not investment advice, and that no outcome is guaranteed.", type: "check", wide: true, required: true }, ] }, ]; function ApplyDialog({ open, onClose }) { const flow = useFlow(APPLY_STEPS, "engine-access"); const done = flow.state === "done"; return ( Close : <> }> {done ? : } {flow.state === "failed" ? : null} ); } /* Inline booking panel for the consultancy page. */ function ConsultFlow() { const flow = useFlow(CONSULT_STEPS, "consultancy"); const done = flow.state === "done"; return ( {done ? : <>
} {flow.state === "failed" ? : null}
); } /* Header CTA that opens the Engine application from anywhere. */ function ApplyButton({ children = "Request access", variant, size = "md", iconRight = "arrow-right" }) { const [open, setOpen] = useState(false); return <> setOpen(false)} /> ; } Object.assign(window, { ApplyDialog, ApplyButton, ConsultFlow, APPLY_STEPS, CONSULT_STEPS, Field, useFlow, FlowBody, Received, SubmitFallback, AX_EMAIL, axGformPost, axGformPrefill });