Skip to content

Commit

Permalink
feat: code review reafactor
Browse files Browse the repository at this point in the history
  • Loading branch information
r1skz3ro committed Jul 4, 2024
1 parent e6fdf0d commit b8f3f36
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 116 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default function PeopleLayout({ children }: Readonly<{ children: React.Re
<div className="w-full">
<WorkflowTopbar />
<main className="p-8">
<div className="grid grid-cols-[minmax(200px,1fr),minmax(400px,1100px),1fr]">
<div className="grid grid-cols-workflow">
<EmployeeSideStepper />
<div className="col-span-1 px-8">{children}</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,83 +1,3 @@
'use client';
import { Button } from '@app/components/common/Button';
import { FormProvider } from '@app/components/common/FormProvider';
import { Input } from '@app/components/common/Input';
import { Typography } from '@app/components/common/Typography';
import { routes } from '@app/constants';
import { usePeopleStore } from '@app/store/peopleStore';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { PersonalDetails } from '@app/components/pages/PersonalDetails/PersonalDetails';

enum PersonalDetailsFormNames {
firstName = 'firstName',
lastName = 'lastName',
email = 'email',
}
interface PersonalDetailsForm {
[PersonalDetailsFormNames.firstName]: string;
[PersonalDetailsFormNames.lastName]: string;
[PersonalDetailsFormNames.email]: string;
}

export default function PersonalDetails() {
const form = useForm<PersonalDetailsForm>({
mode: 'onChange',
defaultValues: {
[PersonalDetailsFormNames.firstName]: '',
[PersonalDetailsFormNames.lastName]: '',
[PersonalDetailsFormNames.email]: '',
},
});
const { isDirty, isValid } = form.formState;
const [formValid, setFormValid] = useState(false);
const updateProgress = usePeopleStore((state) => state.updateProgress);

useEffect(() => {
setFormValid(isDirty && isValid);
}, [isDirty, isValid]);

// INFO: update progress in sidebar stepper
useEffect(() => {
if (formValid) updateProgress({ [routes.people.addNew.personalDetails]: 'completed' });
else updateProgress({ [routes.people.addNew.personalDetails]: 'inProgress' });
}, [formValid, updateProgress]);

return (
<FormProvider<PersonalDetailsForm> form={form}>
<Typography variant="head-m/semibold" className="mb-6">
Personal details
</Typography>
<div className="mb-6 grid w-full grid-cols-2 gap-x-8 gap-y-6 rounded-[20px] border border-navy-200 bg-white p-8">
<Input
name={PersonalDetailsFormNames.firstName}
label="First name"
options={{
minLength: { value: 2, message: 'First name must contain at least 2 characters' },
required: { value: true, message: 'First Name is required' },
}}
/>
<Input
name={PersonalDetailsFormNames.lastName}
label="Last name"
options={{
minLength: { value: 2, message: 'Last name must contain at least 2 characters' },
required: { value: true, message: 'Last name is required' },
}}
/>
<Input
name={PersonalDetailsFormNames.email}
label="Email"
options={{
pattern: { value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, message: 'invalid email address' },
required: { value: true, message: 'Email is required' },
}}
/>
</div>
<div className="flex justify-end">
<Button styleType="primary" variant="border" onClick={(e) => e.preventDefault()} disabled={!formValid}>
Continue
</Button>
</div>
</FormProvider>
);
}
export default PersonalDetails;
10 changes: 6 additions & 4 deletions frontend/src/app/(app)/(root)/people/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import Link from 'next/link';
export default function People() {
return (
<div>
<h1 className="mb-10 text-lg font-semibold leading-6 text-navy-900">People</h1>
<Button>
<Link href={routes.people.addNew.personalDetails}>+ Employee</Link>
</Button>
<div className="mb-6 flex items-center justify-between">
<h1 className="text-lg font-semibold leading-6 text-navy-900">People</h1>
<Button>
<Link href={routes.people.addNew.personalDetails}>+ Employee</Link>
</Button>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
'use client';
import { usePeopleStore } from '@app/store/peopleStore';
import { SideStepper, StepStates } from '../SideStepper';
import { useEffect, useState } from 'react';
import { usePathname } from 'next/navigation';
import { AddNewPersonRouteKeys } from './EmployeeSideStepper.interface';
import { addEmployeeInitialSteps } from './EmployeeSideStepper.const';
import { usePeopleStore } from '@app/store/people/store';

export const EmployeeSideStepper = () => {
const progress = usePeopleStore((state) => state.progress);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { routes } from '@app/constants';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { PersonalDetailsForm, PersonalDetailsFormNames } from './PersonalDetails.interface';
import { usePeopleStore } from '@app/store/people/store';

export const usePersonalDetails = () => {
const form = useForm<PersonalDetailsForm>({
mode: 'onChange',
defaultValues: {
[PersonalDetailsFormNames.firstName]: '',
[PersonalDetailsFormNames.lastName]: '',
[PersonalDetailsFormNames.email]: '',
},
});
const { isDirty, isValid } = form.formState;
const [formValid, setFormValid] = useState(false);
const updateProgress = usePeopleStore((state) => state.updateProgress);

useEffect(() => {
setFormValid(isDirty && isValid);
}, [isDirty, isValid]);

// INFO: update progress in sidebar stepper
useEffect(() => {
if (formValid) updateProgress({ [routes.people.addNew.personalDetails]: 'completed' });
else updateProgress({ [routes.people.addNew.personalDetails]: 'inProgress' });
}, [formValid, updateProgress]);

return { form, formValid };
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const PersonalDetailsFormNames = {
firstName: 'firstName',
lastName: 'lastName',
email: 'email',
} as const;

export interface PersonalDetailsForm {
[PersonalDetailsFormNames.firstName]: string;
[PersonalDetailsFormNames.lastName]: string;
[PersonalDetailsFormNames.email]: string;
}
50 changes: 50 additions & 0 deletions frontend/src/components/pages/PersonalDetails/PersonalDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use client';
import { Button } from '@app/components/common/Button';
import { FormProvider } from '@app/components/common/FormProvider';
import { Input } from '@app/components/common/Input';
import { Typography } from '@app/components/common/Typography';
import { PersonalDetailsForm, PersonalDetailsFormNames } from './PersonalDetails.interface';
import { usePersonalDetails } from './PersonalDetails.hooks';

export const PersonalDetails = () => {
const { form, formValid } = usePersonalDetails();

return (
<FormProvider<PersonalDetailsForm> form={form}>
<Typography variant="head-m/semibold" className="mb-6">
Personal details
</Typography>
<div className="mb-6 grid w-full grid-cols-2 gap-x-8 gap-y-6 rounded-[20px] border border-navy-200 bg-white p-8">
<Input
name={PersonalDetailsFormNames.firstName}
label="First name"
options={{
minLength: { value: 2, message: 'First name must contain at least 2 characters' },
required: { value: true, message: 'First Name is required' },
}}
/>
<Input
name={PersonalDetailsFormNames.lastName}
label="Last name"
options={{
minLength: { value: 2, message: 'Last name must contain at least 2 characters' },
required: { value: true, message: 'Last name is required' },
}}
/>
<Input
name={PersonalDetailsFormNames.email}
label="Email"
options={{
pattern: { value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, message: 'invalid email address' },
required: { value: true, message: 'Email is required' },
}}
/>
</div>
<div className="flex justify-end">
<Button styleType="primary" variant="border" onClick={(e) => e.preventDefault()} disabled={!formValid}>
Continue
</Button>
</div>
</FormProvider>
);
};
1 change: 1 addition & 0 deletions frontend/src/components/pages/PersonalDetails/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { PersonalDetails } from './PersonalDetails';
1 change: 1 addition & 0 deletions frontend/src/store/people/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { usePeopleStore } from './store';
9 changes: 9 additions & 0 deletions frontend/src/store/people/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { AddNewPersonRouteKeys } from '@app/components/modules/EmployeeSideStepper';
import { StepStates } from '@app/components/modules/SideStepper';

export type Progress = Record<AddNewPersonRouteKeys, StepStates>;

export interface PeopleState {
progress: Progress;
updateProgress: (newProgress: Partial<Progress>) => void;
}
18 changes: 18 additions & 0 deletions frontend/src/store/people/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { routes } from '@app/constants';
import { create } from 'zustand';
import { PeopleState } from './interfaces';

const initialState: PeopleState = {
progress: {
[routes.people.addNew.personalDetails]: 'notStarted',
[routes.people.addNew.mainLadder]: 'notStarted',
},
updateProgress: () => {},
};

const usePeopleStore = create<PeopleState>()((set) => ({
...initialState,
updateProgress: (newProgress) => set((state) => ({ progress: { ...state.progress, ...newProgress } })),
}));

export { usePeopleStore };
27 changes: 0 additions & 27 deletions frontend/src/store/peopleStore.ts

This file was deleted.

5 changes: 4 additions & 1 deletion frontend/tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const config: Config = {
},
grey: {
800: '#2C2E3A',
}
},
},
fontSize: {
xs: ['0.75rem', '1rem'], // Body XS
Expand All @@ -70,6 +70,9 @@ const config: Config = {
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
},
gridTemplateColumns: {
workflow: 'minmax(200px,1fr),minmax(400px,1100px),1fr',
},
},
},
plugins: [require('@tailwindcss/typography')],
Expand Down

0 comments on commit b8f3f36

Please sign in to comment.