1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
"use client";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
const consumerDomains = [
"gmail.com",
"yahoo.com",
"hotmail.com",
"outlook.com",
"icloud.com",
"aol.com",
"proton.me",
"protonmail.com",
];
type Status = "idle" | "loading" | "success" | "error";
export function RequestForm() {
const [status, setStatus] = useState<Status>("idle");
const [error, setError] = useState("");
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setError("");
const form = e.currentTarget;
const data = new FormData(form);
const name = String(data.get("name") || "").trim();
const email = String(data.get("email") || "").trim();
const company = String(data.get("company") || "").trim();
const role = String(data.get("role") || "").trim();
const outcomes = String(data.get("outcomes") || "").trim();
if (!name || !email || !company || !role || !outcomes) {
setStatus("error");
setError("Every field is required. Alignment begins with completeness.");
return;
}
const domain = email.split("@")[1]?.toLowerCase();
if (!domain || !email.includes("@")) {
setStatus("error");
setError("Please provide an institutional email.");
return;
}
if (consumerDomains.includes(domain)) {
setStatus("error");
setError(
"Consumer inboxes cannot attest PPoE. Please use your institutional email."
);
return;
}
setStatus("loading");
await new Promise((r) => setTimeout(r, 900));
setStatus("success");
}
if (status === "success") {
return (
<div className="rounded-3xl border border-fuchsia-400/30 bg-gradient-to-br from-violet-500/20 to-cyan-500/10 p-8">
<p className="font-mono text-[11px] uppercase tracking-[0.2em] text-primary">
Request received
</p>
<h2 className="mt-3 font-heading text-3xl text-foreground">
An outcomes partner will be in touch.
</h2>
<p className="mt-3 text-sm leading-relaxed text-muted-foreground">
Fit is a mutual decision. If your operating thesis, your lake, and
our fabric are prepared to compound, we will schedule a working
session — not a demo.
</p>
</div>
);
}
return (
<form onSubmit={onSubmit} className="space-y-5" noValidate>
<Field id="name" label="Full name" autoComplete="name" />
<Field
id="email"
label="Institutional email"
type="email"
autoComplete="email"
/>
<Field id="company" label="Institution" autoComplete="organization" />
<Field id="role" label="Role" placeholder="Chief Transformation Officer" />
<div className="space-y-2">
<Label htmlFor="outcomes">
What outcomes are you looking to operationalize?
</Label>
<Textarea
id="outcomes"
name="outcomes"
rows={5}
className="min-h-28 text-sm"
placeholder="Be specific about the thesis, not the tools. The fabric will meet you there."
/>
</div>
{status === "error" && error ? (
<p className="text-sm text-destructive" role="alert">
{error}
</p>
) : null}
<Button
type="submit"
disabled={status === "loading"}
className="h-11 w-full px-5 sm:w-auto"
>
{status === "loading" ? "Attesting request…" : "Request access"}
</Button>
</form>
);
}
function Field({
id,
label,
type = "text",
autoComplete,
placeholder,
}: {
id: string;
label: string;
type?: string;
autoComplete?: string;
placeholder?: string;
}) {
return (
<div className="space-y-2">
<Label htmlFor={id}>{label}</Label>
<Input
id={id}
name={id}
type={type}
autoComplete={autoComplete}
placeholder={placeholder}
className="h-10"
/>
</div>
);
}
|