Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MR-3576] Add required and optional labels to fields #1923

Merged
merged 25 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
013e65b
add and use theme color for hints
pearl-truss Sep 7, 2023
a9d9e02
start adding required labels
pearl-truss Sep 8, 2023
5c734a6
add inline required labels where possible
pearl-truss Sep 8, 2023
76bbc36
add styling to inline required label
pearl-truss Sep 8, 2023
f5fb84f
Add required lable to actuary fields
pearl-truss Sep 8, 2023
52edc2f
Add required label to file uploads
pearl-truss Sep 8, 2023
9407ddd
Add required label to FieldYesNo component
pearl-truss Sep 8, 2023
d953034
conditionally display required or optional label depending on whats p…
pearl-truss Sep 8, 2023
39be654
pass required prop to contacts
pearl-truss Sep 8, 2023
ffe0c92
include required/optional label for textarea
pearl-truss Sep 8, 2023
6a51958
add new styles for textarea
pearl-truss Sep 8, 2023
80e9a59
add optional label to supporting documents upload field
pearl-truss Sep 8, 2023
dec7e69
Merge branch 'main' of https://github.com/Enterprise-CMCS/managed-car…
pearl-truss Sep 8, 2023
92239f7
update so that required/optional labels are on the contacts and rate …
pearl-truss Sep 13, 2023
04ae287
update styling
pearl-truss Sep 13, 2023
cfd80fa
add correct file types for supporting rate docs
pearl-truss Sep 13, 2023
c930bd7
clean up single rate cert file
pearl-truss Sep 14, 2023
04f770e
Merge branch 'main' of https://github.com/Enterprise-CMCS/managed-car…
pearl-truss Sep 14, 2023
678779e
ensure file upload only shows required/optional contract and rate pages
pearl-truss Sep 14, 2023
2f64d62
remove the showRequiredOptionalLabel prop
pearl-truss Sep 14, 2023
0a3c861
add required labels to the submission type page
pearl-truss Sep 14, 2023
1a1a554
add required/optional labels to the Contacts page
pearl-truss Sep 15, 2023
14d88d8
cypress re-run
pearl-truss Sep 15, 2023
1d374ec
Add required/optio
pearl-truss Sep 15, 2023
674ed4f
fix unit test
pearl-truss Sep 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,15 @@
.fileInputHint {
display: flex;
flex-direction: column;
color: #71767a;
color: theme-color-hint;
margin-bottom: 0.5rem;
}

.requiredOptionalText {
display: block;
color: $theme-color-hint;
}

.fileSummary {
font-weight: normal;
@include u-font('sans', 'sm');
Expand Down
5 changes: 4 additions & 1 deletion services/app-web/src/components/FileUpload/FileUpload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ export const FileUpload = ({
const fileInputRef = useRef<FileInputRef>(null) // reference to the HTML input which has files
const summaryRef = useRef<HTMLHeadingElement>(null) // reference to the heading that we will focus
const previousFileItems = usePrevious(fileItems)
const isRequired = inputProps['aria-required']
// eslint-disable-next-line @typescript-eslint/no-unused-vars

const handleCheckboxClick = (
event: React.ChangeEvent<HTMLInputElement>
) => {
Expand Down Expand Up @@ -424,6 +424,9 @@ export const FileUpload = ({
<Label className={isLabelVisible ? '' : 'srOnly'} htmlFor={id}>
{label}
</Label>
<span className={styles.requiredOptionalText}>
{isRequired ? 'Required' : 'Optional'}
</span>

<PoliteErrorMessage id={`${id}-error`}>{error}</PoliteErrorMessage>
{hint && (
Expand Down
3 changes: 3 additions & 0 deletions services/app-web/src/components/FileUpload/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ export const ACCEPTED_SUBMISSION_FILE_TYPES =

export const ACCEPTED_RATE_CERTIFICATION_FILE_TYPES =
'application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document'

export const ACCEPTED_RATE_SUPPORTING_DOCS_FILE_TYPES =
'application/pdf,text/csv,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel.sheet.macroEnabled.12'
1 change: 1 addition & 0 deletions services/app-web/src/components/FileUpload/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export { FileUpload } from './FileUpload'
export {
ACCEPTED_SUBMISSION_FILE_TYPES,
ACCEPTED_RATE_CERTIFICATION_FILE_TYPES,
ACCEPTED_RATE_SUPPORTING_DOCS_FILE_TYPES,
} from './constants'
export {
hasNoLoadingFiles,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import '../../../styles/uswdsImports.scss';
@import '../../../styles/custom.scss';

.requiredOptionalText {
display: block;
color: $theme-color-hint;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react'
import { useField } from 'formik'
import { Label, Textarea, FormGroup } from '@trussworks/react-uswds'
import { PoliteErrorMessage } from '../..'
import styles from './FieldTextarea.module.scss'

/**
* This component renders a ReactUSWDS TextArea component inside of a FormGroup,
Expand Down Expand Up @@ -34,6 +35,7 @@ export const FieldTextarea = ({
...inputProps
}: TextAreaProps): React.ReactElement => {
const [field, meta] = useField({ name })
const isRequired = inputProps['aria-required']

// Latch into onBlur to do any input cleaning
// Initial use case is to trim away trailing whitespace in email addresses
Expand All @@ -50,6 +52,9 @@ export const FieldTextarea = ({
<Label htmlFor={id} error={showError}>
{label}
</Label>
<span className={styles.requiredOptionalText}>
{isRequired ? 'Required' : 'Optional'}
</span>
{showError && <PoliteErrorMessage>{meta.error}</PoliteErrorMessage>}
{hint && (
<div
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
@import '../../../styles/uswdsImports.scss';
@import '../../../styles/custom.scss';

.optionsContainer {
display: flex;
}
Expand All @@ -18,3 +21,8 @@
.no {
margin-left: 3em;
}

.requiredOptionalText {
display: block;
color: $theme-color-hint;
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ export const FieldYesNo = ({

const isRequired =
inputProps['aria-required'] !== false && inputProps.required !== false // consumer must explicitly say this field is not required, otherwise we assume aria-required

return (
<Fieldset
role="radiogroup"
Expand All @@ -57,6 +56,11 @@ export const FieldYesNo = ({
className={classes}
data-testid="yes-no-radio-fieldset"
>
{inputProps['aria-required'] !== undefined && (
<span className={styles.requiredOptionalText}>
{isRequired ? 'Required' : 'Optional'}
</span>
)}
{showError && <PoliteErrorMessage>{meta.error}</PoliteErrorMessage>}
{hint && (
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Fieldset, FormGroup } from '@trussworks/react-uswds'
import { FieldRadio, FieldTextInput } from '../../../components/Form'
import { PoliteErrorMessage } from '../../../components/PoliteErrorMessage'
import { RateCertFormType } from '../RateDetails/SingleRateCert/SingleRateCert'
import styles from '../StateSubmissionForm.module.scss'

type FormError =
FormikErrors<RateCertFormType>[keyof FormikErrors<RateCertFormType>]
Expand Down Expand Up @@ -35,11 +36,11 @@ export const ActuaryContactFields = ({

return (
<Fieldset legend={fieldSetLegend}>
<span className={styles.requiredOptionalText}>Required</span>
<FieldTextInput
name={`${fieldNamePrefix}.name`}
id={`${fieldNamePrefix}.name`}
label="Name"
aria-required={false}
showError={Boolean(
showFieldErrors(getIn(errors, `${fieldNamePrefix}.name`))
)}
Expand All @@ -52,7 +53,6 @@ export const ActuaryContactFields = ({
name={`${fieldNamePrefix}.titleRole`}
id={`${fieldNamePrefix}.titleRole`}
label="Title/Role"
aria-required={false}
showError={Boolean(
showFieldErrors(
getIn(errors, `${fieldNamePrefix}.titleRole`)
Expand All @@ -66,7 +66,6 @@ export const ActuaryContactFields = ({
name={`${fieldNamePrefix}.email`}
id={`${fieldNamePrefix}.email`}
label="Email"
aria-required={false}
showError={Boolean(
showFieldErrors(getIn(errors, `${fieldNamePrefix}.email`))
)}
Expand All @@ -82,6 +81,7 @@ export const ActuaryContactFields = ({
<label htmlFor={`${fieldNamePrefix}.actuarialFirm`}>
Actuarial firm
</label>
<span className={styles.requiredOptionalText}>Required</span>
{showFieldErrors(
getIn(errors, `${fieldNamePrefix}.actuarialFirm`)
) && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ describe('Contacts', () => {

await waitFor(() => {
expect(screen.getByTestId('state-contacts')).toBeInTheDocument()
expect(screen.getByText('State contacts 1')).toBeInTheDocument()
expect(screen.getByLabelText('Name')).toBeInTheDocument()
expect(screen.getByLabelText('Title/Role')).toBeInTheDocument()
expect(screen.getByLabelText('Email')).toBeInTheDocument()
Expand All @@ -57,9 +58,10 @@ describe('Contacts', () => {
}
)

expect(
screen.getByText(/A state contact is required/)
).toBeInTheDocument()
const requiredLabels = await screen.findAllByText('Required')
expect(requiredLabels).toHaveLength(1)
const optionalLabels = await screen.queryAllByText('Optional')
expect(optionalLabels).toHaveLength(0)
})

it('displays correct form guidance for contract and rates submission', async () => {
Expand All @@ -75,9 +77,10 @@ describe('Contacts', () => {
}
)

expect(
screen.getByText('A state contact is required')
).toBeInTheDocument()
const requiredLabels = await screen.findAllByText('Required')
expect(requiredLabels).toHaveLength(2)
const optionalLabels = await screen.queryAllByText('Optional')
expect(optionalLabels).toHaveLength(0)
expect(
screen.getByText('Additional Actuary Contacts')
).toBeInTheDocument()
Expand Down
20 changes: 15 additions & 5 deletions services/app-web/src/pages/StateSubmission/Contacts/Contacts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,9 @@ export const Contacts = ({
// Also handles the difference between State Contacts and Actuary Contacts
const handleContactLegend = (index: number, contactText: string) => {
const count = index + 1
const required = index ? '' : ' (required)'

if (contactText === 'State') {
return `State contacts ${count} ${required}`
return `State contacts ${count}`
}

if (contactText === 'Actuary') {
Expand Down Expand Up @@ -297,9 +296,6 @@ export const Contacts = ({
communication about this submission.
</p>
<legend className="srOnly">State contacts</legend>
<span id="form-guidance">
A state contact is required
</span>

{shouldValidate && (
<ErrorSummary
Expand Down Expand Up @@ -329,6 +325,13 @@ export const Contacts = ({
'State'
)}
>
<span
className={
styles.requiredOptionalText
}
>
Required
</span>
<FieldTextInput
id={`stateContacts.${index}.name`}
label="Name"
Expand Down Expand Up @@ -543,6 +546,13 @@ export const Contacts = ({
className={styles.radioGroup}
legend="Communication preference between CMS Office of the Actuary (OACT) and all state’s actuaries (i.e. certifying actuaries and additional actuary contacts)"
>
<span
className={
styles.requiredOptionalText
}
>
Required
</span>
{showFieldErrors(`True`) && (
<ErrorMessage
name={`actuaryCommunicationPreference`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,13 @@ describe('ContractDetails', () => {
},
}
)

expect(screen.getByText(/All fields are required/)).toBeInTheDocument()
expect(
screen.queryByText(/All fields are required/)
).not.toBeInTheDocument()
const requiredLabels = await screen.findAllByText('Required')
expect(requiredLabels).toHaveLength(6)
const optionalLabels = await screen.queryAllByText('Optional')
expect(optionalLabels).toHaveLength(0)
})

describe('Contract documents file upload', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,9 +499,6 @@ export const ContractDetails = ({
>
<fieldset className="usa-fieldset">
<legend className="srOnly">Contract Details</legend>
<span id="form-guidance">
All fields are required
</span>

{shouldValidate && (
<ErrorSummary
Expand Down Expand Up @@ -571,6 +568,11 @@ export const ContractDetails = ({
className={styles.radioGroup}
legend="Contract status"
>
<span
className={styles.requiredOptionalText}
>
Required
</span>
{showFieldErrors(
errors.contractExecutionStatus
) && (
Expand Down Expand Up @@ -616,6 +618,13 @@ export const ContractDetails = ({
: 'Contract effective dates'
}
>
<span
className={
styles.requiredOptionalText
}
>
Required
</span>
{showFieldErrors(
errors.contractDateStart ||
errors.contractDateEnd
Expand Down Expand Up @@ -697,6 +706,13 @@ export const ContractDetails = ({
aria-required
legend="Managed Care entities"
>
<span
className={
styles.requiredOptionalText
}
>
Required
</span>
<Link
variant="external"
href={
Expand Down Expand Up @@ -762,6 +778,13 @@ export const ContractDetails = ({
aria-required
legend="Active federal operating authority"
>
<span
className={
styles.requiredOptionalText
}
>
Required
</span>
<Link
variant="external"
href={
Expand Down Expand Up @@ -815,6 +838,13 @@ export const ContractDetails = ({
: 'Does this contract action include new or modified provisions related to any of the following'
}
>
<span
className={
styles.requiredOptionalText
}
>
Required
</span>
{applicableProvisions.map(
(modifiedProvisionName) => (
<FieldYesNo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export const PackagesWithSharedRates = ({
name={`${fieldNamePrefix}.hasSharedRateCert`}
label="Was this rate certification uploaded to any other submissions?"
showError={Boolean(showFieldErrors('hasSharedRateCert'))}
aria-required
/>

{getIn(values, `${fieldNamePrefix}.hasSharedRateCert`) ===
Expand All @@ -131,6 +132,9 @@ export const PackagesWithSharedRates = ({
Please select the submissions that also contain this
rate certification.
</Label>
<span className={styles.requiredOptionalText}>
Required
</span>
<Link
aria-label="View all submissions (opens in new window)"
href={'/dashboard'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ describe('RateDetails', () => {
})

it('displays correct form guidance', async () => {
ldUseClientSpy({ 'supporting-docs-by-rate': true })

renderWithProviders(
<RateDetails
draftSubmission={emptyRateDetailsDraft()}
Expand All @@ -100,8 +102,12 @@ describe('RateDetails', () => {
}
)
expect(
screen.getByText(/All fields are required/)
).toBeInTheDocument()
screen.queryByText(/All fields are required/)
).not.toBeInTheDocument()
const requiredLabels = await screen.findAllByText('Required')
expect(requiredLabels).toHaveLength(6)
const optionalLabels = await screen.queryAllByText('Optional')
expect(optionalLabels).toHaveLength(1)
})

it('loads with empty rate type and document upload fields visible', async () => {
Expand Down Expand Up @@ -1677,7 +1683,7 @@ describe('RateDetails', () => {
'Upload one rate certification document'
)
const supportingDocsInput = screen.getByLabelText(
'Upload supporting documents (optional)'
'Upload supporting documents'
)
const backButton = screen.getByRole('button', {
name: 'Back',
Expand Down
Loading
Loading