Skip to content

Commit

Permalink
Merge pull request #22 from Developer-DAO/registration
Browse files Browse the repository at this point in the history
Registration
  • Loading branch information
vorcigernix authored Feb 11, 2024
2 parents 2504f11 + b683a58 commit 00b62f3
Show file tree
Hide file tree
Showing 15 changed files with 3,397 additions and 100 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

# testing
/coverage
/playwright-report

# next.js
/.next/
Expand All @@ -34,6 +35,12 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts


# lockfiles
yarn.lock

# tests
/test-results/
/playwright-report/
/blob-report/
Expand Down
54 changes: 42 additions & 12 deletions app/authentication/_components/user-login-form.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
"use client"

import * as React from "react"

import { useAccount, useConnect, useDisconnect } from 'wagmi'
import { cn } from "@/lib/utils"
import { Icons } from "@/components/ui/icons"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { HoverCard, HoverCardContent, HoverCardTrigger } from "@/components/ui/hover-card"
import { WalletButton } from "@/components/wallet-buttons"

interface UserAuthFormProps extends React.HTMLAttributes<HTMLDivElement> {}
interface UserAuthFormProps extends React.HTMLAttributes<HTMLDivElement> { }

export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
export default function UserLoginForm({ className, ...props }: UserAuthFormProps) {
const [isLoading, setIsLoading] = React.useState<boolean>(false)

const account = useAccount()
const { connectors, connect, status, error } = useConnect()
const { disconnect } = useDisconnect()

async function onSubmit(event: React.SyntheticEvent) {
event.preventDefault()
setIsLoading(true)
Expand All @@ -22,17 +28,41 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
}, 3000)
}

const loginButtons = connectors.map((connector) =>
connector.name.toLowerCase() === "injected" ? null : (
<WalletButton
connector={connector}
isLoading={isLoading}
connect={connect}
key={connector.uid}
/>
)
);

return (
<div className={cn("grid gap-6", className)} {...props}>
<Button variant="outline" type="button" disabled={isLoading} className="p-2">
{isLoading ? (
<Icons.spinner className="mr-2 h-6 w-6 animate-spin" />
) : (
<Icons.ethereum className="mr-2 h-6 w-6" />
)}{" "}
Wallet
</Button>

{account.status === 'connected' ? (
<HoverCard>
<HoverCardTrigger asChild>
<Button variant="destructive" onClick={() => disconnect()}>Disconnect</Button>
</HoverCardTrigger>
<HoverCardContent className="w-80">
<div className="flex justify-between space-x-4">
<div className="space-y-1">
<h4 className="text-sm font-semibold">connected as</h4>
<div className="text-xs">
{JSON.stringify(account.addresses[0].replaceAll(account.addresses[0].slice(8, 36), '...'))}
</div>
</div>
</div>
</HoverCardContent>
</HoverCard>
) : (
<div className="grid gap-1">
{loginButtons}
</div>
)}
<div className="relative">
<div className="relative flex justify-center text-xs uppercase">
<span className="bg-background px-2 text-neutral-500">
Expand Down Expand Up @@ -79,7 +109,7 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
</Button>
</div>
</form>


</div>
)
Expand Down
198 changes: 144 additions & 54 deletions app/authentication/_components/user-reg-form.tsx
Original file line number Diff line number Diff line change
@@ -1,72 +1,162 @@
"use client"

import * as React from "react"

import { useAccount, useConnect, useDisconnect } from 'wagmi'
import { cn } from "@/lib/utils"
import { Icons } from "@/components/ui/icons"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { HoverCard, HoverCardContent, HoverCardTrigger } from "@/components/ui/hover-card"
import { WalletButton } from "@/components/wallet-buttons"
import { SubmitButton } from "@/components/form-submit-button";
import { registerUser } from "../authbfe";
import { useFormState, useFormStatus } from "react-dom";

interface UserAuthFormProps extends React.HTMLAttributes<HTMLDivElement> {}
interface UserAuthFormProps extends React.HTMLAttributes<HTMLDivElement> { }

export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
const [isLoading, setIsLoading] = React.useState<boolean>(false)

async function onSubmit(event: React.SyntheticEvent) {
event.preventDefault()
setIsLoading(true)
export default function UserRegForm({ className, ...props }: UserAuthFormProps) {

setTimeout(() => {
setIsLoading(false)
}, 3000)
}
const account = useAccount()
const { connectors, connect, status, error } = useConnect()
const { disconnect } = useDisconnect()

return (
<div className={cn("grid gap-6", className)} {...props}>
<Button variant="outline" type="button" disabled={isLoading} className="p-2">
{isLoading ? (
<Icons.spinner className="mr-2 h-6 w-6 animate-spin" />
) : (
<Icons.ethereum className="mr-2 h-6 w-6" />
)}{" "}
Wallet
</Button>
const [state, formAction] = useFormState(registerUser, null);

<div className="relative">
<div className="relative flex justify-center text-xs uppercase">
<span className="bg-background px-2 text-neutral-500">
And continue with
</span>
</div>
</div>
const walletButtons = connectors.map((connector) =>
connector.name.toLowerCase() === "injected" ? null : (
<WalletButton
connector={connector}
isLoading={status === 'pending'}
connect={connect}
key={connector.uid}
/>
)
);

<form onSubmit={onSubmit}>
<div className="grid gap-2">
<div className="grid gap-1">
<Label className="sr-only" htmlFor="email">
Email
</Label>
<Input
id="email"
placeholder="name@example.com"
type="email"
autoCapitalize="none"
autoComplete="email"
autoCorrect="off"
disabled={isLoading}
/>
return (
<>
{!state ? (
<div className={cn("grid gap-6", className)} {...props}>
{account.status === 'connected' ? (
<HoverCard>
<HoverCardTrigger asChild>
<Button variant="destructive" onClick={() => disconnect()}>Disconnect</Button>
</HoverCardTrigger>
<HoverCardContent className="w-80">
<div className="flex justify-between space-x-4">
<div className="space-y-1">
<h4 className="text-sm font-semibold">connected as</h4>
<div className="text-xs">
{JSON.stringify(account.addresses[0].replaceAll(account.addresses[0].slice(8, 36), '...'))}
</div>
</div>
</div>
</HoverCardContent>
</HoverCard>
) : (
<div className="grid gap-1">
{walletButtons}
</div>
)}
<div className="relative">
<div className="relative flex justify-center text-xs uppercase">
<span className="bg-background px-2 text-neutral-500">
And continue with
</span>
</div>
</div>
<Button disabled={isLoading}>
{isLoading && (
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
)}
Sign In with Email
</Button>
</div>
</form>


</div>
<form action={formAction}>
<input type="hidden" name="wallet" id="wallet" value={account.addresses?.[0]} />
<div className="grid gap-2">
<div className="grid gap-1">
<Label className="sr-only" htmlFor="email">
Email
</Label>
<Input
id="email"
name="email"
placeholder="name@example.com"
type="email"
autoCapitalize="none"
autoComplete="email"
autoCorrect="off"
/>
</div>
<div className="grid gap-1">
<Label className="sr-only" htmlFor="password">
Password
</Label>
<Input
id="password"
name="password"
placeholder="******"
type="password"
autoCapitalize="none"
autoComplete="email"
autoCorrect="off"
/>
</div>
<SubmitButton />
</div>
</form>
</div>
) : (<>
{state.success ? (<>
<div className="relative items-center w-full py-12 mx-auto max-w-7xl">
<div className="flex w-full mx-auto">
<div className="relative inline-flex items-center m-auto align-middle">
<div className="relative max-w-6xl p-6 overflow-hidden bg-white rounded-3xl">
<div className="relative max-w-lg">
<div><p className="text-2xl font-medium tracking-tight text-black sm:text-4xl">
Welcome on board!
</p>
<p className="max-w-xl mt-4 text-base tracking-tight text-neutral-600">
Check your email for a confirmation link. If you don't see it, check your spam folder please.
</p>
</div>
<div className="flex flex-col items-center justify-center gap-3 mt-10 lg:flex-row lg:justify-start">
<a href="/authentication/login" className="items-center justify-center w-full px-6 py-2.5 text-center text-white duration-200 bg-black border-2 border-black rounded-full inline-flex hover:bg-transparent hover:border-black hover:text-black focus:outline-none lg:w-auto focus-visible:outline-black text-sm focus-visible:ring-black">
Login &nbsp; →
</a>
<a href="/contact" className="inline-flex items-center justify-center text-sm font-semibold text-black duration-200 hover:text-blue-500 focus:outline-none focus-visible:outline-gray-600">
Contact us &nbsp; →
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</>) : (<>
<div className="relative items-center w-full py-12 mx-auto max-w-7xl">
<div className="flex w-full mx-auto">
<div className="relative inline-flex items-center m-auto align-middle">
<div className="relative max-w-6xl p-6 overflow-hidden bg-white rounded-3xl">
<div className="relative max-w-lg">
<div><p className="text-2xl font-medium tracking-tight text-red-500 sm:text-4xl">
This is an Error
</p>
<p className="max-w-xl mt-4 text-base tracking-tight text-neutral-600">
We failed to register you. Are you already registered? Please contact us if the problem persists.
</p>
</div>
<div className="flex flex-col items-center justify-center gap-3 mt-10 lg:flex-row lg:justify-start">
<a href="/authentication/reset" className="items-center justify-center w-full px-6 py-2.5 text-center text-white duration-200 bg-black border-2 border-black rounded-full inline-flex hover:bg-transparent hover:border-black hover:text-black focus:outline-none lg:w-auto focus-visible:outline-black text-sm focus-visible:ring-black">
Reset password &nbsp; →
</a>
<a href="/contact" className="inline-flex items-center justify-center text-sm font-semibold text-black duration-200 hover:text-blue-500 focus:outline-none focus-visible:outline-gray-600">
Contact us &nbsp; →
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</>)}
</>)}
</>
)
}
27 changes: 27 additions & 0 deletions app/authentication/authbfe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use server"
export async function registerUser(prevState: any, formData: FormData) {

const rawFormData = {
email: formData.get('email'),
wallet: formData.get('wallet'),
password: formData.get('password'),
}

//console.log(rawFormData);

const response = await fetch('http://0.0.0.0:3000/api/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(rawFormData),
})
const result = await response;
if (result.status === 200) {
return { message: `Registered user ${rawFormData.email}`, success: true };
}
else {

return { message: `Error: ${result.statusText}`, success: false };
}
}
6 changes: 4 additions & 2 deletions app/authentication/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import Image from "next/image"
import Link from "next/link"
import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"
import { UserAuthForm } from "@/app/authentication/_components/user-login-form";
import { Icons } from "@/components/ui/icons"
import dynamic from "next/dynamic"

const UserLoginForm = dynamic(() => import('@/app/authentication/_components/user-login-form'), { ssr: false })

export const metadata: Metadata = {
title: "Authentication",
Expand Down Expand Up @@ -49,7 +51,7 @@ export default function AuthenticationPage() {
Connect wallet or enter your email and password below to log in.
</p>
</div>
<UserAuthForm />
<UserLoginForm />
<p className="px-8 text-center text-sm text-neutral-400">
By clicking continue, you agree to our{" "}
<Link
Expand Down
Loading

0 comments on commit 00b62f3

Please sign in to comment.