Skip to content

Commit

Permalink
feat: move step1 email field to settings (#7794)
Browse files Browse the repository at this point in the history
* feat: add onblur to single select component

* feat: add single select to email notifications page

* feat: add separate notify or step 1 in mrf send outcome email logic

* feat: remove email field in step 1 of workflow builder

* fix: add ChangeHandler

* feat: remove validation in FE to account for deleted email field id

* feat: add tc for step 1 field

* feat: add chromatic tc for step 1 in settings page

* chore: remove unused import

* fix: onBlur typing

* feat: add default for emailFieldNotificationId
  • Loading branch information
kevin9foong authored Oct 28, 2024
1 parent f4a1eed commit 4434cef
Show file tree
Hide file tree
Showing 20 changed files with 565 additions and 234 deletions.
1 change: 1 addition & 0 deletions frontend/src/components/Dropdown/SelectContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ interface SelectContextReturn<Item extends ComboboxItem = ComboboxItem>
virtualListRef: RefObject<VirtuosoHandle>
/** Height to assign to virtual list */
virtualListHeight: number
onBlur?: () => void
}

export const SelectContext = createContext<SelectContextReturn | undefined>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ export interface SingleSelectProviderProps<
value: string
/** Controlled selected item onChange handler */
onChange: (value: string) => void
onBlur?: () => void
/** Function based on which items in dropdown are filtered. Default filter filters by fuzzy match. */
filter?(items: Item[], value: string): Item[]
filter?: (items: Item[], value: string) => Item[]
/** Initial dropdown opened state. */
initialIsOpen?: boolean
/** Props to override default useComboboxProps, if any. */
Expand All @@ -45,6 +46,7 @@ export interface SingleSelectProviderProps<
export const SingleSelectProvider = ({
items: rawItems,
value,
onBlur,
onChange,
name,
filter = defaultFilter,
Expand Down Expand Up @@ -272,6 +274,7 @@ export const SingleSelectProvider = ({
virtualListRef,
virtualListHeight,
fullWidth,
onBlur,
}}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const SelectCombobox = forwardRef<HTMLInputElement>(
isOpen,
resetInputValue,
inputRef,
onBlur,
} = useSelectContext()

const mergedInputRef = useMergeRefs(inputRef, ref)
Expand All @@ -51,7 +52,7 @@ export const SelectCombobox = forwardRef<HTMLInputElement>(
}, [isDisabled, isReadOnly, toggleMenu])

return (
<Flex>
<Flex onBlur={onBlur}>
<InputGroup
pos="relative"
display="grid"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,30 +152,6 @@ const workflow_step_2_with_all_fields_deleted: FormWorkflowStepDto = {
edit: ['deleted_object_id_1', 'deleted_object_id_2'],
}

const workflow_step_1_with_respondent: FormWorkflowStepDto = {
_id: '61e6857c9c794b0012f1c6g1',
workflow_type: WorkflowType.Dynamic,
field: form_field_5._id,
edit: [
form_field_1._id,
form_field_2._id,
form_field_5._id,
form_field_6._id,
],
}

const workflow_step_1_with_deleted_respondent: FormWorkflowStepDto = {
_id: '61e6857c9c794b0012f1c6g9',
workflow_type: WorkflowType.Dynamic,
field: 'invalid_object_id',
edit: [
form_field_1._id,
form_field_2._id,
form_field_5._id,
form_field_6._id,
],
}

const workflow_step_3_with_approval: FormWorkflowStepDto = {
_id: '61e6857c9c794b0012f1c6g2',
workflow_type: WorkflowType.Dynamic,
Expand Down Expand Up @@ -231,12 +207,16 @@ MobileWithWorkflow.parameters = {
chromatic: { viewports: [viewports.xs] },
}

export const Step1Respondent = Template.bind({})
Step1Respondent.parameters = {
export const Step1 = Template.bind({})
Step1.parameters = {
msw: buildMswRoutes({
...FORM_WITH_WORKFLOW,
workflow: [workflow_step_1_with_respondent],
workflow: [workflow_step_1],
}),
documentation: {
storyDescription:
'Step 1 of a workflow should not show any respondent selected',
},
}

export const Step3Approval = Template.bind({})
Expand All @@ -247,14 +227,6 @@ Step3Approval.parameters = {
}),
}

export const Step1RespondentDeleted = Template.bind({})
Step1RespondentDeleted.parameters = {
msw: buildMswRoutes({
...FORM_WITH_WORKFLOW,
workflow: [workflow_step_1_with_deleted_respondent],
}),
}

export const Step3ApprovalFieldDeleted = Template.bind({})
Step3ApprovalFieldDeleted.parameters = {
msw: buildMswRoutes({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,36 +203,6 @@ export const DeletedApprovalFieldSelected = {
},
}

export const DeletedStep1RespondentSelected = {
args: {
stepNumber: 0,
defaultValues: {
workflow_type: WorkflowType.Dynamic,
field: 'deleted_objectId',
edit: [form_field_3._id],
},
},
parameters: {
docs: {
description: {
component:
'When submit is clicked, no validation error should occur since email field is set to empty string',
},
},
},
}

export const Step1RespondentSelected = {
args: {
stepNumber: 0,
defaultValues: {
workflow_type: WorkflowType.Dynamic,
field: form_field_3._id,
edit: [form_field_3._id],
},
},
}

export const Step3AllSelectedValid = {
args: {
stepNumber: 2,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useCallback } from 'react'
import { Controller, UseFormReturn } from 'react-hook-form'
import { As, FormControl, Stack, Text } from '@chakra-ui/react'
import { get } from 'lodash'
Expand Down Expand Up @@ -202,18 +201,12 @@ export const RespondentBlock = ({
stepNumber,
isLoading,
formMethods,
user,
}: RespondentBlockProps): JSX.Element => {
const {
formState: { errors },
watch,
setValue,
control,
} = formMethods

// TODO: (MRF-email-notif) Remove isTest check when MRF email notifications is out of beta
const isTest = import.meta.env.STORYBOOK_NODE_ENV === 'test'

const { emailFormFields = [] } = useAdminFormWorkflow()

const emailFieldItems = emailFormFields.map(
Expand All @@ -223,22 +216,6 @@ export const RespondentBlock = ({
icon: BASICFIELD_TO_DRAWER_META[fieldType].icon,
}),
)
const emailFieldIds = emailFormFields.map(({ _id }) => _id)

const getValueIfNotDeleted = useCallback(
// Why: When the Yes/No field has been deleted, the approval_field is still set to the
// invalid form field id but cannot be seen or cleared in the SingleSelect component
// since no matching Yes/No item can be found.
// Hence, we clear the approval_field to allow the user to re-select a new valid value.
(value: string) => {
if (!isLoading && value && !emailFieldIds.includes(value)) {
setValue('field', '')
return ''
}
return value
},
[isLoading, setValue, emailFieldIds],
)

const selectedWorkflowType = watch('workflow_type')

Expand All @@ -247,47 +224,10 @@ export const RespondentBlock = ({
return (
<EditStepBlockContainer>
{isFirstStep ? (
<>
{/* TODO: (MRF-email-notif) Remove isTest and betaFlag check when MRF email
notifications is out of beta */}
{isTest || user?.betaFlags?.mrfEmailNotifications ? (
<FormControl isInvalid={!!errors.field}>
<FormLabel style={textStyles.h4}>
Select email field for notifications to be sent to this
respondent
</FormLabel>
<Controller
name="field"
rules={{
validate: (selectedValue) => {
return (
!selectedValue ||
!emailFieldItems ||
emailFieldItems.some(
({ value: fieldValue }) => fieldValue === selectedValue,
) ||
'Field is not an email field'
)
},
}}
control={control}
render={({ field: { value = '', ...rest } }) => (
<SingleSelect
isDisabled={isLoading}
placeholder="Select an email field from your form"
items={emailFieldItems}
value={getValueIfNotDeleted(value)}
isClearable
{...rest}
/>
)}
/>
<FormErrorMessage>{errors.field?.message}</FormErrorMessage>
</FormControl>
) : (
<Text>Anyone you share the form link with</Text>
)}
</>
<Stack spacing="0.5rem">
<Text style={textStyles.h4}>Respondent in this step</Text>
<Text>Anyone who has access to your form</Text>
</Stack>
) : (
<FormControl
isReadOnly={isLoading}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,6 @@ interface RespondentBadgeProps {
step: FormWorkflowStepDto
idToFieldMap: Dictionary<FormFieldWithQuestionNo<FormField>>
}
const FirstStepRespondentBadge = ({
step,
idToFieldMap,
}: RespondentBadgeProps): JSX.Element | null => {
if (
step.workflow_type === WorkflowType.Static ||
(step.workflow_type === WorkflowType.Dynamic && !step.field)
) {
return (
<FieldLogicBadge
defaults={{
variant: 'info',
message: 'No email field included in this step',
}}
/>
)
}
return <FieldLogicBadge field={idToFieldMap[step.field]} />
}

const SubsequentStepRespondentBadges = ({
step,
Expand Down Expand Up @@ -179,14 +160,7 @@ export const InactiveStepBlock = ({
{/* TODO: (MRF-email-notif) Remove isTest and betaFlag check when MRF email
notifications is out of beta */}
{isFirstStep ? (
isTest || user?.betaFlags?.mrfEmailNotifications ? (
<FirstStepRespondentBadge
step={step}
idToFieldMap={idToFieldMap}
/>
) : (
<Text>Anyone you share the form link with</Text>
)
<Text>Anyone who has access to your form</Text>
) : (
<Flex
flexDir={{ base: 'column', md: 'row' }}
Expand Down
Loading

0 comments on commit 4434cef

Please sign in to comment.