Skip to content

Commit 9b4d195

Browse files
authored
feat: implement admin signup flow (#73)
* Implement complete admin signup flow with email and wallet signin options * feat: display starknet wallets
1 parent a89f183 commit 9b4d195

15 files changed

Lines changed: 705 additions & 3 deletions

public/qrcode.png

24.5 KB
Loading
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from 'react'
2+
import { ChevronLeft } from 'lucide-react';
3+
4+
export default function BackButton({ onBack }: { onBack: () => void }) {
5+
return (
6+
<button
7+
type="button"
8+
className="flex items-center gap-1 mb-6 border-[#E7E7E7] border rounded-md w-fit px-2 py-1"
9+
onClick={onBack}
10+
>
11+
<ChevronLeft className="w-8 h-8 text-gray-300" />
12+
<span className="text-gray-500 text-base font-medium">Back</span>
13+
</button>
14+
);
15+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { SignInStep } from '@/lib/types';
2+
import React, { useEffect } from 'react';
3+
import WalletIcon from '@/components/svg/WalletIcon';
4+
5+
interface Props {
6+
onBack: () => void;
7+
onStepChange: (step: SignInStep) => void;
8+
}
9+
10+
11+
export default function ConnectingStep({ onBack, onStepChange }: Props) {
12+
useEffect(() => {
13+
const timer = setTimeout(() => {
14+
onStepChange("signature");
15+
}, 3000);
16+
17+
return () => clearTimeout(timer);
18+
}, [onStepChange]);
19+
20+
return (
21+
<div className="min-h-screen bg-gray-100 flex items-center justify-center font-inter">
22+
<div className="bg-white rounded-2xl shadow-lg w-full max-w-md px-6 py-8 sm:px-10 sm:py-10 flex flex-col items-center">
23+
<div className="flex items-center gap-3 mb-8">
24+
<div className="w-12 h-12 rounded-full bg-blue-600 flex items-center justify-center">
25+
<WalletIcon />
26+
</div>
27+
<span className="text-xl font-bold text-gray-900">Braavos</span>
28+
</div>
29+
<div className="flex flex-col items-center mb-8">
30+
<div className="w-24 h-24 rounded-full bg-blue-50 flex items-center justify-center mb-6">
31+
<div className="w-6 h-6 rounded-full bg-blue-600"></div>
32+
</div>
33+
<div className="text-base text-gray-500 text-center font-medium">Connecting to Wallet...</div>
34+
</div>
35+
<button
36+
onClick={() => onStepChange("signature")}
37+
className="w-full h-full py-3 bg-gradient-to-b font-semibold text-base shadow-sm hover:from-blue-200 hover:to-blue-300 transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 rounded-md bg-[linear-gradient(to_bottom,_#EDF7FF_100%,_#096CFF_30%)]
38+
hover:bg-gray-200"
39+
>
40+
Cancel
41+
</button>
42+
</div>
43+
</div>
44+
);
45+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import React, { useState, } from "react";
2+
import { Eye, EyeOff, Lock } from "lucide-react";
3+
import BackButton from "./BackButton";
4+
import { SignInStep } from "@/lib/types";
5+
6+
7+
interface EmailSignInStepProps {
8+
onBack: () => void;
9+
onStepChange: (step: SignInStep) => void;
10+
}
11+
12+
const emailRegex = /^[\w-.]+@([\w-]+\.)+[\w-]{2,}$/i;
13+
14+
export default function EmailSignInStep({
15+
onBack,
16+
onStepChange,
17+
}: EmailSignInStepProps) {
18+
const [showPassword, setShowPassword] = useState(false);
19+
const [email, setEmail] = useState("");
20+
const [password, setPassword] = useState("");
21+
const [emailError, setEmailError] = useState("");
22+
23+
const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
24+
const value = e.target.value;
25+
setEmail(value);
26+
if (value.length === 0 || emailRegex.test(value)) {
27+
setEmailError("");
28+
} else {
29+
setEmailError("Please enter a valid email address");
30+
}
31+
};
32+
33+
const handleSubmit = (e: React.FormEvent) => {
34+
e.preventDefault();
35+
if (!emailRegex.test(email)) {
36+
setEmailError("Please enter a valid email address");
37+
return;
38+
} else {
39+
setEmailError("");
40+
onStepChange("success");
41+
}
42+
};
43+
44+
return (
45+
<div className="min-h-screen flex items-center justify-center bg-gray-100 font-inter">
46+
<div className="bg-white rounded-xl shadow-md p-6 w-full max-w-xl">
47+
<BackButton onBack={onBack} />
48+
49+
<h2 className="text-2xl font-inter font-semibold text-[#5D5D5D] mb-1">
50+
Welcome Back
51+
</h2>
52+
<p className="text-[#5D5D5D] text-base font-inter mb-8">
53+
Enter your registered email address and password
54+
</p>
55+
56+
<form className="flex flex-col gap-6" onSubmit={handleSubmit}>
57+
<div>
58+
<label
59+
className="block text-[#5D5D5D] text-base font-inter mb-2"
60+
htmlFor="email"
61+
>
62+
Email Address
63+
</label>
64+
<input
65+
id="email"
66+
type="email"
67+
className="rounded-md border border-gray-300 py-2 w-full px-5 focus:outline-none focus:ring-2 focus:ring-blue-100 placeholder:text-[#B0B0B0] font-normal text-base h-[50px]"
68+
placeholder="Enter Email address"
69+
value={email}
70+
onChange={handleEmailChange}
71+
autoComplete="email"
72+
/>
73+
{emailError && (
74+
<p className="text-base text-red-500 mt-1">{emailError}</p>
75+
)}
76+
</div>
77+
78+
<div>
79+
<div className="flex items-center justify-between mb-1">
80+
<label
81+
className="block text-[#5D5D5D] text-base font-inter"
82+
htmlFor="password"
83+
>
84+
Password
85+
</label>
86+
<a
87+
href="#"
88+
className="text-[#096CFF] text-base font-inter hover:underline"
89+
>
90+
Forgot Password?
91+
</a>
92+
</div>
93+
<div className="relative">
94+
<span className="absolute left-3 top-1/2 -translate-y-1/2">
95+
<Lock className="w-4 h-4 text-gray-400" />
96+
</span>
97+
<input
98+
id="password"
99+
type={showPassword ? "text" : "password"}
100+
className="rounded-md border border-gray-300 px-3 py-2 w-full pl-10 pr-10 focus:outline-none focus:ring-2 focus:ring-blue-100 placeholder:text-[#B0B0B0] font-normal text-base h-[50px]"
101+
placeholder="Enter Password"
102+
value={password}
103+
onChange={(e) => setPassword(e.target.value)}
104+
autoComplete="current-password"
105+
/>
106+
<button
107+
type="button"
108+
onClick={() => setShowPassword(!showPassword)}
109+
className="absolute right-3 top-1/2 -translate-y-1/2"
110+
>
111+
{showPassword ? (
112+
<EyeOff className="w-4 h-4 text-gray-400" />
113+
) : (
114+
<Eye className="w-4 h-4 text-gray-400" />
115+
)}
116+
</button>
117+
</div>
118+
</div>
119+
120+
<button
121+
type="submit"
122+
className="w-full bg-[#096CFF] text-white py-3 px-4 rounded-md font-inter font-medium text-base hover:bg-blue-700 transition-colors h-[50px]"
123+
>
124+
Sign In
125+
</button>
126+
</form>
127+
</div>
128+
</div>
129+
);
130+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React from "react";
2+
import BackButton from "./BackButton";
3+
import { SignInStep } from "@/lib/types";
4+
5+
interface QRCodeStepProps {
6+
onBack: () => void;
7+
onStepChange: (step: SignInStep) => void;
8+
}
9+
10+
export default function QRCodeStep({ onBack, onStepChange }: QRCodeStepProps) {
11+
return (
12+
<div className="min-h-screen flex items-center justify-center bg-gray-100">
13+
<div className="bg-white rounded-2xl shadow-lg p-10 w-full max-w-lg flex flex-col ">
14+
<BackButton onBack={onBack} />
15+
16+
<div className="flex items-center max-w-xs gap-x-1 mx-auto">
17+
<div className="w-10 h-10 flex items-center justify-center rounded-full bg-blue-600 ">
18+
<span className="text-white text-3xl font-bold">B</span>
19+
</div>
20+
<div className="text-2xl font-bold text-gray-900">Braavos</div>
21+
</div>
22+
23+
<div className="flex mt-8 gap-x-3 items-center rounded-lg max-w-xs mx-auto ">
24+
<div
25+
onClick={() => onStepChange("connecting")}
26+
className="bg-gray-300 cursor-pointer rounded-lg w-fit text-[#454545] px-6 py-3 text-base text-center"
27+
>
28+
Website
29+
</div>
30+
<div className="bg-gray-100 rounded-lg w-fit text-[#454545] px-6 py-3 text-base text-center">
31+
Mobile App
32+
</div>
33+
</div>
34+
<div className="flex items-center justify-center">
35+
<div className=" w-[180px] h-[180px] mt-8 rounded-lg ">
36+
<img
37+
src="/qrcode.png"
38+
alt="QR Code"
39+
className="w-full h-full object-contain"
40+
/>
41+
</div>
42+
</div>
43+
44+
<div className="text-base text-gray-600 text-center mt-6">
45+
Scan to connect and log-In with Braavos app
46+
</div>
47+
</div>
48+
</div>
49+
);
50+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { SignInStep } from "@/lib/types";
2+
import React, { useEffect } from "react";
3+
4+
interface Props {
5+
onBack: () => void;
6+
onStepChange: (step: SignInStep) => void;
7+
}
8+
9+
export default function SignatureStep({ onBack, onStepChange }: Props) {
10+
useEffect(() => {
11+
const timer = setTimeout(() => {
12+
onStepChange("success");
13+
}, 3000);
14+
15+
return () => clearTimeout(timer);
16+
}, [onStepChange]);
17+
18+
return (
19+
<div className="min-h-screen bg-gray-100 flex items-center justify-center font-inter">
20+
<div className="bg-white rounded-2xl shadow-lg w-full max-w-md px-6 py-8 sm:px-10 sm:py-10 flex flex-col items-center">
21+
<div className="flex flex-col items-center mb-8">
22+
<div className="w-24 h-24 flex items-center justify-center mb-6">
23+
24+
<div className="w-24 h-24 rounded-full border-8 !border-blue-600 flex items-center justify-center">
25+
<div className="w-6 h-6 rounded-full border-4 !border-blue-100"></div>
26+
</div>
27+
</div>
28+
<div className="text-base text-gray-500 text-center font-medium max-w-xs">
29+
Sign the message in your wallet
30+
<br />
31+
to confirm the authentication process
32+
</div>
33+
</div>
34+
<button
35+
onClick={() => onStepChange("success")}
36+
className="w-full h-full py-3 bg-gradient-to-b font-semibold text-base shadow-sm hover:from-blue-200 hover:to-blue-300 transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 rounded-md bg-[linear-gradient(to_bottom,_#EDF7FF_100%,_#096CFF_30%)]
37+
hover:bg-gray-200"
38+
>
39+
Cancel
40+
</button>
41+
</div>
42+
</div>
43+
);
44+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React from "react";
2+
import CheckIcon from "@/components/svg/CheckIcon";
3+
4+
interface SuccessStepProps {
5+
onProceed: () => void;
6+
}
7+
8+
export default function SuccessStep({
9+
onProceed,
10+
}: SuccessStepProps) {
11+
return (
12+
<div className="min-h-screen bg-gray-100 flex items-center justify-center font-inter">
13+
<div className="bg-white rounded-2xl shadow-lg w-full max-w-md px-6 py-8 sm:px-10 sm:py-10 flex flex-col items-center ">
14+
<div className="flex flex-col items-center mb-8">
15+
<div className="w-30 h-30 flex items-center justify-center mb-8">
16+
<div className="w-30 h-30 rounded-full bg-blue-100 flex items-center justify-center">
17+
<div className="w-20 h-20 rounded-full bg-blue-600 flex items-center justify-center">
18+
<CheckIcon />
19+
</div>
20+
</div>
21+
</div>
22+
<div className="text-xl font-medium text-gray-800 text-center">
23+
Bravoos Wallet Connected
24+
</div>
25+
</div>
26+
<button
27+
onClick={onProceed}
28+
className="px-6 py-4 w-full rounded-md bg-blue-600 text-white hover:bg-blue-700 transition"
29+
>
30+
Proceed
31+
</button>
32+
</div>
33+
</div>
34+
);
35+
}

0 commit comments

Comments
 (0)