Skip to content

Commit

Permalink
⚡ [#76] Lazy load appointment routes/components
Browse files Browse the repository at this point in the history
Most forms won't need this code, so we can lazy load it instead.
  • Loading branch information
sergei-maertens committed Jan 24, 2025
1 parent 71a688b commit a0f2792
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ describe('Create appointment session expiration', () => {
});

// select a product
const dropdowns = screen.getAllByRole('combobox');
const dropdowns = await screen.findAllByRole('combobox');
expect(dropdowns).toHaveLength(1);
await user.click(dropdowns[0]);
await user.keyboard('[ArrowDown]');
Expand Down
17 changes: 17 additions & 0 deletions src/components/appointments/CreateAppointment/LandingPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {Navigate, useSearchParams} from 'react-router-dom';

import {APPOINTMENT_STEP_PATHS} from './steps';

// TODO: replace with loader that redirects at the route level
export const LandingPage = () => {
const [params] = useSearchParams();
return (
<Navigate
replace
to={{
pathname: APPOINTMENT_STEP_PATHS[0],
search: `?${params}`,
}}
/>
);
};
20 changes: 0 additions & 20 deletions src/components/appointments/CreateAppointment/steps.jsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,22 @@
import {defineMessage} from 'react-intl';
import {Navigate, useSearchParams} from 'react-router-dom';

import {ChooseProductStep, ContactDetailsStep, LocationAndTimeStep} from '../steps';

export const APPOINTMENT_STEPS = [
{
path: 'producten',
element: <ChooseProductStep navigateTo="../kalender" />,
name: defineMessage({
description: "Appointments navbar title for 'products' step",
defaultMessage: 'Product',
}),
},
{
path: 'kalender',
element: <LocationAndTimeStep navigateTo="../contactgegevens" />,
name: defineMessage({
description: "Appointments navbar title for 'location and time' step",
defaultMessage: 'Location and time',
}),
},
{
path: 'contactgegevens',
element: <ContactDetailsStep navigateTo="../overzicht" />,
name: defineMessage({
description: "Appointments navbar title for 'contact details' step",
defaultMessage: 'Contact details',
Expand All @@ -31,17 +25,3 @@ export const APPOINTMENT_STEPS = [
];

export const APPOINTMENT_STEP_PATHS = APPOINTMENT_STEPS.map(s => s.path);

// TODO: replace with loader that redirects at the route level
export const LandingPage = () => {
const [params] = useSearchParams();
return (
<Navigate
replace
to={{
pathname: APPOINTMENT_STEP_PATHS[0],
search: `?${params}`,
}}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ describe('Cancelling an appointment', () => {
it('renders the correct page for a cancel route', async () => {
render(<Wrapper />);

const textbox = screen.getByRole('textbox', {name: 'Your email address'});
const textbox = await screen.findByRole('textbox', {name: 'Your email address'});
expect(textbox).toBeVisible();
expect(textbox.name).toBe('email');
expect(screen.getByRole('button')).toBeVisible();
Expand Down
22 changes: 21 additions & 1 deletion src/components/appointments/index.jsx
Original file line number Diff line number Diff line change
@@ -1 +1,21 @@
export {default as CreateAppointment} from './CreateAppointment';
/**
* This module acts as the (lazy loaded) entry point for the appointments chunk.
*/
import CreateAppointment from './CreateAppointment';
import Confirmation from './CreateAppointment/Confirmation';
import {LandingPage} from './CreateAppointment/LandingPage';
import Summary from './CreateAppointment/Summary';
import {CancelAppointment, CancelAppointmentSuccess} from './cancel';
import {ChooseProductStep, ContactDetailsStep, LocationAndTimeStep} from './steps';

export {
CreateAppointment,
Confirmation,
LandingPage,
Summary,
CancelAppointment,
CancelAppointmentSuccess,
ChooseProductStep,
ContactDetailsStep,
LocationAndTimeStep,
};
17 changes: 6 additions & 11 deletions src/routes/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import {Cosign} from 'components/CoSign';
import ErrorBoundary from 'components/Errors/ErrorBoundary';
import Form from 'components/Form';
import SessionExpired from 'components/Sessions/SessionExpired';
import {CreateAppointment} from 'components/appointments';

import {createAppointmentRoutes, manageAppointmentRoutes} from './appointments';
import appointmentRoutes from './appointments';
import cosignRoutes from './cosign';
import formRoutes from './form';

Expand All @@ -23,15 +22,6 @@ const routes = [
path: '*',
element: <App />,
children: [
{
path: 'afspraak-annuleren/*',
children: manageAppointmentRoutes,
},
{
path: 'afspraak-maken/*',
element: <CreateAppointment />,
children: createAppointmentRoutes,
},
{
path: 'cosign/*',
element: <Cosign />,
Expand All @@ -45,6 +35,11 @@ const routes = [
</ErrorBoundary>
),
},
// appointments splat
{
path: '*',
children: appointmentRoutes,
},
// All the rest goes to the formio-based form flow
{
path: '*',
Expand Down
78 changes: 63 additions & 15 deletions src/routes/appointments.jsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,89 @@
import ErrorBoundary from 'components/Errors/ErrorBoundary';
import Confirmation from 'components/appointments/CreateAppointment/Confirmation';
import Summary from 'components/appointments/CreateAppointment/Summary';
import {APPOINTMENT_STEPS, LandingPage} from 'components/appointments/CreateAppointment/steps';
import {CancelAppointment, CancelAppointmentSuccess} from 'components/appointments/cancel';

/**
* Route subtree for appointment forms.
*/
const createAppointmentRoutes = [
{
path: '',
element: <LandingPage />,
lazy: async () => {
const {LandingPage} = await import('components/appointments');
return {element: <LandingPage />};
},
},
{
path: 'producten',
lazy: async () => {
const {ChooseProductStep} = await import('components/appointments');
return {element: <ChooseProductStep navigateTo="../kalender" />};
},
},
{
path: 'kalender',
lazy: async () => {
const {LocationAndTimeStep} = await import('components/appointments');
return {element: <LocationAndTimeStep navigateTo="../contactgegevens" />};
},
},
{
path: 'contactgegevens',
lazy: async () => {
const {ContactDetailsStep} = await import('components/appointments');
return {element: <ContactDetailsStep navigateTo="../overzicht" />};
},
},
...APPOINTMENT_STEPS.map(({path, element}) => ({path, element})),
{
path: 'overzicht',
element: <Summary />,
lazy: async () => {
const {Summary} = await import('components/appointments');
return {element: <Summary />};
},
},
{
path: 'bevestiging',
element: <Confirmation />,
lazy: async () => {
const {Confirmation} = await import('components/appointments');
return {element: <Confirmation />};
},
},
];

const manageAppointmentRoutes = [
{
path: '',
element: (
<ErrorBoundary>
<CancelAppointment />
</ErrorBoundary>
),
lazy: async () => {
const {CancelAppointment} = await import('components/appointments');
return {
element: (
<ErrorBoundary>
<CancelAppointment />
</ErrorBoundary>
),
};
},
},
{
path: 'succes',
element: <CancelAppointmentSuccess />,
lazy: async () => {
const {CancelAppointmentSuccess} = await import('components/appointments');
return {element: <CancelAppointmentSuccess />};

Check warning on line 69 in src/routes/appointments.jsx

View check run for this annotation

Codecov / codecov/patch

src/routes/appointments.jsx#L67-L69

Added lines #L67 - L69 were not covered by tests
},
},
];

const appointmentRoutes = [
{
path: 'afspraak-annuleren/*',
children: manageAppointmentRoutes,
},
{
path: 'afspraak-maken/*',
children: createAppointmentRoutes,
lazy: async () => {
const {CreateAppointment} = await import('components/appointments');
return {element: <CreateAppointment />};
},
},
];

export {createAppointmentRoutes, manageAppointmentRoutes};
export default appointmentRoutes;

0 comments on commit a0f2792

Please sign in to comment.