Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into documents-table
Browse files Browse the repository at this point in the history
  • Loading branch information
danielnaab committed Nov 18, 2024
2 parents a65dc8f + 5ee8954 commit e4559ed
Show file tree
Hide file tree
Showing 38 changed files with 1,249 additions and 69 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 10x Access to Justice Tooling
# 10x Forms Platform

Test bed for ATJ platform tooling, completed as part of the [10x Digital Access to Justice Platform](https://trello.com/c/25Jl6NwJ/207-digital-access-to-justice-platform) project.
Test bed for 10x forms tooling, completed as part of the [10x Forms Platform](https://github.com/orgs/GSA-TTS/projects/38?pane=issue&itemId=58755590&issue=GSA-TTS%7C10x-projects%7C29) project.

## Overview

Expand All @@ -17,13 +17,13 @@ The platform is made up of the following high-level terms.

### Key personas

- Content authors: legal experts who craft guided interview experiences via a "no code" interface
- Self-represented litigants (SREs): end-users who interact with the court via guided interviews created by content authors
- Form Builders: government program office staff or UX experts who create and publish "guided interview" web experiences for members of the public and fellow government staff via a friendly browser-based app, no coding necessary. For examples of "guided interview" style web experiences, check out [IRS Direct File](https://coforma.io/case-studies/irs-direct-file#results) (filing your taxes), [GetCalFresh](https://codeforamerica.org/news/overcoming-barriers-setting-expectations-for-calfresh-eligibility/) (Applying for food benefits) and [Court Forms Online](https://courtformsonline.org/) (filing court documents).
- Form Fillers: folks who provide info to the government via guided interviews created by Form Builders

### Things

- **Blueprint**: produced by a content author, the blueprint defines the structure of an interactive session between a court and an SRL
- **Conversation**: one instance of a blueprint; the interactive session between a court and an SRL. Other terms for this concept include dialogue or session.
- **Blueprint**: produced by a form builder, the blueprint defines the structure of an interactive session between a government office and a form filler.
- **Conversation**: one instance of a blueprint; the interactive session between a government office and a form filler. Other terms for this concept include dialogue or session.
- **Pattern/template**: the building blocks of a blueprint, patterns implement UX best-practices, defining the content and behavior of the user interface.
- **Prompt**: produced by a pattern, the prompt defines what is presented to the end user at single point in a conversation.
- **Component**: user interface component that acts as the building block of prompts.
Expand Down Expand Up @@ -61,6 +61,7 @@ To start developing with hot reloading, use:
```bash
pnpm build
```

then run:

```bash
Expand Down
4 changes: 2 additions & 2 deletions apps/spotlight/src/lib/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type GithubRepository = {

export const DEFAULT_REPOSITORY: GithubRepository = {
owner: 'gsa-tts',
repository: 'atj-platform',
repository: 'forms',
branch: 'main',
commit: 'main',
};
Expand All @@ -28,7 +28,7 @@ export const getGithubRepository = async (
const { execSync } = await import('child_process');
return {
owner: env.OWNER || 'gsa-tts',
repository: env.REPOSITORY || 'atj-platform',
repository: env.REPOSITORY || 'forms',
branch: env.BRANCH || 'main',
commit: execSync('git rev-parse HEAD').toString().trim(),
};
Expand Down
2 changes: 1 addition & 1 deletion infra/cdktf/__tests__/main-test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'cdktf/lib/testing/adapters/jest';

describe('atj-platform app stack', () => {
describe('Forms Platform app stack', () => {
it.todo('should be tested');
});
2 changes: 1 addition & 1 deletion infra/cdktf/src/lib/cloud.gov/node-astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class AstroService extends Construct {
new cloudfoundry.app.App(this, `${id}-app`, {
name: `${id}-app`,
space: spaceId,
dockerImage: `ghcr.io/gsa-tts/atj-platform/${imageName}`,
dockerImage: `ghcr.io/gsa-tts/forms/${imageName}`,
memory: 1024,
diskQuota: 4096,
healthCheckType: 'http',
Expand Down
24 changes: 19 additions & 5 deletions packages/common/src/locales/en/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const en = {
fieldLabel: 'Page title',
},
paragraph: {
fieldLabel: 'Paragraph Text',
fieldLabel: 'Paragraph text',
displayName: 'Paragraph',
errorTextMustContainChar: 'String must contain at least 1 character(s)',
},
Expand All @@ -48,17 +48,31 @@ export const en = {
},
selectDropdown: {
...defaults,
displayName: 'Select Dropdown label',
fieldLabel: 'Select Dropdown label',
displayName: 'Select dropdown label',
fieldLabel: 'Select dropdown label',
errorTextMustContainChar: 'String must contain at least 1 character(s)',
},
dateOfBirth: {
...defaults,
displayName: 'Date of Birth label',
fieldLabel: 'Date Of Birth label',
displayName: 'Date of birth label',
fieldLabel: 'Date of birth label',
hintLabel: 'Date of Birth Hint label',
hint: 'For example: January 19 2000',
errorTextMustContainChar: 'String must contain at least 1 character(s)',
},
emailInput: {
...defaults,
displayName: 'Email Input label',
fieldLabel: 'Email Input label',
errorTextMustContainChar: 'String must contain at least 1 character(s)',
},
phoneNumber: {
...defaults,
displayName: 'Phone number label',
fieldLabel: 'Phone number label',
hintLabel: 'Phone number hint label',
hint: '10-digit, U.S. only, for example 999-999-9999',
errorTextMustContainChar: 'String must contain at least 1 character(s)',
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { type Meta, type StoryObj } from '@storybook/react';

import { EmailInputPattern } from './EmailInput.js';

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

export default meta;

export const Default: StoryObj<typeof EmailInputPattern> = {
args: {
emailId: 'email',
label: 'Email address',
required: true,
},
};

export const WithoutRequired: StoryObj<typeof EmailInputPattern> = {
args: {
emailId: 'email',
label: 'Email address',
required: false,
},
};

export const WithError: StoryObj<typeof EmailInputPattern> = {
args: {
emailId: 'email',
label: 'Email address with error',
required: true,
error: {
type: 'custom',
message: 'This field has an error',
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* @vitest-environment jsdom
*/
import { describeStories } from '../../../test-helper.js';
import meta, * as stories from './EmailInput.stories.js';

describeStories(meta, stories);
37 changes: 37 additions & 0 deletions packages/design/src/Form/components/EmailInput/EmailInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { useFormContext } from 'react-hook-form';
import { type EmailInputProps } from '@atj/forms';
import { type PatternComponent } from '../../index.js';

export const EmailInputPattern: PatternComponent<EmailInputProps> = ({
emailId,
label,
required,
error,
}) => {
const { register } = useFormContext();

return (
<fieldset className="usa-fieldset">
<div className="usa-form-group">
<label className="usa-label" htmlFor={emailId}>
{label}
{required && <span className="required-indicator">*</span>}
</label>
<input
className="usa-input margin-bottom-1"
id={emailId}
type="email"
autoCapitalize="off"
autoCorrect="off"
{...register(emailId, { required })}
/>
</div>
{error && (
<span className="error-message" style={{ color: 'red' }}>
{error.message}
</span>
)}
</fieldset>
);
};
3 changes: 3 additions & 0 deletions packages/design/src/Form/components/EmailInput/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { EmailInputPattern } from './EmailInput.js';

export default EmailInputPattern;
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { type Meta, type StoryObj } from '@storybook/react';

import { PhoneNumberPattern } from './PhoneNumber.js';

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

export default meta;

export const Default: StoryObj<typeof PhoneNumberPattern> = {
args: {
phoneId: 'phone',
label: 'Phone number',
required: false,
},
};

export const WithRequired: StoryObj<typeof PhoneNumberPattern> = {
args: {
phoneId: 'phone',
label: 'Phone number',
required: true,
},
};

export const WithError: StoryObj<typeof PhoneNumberPattern> = {
args: {
phoneId: 'phone',
label: 'Phone number with error',
required: true,
error: {
type: 'custom',
message: 'This field has an error',
},
},
};

export const WithHint: StoryObj<typeof PhoneNumberPattern> = {
args: {
phoneId: 'phone',
label: 'Phone number',
hint: '10-digit, U.S. only, for example 999-999-9999',
required: true,
},
};

export const WithHintAndError: StoryObj<typeof PhoneNumberPattern> = {
args: {
phoneId: 'phone',
label: 'Phone number',
hint: '10-digit, U.S. only, for example 999-999-9999',
required: true,
error: {
type: 'custom',
message: 'This field has an error',
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* @vitest-environment jsdom
*/
import { describeStories } from '../../../test-helper.js';
import meta, * as stories from './PhoneNumber.stories.js';

describeStories(meta, stories);
57 changes: 57 additions & 0 deletions packages/design/src/Form/components/PhoneNumber/PhoneNumber.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react';
import classNames from 'classnames';
import { useFormContext } from 'react-hook-form';
import { type PhoneNumberProps } from '@atj/forms';
import { type PatternComponent } from '../../index.js';

export const PhoneNumberPattern: PatternComponent<PhoneNumberProps> = ({
phoneId,
hint,
label,
required,
error,
value,
}) => {
const { register } = useFormContext();

return (
<fieldset className="usa-fieldset">
<div className={classNames('usa-form-group margin-top-2')}>
<label
className={classNames('usa-label', {
'usa-label--error': error,
})}
id={`input-message-${phoneId}`}
htmlFor={phoneId}
>
{label}
{required && <span className="required-indicator">*</span>}
</label>
{hint && (
<div className="usa-hint" id="primaryPnHint">
{hint}
</div>
)}
{error && (
<div
className="usa-error-message"
id={`input-error-message-${phoneId}`}
role="alert"
>
{error.message}
</div>
)}
<input
className={classNames('usa-input', {
'usa-input--error': error,
})}
id={phoneId}
type="tel"
defaultValue={value}
{...register(phoneId, { required })}
aria-describedby="primaryPnHint"
/>
</div>
</fieldset>
);
};
3 changes: 3 additions & 0 deletions packages/design/src/Form/components/PhoneNumber/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { PhoneNumberPattern } from './PhoneNumber.js';

export default PhoneNumberPattern;
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { type Meta, type StoryObj } from '@storybook/react';
import { SelectDropdownPattern } from './SelectDropdown.js';

const meta: Meta<typeof SelectDropdownPattern> = {
title: 'patterns/SelectPattern',
title: 'patterns/SelectDropdownPattern',
component: SelectDropdownPattern,
decorators: [
(Story, args) => {
Expand Down
Loading

0 comments on commit e4559ed

Please sign in to comment.