From ad9b6b387aa4cc944cd1041ae9bf8d46672deb26 Mon Sep 17 00:00:00 2001 From: Zintarh Date: Mon, 28 Jul 2025 17:00:55 +0100 Subject: [PATCH 1/2] Implement complete admin signup flow with email and wallet signin options --- public/qrcode.png | Bin 0 -> 25100 bytes .../admin/signup/components/BackButton.tsx | 15 ++ .../signup/components/ConnectingStep.tsx | 45 ++++++ .../signup/components/EmailSignInStep.tsx | 128 ++++++++++++++++++ .../admin/signup/components/QRCodeStep.tsx | 50 +++++++ .../admin/signup/components/SignatureStep.tsx | 44 ++++++ .../admin/signup/components/SuccessStep.tsx | 35 +++++ .../signup/components/WalletSelectionStep.tsx | 71 ++++++++++ src/app/admin/signup/page.tsx | 119 ++++++++++++++++ src/components/svg/CheckIcon.tsx | 18 +++ src/components/svg/GoogleIcon2.tsx | 17 +++ src/components/svg/MetaMaskIcon.tsx | 20 +++ src/components/svg/WalletConnectIcon.tsx | 20 +++ src/components/svg/WalletIcon.tsx | 19 +++ src/lib/types.ts | 15 +- 15 files changed, 613 insertions(+), 3 deletions(-) create mode 100644 public/qrcode.png create mode 100644 src/app/admin/signup/components/BackButton.tsx create mode 100644 src/app/admin/signup/components/ConnectingStep.tsx create mode 100644 src/app/admin/signup/components/EmailSignInStep.tsx create mode 100644 src/app/admin/signup/components/QRCodeStep.tsx create mode 100644 src/app/admin/signup/components/SignatureStep.tsx create mode 100644 src/app/admin/signup/components/SuccessStep.tsx create mode 100644 src/app/admin/signup/components/WalletSelectionStep.tsx create mode 100644 src/app/admin/signup/page.tsx create mode 100644 src/components/svg/CheckIcon.tsx create mode 100644 src/components/svg/GoogleIcon2.tsx create mode 100644 src/components/svg/MetaMaskIcon.tsx create mode 100644 src/components/svg/WalletConnectIcon.tsx create mode 100644 src/components/svg/WalletIcon.tsx diff --git a/public/qrcode.png b/public/qrcode.png new file mode 100644 index 0000000000000000000000000000000000000000..6cf1f2f395e5c633acfadcbae3e01d8d482c5e7d GIT binary patch literal 25100 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 void }) { + return ( + + ); +} diff --git a/src/app/admin/signup/components/ConnectingStep.tsx b/src/app/admin/signup/components/ConnectingStep.tsx new file mode 100644 index 0000000..badd34e --- /dev/null +++ b/src/app/admin/signup/components/ConnectingStep.tsx @@ -0,0 +1,45 @@ +import { SignInStep } from '@/lib/types'; +import React, { useEffect } from 'react'; +import WalletIcon from '@/components/svg/WalletIcon'; + +interface Props { + onBack: () => void; + onStepChange: (step: SignInStep) => void; +} + + +export default function ConnectingStep({ onBack, onStepChange }: Props) { + useEffect(() => { + const timer = setTimeout(() => { + onStepChange("signature"); + }, 3000); + + return () => clearTimeout(timer); + }, [onStepChange]); + + return ( +

+
+
+
+ +
+ Braavos +
+
+
+
+
+
Connecting to Wallet...
+
+ +
+
+ ); +} \ No newline at end of file diff --git a/src/app/admin/signup/components/EmailSignInStep.tsx b/src/app/admin/signup/components/EmailSignInStep.tsx new file mode 100644 index 0000000..33227e1 --- /dev/null +++ b/src/app/admin/signup/components/EmailSignInStep.tsx @@ -0,0 +1,128 @@ +import React, { useState } from "react"; +import { Lock, Eye, EyeOff } from "lucide-react"; +import BackButton from "./BackButton"; +import { SignInStep } from "@/lib/types"; + +interface EmailSignInStepProps { + onBack: () => void; + onStepChange: (step: SignInStep) => void; +} + +const emailRegex = /^[\w-.]+@([\w-]+\.)+[\w-]{2,}$/i; + +export default function EmailSignInStep({ + onBack, + onStepChange, +}: EmailSignInStepProps) { + const [showPassword, setShowPassword] = useState(false); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [emailError, setEmailError] = useState(""); + + const handleEmailChange = (e: React.ChangeEvent) => { + const value = e.target.value; + setEmail(value); + if (value.length === 0 || emailRegex.test(value)) { + setEmailError(""); + } else { + setEmailError("Please enter a valid email address"); + } + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + if (!emailRegex.test(email)) { + setEmailError("Please enter a valid email address"); + return; + } else { + setEmailError(""); + onStepChange("success"); + } + }; + + return ( +
+
+ + +

+ Welcome Back +

+

+ Enter your registered email address and password +

+
+
+ + + {emailError && ( +

{emailError}

+ )} +
+ +
+
+ + + Forgot Password? + +
+
+ + + + setPassword(e.target.value)} + autoComplete="current-password" + /> + +
+
+ +
+
+
+ ); +} diff --git a/src/app/admin/signup/components/QRCodeStep.tsx b/src/app/admin/signup/components/QRCodeStep.tsx new file mode 100644 index 0000000..18526ce --- /dev/null +++ b/src/app/admin/signup/components/QRCodeStep.tsx @@ -0,0 +1,50 @@ +import React from "react"; +import BackButton from "./BackButton"; +import { SignInStep } from "@/lib/types"; + +interface QRCodeStepProps { + onBack: () => void; + onStepChange: (step: SignInStep) => void; +} + +export default function QRCodeStep({ onBack, onStepChange }: QRCodeStepProps) { + return ( +
+
+ + +
+
+ B +
+
Braavos
+
+ +
+
onStepChange("connecting")} + className="bg-gray-300 cursor-pointer rounded-lg w-fit text-[#454545] px-6 py-3 text-base text-center" + > + Website +
+
+ Mobile App +
+
+
+
+ QR Code +
+
+ +
+ Scan to connect and log-In with Braavos app +
+
+
+ ); +} diff --git a/src/app/admin/signup/components/SignatureStep.tsx b/src/app/admin/signup/components/SignatureStep.tsx new file mode 100644 index 0000000..52200d6 --- /dev/null +++ b/src/app/admin/signup/components/SignatureStep.tsx @@ -0,0 +1,44 @@ +import { SignInStep } from "@/lib/types"; +import React, { useEffect } from "react"; + +interface Props { + onBack: () => void; + onStepChange: (step: SignInStep) => void; +} + +export default function SignatureStep({ onBack, onStepChange }: Props) { + useEffect(() => { + const timer = setTimeout(() => { + onStepChange("success"); + }, 3000); + + return () => clearTimeout(timer); + }, [onStepChange]); + + return ( +
+
+
+
+ +
+
+
+
+
+ Sign the message in your wallet +
+ to confirm the authentication process +
+
+ +
+
+ ); +} diff --git a/src/app/admin/signup/components/SuccessStep.tsx b/src/app/admin/signup/components/SuccessStep.tsx new file mode 100644 index 0000000..f55c109 --- /dev/null +++ b/src/app/admin/signup/components/SuccessStep.tsx @@ -0,0 +1,35 @@ +import React from "react"; +import CheckIcon from "@/components/svg/CheckIcon"; + +interface SuccessStepProps { + onProceed: () => void; +} + +export default function SuccessStep({ + onProceed, +}: SuccessStepProps) { + return ( +
+
+
+
+
+
+ +
+
+
+
+ Bravoos Wallet Connected +
+
+ +
+
+ ); +} diff --git a/src/app/admin/signup/components/WalletSelectionStep.tsx b/src/app/admin/signup/components/WalletSelectionStep.tsx new file mode 100644 index 0000000..6c410f5 --- /dev/null +++ b/src/app/admin/signup/components/WalletSelectionStep.tsx @@ -0,0 +1,71 @@ +import React from "react"; +import { ChevronLeft } from "lucide-react"; +import { SignInStep } from "@/lib/types"; +import BackButton from "./BackButton"; +import MetaMaskIcon from "@/components/svg/MetaMaskIcon"; +import WalletConnectIcon from "@/components/svg/WalletConnectIcon"; + +interface WalletSelectionStepProps { + onBack: () => void; + onStepChange: (step: SignInStep) => void; +} + + + +export default function WalletSelectionStep({ + onBack, + onStepChange, +}: WalletSelectionStepProps) { + return ( +
+
+ + +

Welcome Back

+ +

+ Connect to your registered wallet address to Signin +

+ +
+
onStepChange("qrCode")} + className="rounded-lg border border-[#E7E7E7] p-4 flex items-center justify-between cursor-pointer hover:bg-gray-50 transition" + > +
+ + + MetaMask + +
+ +
+
onStepChange("qrCode")} + className="rounded-lg border border-[#E7E7E7] p-4 flex items-center justify-between" + > +
+ + + WalletConnect + +
+ +
+
+ +
+

+ By connecting your wallet, you agree to our{" "} + Terms and Conditions and our{" "} + Privacy Policy +

+
+
+
+ ); +} diff --git a/src/app/admin/signup/page.tsx b/src/app/admin/signup/page.tsx new file mode 100644 index 0000000..f8018b7 --- /dev/null +++ b/src/app/admin/signup/page.tsx @@ -0,0 +1,119 @@ +"use client"; +import React, { useState } from "react"; +import { LinkIcon } from "lucide-react"; +import GoogleIcon2 from "@/components/svg/GoogleIcon2"; +import dynamic from "next/dynamic"; +import { SignInStep } from "@/lib/types"; +import QRCodeStep from "./components/QRCodeStep"; +import ConnectingStep from "./components/ConnectingStep"; +import SignatureStep from "./components/SignatureStep"; +import SuccessStep from "./components/SuccessStep"; + +const EmailSignInStep = dynamic(() => import("./components/EmailSignInStep"), { + ssr: false, +}); + +const WalletSelectionStep = dynamic(() => import("./components/WalletSelectionStep"), { + ssr: false, +}); + +function Stepper({ + step, + onStepChange, +}: { + step: SignInStep; + onStepChange: (step: SignInStep) => void; +}) { + if (step === "emailSignIn") { + return ( + onStepChange("adminSignIn")} + onStepChange={onStepChange} + /> + ); + } + if (step === "walletSelection") { + return ( + onStepChange("emailSignIn")} + onStepChange={onStepChange} + /> + ); + } + + if (step === "qrCode") { + return ( + onStepChange("walletSelection")} onStepChange={onStepChange} /> + ); + } + + if (step === "connecting") { + return ( + onStepChange("walletSelection")} + onStepChange={onStepChange} + /> + ); + } + + if (step === "signature") { + return ( + onStepChange("walletSelection")} + onStepChange={onStepChange} + /> + ); + } + + if (step === "success") { + return onStepChange("adminSignIn")} />; + } + + return ; +} + +function AdminSignIn({ + onStepChange, +}: { + onStepChange: (step: SignInStep) => void; +}) { + return ( +
+
+

+ How would you like to sign-in +

+
+ + +
+
+
+ ); +} + +export default function AdminSignInPage() { + const [step, setStep] = useState("adminSignIn"); + const handleStepChange = (newStep: SignInStep) => setStep(newStep); + return ; +} diff --git a/src/components/svg/CheckIcon.tsx b/src/components/svg/CheckIcon.tsx new file mode 100644 index 0000000..5ccded2 --- /dev/null +++ b/src/components/svg/CheckIcon.tsx @@ -0,0 +1,18 @@ +import * as React from "react" +import { SVGProps } from "react" + +const CheckIcon = (props: SVGProps) => ( + +) + +export default CheckIcon diff --git a/src/components/svg/GoogleIcon2.tsx b/src/components/svg/GoogleIcon2.tsx new file mode 100644 index 0000000..2fb4762 --- /dev/null +++ b/src/components/svg/GoogleIcon2.tsx @@ -0,0 +1,17 @@ +import * as React from "react" +import { SVGProps } from "react" +const GoogleIcon2 = (props: SVGProps) => ( + + + +) +export default GoogleIcon2 diff --git a/src/components/svg/MetaMaskIcon.tsx b/src/components/svg/MetaMaskIcon.tsx new file mode 100644 index 0000000..4102289 --- /dev/null +++ b/src/components/svg/MetaMaskIcon.tsx @@ -0,0 +1,20 @@ +import * as React from "react" +import { SVGProps } from "react" + +const MetaMaskIcon = (props: SVGProps) => ( + + + + MetaMask + + +) + +export default MetaMaskIcon diff --git a/src/components/svg/WalletConnectIcon.tsx b/src/components/svg/WalletConnectIcon.tsx new file mode 100644 index 0000000..dc53fb1 --- /dev/null +++ b/src/components/svg/WalletConnectIcon.tsx @@ -0,0 +1,20 @@ +import * as React from "react" +import { SVGProps } from "react" + +const WalletConnectIcon = (props: SVGProps) => ( + + + + WC + + +) + +export default WalletConnectIcon diff --git a/src/components/svg/WalletIcon.tsx b/src/components/svg/WalletIcon.tsx new file mode 100644 index 0000000..bfe3109 --- /dev/null +++ b/src/components/svg/WalletIcon.tsx @@ -0,0 +1,19 @@ +import * as React from "react" +import { SVGProps } from "react" + +const WalletIcon = (props: SVGProps) => ( + +) + +export default WalletIcon diff --git a/src/lib/types.ts b/src/lib/types.ts index c271a1d..e5e6d46 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -2,8 +2,17 @@ export type ClubDetailsProps = { id: string; name: string; isPublic: boolean; - memberCount: number; - sessionsInfo: string; + memberCount: number; + sessionsInfo: string; unreadNotifications: number; - authorAvatars: string[]; + authorAvatars: string[]; }; + +export type SignInStep = + | "adminSignIn" + | "emailSignIn" + | "walletSelection" + | "qrCode" + | "connecting" + | "signature" + | "success"; From 1f38f00c76676a7f44e281320d3017b75af8dba4 Mon Sep 17 00:00:00 2001 From: Zintarh Date: Tue, 29 Jul 2025 08:21:43 +0100 Subject: [PATCH 2/2] feat: display starknet wallets --- .../signup/components/EmailSignInStep.tsx | 16 +- .../signup/components/WalletSelectionStep.tsx | 166 ++++++++++++++---- 2 files changed, 137 insertions(+), 45 deletions(-) diff --git a/src/app/admin/signup/components/EmailSignInStep.tsx b/src/app/admin/signup/components/EmailSignInStep.tsx index 33227e1..efa2fe4 100644 --- a/src/app/admin/signup/components/EmailSignInStep.tsx +++ b/src/app/admin/signup/components/EmailSignInStep.tsx @@ -1,8 +1,9 @@ -import React, { useState } from "react"; -import { Lock, Eye, EyeOff } from "lucide-react"; +import React, { useState, } from "react"; +import { Eye, EyeOff, Lock } from "lucide-react"; import BackButton from "./BackButton"; import { SignInStep } from "@/lib/types"; + interface EmailSignInStepProps { onBack: () => void; onStepChange: (step: SignInStep) => void; @@ -51,6 +52,7 @@ export default function EmailSignInStep({

Enter your registered email address and password

+
+
diff --git a/src/app/admin/signup/components/WalletSelectionStep.tsx b/src/app/admin/signup/components/WalletSelectionStep.tsx index 6c410f5..0cbe0f4 100644 --- a/src/app/admin/signup/components/WalletSelectionStep.tsx +++ b/src/app/admin/signup/components/WalletSelectionStep.tsx @@ -1,9 +1,11 @@ -import React from "react"; -import { ChevronLeft } from "lucide-react"; +import React, { useState, useEffect } from "react"; +import { Wallet } from "lucide-react"; import { SignInStep } from "@/lib/types"; import BackButton from "./BackButton"; -import MetaMaskIcon from "@/components/svg/MetaMaskIcon"; -import WalletConnectIcon from "@/components/svg/WalletConnectIcon"; +import { useWalletContext } from "@/components/blockchain/WalletProvider"; +import { useConnect, useAccount, Connector } from "@starknet-react/core"; +import { StarknetkitConnector, useStarknetkitConnectModal } from "starknetkit"; +import { WebWalletConnector } from "starknetkit/webwallet"; interface WalletSelectionStepProps { onBack: () => void; @@ -16,6 +18,80 @@ export default function WalletSelectionStep({ onBack, onStepChange, }: WalletSelectionStepProps) { + const [selectedWallet, setSelectedWallet] = useState(null); + const [isConnecting, setIsConnecting] = useState(false); + const [connectionError, setConnectionError] = useState(""); + + const { connect, connectors } = useConnect(); + const { isConnected, address } = useAccount(); + const { connectWallet } = useWalletContext(); + + // Customize WebWalletConnector with an icon + const customizedConnectors = connectors.map((connector) => { + if (connector instanceof WebWalletConnector) { + return new WebWalletConnector({}); + } + return connector; + }); + + const { starknetkitConnectModal } = useStarknetkitConnectModal({ + connectors: customizedConnectors as StarknetkitConnector[], + }); + + const handleWalletConnect = async (connector: Connector) => { + try { + setIsConnecting(true); + setConnectionError(""); + setSelectedWallet(connector.id); + + await connect({ connector }); + + // Wait a bit for connection to establish + setTimeout(() => { + if (isConnected) { + onStepChange("success"); + } + }, 1000); + } catch (error) { + console.error("Connection failed:", error); + setConnectionError("Failed to connect wallet. Please try again."); + setSelectedWallet(null); + } finally { + setIsConnecting(false); + } + }; + + const handleStarknetkitConnect = async () => { + try { + setIsConnecting(true); + setConnectionError(""); + + const { connector } = await starknetkitConnectModal(); + if (connector) { + await connect({ connector: connector as Connector }); + setTimeout(() => { + if (isConnected) { + onStepChange("success"); + } + }, 1000); + } + } catch (error) { + console.error("Connection failed:", error); + setConnectionError("Failed to connect wallet. Please try again."); + } finally { + setIsConnecting(false); + } + }; + + // // Check if already connected + // useEffect(() => { + // if (isConnected && address) { + // onStepChange("success"); + // } + // }, [isConnected, address, onStepChange]); + + + return (
@@ -24,45 +100,59 @@ export default function WalletSelectionStep({

Welcome Back

- Connect to your registered wallet address to Signin + Connect to your registered wallet address to sign in

- -
-
onStepChange("qrCode")} - className="rounded-lg border border-[#E7E7E7] p-4 flex items-center justify-between cursor-pointer hover:bg-gray-50 transition" - > -
- - - MetaMask - -
- + + {connectionError && ( +
+

{connectionError}

-
onStepChange("qrCode")} - className="rounded-lg border border-[#E7E7E7] p-4 flex items-center justify-between" - > -
- - - WalletConnect - -
- + )} + +
+ {/* Available Wallets */} +
+ {connectors.map((connector) => ( + + )} +
+ + ))}
- -
-

+ +

+

By connecting your wallet, you agree to our{" "} - Terms and Conditions and our{" "} - Privacy Policy + Terms and Conditions and our{" "} + Privacy Policy