Skip to content

Commit

Permalink
PDF generation for DOJ demo (#155)
Browse files Browse the repository at this point in the history
* Add a regex to more strictly validate option IDs

* Wire checkbox and radio group to form handling.

* Create stories for checkbox and radio group patterns; remove old components.
  • Loading branch information
danielnaab authored Jun 5, 2024
1 parent 01f7d5a commit e34c05a
Show file tree
Hide file tree
Showing 12 changed files with 178 additions and 130 deletions.
41 changes: 32 additions & 9 deletions packages/design/src/Form/components/Checkbox/Checkbox.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
import Checkbox from './Checkbox';
import React from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { type Meta, type StoryObj } from '@storybook/react';

export default {
component: Checkbox,
title: 'Components/Checkbox',
import { CheckboxPattern } from './Checkbox';
import { CheckboxProps } from '@atj/forms';

const meta: Meta<typeof CheckboxPattern> = {
title: 'patterns/CheckboxPattern',
component: CheckboxPattern,
decorators: [
(Story, args) => {
const FormDecorator = () => {
const formMethods = useForm();
return (
<FormProvider {...formMethods}>
<Story {...args} />
</FormProvider>
);
};
return <FormDecorator />;
},
],
tags: ['autodocs'],
};

export const Primary = {
export default meta;

export const Default = {
args: {
id: '1',
label: 'Primary label Text',
},
};
_patternId: '',
type: 'checkbox',
id: 'checkbox-1',
label: 'Checkbox 1',
defaultChecked: true,
} satisfies CheckboxProps,
} satisfies StoryObj<typeof CheckboxPattern>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* @vitest-environment jsdom
*/
import { describeStories } from '../../../test-helper';
import meta, * as stories from './Checkbox.stories';

describeStories(meta, stories);
18 changes: 8 additions & 10 deletions packages/design/src/Form/components/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import React from 'react';
import { useFormContext } from 'react-hook-form';

type CheckboxProps = {
id: string;
name: string;
label: string;
defaultChecked: boolean;
};
import { type CheckboxProps } from '@atj/forms';

import { type PatternComponent } from '../../../Form';

export default function Checkbox(props: CheckboxProps) {
export const CheckboxPattern: PatternComponent<CheckboxProps> = props => {
const { register } = useFormContext();
return (
<div className="usa-checkbox">
<input
id={props.id}
name={props.name}
type="checkbox"
className="usa-checkbox__input"
defaultChecked={props.defaultChecked}
{...register(props.id)}
/>
<label className="usa-checkbox__label" htmlFor={props.id}>
{props.label}
</label>
</div>
);
}
};
19 changes: 1 addition & 18 deletions packages/design/src/Form/components/Checkbox/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,2 @@
import React from 'react';

import { type CheckboxProps } from '@atj/forms';

import { type PatternComponent } from '../../../Form';
import Checkbox from './Checkbox';

const CheckboxPattern: PatternComponent<CheckboxProps> = props => {
return (
<Checkbox
id={props.id}
defaultChecked={props.defaultChecked}
name={props.id}
label={props.label}
/>
);
};

import { CheckboxPattern } from './Checkbox';
export default CheckboxPattern;
Original file line number Diff line number Diff line change
@@ -1,34 +1,48 @@
import { Meta, StoryFn } from '@storybook/react';

import RadioGroup, { RadioInput } from './RadioGroup';
import React from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { type Meta, type StoryObj } from '@storybook/react';

import { RadioGroupPattern } from './RadioGroup';

const meta: Meta = {
title: 'Components/RadioGroup',
component: RadioGroup,
const meta: Meta<typeof RadioGroupPattern> = {
title: 'patterns/RadioGroupPattern',
component: RadioGroupPattern,
decorators: [
(Story, args) => {
const FormDecorator = () => {
const formMethods = useForm();
return (
<FormProvider {...formMethods}>
<Story {...args} />
</FormProvider>
);
};
return <FormDecorator />;
},
],
tags: ['autodocs'],
};
export default meta;

export const Default: StoryFn = () => (
<RadioGroup legend="Select an item">
<RadioInput
id="option-1"
name="select-item"
defaultChecked={false}
label="Option 1"
/>
<RadioInput
id="option-2"
name="select-item"
defaultChecked={false}
label="Option 2"
/>
<RadioInput
id="option-3"
name="select-item"
defaultChecked={true}
label="Option 3"
/>
</RadioGroup>
);
export default meta;
export const Default = {
args: {
_patternId: '',
type: 'radio-group',
groupId: 'radio-group-1',
legend: 'This is a radio group',
options: [
{
id: 'option-1',
name: 'option-1',
label: 'Option 1',
defaultChecked: true,
},
{
id: 'option-2',
name: 'option-2',
label: 'Option 2',
defaultChecked: false,
},
],
},
} satisfies StoryObj<typeof RadioGroupPattern>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* @vitest-environment jsdom
*/
import { describeStories } from '../../../test-helper';
import meta, * as stories from './RadioGroup.stories';

describeStories(meta, stories);
58 changes: 24 additions & 34 deletions packages/design/src/Form/components/RadioGroup/RadioGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,31 @@
import React, { type ReactElement } from 'react';
import React from 'react';
import { useFormContext } from 'react-hook-form';

export type RadioGroupProps = {
legend: string;
children: ReactElement<RadioProps> | ReactElement<RadioProps>[];
};

export default function RadioGroup({ legend, children }: RadioGroupProps) {
return (
<div className="usa-fieldset">
<legend className="usa-legend text-bold">{legend}</legend>
{children}
</div>
);
}
import { type RadioGroupProps } from '@atj/forms';

export type RadioProps = {
id: string;
name: string;
label: string;
disabled?: boolean;
defaultChecked: boolean;
};
import { type PatternComponent } from '../../../Form';

export const RadioInput = (props: RadioProps) => {
export const RadioGroupPattern: PatternComponent<RadioGroupProps> = props => {
const { register } = useFormContext();
return (
<div className="usa-radio">
<input
id={props.id}
name={props.name}
className="usa-radio__input"
type="radio"
disabled={props.disabled}
defaultChecked={props.defaultChecked}
/>
<label htmlFor={props.id} className="usa-radio__label">
{props.label}
</label>
<div className="usa-fieldset">
<legend className="usa-legend text-bold">{props.legend}</legend>
{props.options.map((option, index) => {
return (
<div key={index} className="usa-radio">
<input
className="usa-radio__input"
type="radio"
id={option.id}
{...register(props.groupId)}
value={option.id}
/>
<label htmlFor={option.id} className="usa-radio__label">
{option.label}
</label>
</div>
);
})}
</div>
);
};
22 changes: 1 addition & 21 deletions packages/design/src/Form/components/RadioGroup/index.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,3 @@
import React from 'react';
import { RadioGroupPattern } from './RadioGroup';

import { type RadioGroupProps } from '@atj/forms';

import { type PatternComponent } from '../../../Form';
import RadioGroup, { RadioInput } from './RadioGroup';

const RadioGroupPattern: PatternComponent<RadioGroupProps> = props => {
return (
<RadioGroup legend={props.legend}>
{props.options.map((option, index) => (
<RadioInput
key={index}
id={option.id}
name={option.name}
label={option.label}
defaultChecked={option.defaultChecked}
></RadioInput>
))}
</RadioGroup>
);
};
export default RadioGroupPattern;
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ const pattern: RadioGroupPattern = {
data: {
label: message.patterns.radioGroup.displayName,
options: [
{ label: 'Option 1', id: '1' },
{ label: 'Option 2', id: '2' },
{ label: 'Option 3', id: '3' },
{ label: 'Option 1', id: 'option-1' },
{ label: 'Option 2', id: 'option-2' },
{ label: 'Option 3', id: 'option-3' },
],
},
};
Expand Down Expand Up @@ -117,7 +117,7 @@ export const Error: StoryObj<typeof CheckboxPatternEdit> = {
optionId.blur();

await expect(
await canvas.findByText('Option ID may not contain spaces')
await canvas.findByText('Invalid Option ID')
).toBeInTheDocument();

await userEvent.clear(optionLabel);
Expand Down
1 change: 1 addition & 0 deletions packages/forms/src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export type PageProps = PatternProps<{

export type RadioGroupProps = PatternProps<{
type: 'radio-group';
groupId: string;
legend: string;
options: {
id: string;
Expand Down
4 changes: 4 additions & 0 deletions packages/forms/src/documents/pdf/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export const createFormOutputFieldData = (
return;
}
const outputFieldId = output.formFields[patternId];
if (outputFieldId === '') {
console.error(`empty outputFieldId for patternId: ${patternId}`);
return;
}
results[outputFieldId] = {
type: docField.type,
value: formData[patternId],
Expand Down
Loading

0 comments on commit e34c05a

Please sign in to comment.