Merge pull request 'feat: register page' (#91)
Reviewed-on: #91 Reviewed-by: Dominik <mail@dominikstahl.dev>
This commit is contained in:
commit
15fbf27459
3 changed files with 81 additions and 18 deletions
|
@ -104,7 +104,7 @@ This project is built with a modern tech stack:
|
||||||
yarn prisma:generate
|
yarn prisma:generate
|
||||||
```
|
```
|
||||||
```bash
|
```bash
|
||||||
yarn prisa:db:push
|
yarn prisma:db:push
|
||||||
```
|
```
|
||||||
- Run the following command to apply migrations and generate Prisma Client:
|
- Run the following command to apply migrations and generate Prisma Client:
|
||||||
```bash
|
```bash
|
||||||
|
|
|
@ -7,12 +7,14 @@ export default function LabeledInput({
|
||||||
placeholder,
|
placeholder,
|
||||||
value,
|
value,
|
||||||
name,
|
name,
|
||||||
|
autocomplete,
|
||||||
}: {
|
}: {
|
||||||
type: 'text' | 'email' | 'password';
|
type: 'text' | 'email' | 'password';
|
||||||
label: string;
|
label: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
autocomplete?: string;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className='grid grid-cols-1 gap-1'>
|
<div className='grid grid-cols-1 gap-1'>
|
||||||
|
@ -24,6 +26,7 @@ export default function LabeledInput({
|
||||||
defaultValue={value}
|
defaultValue={value}
|
||||||
id={name}
|
id={name}
|
||||||
name={name}
|
name={name}
|
||||||
|
autoComplete={autocomplete}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,19 +1,30 @@
|
||||||
|
'use client';
|
||||||
import { signIn } from '@/auth';
|
import { signIn } from '@/auth';
|
||||||
import LabeledInput from '@/components/labeled-input';
|
import LabeledInput from '@/components/labeled-input';
|
||||||
import { Button } from '@/components/custom-ui/button';
|
import { Button } from '@/components/custom-ui/button';
|
||||||
import { AuthError } from 'next-auth';
|
import { AuthError } from 'next-auth';
|
||||||
import { redirect } from 'next/navigation';
|
import { redirect } from 'next/navigation';
|
||||||
|
import { useRef, useState } from 'react';
|
||||||
|
|
||||||
const SIGNIN_ERROR_URL = '/error';
|
const SIGNIN_ERROR_URL = '/error';
|
||||||
|
|
||||||
export default function LoginForm() {
|
export default function LoginForm() {
|
||||||
|
const [isSignUp, setIsSignUp] = useState(false);
|
||||||
|
|
||||||
|
const formRef = useRef<HTMLFormElement>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
|
ref={formRef}
|
||||||
className='flex flex-col gap-5 w-full'
|
className='flex flex-col gap-5 w-full'
|
||||||
action={async (formData) => {
|
action={async (formData) => {
|
||||||
'use server';
|
'use client';
|
||||||
try {
|
try {
|
||||||
|
if (isSignUp) {
|
||||||
|
// handle sign up logic here
|
||||||
|
} else {
|
||||||
await signIn('credentials', formData);
|
await signIn('credentials', formData);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof AuthError) {
|
if (error instanceof AuthError) {
|
||||||
return redirect(`${SIGNIN_ERROR_URL}?error=${error.type}`);
|
return redirect(`${SIGNIN_ERROR_URL}?error=${error.type}`);
|
||||||
|
@ -22,6 +33,46 @@ export default function LoginForm() {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{isSignUp ? (
|
||||||
|
<>
|
||||||
|
<LabeledInput
|
||||||
|
type='text'
|
||||||
|
label='First Name'
|
||||||
|
placeholder='Your first name'
|
||||||
|
name='firstName'
|
||||||
|
autocomplete='given-name'
|
||||||
|
/>
|
||||||
|
<LabeledInput
|
||||||
|
type='text'
|
||||||
|
label='Last Name'
|
||||||
|
placeholder='Your last name'
|
||||||
|
name='lastName'
|
||||||
|
autocomplete='family-name'
|
||||||
|
/>
|
||||||
|
<LabeledInput
|
||||||
|
type='email'
|
||||||
|
label='E-Mail'
|
||||||
|
placeholder='Your email address'
|
||||||
|
name='email'
|
||||||
|
autocomplete='email'
|
||||||
|
/>
|
||||||
|
<LabeledInput
|
||||||
|
type='password'
|
||||||
|
label='Password'
|
||||||
|
placeholder='Create a password'
|
||||||
|
name='password'
|
||||||
|
autocomplete='new-password'
|
||||||
|
/>
|
||||||
|
<LabeledInput
|
||||||
|
type='password'
|
||||||
|
label='Confirm Password'
|
||||||
|
placeholder='Repeat your password'
|
||||||
|
name='confirmPassword'
|
||||||
|
autocomplete='new-password'
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
<LabeledInput
|
<LabeledInput
|
||||||
type='email'
|
type='email'
|
||||||
label='E-Mail or Username'
|
label='E-Mail or Username'
|
||||||
|
@ -34,12 +85,21 @@ export default function LoginForm() {
|
||||||
placeholder="Let's hope you remember it"
|
placeholder="Let's hope you remember it"
|
||||||
name='password'
|
name='password'
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<div className='grid grid-rows-2 gap-2'>
|
<div className='grid grid-rows-2 gap-2'>
|
||||||
<Button type='submit' variant='primary'>
|
<Button type='submit' variant='primary'>
|
||||||
Login
|
{isSignUp ? 'Sign Up' : 'Login'}
|
||||||
</Button>
|
</Button>
|
||||||
<Button type='submit' variant='outline_primary'>
|
<Button
|
||||||
Sign Up
|
type='button'
|
||||||
|
variant='outline_primary'
|
||||||
|
onClick={() => {
|
||||||
|
formRef.current?.reset();
|
||||||
|
setIsSignUp((v) => !v);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isSignUp ? 'Back to Login' : 'Sign Up'}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue