Skip to content

Commit

Permalink
feat: dynamic routing
Browse files Browse the repository at this point in the history
  • Loading branch information
justynoh committed Feb 14, 2024
1 parent 7497828 commit b428061
Show file tree
Hide file tree
Showing 23 changed files with 715 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const ActiveLogicBlock = ({
handleOpenDeleteModal={handleOpenDeleteModal}
onSubmit={handleSubmit}
defaultValues={logic}
submitButtonLabel="Save changes"
submitButtonLabel="Save"
/>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const NewLogicBlock = ({
isLoading={createLogicMutation.isLoading}
defaultValues={_defaultValues}
onSubmit={handleSubmit}
submitButtonLabel="Add logic"
submitButtonLabel="Add step"
/>
)
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { useCallback } from 'react'

import { FormWorkflowStepDto, WorkflowType } from '~shared/types'
import {
FormWorkflowStep,
FormWorkflowStepDto,
WorkflowType,
} from '~shared/types'

import {
setToInactiveSelector,
useAdminWorkflowStore,
} from '../../../adminWorkflowStore'
import { useWorkflowMutations } from '../../../mutations'
import { EditStepInputs } from '../../../types'
import { EditStepBlock } from '../EditStepBlock'

export interface ActiveStepBlockProps {
Expand All @@ -23,15 +26,22 @@ export const ActiveStepBlock = ({
}: ActiveStepBlockProps): JSX.Element => {
const { updateStepMutation } = useWorkflowMutations()
const setToInactive = useAdminWorkflowStore(setToInactiveSelector)

const defaultValues =
// A bit of instrumentation to convert the emails array to a single email
step.workflow_type === WorkflowType.Static
? {
...step,
emails: step.emails[0],
}
: step

const handleSubmit = useCallback(
(inputs: EditStepInputs) =>
(step: FormWorkflowStep) =>
updateStepMutation.mutate(
{
stepNumber,
updateStepBody: {
workflow_type: WorkflowType.Static,
emails: inputs.email ? [inputs.email] : [],
},
updateStepBody: step,
},
{
onSuccess: () => setToInactive(),
Expand All @@ -46,7 +56,7 @@ export const ActiveStepBlock = ({
isLoading={updateStepMutation.isLoading}
handleOpenDeleteModal={handleOpenDeleteModal}
onSubmit={handleSubmit}
defaultValues={{ email: step.emails[0] }}
defaultValues={defaultValues}
submitButtonLabel="Save step"
/>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useLayoutEffect, useRef } from 'react'
import { useForm } from 'react-hook-form'
import { Box, Stack } from '@chakra-ui/react'
import { merge } from 'lodash'

import { FormWorkflowStep, WorkflowType } from '~shared/types'

import { SaveActionGroup } from '~features/admin-form/create/logic/components/LogicContent/EditLogicBlock/EditCondition'

Expand All @@ -18,7 +19,7 @@ import { RespondentBlock } from './RespondentBlock'
export interface EditLogicBlockProps {
/** Sets default values of inputs if this is provided */
defaultValues?: Partial<EditStepInputs>
onSubmit: (inputs: EditStepInputs) => void
onSubmit: (inputs: FormWorkflowStep) => void

stepNumber: number
submitButtonLabel: string
Expand All @@ -37,8 +38,7 @@ export const EditStepBlock = ({
const setToInactive = useAdminWorkflowStore(setToInactiveSelector)

const formMethods = useForm<EditStepInputs>({
defaultValues: merge({ emails: [] }, defaultValues),
shouldUnregister: true,
defaultValues,
})

const wrapperRef = useRef<HTMLDivElement | null>(null)
Expand All @@ -55,9 +55,33 @@ export const EditStepBlock = ({
}
}, [])

const isFirstStep = isFirstStepByStepNumber(stepNumber)
const handleSubmit = formMethods.handleSubmit((inputs: EditStepInputs) => {
let step: FormWorkflowStep
switch (inputs.workflow_type) {
case WorkflowType.Static: {
step = {
workflow_type: WorkflowType.Static,
emails: inputs.emails ? [inputs.emails] : [],
}
break
}
case WorkflowType.Dynamic: {
if (!inputs.field) return
step = {
workflow_type: WorkflowType.Dynamic,
field: inputs.field,
}
break
}
default: {
const _: never = inputs.workflow_type

Check warning on line 77 in frontend/src/features/admin-form/create/workflow/components/WorkflowContent/EditStepBlock/EditStepBlock.tsx

View workflow job for this annotation

GitHub Actions / frontend_lint

'_' is assigned a value but never used
throw new Error('Invalid workflow type')
}
}
onSubmit(step)
})

const handleSubmit = formMethods.handleSubmit((inputs) => onSubmit(inputs))
const isFirstStep = isFirstStepByStepNumber(stepNumber)

return (
<Stack
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { Controller, UseFormReturn } from 'react-hook-form'
import { FormControl, Stack, Text } from '@chakra-ui/react'
import { Flex, FormControl, Stack, Text } from '@chakra-ui/react'
import isEmail from 'validator/lib/isEmail'

import { WorkflowType } from '~shared/types'

import { SingleSelect } from '~components/Dropdown'
import FormErrorMessage from '~components/FormControl/FormErrorMessage'
import Input from '~components/Input'
import Radio from '~components/Radio'

import { BASICFIELD_TO_DRAWER_META } from '~features/admin-form/create/constants'
import { EditStepInputs } from '~features/admin-form/create/workflow/types'

import { useAdminFormWorkflow } from '../../../hooks/useAdminFormWorkflow'
import { isFirstStepByStepNumber } from '../utils/isFirstStepByStepNumber'

interface RespondentBlockProps {
Expand All @@ -22,9 +28,12 @@ export const RespondentBlock = ({
}: RespondentBlockProps): JSX.Element => {
const {
formState: { errors },
control,
register,
watch,
} = formMethods

const selectedWorkflowType = watch('workflow_type')

const isFirstStep = isFirstStepByStepNumber(stepNumber)

return (
Expand All @@ -35,17 +44,78 @@ export const RespondentBlock = ({
px={{ base: '1.5rem', md: '2rem' }}
>
<Text textStyle="subhead-3">Respondent in this step</Text>

{isFirstStep ? (
<Text>Anyone you share the form link with</Text>
) : (
<>
<FormControl
isReadOnly={isLoading}
id="workflowType"
isRequired
isInvalid={!!errors.workflow_type}
>
<Radio.RadioGroup defaultValue={selectedWorkflowType}>
<Flex flexDir="row">
<Radio
allowDeselect={false}
value={WorkflowType.Static}
{...register('workflow_type')}
>
Assign by a specific email
</Radio>
<Radio
allowDeselect={false}
value={WorkflowType.Dynamic}
{...register('workflow_type')}
>
Assign from email field on form
</Radio>
</Flex>
</Radio.RadioGroup>
<FormErrorMessage>{errors.workflow_type?.message}</FormErrorMessage>
</FormControl>

<RespondentInput isLoading={isLoading} formMethods={formMethods} />
</>
)}
</Stack>
)
}

type RespondentInputProps = Omit<RespondentBlockProps, 'stepNumber'>

const RespondentInput = ({ isLoading, formMethods }: RespondentInputProps) => {
const { emailFormFields = [] } = useAdminFormWorkflow()

const emailFieldItems = emailFormFields.map(
({ _id, questionNumber, title, fieldType }) => ({
label: `${questionNumber}. ${title}`,
value: _id,
icon: BASICFIELD_TO_DRAWER_META[fieldType].icon,
}),
)

const {
formState: { errors },
control,
watch,
} = formMethods

const watchedWorkflowType = watch('workflow_type')

switch (watchedWorkflowType) {
case WorkflowType.Static:
return (
<FormControl
isReadOnly={isLoading}
id="emails"
isRequired
isInvalid={!!errors.email}
isInvalid={!!errors.emails}
key="emails"
>
<Controller
name="email"
name="emails"
control={control}
rules={{
required: 'Please add an email',
Expand All @@ -58,9 +128,44 @@ export const RespondentBlock = ({
<Input placeholder="me@example.com" {...field} />
)}
/>
<FormErrorMessage>{errors.email?.message}</FormErrorMessage>
<FormErrorMessage>{errors.emails?.message}</FormErrorMessage>
</FormControl>
)}
</Stack>
)
)
case WorkflowType.Dynamic:
return (
<FormControl
isReadOnly={isLoading}
id="field"
isRequired
isInvalid={!!errors.field}
>
<Controller
control={control}
name="field"
rules={{
required: 'Please select a question',
validate: (value) =>
!emailFormFields ||
emailFormFields.some(({ _id }) => _id === value) ||
'Field is not an email field',
}}
render={({ field: { value = '', ...rest } }) => (
<SingleSelect
isDisabled={isLoading}
isClearable={false}
placeholder="Select a question"
items={emailFieldItems}
value={value}
{...rest}
/>
)}
/>
<FormErrorMessage>{errors.field?.message}</FormErrorMessage>
</FormControl>
)
default: {
const _: never = watchedWorkflowType

Check warning on line 167 in frontend/src/features/admin-form/create/workflow/components/WorkflowContent/EditStepBlock/RespondentBlock.tsx

View workflow job for this annotation

GitHub Actions / frontend_lint

'_' is assigned a value but never used
throw new Error('Invalid workflow type')
}
}
}
Loading

0 comments on commit b428061

Please sign in to comment.