Skip to content

Commit

Permalink
Resolved conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
kanatagu committed Jan 31, 2024
2 parents 2bc1742 + 788bc21 commit 3599251
Show file tree
Hide file tree
Showing 19 changed files with 417 additions and 275 deletions.
51 changes: 51 additions & 0 deletions app/(auth)/change-password/action/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { NextRequest, NextResponse } from 'next/server'
import type { ChangePasswordSchema } from '@/(auth)/change-password/schema'
import { createClient } from '@/(auth)/supabase/with-request'

const assertVerifyOldPassword = async (
supabase: ReturnType<typeof createClient>['supabase'],
data: ChangePasswordSchema
): Promise<
| { kind: 'verified' }
| { kind: 'noSession'; message: string }
| { kind: 'wrongPassword'; message: string }
> => {
const {
data: { session },
error
} = await supabase.auth.getSession()
if (error || !session?.user.email) {
return { kind: 'noSession', message: 'user session is not detected' }
}

const {
error: signInError,
data: { session: signInSession }
} = await supabase.auth.signInWithPassword({
email: session.user.email,
password: data.oldPassword
})
if (signInError || !signInSession) {
return { kind: 'wrongPassword', message: 'Old Password is not correct' }
}
return { kind: 'verified' }
}

export const POST = async (req: NextRequest): Promise<NextResponse> => {
const { supabase } = createClient(req)

const data = (await req.json()) as ChangePasswordSchema
const res = await assertVerifyOldPassword(supabase, data)
if (res.kind !== 'verified') {
return NextResponse.json(res.message, { status: 401 })
}

const { error } = await supabase.auth.updateUser({
password: data.newPassword
})
if (error) {
return NextResponse.json(error.message, { status: 500 })
} else {
return NextResponse.json('ok', { status: 200 })
}
}
100 changes: 100 additions & 0 deletions app/(auth)/change-password/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
'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 { useRouter } from 'next/navigation'
import {
changePasswordResolver,
ChangePasswordSchema
} from '@/(auth)/change-password/schema'
import { PrimaryButton } from '@/components/button'

export default function ChangePassword() {
const toast = useToast()
const [isLoading, setIsLoading] = useBoolean()
const [toastId, setToastId] = useState<ReturnType<typeof toast> | undefined>(
undefined
)
const router = useRouter()

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

const changePasswordHandler = handleSubmit(
async (data: ChangePasswordSchema) => {
setIsLoading.on()
const response = await fetch('/change-password/action', {
method: 'POST',
body: JSON.stringify(data)
})
setIsLoading.off()
if (response.ok) {
router.push('/')
} else if (!toastId) {
const res = toast({
title: "We're sorry, but you failed to change your password.",
description: await response.json(),
status: 'error',
duration: 5000,
isClosable: true,
position: 'top',
onCloseComplete() {
setToastId(undefined)
}
})
setToastId(res)
}
}
)

return (
<>
<Heading>Change Password</Heading>
<Box as="form" onSubmit={changePasswordHandler}>
<Flex flexDirection={'column'}>
<FormControl isInvalid={!!errors.oldPassword}>
<FormLabel>Old Password</FormLabel>
<Input type="password" {...register('oldPassword')} />
{errors.oldPassword && (
<FormErrorMessage>{errors.oldPassword.message}</FormErrorMessage>
)}
</FormControl>
<FormControl isInvalid={!!errors.newPassword}>
<FormLabel>New Password</FormLabel>
<Input type="password" {...register('newPassword')} />
{errors.newPassword && (
<FormErrorMessage>{errors.newPassword.message}</FormErrorMessage>
)}
</FormControl>
<FormControl isInvalid={!!errors.confirmNewPassword}>
<FormLabel>Confirm New Password</FormLabel>
<Input type="password" {...register('confirmNewPassword')} />
{errors.confirmNewPassword && (
<FormErrorMessage>
{errors.confirmNewPassword.message}
</FormErrorMessage>
)}
</FormControl>
<PrimaryButton isLoading={isLoading} type={'submit'}>
Change Password
</PrimaryButton>
</Flex>
</Box>
</>
)
}
25 changes: 25 additions & 0 deletions app/(auth)/change-password/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { zodResolver } from '@hookform/resolvers/zod'
import * as z from 'zod'

const changePasswordSchema = z
.object({
// No need for daring to notify users old password policy in terms of security enhancement.
oldPassword: z.string().min(1, { message: 'password is required' }),
newPassword: z
.string()
.min(8, { message: 'Password must contain at least 8 character(s)' }),
confirmNewPassword: z.string().min(8, {
message: 'Password must contain at least 8 character(s)'
})
})
.refine((schema) => schema.newPassword === schema.confirmNewPassword, {
path: ['confirmNewPassword'],
message: 'Your password and confirmation password must match'
})
.refine((schema) => schema.oldPassword !== schema.newPassword, {
path: ['confirmNewPassword'],
message: 'Old password and new password must be different'
})

export type ChangePasswordSchema = z.infer<typeof changePasswordSchema>
export const changePasswordResolver = zodResolver(changePasswordSchema)
2 changes: 1 addition & 1 deletion app/(auth)/signin/action/index.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 { SignInSchema } from '@/(auth)/signin/schema'
import { createClient } from '@/(auth)/supabase/server'
import { createClient } from '@/(auth)/supabase/with-cookie'

export const signIn = async ({
email,
Expand Down
2 changes: 1 addition & 1 deletion app/(auth)/signout/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 { USER_UUID_COOKIE_NAME } from '@/(auth)/constants'
import { createClient } from '@/(auth)/supabase/server'
import { createClient } from '@/(auth)/supabase/with-cookie'

export const signOut = async (): Promise<void> => {
const c = cookies()
Expand Down
2 changes: 1 addition & 1 deletion app/(auth)/signup/email/action/index.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/server'
import { createClient } from '@/(auth)/supabase/with-cookie'

export const signUp = async ({
email,
Expand Down
File renamed without changes.
File renamed without changes.
17 changes: 0 additions & 17 deletions app/account/layout.tsx

This file was deleted.

4 changes: 3 additions & 1 deletion app/account/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ export default function AccountPage() {
return (
<>
{loading || !data?.usersCollection ? (
<Loading />
<Flex minH="100vh" align="center" justify="center">
<Loading />
</Flex>
) : (
<Box as="main" minH="100svh" bg={bg} color={color}>
<Container
Expand Down
30 changes: 14 additions & 16 deletions app/activity/[id]/components/activity-info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,20 @@ type ActivityInfoProps = {

export const ActivityInfo = ({ memo, cost }: ActivityInfoProps) => {
return (
<>
<VStack spacing="4" align="stretch">
<Box mt={{ base: '40px', md: '48px' }}>
<Heading fontSize={{ base: 'lg', md: 'xl' }}>Memo</Heading>
<Text pt="2" fontSize={{ base: 'md', md: 'lg' }}>
{memo}
</Text>
</Box>
<VStack spacing="4" align="stretch">
<Box mt={{ base: '40px', md: '48px' }}>
<Heading fontSize={{ base: 'lg', md: 'xl' }}>Memo</Heading>
<Text pt="2" fontSize={{ base: 'md', md: 'lg' }}>
{memo}
</Text>
</Box>

<Box mt={{ base: '40px', md: '48px' }}>
<Heading fontSize={{ base: 'lg', md: 'xl' }}>Cost</Heading>
<Text pt="2" fontSize={{ base: 'md', md: 'lg' }}>
${cost}
</Text>
</Box>
</VStack>
</>
<Box mt={{ base: '40px', md: '48px' }}>
<Heading fontSize={{ base: 'lg', md: 'xl' }}>Cost</Heading>
<Text pt="2" fontSize={{ base: 'md', md: 'lg' }}>
${cost}
</Text>
</Box>
</VStack>
)
}
52 changes: 25 additions & 27 deletions app/activity/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,37 +32,35 @@ export default function ActivityDetails({
const activityData = data?.activityCollection?.edges[0]?.node

return (
<>
<Box as="main" minH="100vh" bg={bg} color={color}>
{!activityData || loading ? (
<Flex minH="84vh" align="center" justify="center">
<Flex minH="100vh" align="center" justify="center">
<Loading />
</Flex>
) : (
<Box minHeight="100vh" as="main" bg={bg} color={color}>
<Container
maxW={{ base: '100%', md: '742px' }}
pt={{ base: '20px', md: '30px' }}
pb={{ base: '40px', md: '80px' }}
>
<ActivityHeader
title={activityData.title}
time_from={activityData.time_from}
time_to={activityData?.time_to}
address={activityData?.address}
url={activityData?.url}
/>
{/* TODO: Fetch images from the database once available. */}
<Carousel urls={dummyUrls} />
<ActivityInfo memo={activityData?.memo} cost={activityData?.cost} />
<Box mt="60px" display="flex" alignItems="center">
<FiChevronLeft />
<Link ml="2%" href="/">
Got back to Trip Details
</Link>
</Box>
</Container>
</Box>
<Container
maxW={{ base: '100%', md: '742px' }}
pt={{ base: '20px', md: '30px' }}
pb={{ base: '40px', md: '80px' }}
>
<ActivityHeader
title={activityData.title}
time_from={activityData.time_from}
time_to={activityData?.time_to}
address={activityData?.address}
url={activityData?.url}
/>
{/* TODO: Fetch images from the database once available. */}
<Carousel urls={dummyUrls} />
<ActivityInfo memo={activityData?.memo} cost={activityData?.cost} />
<Box mt="60px" display="flex" alignItems="center">
<FiChevronLeft />
<Link ml="2%" href="/">
Got back to Trip Details
</Link>
</Box>
</Container>
)}
</>
</Box>
)
}
27 changes: 11 additions & 16 deletions app/activity/create/page.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
'use client'

import { Box, Container, Heading, useColorModeValue } from '@chakra-ui/react'
import { Header, Footer } from '@/components/navigation'
import { FormActivity } from './components'

export default function CreateActivityPage() {
const bg = useColorModeValue('white', 'gray.800')
const color = useColorModeValue('black', 'gray.300')

return (
<>
<Box as="main" minH="100vh" bg={bg} color={color}>
<Header />
<Container
pt={{ base: '20px', md: '40px' }}
pb={{ base: '40px', md: '70px' }}
>
<Heading as={'h1'} fontSize={{ base: '2xl', md: '4xl' }}>
Create Activity
</Heading>
<FormActivity />
</Container>
<Footer />
</Box>
</>
<Box as="main" minH="100vh" bg={bg} color={color}>
<Container
pt={{ base: '20px', md: '40px' }}
pb={{ base: '40px', md: '70px' }}
>
<Heading as={'h1'} fontSize={{ base: '2xl', md: '4xl' }}>
Create Activity
</Heading>
<FormActivity />
</Container>
</Box>
)
}
Loading

0 comments on commit 3599251

Please sign in to comment.