Skip to content

Commit 840758b

Browse files
committed
fix issue with onBeforePageChange breaking the form, add test, update demos
1 parent c97a99c commit 840758b

File tree

6 files changed

+57
-23
lines changed

6 files changed

+57
-23
lines changed

docs/src/app/demos/building/sequence.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ const environmentalImpactAssessmentPage: BuildingFormPage = {
101101

102102
// Site Plan Submission Sequence
103103
const sitePlanSubmissionSequence: BuildingFormSequence = {
104-
id: 'sitePlanSubmission',
104+
id: 'sitePlanSubmissionSequence',
105105
pages: [sitePlanSubmissionPage, environmentalImpactAssessmentPage],
106106
};
107107

docs/src/app/layout.tsx

+7-5
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ export default function RootLayout({
99
}>) {
1010
return (
1111
<html lang="en">
12-
<body className="antialiased">{children}</body>
13-
<div className="container max-w-3xl mx-auto p-4 text-sm text-gray-400">
14-
<hr className="mb-3" />
15-
&copy; 2024 Stu Kabakoff
16-
</div>
12+
<body className="antialiased">
13+
{children}
14+
<div className="container max-w-3xl mx-auto p-4 text-sm text-gray-400">
15+
<hr className="mb-3" />
16+
&copy; 2024 Stu Kabakoff
17+
</div>
18+
</body>
1719
</html>
1820
);
1921
}

docs/src/components/FormLibrary.tsx

+8-8
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export const FormFieldContainer = ({
5757
</>
5858
)}
5959

60-
{!hideError ? (
60+
{error || !hideError ? (
6161
<div>
6262
<ErrorText error={error} />
6363
</div>
@@ -172,7 +172,6 @@ export const FileInput = forwardRef<
172172
HTMLInputElement,
173173
React.HTMLProps<HTMLInputElement> &
174174
Omit<AdditionalProps, 'error'> & {
175-
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
176175
setValue: UseFormSetValue<any>;
177176
name: string;
178177
error?: Partial<{ [K in keyof DocumentReference]: FieldError }>;
@@ -190,15 +189,16 @@ export const FileInput = forwardRef<
190189
setValue(name, undefined);
191190
}
192191
};
192+
const errorToUse = error
193+
? {
194+
message: 'Please check the box to "upload" a file',
195+
type: 'required',
196+
}
197+
: undefined;
193198
return (
194199
<Checkbox
195200
name={name}
196-
error={
197-
error?.fileName ||
198-
error?.fileSize ||
199-
error?.fileType ||
200-
error?.fileUrl
201-
}
201+
error={errorToUse}
202202
{...rest}
203203
onChange={handleChange}
204204
ref={ref}

docs/src/components/SequenceVisualizer/index.tsx

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
import classNames from 'classnames';
22

33
import styles from './SequenceVisualizer.module.css';
4-
import type { SequenceChild } from '../../../../src/types';
4+
import type { DeepPartial, SequenceChild } from '../../../../src/types';
55

66
type SequenceVisualizerProps<T> = {
7-
data: T;
8-
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
7+
data: DeepPartial<T>;
98
currentPage: SequenceChild<T, any, any>;
10-
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
119
pages: SequenceChild<T, any, any>[];
12-
idPrefix?: string;
1310
goToPage: (page: string) => void;
1411
};
1512

@@ -18,7 +15,6 @@ export function SequenceVisualizer<T>({
1815
currentPage,
1916
pages,
2017
goToPage,
21-
idPrefix = '',
2218
}: SequenceVisualizerProps<T>) {
2319
return (
2420
<div className={styles.visualizer}>
@@ -28,13 +24,14 @@ export function SequenceVisualizer<T>({
2824
isRequired && 'isComplete' in page && page.isComplete(data);
2925
const isForm = 'Component' in page;
3026
const clickHandler = isForm
31-
? () => goToPage(`${idPrefix}${page.id}`)
27+
? () => goToPage(page.id)
3228
: undefined;
3329
return (
3430
<div
3531
className={classNames(
3632
styles.page,
37-
`${idPrefix}${page.id}` === currentPage.id &&
33+
!('pages' in page) &&
34+
page.id === currentPage.id &&
3835
styles.currentPage,
3936
isRequired && isComplete && styles.complete,
4037
!isRequired && styles.notNeeded,
@@ -55,7 +52,6 @@ export function SequenceVisualizer<T>({
5552
data={data}
5653
currentPage={currentPage}
5754
pages={page.pages}
58-
idPrefix={`${idPrefix}${page.id}.`}
5955
goToPage={goToPage}
6056
/>
6157
)}

src/__tests__/callbacks.spec.tsx

+34
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import React from 'react';
12
import { renderHook, act } from '@testing-library/react';
23
import { useMultiPageFormBase } from '../base';
34

@@ -137,4 +138,37 @@ describe('useMultiPageFormBase - Callback Invocation Tests', () => {
137138
expect(onValidationError).toHaveBeenCalledWith(errorList);
138139
expect(result.current.currentPage.id).toBe('page1');
139140
});
141+
142+
it('can advance when onBeforePageChange is "fixed"', async () => {
143+
// Initially, onBeforePageChange returns false
144+
let allowNavigation = false;
145+
const onBeforePageChange = jest.fn(() => allowNavigation);
146+
147+
const { result } = renderHook(() =>
148+
useMultiPageFormBase({
149+
getCurrentData,
150+
pages,
151+
onBeforePageChange,
152+
}),
153+
);
154+
155+
// First attempt to advance; should be prevented
156+
await act(async () => {
157+
await result.current.advance();
158+
});
159+
160+
expect(onBeforePageChange).toHaveBeenCalledTimes(1);
161+
expect(result.current.currentPage.id).toBe('page1');
162+
163+
// Now, "fix" onBeforePageChange to return true
164+
allowNavigation = true;
165+
166+
// Second attempt to advance; should proceed
167+
await act(async () => {
168+
await result.current.advance();
169+
});
170+
171+
expect(onBeforePageChange).toHaveBeenCalledTimes(2);
172+
expect(result.current.currentPage.id).toBe('page2');
173+
});
140174
});

src/base.ts

+2
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,14 @@ export function useMultiPageFormBase<DataT, ComponentProps, ErrorList>({
178178
pagesMap[pages[currentPageIndex].id],
179179
);
180180
if (errorList === false) {
181+
advanceAndNavState.current.navigating = false;
181182
return;
182183
}
183184
if (errorList !== true && errorList) {
184185
if (onValidationError) {
185186
onValidationError(errorList);
186187
}
188+
advanceAndNavState.current.navigating = false;
187189
return;
188190
}
189191
}

0 commit comments

Comments
 (0)