diff --git a/public/qrcode.png b/public/qrcode.png new file mode 100644 index 0000000..6cf1f2f Binary files /dev/null and b/public/qrcode.png differ diff --git a/src/app/admin/signup/components/BackButton.tsx b/src/app/admin/signup/components/BackButton.tsx new file mode 100644 index 0000000..9ebe018 --- /dev/null +++ b/src/app/admin/signup/components/BackButton.tsx @@ -0,0 +1,15 @@ +import React from 'react' +import { ChevronLeft } from 'lucide-react'; + +export default function BackButton({ onBack }: { onBack: () => 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..efa2fe4 --- /dev/null +++ b/src/app/admin/signup/components/EmailSignInStep.tsx @@ -0,0 +1,130 @@ +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; +} + +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..0cbe0f4 --- /dev/null +++ b/src/app/admin/signup/components/WalletSelectionStep.tsx @@ -0,0 +1,161 @@ +import React, { useState, useEffect } from "react"; +import { Wallet } from "lucide-react"; +import { SignInStep } from "@/lib/types"; +import BackButton from "./BackButton"; +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; + onStepChange: (step: SignInStep) => void; +} + + + +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 ( +
+
+ + +

Welcome Back

+ +

+ Connect to your registered wallet address to sign in +

+ + {connectionError && ( +
+

{connectionError}

+
+ )} + +
+ {/* Available Wallets */} +
+ {connectors.map((connector) => ( + + )} +
+ + ))} +
+
+ +
+

+ 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";