Skip to content

Commit cf083ef

Browse files
authored
feat: implement waitlist screen Closes #236 (#263)
* feat: implement waitlist screen Closes #236 * feature/waitlist-screen
1 parent 7ca3645 commit cf083ef

File tree

3 files changed

+156
-6582
lines changed

3 files changed

+156
-6582
lines changed

frontend/components/Waitlist.tsx

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
"use client";
2+
3+
import { useState, FormEvent } from "react";
4+
5+
export default function Waitlist() {
6+
const [email, setEmail] = useState("");
7+
const [name, setName] = useState("");
8+
const [status, setStatus] = useState<
9+
"idle" | "loading" | "success" | "error"
10+
>("idle");
11+
const [errorMessage, setErrorMessage] = useState("");
12+
13+
const validateEmail = (email: string): boolean => {
14+
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
15+
return re.test(email);
16+
};
17+
18+
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
19+
e.preventDefault();
20+
21+
if (!name.trim()) {
22+
setStatus("error");
23+
setErrorMessage("Please enter your name");
24+
return;
25+
}
26+
27+
if (!validateEmail(email)) {
28+
setStatus("error");
29+
setErrorMessage("Please enter a valid email address");
30+
return;
31+
}
32+
33+
setStatus("loading");
34+
setErrorMessage("");
35+
36+
// Simulate API call - replace with actual endpoint
37+
try {
38+
await new Promise((resolve) => setTimeout(resolve, 1500));
39+
setStatus("success");
40+
setName("");
41+
setEmail("");
42+
} catch (error) {
43+
setStatus("error");
44+
setErrorMessage("Something went wrong. Please try again.");
45+
}
46+
};
47+
48+
return (
49+
<div className="min-h-screen bg-[#0a0a0a] flex items-center justify-center px-4 sm:px-6 lg:px-8">
50+
<div className="max-w-md w-full space-y-8">
51+
<div className="text-center">
52+
<h1 className="text-[#00D9D9] text-4xl font-bold tracking-tight">
53+
PrediFi
54+
</h1>
55+
<div className="mt-6">
56+
<h2 className="text-3xl font-bold text-white">Join the Waitlist</h2>
57+
<p className="mt-3 text-gray-400 text-base">
58+
Be among the first to experience decentralized prediction markets
59+
</p>
60+
</div>
61+
</div>
62+
63+
{/* Form */}
64+
{status !== "success" ? (
65+
<form onSubmit={handleSubmit} className="mt-8 space-y-6">
66+
<div className="space-y-4">
67+
<div>
68+
<label htmlFor="name" className="sr-only">
69+
Full Name
70+
</label>
71+
<input
72+
id="name"
73+
name="name"
74+
type="text"
75+
required
76+
value={name}
77+
onChange={(e) => setName(e.target.value)}
78+
className="appearance-none relative block w-full px-4 py-3 border border-gray-700 bg-[#1a1a1a] placeholder-gray-500 text-white rounded-lg focus:outline-none focus:ring-2 focus:ring-[#00D9D9] focus:border-transparent transition-all"
79+
placeholder="Full Name"
80+
disabled={status === "loading"}
81+
/>
82+
</div>
83+
<div>
84+
<label htmlFor="email" className="sr-only">
85+
Email Address
86+
</label>
87+
<input
88+
id="email"
89+
name="email"
90+
type="email"
91+
required
92+
value={email}
93+
onChange={(e) => setEmail(e.target.value)}
94+
className="appearance-none relative block w-full px-4 py-3 border border-gray-700 bg-[#1a1a1a] placeholder-gray-500 text-white rounded-lg focus:outline-none focus:ring-2 focus:ring-[#00D9D9] focus:border-transparent transition-all"
95+
placeholder="Email Address"
96+
disabled={status === "loading"}
97+
/>
98+
</div>
99+
</div>
100+
101+
{status === "error" && (
102+
<div className="rounded-lg bg-red-900/20 border border-red-800 p-3">
103+
<p className="text-sm text-red-400 text-center">
104+
{errorMessage}
105+
</p>
106+
</div>
107+
)}
108+
109+
<button
110+
type="submit"
111+
disabled={status === "loading"}
112+
className="group relative w-full flex justify-center py-3 px-4 border border-transparent text-base font-medium rounded-lg text-black bg-[#00D9D9] hover:bg-[#00c4c4] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#00D9D9] transition-all disabled:opacity-50 disabled:cursor-not-allowed"
113+
>
114+
{status === "loading" ? "Joining..." : "Join Waitlist"}
115+
</button>
116+
</form>
117+
) : (
118+
<div className="mt-8 rounded-lg bg-[#00D9D9]/10 border border-[#00D9D9] p-8 text-center space-y-4">
119+
<div className="mx-auto w-16 h-16 bg-[#00D9D9] rounded-full flex items-center justify-center">
120+
<svg
121+
className="w-8 h-8 text-black"
122+
fill="none"
123+
stroke="currentColor"
124+
viewBox="0 0 24 24"
125+
>
126+
<path
127+
strokeLinecap="round"
128+
strokeLinejoin="round"
129+
strokeWidth={3}
130+
d="M5 13l4 4L19 7"
131+
/>
132+
</svg>
133+
</div>
134+
<h3 className="text-2xl font-bold text-white">
135+
You're on the list!
136+
</h3>
137+
<p className="text-gray-400">
138+
We'll notify you when PrediFi launches. Get ready to predict!
139+
</p>
140+
</div>
141+
)}
142+
143+
{/* Footer */}
144+
<p className="mt-8 text-center text-sm text-gray-500">
145+
Already have an account?{" "}
146+
<a
147+
href="/login"
148+
className="text-[#00D9D9] hover:text-[#00c4c4] font-medium transition-colors"
149+
>
150+
Sign in
151+
</a>
152+
</p>
153+
</div>
154+
</div>
155+
);
156+
}

0 commit comments

Comments
 (0)