Skip to content

Commit 0477384

Browse files
authored
Merge pull request #1533 from LightOfHeaven1994/progress-after-submission-wizard
feat(wizard): add wizard progress after submission option
2 parents faea43a + bf96224 commit 0477384

File tree

6 files changed

+185
-42
lines changed

6 files changed

+185
-42
lines changed

packages/common/src/wizard/reducer.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const createSchema = ({ formOptions, fields }) => {
2222
field.substepOf,
2323
index,
2424
primary: !schema[schema.length - 1] || !field.substepOf || field.substepOf !== schema[schema.length - 1].substepOf,
25+
isProgressAfterSubmissionStep: field.isProgressAfterSubmissionStep,
2526
},
2627
];
2728

packages/pf4-component-mapper/demo/demo-schemas/wizard-schema.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,3 +441,62 @@ export const wizardSchemaMoreSubsteps = {
441441
}
442442
]
443443
};
444+
445+
export const wizardSchemaProgressAfterSubmission = {
446+
fields: [
447+
{
448+
component: componentTypes.WIZARD,
449+
name: 'progress-wizard',
450+
title: 'Progress after submission',
451+
description: 'This wizard shows a progress step after submission',
452+
fields: [
453+
{
454+
title: 'Step 1',
455+
name: 'step-1',
456+
nextStep: 'step-2',
457+
fields: [
458+
{
459+
component: componentTypes.TEXT_FIELD,
460+
name: 'name',
461+
label: 'Name',
462+
isRequired: true,
463+
validate: [
464+
{
465+
type: validatorTypes.REQUIRED
466+
}
467+
]
468+
}
469+
]
470+
},
471+
{
472+
title: 'Step 2',
473+
name: 'step-2',
474+
nextStep: 'progress-step',
475+
fields: [
476+
{
477+
component: componentTypes.TEXT_FIELD,
478+
name: 'email',
479+
label: 'Email',
480+
isRequired: true,
481+
validate: [
482+
{
483+
type: validatorTypes.REQUIRED
484+
}
485+
]
486+
}
487+
]
488+
},
489+
{
490+
name: 'progress-step',
491+
isProgressAfterSubmissionStep: true,
492+
fields: [
493+
{
494+
name: 'progress-content',
495+
component: 'progress-step-content'
496+
}
497+
]
498+
}
499+
]
500+
}
501+
]
502+
};

packages/pf4-component-mapper/demo/index.js

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
11
import React from 'react';
22
import { createRoot } from 'react-dom/client';
3-
import { FormRenderer } from '@data-driven-forms/react-form-renderer';
3+
import { FormRenderer, WizardContext } from '@data-driven-forms/react-form-renderer';
44
import { arraySchemaDDF } from './demo-schemas/widget-schema';
55
import { componentMapper, FormTemplate } from '../src';
6-
import { Title, Button, Toolbar, ToolbarGroup, ToolbarItem } from '@patternfly/react-core';
6+
import {
7+
Title,
8+
Button,
9+
Toolbar,
10+
ToolbarGroup,
11+
ToolbarItem,
12+
EmptyState,
13+
EmptyStateBody,
14+
EmptyStateFooter,
15+
EmptyStateActions,
16+
Progress,
17+
Bullseye
18+
} from '@patternfly/react-core';
19+
import { CogsIcon } from '@patternfly/react-icons';
720
import {
821
wizardSchema,
922
wizardSchemaWithFunction,
1023
wizardSchemaSimple,
1124
wizardSchemaSubsteps,
1225
wizardSchemaMoreSubsteps,
26+
wizardSchemaProgressAfterSubmission,
1327
} from './demo-schemas/wizard-schema';
1428
import sandboxSchema from './demo-schemas/sandbox';
1529
import dualSchema from './demo-schemas/dual-list-schema';
@@ -18,6 +32,48 @@ import selectSchema from './demo-schemas/select-schema';
1832

1933
const Summary = (props) => <div>Custom summary component.</div>;
2034

35+
const ProgressStepContent = () => {
36+
const { jumpToStep } = React.useContext(WizardContext);
37+
const [percentValidated, setPercentValidated] = React.useState(0);
38+
39+
const tick = React.useCallback(() => {
40+
if (percentValidated < 100) {
41+
setPercentValidated(prevValue => prevValue + 20);
42+
}
43+
}, [percentValidated]);
44+
45+
React.useEffect(() => {
46+
const interval = setInterval(() => tick(), 1000);
47+
return () => clearInterval(interval);
48+
}, [tick]);
49+
50+
return (
51+
<Bullseye>
52+
<EmptyState
53+
headingLevel="h4"
54+
titleText={percentValidated === 100 ? 'Validation complete' : 'Validating credentials'}
55+
icon={CogsIcon}
56+
variant="lg"
57+
>
58+
<EmptyStateBody>
59+
<Progress value={percentValidated} measureLocation="outside" aria-label="Wizard validation progress" />
60+
</EmptyStateBody>
61+
<EmptyStateBody>
62+
Description can be used to further elaborate on the validation step, or give the user a better idea of how
63+
long the process will take.
64+
</EmptyStateBody>
65+
<EmptyStateFooter>
66+
<EmptyStateActions>
67+
<Button isDisabled={percentValidated !== 100} onClick={() => jumpToStep(0)}>
68+
Go to beginning
69+
</Button>
70+
</EmptyStateActions>
71+
</EmptyStateFooter>
72+
</EmptyState>
73+
</Bullseye>
74+
);
75+
};
76+
2177
const fieldArrayState = {
2278
schema: arraySchemaDDF,
2379
additionalOptions: {
@@ -135,6 +191,19 @@ class App extends React.Component {
135191
FormTemplate={(props) => <FormTemplate {...props} showFormControls={this.state.additionalOptions.showFormControls} />}
136192
{...this.state.additionalOptions}
137193
/>
194+
<div>Progress after submission</div>
195+
<FormRenderer
196+
onSubmit={console.log}
197+
componentMapper={{
198+
...componentMapper,
199+
summary: Summary,
200+
'progress-step-content': ProgressStepContent,
201+
}}
202+
onCancel={() => console.log('Cancel action')}
203+
schema={wizardSchemaProgressAfterSubmission}
204+
FormTemplate={(props) => <FormTemplate {...props} showFormControls={this.state.additionalOptions.showFormControls} />}
205+
{...this.state.additionalOptions}
206+
/>
138207
</>
139208
)}
140209
</div>

packages/pf4-component-mapper/src/wizard/wizard-components/wizard-nav.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const WizardNavigationInternal = React.memo(
2222
({ navSchema, activeStepIndex, maxStepIndex, jumpToStep, valid, validating }) => (
2323
<Fragment>
2424
{navSchema
25-
.filter((field) => field.primary)
25+
.filter((field) => field.primary && !field.isProgressAfterSubmissionStep)
2626
.map((step) => {
2727
const substeps = step.substepOf && navSchema.filter((field) => field.substepOf === step.substepOf);
2828

packages/pf4-component-mapper/src/wizard/wizard.js

Lines changed: 52 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ const WizardInternal = ({
8585
return null;
8686
}
8787

88+
const isProgressAfterSubmissionStep = currentStep.isProgressAfterSubmissionStep;
89+
8890
return (
8991
<Modal
9092
inModal={inModal}
@@ -117,45 +119,57 @@ const WizardInternal = ({
117119
closeButtonAriaLabel={closeButtonAriaLabel}
118120
/>
119121
)}
120-
<WizardToggle activeStepIndex={activeStepIndex} currentStep={currentStep} navSchema={navSchema} isOpen={state.openNav} dispatch={dispatch} />
121-
<div className="pf-v6-c-wizard__outer-wrap">
122-
<div className="pf-v6-c-wizard__inner-wrap">
123-
<WizardNav aria-label={navAriaLabel} isExpanded={state.openNav}>
124-
<FormSpy subscription={{ values: true, valid: true, validating: true }}>
125-
{({ values, valid, validating }) => (
126-
<WizardNavigation
127-
navSchema={navSchema}
128-
activeStepIndex={activeStepIndex}
129-
valid={valid}
130-
maxStepIndex={maxStepIndex}
131-
jumpToStep={(...args) => {
132-
state.openNav && dispatch({ type: 'closeNav' });
133-
return jumpToStep(...args);
134-
}}
135-
crossroads={crossroads}
136-
isDynamic={isDynamic}
137-
values={values}
138-
setPrevSteps={setPrevSteps}
139-
validating={validating}
140-
/>
141-
)}
142-
</FormSpy>
143-
</WizardNav>
144-
<WizardStep
145-
conditionalSubmitFlag={conditionalSubmitFlag}
146-
buttonLabels={buttonLabels}
147-
buttonsClassName={buttonsClassName}
148-
showTitles={showTitles}
149-
hasNoBodyPadding={hasNoBodyPadding}
150-
StepTemplate={StepTemplate}
151-
{...currentStep}
152-
formOptions={formOptions}
153-
handleNext={(nextStep) => handleNext(nextStep)}
154-
handlePrev={handlePrev}
155-
disableBack={activeStepIndex === 0}
122+
{isProgressAfterSubmissionStep ? (
123+
currentStep.fields.map((item) => formOptions.renderForm([item], formOptions))
124+
) : (
125+
<>
126+
<WizardToggle
127+
activeStepIndex={activeStepIndex}
128+
currentStep={currentStep}
129+
navSchema={navSchema}
130+
isOpen={state.openNav}
131+
dispatch={dispatch}
156132
/>
157-
</div>
158-
</div>
133+
<div className="pf-v6-c-wizard__outer-wrap">
134+
<div className="pf-v6-c-wizard__inner-wrap">
135+
<WizardNav aria-label={navAriaLabel} isExpanded={state.openNav}>
136+
<FormSpy subscription={{ values: true, valid: true, validating: true }}>
137+
{({ values, valid, validating }) => (
138+
<WizardNavigation
139+
navSchema={navSchema}
140+
activeStepIndex={activeStepIndex}
141+
valid={valid}
142+
maxStepIndex={maxStepIndex}
143+
jumpToStep={(...args) => {
144+
state.openNav && dispatch({ type: 'closeNav' });
145+
return jumpToStep(...args);
146+
}}
147+
crossroads={crossroads}
148+
isDynamic={isDynamic}
149+
values={values}
150+
setPrevSteps={setPrevSteps}
151+
validating={validating}
152+
/>
153+
)}
154+
</FormSpy>
155+
</WizardNav>
156+
<WizardStep
157+
conditionalSubmitFlag={conditionalSubmitFlag}
158+
buttonLabels={buttonLabels}
159+
buttonsClassName={buttonsClassName}
160+
showTitles={showTitles}
161+
hasNoBodyPadding={hasNoBodyPadding}
162+
StepTemplate={StepTemplate}
163+
{...currentStep}
164+
formOptions={formOptions}
165+
handleNext={(nextStep) => handleNext(nextStep)}
166+
handlePrev={handlePrev}
167+
disableBack={activeStepIndex === 0}
168+
/>
169+
</div>
170+
</div>
171+
</>
172+
)}
159173
</div>
160174
</Modal>
161175
);

packages/react-form-renderer/src/tests/form-renderer/condition.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ describe('condition test', () => {
676676
await waitFor(() => {
677677
expect(errorSpy).toHaveBeenCalled();
678678
// eslint-disable-next-line no-console
679-
const errorMessage = console.error.mock.calls.map(call => call[0]).join(' ');
679+
const errorMessage = console.error.mock.calls.map((call) => call[0]).join(' ');
680680
expect(errorMessage).toContain('Received invalid setterValue. Expected object, received: ');
681681
});
682682
});

0 commit comments

Comments
 (0)