Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…e-review into mcr-4043-frontend-read-state-json-data
  • Loading branch information
pearl-truss committed May 13, 2024
2 parents 5be80db + 2c7f44f commit e152faf
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 148 deletions.
4 changes: 2 additions & 2 deletions docs/technical-design/howto-update-state-programs.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ The source of truth for that file comes from a CSV maintained by product and des
1. Download the latest version of csv from google docs when prompted by product/design.
2. Run the script following the command listed in the `import-programs.ts`. This will overwrite existing state programs JSON with the new output. Your usage of the script will likely look something like this: `cd scripts && yarn tsc && node import-programs.js path/to/data.csv > ../services/app-web/src/common-code/data/statePrograms.json`
3. Double check the diff. It's important not to delete any programs that have already been used for a submission because although programs are not in the database, we still store references to the program ID in postgres as if they are stable. Also, we want to be sure we are only changing programs expected to change.
4. Make a PR to update the statePrograms file in the codebase
5. If an ID wasn't present on the spreadsheet and was autogenerated by the script, be sure to add the id to the spreadsheet so that it's reflected there
4. For any newly created programs, manually populate the `id` field using a UUID generator
5. Make a PR to update the statePrograms file in the codebase
5 changes: 5 additions & 0 deletions scripts/import-programs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ fs.createReadStream(file)
process.exit(1)
}

if (!data.id) {
console.error('No ID set for program, make sure to set an ID in the spreadsheet', data)
process.exit(1)
}

if (!states[code]) {
states[code] = {
name: stateNames[code],
Expand Down
99 changes: 59 additions & 40 deletions services/app-web/src/pages/LinkYourRates/LinkRateSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import React from 'react'
import Select, { ActionMeta, AriaOnFocus, Props } from 'react-select'
import Select, {
ActionMeta,
AriaOnFocus,
Props,
FormatOptionLabelMeta,
SingleValue,
createFilter,
} from 'react-select'
import styles from '../../components/Select/RateSelect/RateSelect.module.scss'
import { StateUser, useIndexRatesQuery } from '../../gen/gqlClient'
import { useAuth } from '../../contexts/AuthContext'
Expand All @@ -15,9 +22,14 @@ import { useFormikContext } from 'formik'

export interface LinkRateOptionType {
readonly value: string
readonly label: React.ReactElement
readonly label: string
readonly isFixed?: boolean
readonly isDisabled?: boolean
readonly rateCertificationName: string
readonly rateProgramIDs: string
readonly rateDateStart: string
readonly rateDateEnd: string
readonly rateDateCertified: string
}

export type LinkRateSelectPropType = {
Expand All @@ -31,7 +43,7 @@ export const LinkRateSelect = ({
initialValue,
autofill,
...selectProps
}: LinkRateSelectPropType & Props<LinkRateOptionType, true>) => {
}: LinkRateSelectPropType & Props<LinkRateOptionType, false>) => {
const { values }: { values: RateDetailFormConfig } = useFormikContext()
const { data, loading, error } = useIndexRatesQuery()
const { getKey } = useS3()
Expand All @@ -52,32 +64,20 @@ export const LinkRateSelect = ({
const revision = rate.revisions[0]
return {
value: rate.id,
label: (
<>
<strong>{revision.formData.rateCertificationName}</strong>
<div style={{ lineHeight: '50%', fontSize: '14px' }}>
<p>
Programs:&nbsp;
{programNames(
statePrograms,
revision.formData.rateProgramIDs
).join(', ')}
</p>
<p>
Rating period:&nbsp;
{formatCalendarDate(
revision.formData.rateDateStart
)}
-{formatCalendarDate(revision.formData.rateDateEnd)}
</p>
<p>
Certification date:&nbsp;
{formatCalendarDate(
revision.formData.rateDateCertified
)}
</p>
</div>
</>
label:
revision.formData.rateCertificationName ??
'Unknown rate certification',
rateCertificationName:
revision.formData.rateCertificationName ??
'Unknown rate certification',
rateProgramIDs: programNames(
statePrograms,
revision.formData.rateProgramIDs
).join(', '),
rateDateStart: formatCalendarDate(revision.formData.rateDateStart),
rateDateEnd: formatCalendarDate(revision.formData.rateDateEnd),
rateDateCertified: formatCalendarDate(
revision.formData.rateDateCertified
),
}
})
Expand Down Expand Up @@ -108,10 +108,10 @@ export const LinkRateSelect = ({
}

const onInputChange = (
newValue: LinkRateOptionType,
newValue: SingleValue<LinkRateOptionType>,
{ action }: ActionMeta<LinkRateOptionType>
) => {
if (action === 'select-option') {
if (action === 'select-option' && newValue) {
const linkedRateID = newValue.value
const linkedRate = rates.find((rate) => rate.id === linkedRateID)
const linkedRateForm: FormikRateForm = convertGQLRateToRateForm(
Expand All @@ -132,12 +132,27 @@ export const LinkRateSelect = ({
}
}

//Need this to make the label searchable since the rate name is buried in a react element
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const filterOptions = ({ label }: any, input: string) =>
label.props.children[0].props.children
?.toLowerCase()
.includes(input.toLowerCase())
const formatOptionLabel = (
data: LinkRateOptionType,
optionMeta: FormatOptionLabelMeta<LinkRateOptionType>
) => {
if (optionMeta.context === 'menu') {
return (
<>
<strong>{data.rateCertificationName}</strong>
<div style={{ lineHeight: '50%' }}>
<p>Programs: {data.rateProgramIDs}</p>
<p>
Rating period: {data.rateDateStart}-
{data.rateDateEnd}
</p>
<p>Certification date: {data.rateDateCertified}</p>
</div>
</>
)
}
return <div>{data.rateCertificationName}</div>
}

//We track rates that have already been selected to remove them from the dropdown
const selectedRates = values.rateForms.map((rate) => rate.id && rate.id)
Expand All @@ -153,6 +168,7 @@ export const LinkRateSelect = ({
(rate) => !selectedRates.includes(rate.value)
)
}
formatOptionLabel={formatOptionLabel}
isSearchable
maxMenuHeight={400}
aria-label="linked rate (required)"
Expand All @@ -168,11 +184,14 @@ export const LinkRateSelect = ({
}
loadingMessage={() => 'Loading rate certifications...'}
name={name}
filterOption={filterOptions}
filterOption={createFilter({
ignoreCase: true,
trim: true,
matchFrom: 'any' as const,
})}
{...selectProps}
inputId={name}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onChange={onInputChange as any} // TODO see why the types definitions are messed up for react-select "single" (not multi) onChange - may need to upgrade dep if this bug was fixed
onChange={onInputChange}
/>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -549,12 +549,9 @@ const RateDetailsV2 = ({
Additional rate
certification
</h3>
<Button
<button
type="button"
outline
className={
styles.addRateBtn
}
className={`usa-button usa-button--outline ${styles.addRateBtn}`}
onClick={() => {
const newRate =
convertGQLRateToRateForm(
Expand All @@ -572,7 +569,7 @@ const RateDetailsV2 = ({
>
Add another rate
certification
</Button>
</button>
</SectionCard>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -536,18 +536,17 @@ export const SingleRateFormFields = ({
</div>
)
)}
<Button
<button
type="button"
outline
className={styles.addRateBtn}
className={`usa-button usa-button--outline ${styles.addRateBtn}`}
onClick={() => {
push(emptyActuaryContact)
setFocusNewActuaryContact(true)
}}
ref={newActuaryContactButtonRef}
>
Add a certifying actuary
</Button>
</button>
</FormGroup>
)}
</FieldArray>
Expand Down
Loading

0 comments on commit e152faf

Please sign in to comment.