Skip to content

Commit

Permalink
feat: functional register
Browse files Browse the repository at this point in the history
  • Loading branch information
corp-0 committed Mar 5, 2024
1 parent c006b02 commit 02595f5
Show file tree
Hide file tree
Showing 2 changed files with 228 additions and 63 deletions.
77 changes: 77 additions & 0 deletions app/(account)/register/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"use server"

import {FieldError, GeneralError} from "../../../lib/auth/guards";
import {z} from "zod";
import {revalidatePath} from "next/cache";

export interface RegisterResponse {
success: boolean;
error?: GeneralError | FieldError;
}


export const registerAccount = async (_: RegisterResponse, formData: FormData): Promise<RegisterResponse> => {
const schema = z.object({
email: z.string().email(),
unique_identifier: z.string().min(3),
username: z.string().min(3),
password: z.string().min(6)
});

const parsed = schema.safeParse({
email: formData.get('email'),
unique_identifier: formData.get('unique_identifier'),
username: formData.get('username'),
password: formData.get('password')
});

if (!parsed.success) {
const fieldErrors = parsed.error.errors.reduce((acc, error) => {
return {...acc, [error.path[0]]: error.message}
}, {});

return {success: false, error: {status: 400, error: fieldErrors}};
}

const password2 = formData.get('password2');
if (password2 !== parsed.data.password) {
return {
success: false,
error:
{
status: 400,
error: {
password2: ['Passwords do not match']
}
}
}
}

const body = {
email: parsed.data.email,
unique_identifier: parsed.data.unique_identifier,
username: parsed.data.username,
password: parsed.data.password
}

try {
const response = await fetch(`${process.env.CC_API_URL}/accounts/register`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});

if (!response.ok) {
const error = await response.json();
return {success: false, error: error};
}

revalidatePath('register');

return {success: true};
} catch (error) {
return {success: false, error: {status: 500, error: 'An unexpected error occurred'}};
}
}
214 changes: 151 additions & 63 deletions app/(account)/register/page.tsx
Original file line number Diff line number Diff line change
@@ -1,77 +1,165 @@
"use client"

import React from "react";
import Button from "../../common/uiLibrary/Button";
import FormContainer from "../../common/uiLibrary/Layouters/formContainer";
import TextField from "../../common/uiLibrary/forms/textField";
import AlternativeActions from "../../common/uiLibrary/forms/alternativeActions";
import ContactInformation from "../../(home)/contactInformation";
import {useFormState} from "react-dom";
import {registerAccount, RegisterResponse} from "./actions";
import {isFieldError} from "../../../lib/auth/guards";
import { useFormStatus } from "react-dom";
import GenericLoading from "../../common/uiLibrary/genericLoading";

const RegisterPage = () => {
return (

const initialState: RegisterResponse = {
success: false,
error: undefined
}
const [state, formAction] = useFormState(registerAccount, initialState);

const uniqueIdHelperText = () =>
<>
Choose a unique identifier for your account. <b>This identifier is permanent
and cannot be changed later</b>. Please choose carefully!
</>

const usernameHelperText = () =>
<>
Choose a username that will be displayed to other users. This can be changed
later.
</>

const registerForm = () => {
return (
<>
<TextField
label='Your email'
id='email'
name='email'
type='email'
placeholder='[email protected]'
shadow
helperText={(state.error && isFieldError(state.error) && state.error?.error.email) ?
<div className='text-red-700'>
{state.error?.error.email}
</div>
:
usernameHelperText()
}
/>

<TextField
label='Your unique identifier'
id='unique_identifier'
name='unique_identifier'
type='text'
placeholder='YourUniqueID'
required
shadow
helperText={(state.error && isFieldError(state.error) && state.error?.error.unique_identifier) ?
<div className='text-red-700'>
{state.error?.error.unique_identifier}
</div>
:
uniqueIdHelperText()
}
/>

<TextField
label='Username'
id='username'
name='username'
type='text'
placeholder='YourUsername'
required
shadow
helperText={(state.error && isFieldError(state.error) && state.error?.error.username) ?
<div className='text-red-700'>
{state.error?.error.username}
</div>
:
usernameHelperText()
}
/>

<TextField
label='Your password'
id='password'
name='password'
type='password'
placeholder='********'
shadow
required
helperText={ state.error && isFieldError(state.error) && state.error?.error.password &&
<div className='text-red-700'>
{state.error?.error.password}
</div>
}
/>

<TextField
label='Confirm your password'
id='password2'
name='password2'
type='password'
placeholder='********'
shadow
required
helperText={(state.error && isFieldError(state.error) && state.error?.error.password2) ?
<div className='text-red-700'>
{state.error?.error.password2}
</div>
:
usernameHelperText()
}
/>

<Button type="submit" className="mt-4 w-full" filled>Register</Button>

<AlternativeActions
links={[
{link: '/login', linkText: 'Already have an account?'}
]}
/>
</>
)
}
const successMessage = () => {
return (
<div className='flex flex-col gap-4'>
<h3 className="text-lg text-center font-medium text-green-800">Success!</h3>
<p>An email has been sent with instructions to confirm your account.</p>
<p>Please check your inbox and follow the instructions to complete the process.</p>
<p>Didn&apos;t receive the email? Check your Spam folder or try resending the email. Ensure your email
address is
entered correctly.</p>
</div>
)
}

const FormOrLoading = () => {
const {pending} = useFormStatus();
if (pending) {
return (
<div className='absolute top-0 left-0 w-full h-full flex flex-col justify-center items-center bg-black bg-opacity-70 z-10'>
<GenericLoading/>
Loading...
</div>
)
} else {
return registerForm()
}
}

return (
<div className='flex flex-col ' style={{minHeight: 'calc(100vh - 60px)'}}>

<div className='flex-grow'>
<FormContainer title='Create a new account'>
<TextField
label='Your email'
id='email'
type='email'
placeholder='[email protected]'
shadow
/>

<TextField
label='Your unique identifier'
id='unique_identifier'
type='text'
placeholder='YourUniqueID'
required
shadow
helperText={
<>
Choose a unique identifier for your account. <b>This identifier is permanent
and cannot be changed later</b>. Please choose carefully!
</>}
/>

<TextField
label='Username'
id='username'
type='text'
placeholder='YourUsername'
required
shadow
helperText={
<>
Choose a username that will be displayed to other users. This can be changed
later.
</>}
/>

<TextField
label='Your password'
id='password'
type='password'
placeholder='********'
shadow
required
/>

<TextField
label='Confirm your password'
id='password2'
type='password'
placeholder='********'
shadow
required
/>

<Button type="submit" className="mt-4 w-full" filled>Register</Button>

<AlternativeActions
links={[
{link: '/login', linkText: 'Already have an account?'}
]}
/>
<FormContainer action={formAction} title='Create a new account'>
{state.success ? successMessage() : FormOrLoading()}
</FormContainer>
</div>
<ContactInformation/>
Expand Down

0 comments on commit 02595f5

Please sign in to comment.