Skip to content
This repository has been archived by the owner on Jul 13, 2022. It is now read-only.

Commit

Permalink
handle errors and multistep form
Browse files Browse the repository at this point in the history
  • Loading branch information
kymppi committed Mar 24, 2022
1 parent a426d64 commit 3b8fa00
Show file tree
Hide file tree
Showing 17 changed files with 477 additions and 89 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified .yarn/install-state.gz
Binary file not shown.
27 changes: 22 additions & 5 deletions components/Form.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
import { Box } from '@mantine/core';

interface FormProps {
children: JSX.Element;
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
}

const Form: React.FC<FormProps> = ({ children, onSubmit }) => {
return (
<form
onSubmit={onSubmit}
className="flex flex-col items-center justify-center"
<Box
sx={(theme) => ({
flexGrow: 0,
minWidth: '500px',
minHeight: '500px',
display: 'block',
backgroundColor:
theme.colorScheme === 'dark'
? theme.colors.dark[6]
: theme.colors.gray[1],
color:
theme.colorScheme === 'dark'
? theme.colors.blue[4]
: theme.colors.blue[7],
padding: theme.spacing.xl,
borderRadius: theme.radius.lg,
position: 'relative',
})}
>
{children}
</form>
<form onSubmit={onSubmit}>{children}</form>
</Box>
);
};

Expand Down
34 changes: 34 additions & 0 deletions components/forms/Login/EmailStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Button, Group, TextInput } from '@mantine/core';
import { UseFormReturnType } from '@mantine/form/lib/use-form';
import { At } from 'tabler-icons-react';

export interface EmailStepValues {
email: string;
}

type Props = {
form: UseFormReturnType<EmailStepValues>;
error?: string;
};

function FirstStep({ form, error }: Props) {
return (
<>
<TextInput
icon={<At size={20} />}
size="md"
required
label="Käyttäjätunnus"
placeholder="etunimi.sukunimi"
error={error}
{...form.getInputProps('email')}
/>

<Group position="center" mt="xl" grow>
<Button type="submit">Submit</Button>
</Group>
</>
);
}

export default FirstStep;
5 changes: 5 additions & 0 deletions components/forms/Login/FidoStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type Props = {};
function FidoStep({}: Props) {
return <div>FidoStep</div>;
}
export default FidoStep;
5 changes: 5 additions & 0 deletions components/forms/Login/OtpStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type Props = {};
function OtpStep({}: Props) {
return <div>OtpStep</div>;
}
export default OtpStep;
44 changes: 44 additions & 0 deletions components/forms/Login/PasswordStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Avatar, Button, Group, PasswordInput, Title } from '@mantine/core';
import { UseFormReturnType } from '@mantine/form/lib/use-form';

export interface PasswordStepValues {
password: string;
}

type Props = {
form: UseFormReturnType<PasswordStepValues>;
user: {
firstName: string;
photoUri: string;
} | null;
error?: string;
};

function SecondStep({ form, user, error }: Props) {
console.log(error);
return (
<>
{user && (
<Group direction="column" align="center">
<Avatar size="lg" src={user.photoUri} />
<Title order={1}>Hei, {user.firstName}</Title>
</Group>
)}

<PasswordInput
size="md"
required
label="Salasana"
placeholder="*******"
error={error}
{...form.getInputProps('password')}
/>

<Group position="center" mt="xl" grow>
<Button type="submit">Kirjaudu</Button>
</Group>
</>
);
}

export default SecondStep;
5 changes: 5 additions & 0 deletions components/forms/Login/Success.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type Props = {};
function Success({}: Props) {
return <div>Success</div>;
}
export default Success;
116 changes: 116 additions & 0 deletions components/forms/Login/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { Group } from '@mantine/core';
import { useForm } from '@mantine/form';
import { UseFormReturnType } from '@mantine/form/lib/use-form';
import { useState } from 'react';
import useAuthentication from '../../../hooks/useAuthentication';
import Form from '../../Form';
import ThemeToggle from '../../ThemeToggle';
import EmailStep, { EmailStepValues } from './EmailStep';
import FidoStep from './FidoStep';
import OtpStep from './OtpStep';
import PasswordStep, { PasswordStepValues } from './PasswordStep';
import Success from './Success';

type LoginSteps = 'email' | 'password' | 'fido' | 'otp' | 'success';

type Props = {};

function LoginForm({}: Props) {
const [currentStep, setCurrentStep] = useState<LoginSteps>('email');
const [error, setError] = useState<string>();
const [user, setUser] = useState(null);
const { startLoginProcess } = useAuthentication();

const formsList = [
useForm<EmailStepValues>({
initialValues: {
email: '',
},
}),
useForm<PasswordStepValues>({
initialValues: {
password: '',
},
}),
useForm<PasswordStepValues>({
initialValues: {
password: '',
},
}),
useForm<PasswordStepValues>({
initialValues: {
password: '',
},
}),
useForm<PasswordStepValues>({
initialValues: {
password: '',
},
}),
];

const forms = {
email: formsList[0] as UseFormReturnType<EmailStepValues>,
password: formsList[1] as UseFormReturnType<PasswordStepValues>,
fido: formsList[2] as UseFormReturnType<PasswordStepValues>,
otp: formsList[3] as UseFormReturnType<PasswordStepValues>,
success: formsList[4] as UseFormReturnType<PasswordStepValues>,
};

const steps = {
email: <EmailStep form={forms.email} error={error} key="0" />,
password: <PasswordStep form={forms.password} user={user} key="1" />,
fido: <FidoStep key="2" />,
otp: <OtpStep key="3" />,
success: <Success />,
};

const handleSubmit = async (values: EmailStepValues | PasswordStepValues) => {
switch (currentStep) {
case 'email':
const { email } = values as EmailStepValues;
const res = await startLoginProcess(email);

if (res.errors) {
console.log(res.errors);
setError((res.errors[0] as Error).toString());
}

if (res.user != null) {
setUser(res.user as any);
}

setCurrentStep(res.nextScreen as LoginSteps);
}
};

// Make sure that it doesnt go out of bounds
if (steps[currentStep] == undefined || forms[currentStep] == undefined) {
return <h1>You should not be seeing this</h1>;
}

return (
<>
<Form
onSubmit={forms[currentStep].onSubmit((values) => handleSubmit(values))}
>
<Group direction="column" grow>
<Group grow direction="column">
{steps[currentStep]}
</Group>
<Group
sx={(theme) => ({
position: 'absolute',
right: theme.spacing.lg,
bottom: theme.spacing.md,
})}
>
<ThemeToggle />
</Group>
</Group>
</Form>
</>
);
}

export default LoginForm;
Loading

0 comments on commit 3b8fa00

Please sign in to comment.