Skip to content

Commit

Permalink
implemented signin
Browse files Browse the repository at this point in the history
  • Loading branch information
Yo-mah-Ya committed Dec 5, 2023
1 parent 5d2fe85 commit 8d405db
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 4 deletions.
22 changes: 22 additions & 0 deletions app/auth/login/action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use server'
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'
import type { SignInSchema } from '@/auth/login/schema'
import { createClient } from '@/auth/supabase/server'

export const signIn = async ({
email,
password
}: SignInSchema): Promise<void> => {
const supabase = createClient(cookies())

const { error } = await supabase.auth.signInWithPassword({
email,
password
})
if (error) {
throw error
} else {
return redirect('/')
}
}
86 changes: 83 additions & 3 deletions app/auth/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,85 @@
import { Heading } from '@chakra-ui/react'
'use client'
import { useState } from 'react'
import { useForm } from 'react-hook-form'
import {
Box,
Flex,
FormLabel,
FormErrorMessage,
FormControl,
Input,
Heading,
useToast,
useBoolean
} from '@chakra-ui/react'
import { signIn } from '@/auth/login/action'
import { signInResolver, SignInSchema } from '@/auth/login/schema'
import { PrimaryButton } from '@/components/button'

export default function Login() {
return <Heading>Login Page</Heading>
export default function SignIn() {
const toast = useToast()
const [isLoading, setIsLoading] = useBoolean()
const [toastId, setToastId] = useState<ReturnType<typeof toast> | undefined>(
undefined
)

const {
register,
handleSubmit,
formState: { errors }
} = useForm<SignInSchema>({
resolver: signInResolver
})

const signInHandler = handleSubmit(async (data: SignInSchema) => {
try {
setIsLoading.on()
await signIn(data)
} catch (error) {
if (!toastId) {
const res = toast({
title: "We're sorry, but you failed to sign in.",
description: error instanceof Error ? error.message : 'unknown error',
status: 'error',
duration: 5000,
isClosable: true,
position: 'top',
onCloseComplete() {
setToastId(undefined)
}
})
setToastId(res)
}
} finally {
setIsLoading.off()
}
})

return (
<>
<Heading>Welcome Back!</Heading>
<Heading>Sign In</Heading>
<Box as="form" onSubmit={signInHandler}>
<Flex flexDirection={'column'}>
<FormControl isInvalid={!!errors.email}>
<FormLabel>Email address</FormLabel>
<Input {...register('email')} />
{errors.email && (
<FormErrorMessage>{errors.email.message}</FormErrorMessage>
)}
</FormControl>
<FormControl isInvalid={!!errors.password}>
<FormLabel>Password</FormLabel>
<Input type="password" {...register('password')} />
{errors.password && (
<FormErrorMessage>{errors.password.message}</FormErrorMessage>
)}
</FormControl>
<PrimaryButton isLoading={isLoading} type={'submit'}>
Sign In
</PrimaryButton>
</Flex>
</Box>
</>
)
}
12 changes: 12 additions & 0 deletions app/auth/login/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { zodResolver } from '@hookform/resolvers/zod'
import * as z from 'zod'

const signInSchema = z.object({
email: z.string().email('This is not valid email address'),
password: z
.string()
.min(8, { message: 'Password must contain at least 8 character(s)' })
})

export type SignInSchema = z.infer<typeof signInSchema>
export const signInResolver = zodResolver(signInSchema)
2 changes: 1 addition & 1 deletion app/auth/signup/email/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'
import type { SignUpSchema } from '@/auth/signup/email/schema'
import { createClient } from '@/auth/supabase'
import { createClient } from '@/auth/supabase/server'

export const signUp = async ({
email,
Expand Down
4 changes: 4 additions & 0 deletions app/auth/signup/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export default function SignUp() {
</Link>
</ListItem>
</List>
<Heading>Already have an account?</Heading>
<Link href="/auth/login/email">
<SecondaryButton>Sign in to your account?</SecondaryButton>
</Link>
</>
)
}
60 changes: 60 additions & 0 deletions app/auth/supabase/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { createServerClient, type CookieOptions } from '@supabase/ssr'
import { type NextRequest, NextResponse } from 'next/server'

export const createClient = (request: NextRequest) => {
let response = NextResponse.next({
request: {
headers: request.headers
}
})

const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
get(name: string) {
return request.cookies.get(name)?.value
},
set(name: string, value: string, options: CookieOptions) {
// If the cookie is updated, update the cookies for the request and response
request.cookies.set({
name,
value,
...options
})
response = NextResponse.next({
request: {
headers: request.headers
}
})
response.cookies.set({
name,
value,
...options
})
},
remove(name: string, options: CookieOptions) {
// If the cookie is removed, update the cookies for the request and response
request.cookies.set({
name,
value: '',
...options
})
response = NextResponse.next({
request: {
headers: request.headers
}
})
response.cookies.set({
name,
value: '',
...options
})
}
}
}
)

return { supabase, response }
}
File renamed without changes.
24 changes: 24 additions & 0 deletions middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { NextResponse, type NextRequest } from 'next/server'
import { createClient } from '@/auth/supabase/middleware'

export async function middleware(request: NextRequest) {
const { supabase, response } = createClient(request)

// Refresh session if expired - required for Server Components
// https://supabase.com/docs/guides/auth/auth-helpers/nextjs#managing-session-with-middleware
const {
error,
data: { session }
} = await supabase.auth.getSession()

const loginUri = '/auth/login'

if (request.nextUrl.pathname.startsWith(loginUri)) {
return response
}
if (error || !session) {
return NextResponse.redirect(new URL(loginUri, request.url))
}

return response
}

0 comments on commit 8d405db

Please sign in to comment.