Skip to content

Commit

Permalink
start redesigning register flow
Browse files Browse the repository at this point in the history
  • Loading branch information
aryaniyaps committed Mar 5, 2024
1 parent 4aa520e commit 5c03be1
Show file tree
Hide file tree
Showing 14 changed files with 284 additions and 298 deletions.
6 changes: 1 addition & 5 deletions client/app/(authentication)/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@ import * as yup from 'yup';

const loginSchema = yup
.object({
email: yup
.string()
.required('Please enter an email')
.email('Please enter a valid email')
.max(MAX_EMAIL_LENGTH),
email: yup.string().required().email().max(MAX_EMAIL_LENGTH),
})
.required();

Expand Down
2 changes: 1 addition & 1 deletion client/app/(authentication)/register/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RegisterFlowProvider } from '@/components/register-flow-provider';
import { RegisterFlowProvider } from '@/components/register/flow-provider';

export default function RegisterLayout({
children,
Expand Down
108 changes: 19 additions & 89 deletions client/app/(authentication)/register/page.tsx
Original file line number Diff line number Diff line change
@@ -1,104 +1,34 @@
'use client';
import { APP_NAME, MAX_EMAIL_LENGTH } from '@/lib/constants';
import { yupResolver } from '@hookform/resolvers/yup';
import {
Button,
Card,
CardBody,
CardFooter,
CardHeader,
Input,
Link,
} from '@nextui-org/react';
import { Controller, SubmitHandler, useForm } from 'react-hook-form';
import * as yup from 'yup';
import { REGISTER_FLOW_ID_COOKIE } from '@/lib/constants';
import { cookies } from 'next/headers';

import { useRegisterFlow } from '@/components/register-flow-provider';
import { RegisterFlowProvider } from '@/components/register/flow-provider';
import RegisterForm from '@/components/register/register-form';
import { client } from '@/lib/client';

// TODO: change resolver to zod as we are already using it for env management
const registerSchema = yup
.object({
email: yup
.string()
.required('Please enter an email')
.email('Please enter a valid email')
.max(MAX_EMAIL_LENGTH),
})
.required();
export default async function RegisterPage() {
const cookieStore = cookies();
const flowId = cookieStore.get(REGISTER_FLOW_ID_COOKIE);

export default function RegisterPage() {
const { setCurrentStep, setFlowId } = useRegisterFlow();
let flowData;

const { handleSubmit, control, formState, setError } = useForm({
resolver: yupResolver(registerSchema),
defaultValues: { email: '' },
mode: 'onTouched',
});

const onSubmit: SubmitHandler<yup.InferType<typeof registerSchema>> = async (
input
) => {
console.log(input);
if (flowId) {
try {
// start register flow
const { data } = await client.POST('/auth/register/flows/start', {
body: { email: input.email },
params: {
header: { 'user-agent': window.navigator.userAgent },
},
const { data } = await client.GET('/auth/register/flows', {
params: { cookie: { register_flow_id: flowId.value } },
});

if (data) {
setFlowId(data.registerFlow.id);
setCurrentStep(data.registerFlow.currentStep);
flowData = data;
}
} catch (err) {
// TODO: handle email already taken err
setError('email', {
message: 'That email is already in use',
type: 'server',
});
// TODO: handle errs better
// TODO: delete register flow ID cookie if it is invalid
// cookieStore.delete(REGISTER_FLOW_ID_COOKIE);
}
};
}

return (
<Card isFooterBlurred fullWidth className='px-unit-2'>
<CardHeader>
<h1 className='text-md font-semibold'>Create a {APP_NAME} account</h1>
</CardHeader>
<CardBody>
<form onSubmit={handleSubmit(onSubmit)} className='flex flex-col gap-4'>
<Controller
name='email'
control={control}
render={({ field, fieldState }) => {
return (
<Input
{...field}
variant='faded'
type='email'
label='Email address'
errorMessage={fieldState.error?.message}
isInvalid={!!fieldState.error}
/>
);
}}
/>

<Button
color='primary'
type='submit'
isLoading={formState.isSubmitting}
fullWidth
>
Continue
</Button>
</form>
</CardBody>
<CardFooter className='text-sm'>
Have an account?&nbsp;<Link href='/login'>sign in</Link>
</CardFooter>
</Card>
<RegisterFlowProvider flowData={flowData}>
<RegisterForm />
</RegisterFlowProvider>
);
}
105 changes: 0 additions & 105 deletions client/components/register-flow-provider.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';
import { OTPSlot } from '@/components/otp-input';
import { useRegisterFlow } from '@/components/register-flow-provider';
import { useRegisterFlow } from '@/components/register/flow-provider';
import { client } from '@/lib/client';
import { EMAIL_VERIFICATION_CODE_LENGTH } from '@/lib/constants';
import { yupResolver } from '@hookform/resolvers/yup';
Expand All @@ -26,14 +26,10 @@ const registerVerificationSchema = yup
})
.required();

export default function RegisterOTPPage() {
export default function RegisterEmailVerification() {
const { setCurrentStep, flowData } = useRegisterFlow();

const router = useRouter();
const { flowId, email, setCurrentStep, setFlowId, setEmail } =
useRegisterFlow();
if (!flowId || !email) {
// redirect to register page
return router.push('/register');
}

const { control, handleSubmit, formState, setError } = useForm({
resolver: yupResolver(registerVerificationSchema),
Expand All @@ -45,13 +41,10 @@ export default function RegisterOTPPage() {
> = async (input) => {
try {
// verify register flow
const { data } = await client.POST(
'/auth/register/flows/{flow_id}/verify',
{
body: { verificationCode: input.verificationCode },
params: { path: { flow_id: flowId } },
}
);
const { data } = await client.POST('/auth/register/flows/verify', {
body: { verificationCode: input.verificationCode },
params: { cookie: { register_flow_id: flowData!.id } },
});

if (data) {
setCurrentStep(data.registerFlow.currentStep);
Expand All @@ -66,9 +59,9 @@ export default function RegisterOTPPage() {
};

const resendVerificationCode = async () => {
await client.POST('/auth/register/flows/{flow_id}/resend-verification', {
await client.POST('/auth/register/flows/resend-verification', {
params: {
path: { flow_id: flowId },
cookie: { register_flow_id: flowData!.id },
header: { 'user-agent': navigator.userAgent },
},
});
Expand All @@ -80,7 +73,7 @@ export default function RegisterOTPPage() {
<div className='flex flex-col gap-unit-2'>
<h1 className='text-md font-semibold'>Enter Verification Code</h1>
<h3 className='text-xs font-extralight'>
Enter the code we sent to {email}
Enter the code we sent to {flowData?.email}
</h3>
</div>
<Button size='sm' variant='ghost' onClick={resendVerificationCode}>
Expand Down Expand Up @@ -169,12 +162,10 @@ export default function RegisterOTPPage() {
variant='ghost'
fullWidth
onClick={async () => {
await client.POST('/auth/register/flows/{flow_id}/cancel', {
params: { path: { flow_id: flowId } },
await client.POST('/auth/register/flows/cancel', {
params: { cookie: { register_flow_id: flowData!.id } },
});
setFlowId(null);
setCurrentStep(null);
setEmail(null);
router.refresh();
}}
>
Cancel
Expand Down
41 changes: 41 additions & 0 deletions client/components/register/flow-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use client';
import { createContext, useContext, useState } from 'react';

interface RegisterFlowContextType {
setCurrentStep: (step: string | null) => void;
currentStep: string | null;
flowData: { email: string; currentStep: string; id: string } | undefined;
}

// TODO: pass register flow email here
const RegisterFlowContext = createContext<RegisterFlowContextType>({
setCurrentStep(step) {},
currentStep: null,
flowData: undefined,
});

export const useRegisterFlow = () => useContext(RegisterFlowContext);

interface RegisterFlowProviderProps {
flowData: { email: string; currentStep: string; id: string } | undefined;
}

export const RegisterFlowProvider: React.FC<
React.PropsWithChildren<RegisterFlowProviderProps>
> = ({ children, flowData }) => {
const [localCurrentStep, setCurrentStep] = useState<string | null>(
flowData ? flowData.currentStep : null
);

return (
<RegisterFlowContext.Provider
value={{
setCurrentStep,
currentStep: localCurrentStep,
flowData,
}}
>
{children}
</RegisterFlowContext.Provider>
);
};
Loading

0 comments on commit 5c03be1

Please sign in to comment.