Skip to content

Commit

Permalink
feat(v2): allow creation of dropdown fields in admin form builder (#3817
Browse files Browse the repository at this point in the history
)

* feat: add and render initial EditDropdown component

* feat: render dropdown field preview

* ref: inline getButtonText util function back to caller

only used in one place

* ref: rename common/utils.ts to common/constants.ts

since those are actually just constants

* ref: move all EditFieldDecorator instantiations to test utils

* feat: add story

* feat: add default fieldCreation object for dropdown fields

* ref: move EditFieldDecorator to root storybook util

putting it in __tests__ causes cra's jest to complain T_T
  • Loading branch information
karrui authored May 6, 2022
1 parent 9640d77 commit fe41313
Show file tree
Hide file tree
Showing 20 changed files with 222 additions and 175 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import IconButton from '~components/IconButton'
import {
CheckboxField,
DecimalField,
DropdownField,
EmailField,
HomeNoField,
LongTextField,
Expand Down Expand Up @@ -310,6 +311,8 @@ const MemoFieldRow = memo(({ field, ...rest }: MemoFieldRowProps) => {
return <NumberField schema={field} {...rest} />
case BasicField.Decimal:
return <DecimalField schema={field} {...rest} />
case BasicField.Dropdown:
return <DropdownField schema={field} {...rest} />
case BasicField.Statement:
return <ParagraphField schema={field} {...rest} />
case BasicField.ShortText:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { CreatePageDrawerCloseButton } from '../CreatePageDrawerCloseButton'
import {
EditCheckbox,
EditDecimal,
EditDropdown,
EditEmail,
EditHeader,
EditHomeno,
Expand Down Expand Up @@ -131,6 +132,8 @@ export const MemoFieldDrawerContent = memo<MemoFieldDrawerContentProps>(
switch (field.fieldType) {
case BasicField.Checkbox:
return <EditCheckbox {...props} field={field} />
case BasicField.Dropdown:
return <EditDropdown {...props} field={field} />
case BasicField.Mobile:
return <EditMobile {...props} field={field} />
case BasicField.HomeNo:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import NumberInput from '~components/NumberInput'
import Textarea from '~components/Textarea'
import Toggle from '~components/Toggle'

import {
SPLIT_TEXTAREA_TRANSFORM,
SPLIT_TEXTAREA_VALIDATION,
} from './common/constants'
import { DrawerContentContainer } from './common/DrawerContentContainer'
import { FormFieldDrawerActions } from './common/FormFieldDrawerActions'
import { EditFieldProps } from './common/types'
import { useEditFieldForm } from './common/useEditFieldForm'
import {
SPLIT_TEXTAREA_TRANSFORM,
SPLIT_TEXTAREA_VALIDATION,
} from './common/utils'

type EditCheckboxProps = EditFieldProps<CheckboxFieldBase>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,17 @@
import { Box, useDisclosure } from '@chakra-ui/react'
import { DecoratorFn, Meta, Story } from '@storybook/react'
import { Meta, Story } from '@storybook/react'

import { BasicField, DecimalFieldBase } from '~shared/types'

import { StoryRouter } from '~utils/storybook'
import { EditFieldDrawerDecorator, StoryRouter } from '~utils/storybook'

import { BuilderAndDesignContext } from '~features/admin-form/create/builder-and-design/BuilderAndDesignContext'
import { getFieldCreationMeta } from '~features/admin-form/create/builder-and-design/utils/fieldCreation'
import { CreatePageSidebarProvider } from '~features/admin-form/create/common/CreatePageSidebarContext'

import { EditDecimal } from './EditDecimal'

const DEFAULT_DECIMAL_FIELD = getFieldCreationMeta(
BasicField.Decimal,
) as DecimalFieldBase

const EditFieldDrawerDecorator: DecoratorFn = (storyFn) => {
const deleteFieldModalDisclosure = useDisclosure()
return (
<Box maxW="33.25rem">
<CreatePageSidebarProvider>
<BuilderAndDesignContext.Provider
value={{
deleteFieldModalDisclosure,
}}
>
{storyFn()}
</BuilderAndDesignContext.Provider>
</CreatePageSidebarProvider>
</Box>
)
}

export default {
title: 'Features/AdminForm/EditFieldDrawer/EditDecimal',
component: EditDecimal,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Meta, Story } from '@storybook/react'

import { BasicField, DropdownFieldBase } from '~shared/types'

import { createFormBuilderMocks } from '~/mocks/msw/handlers/admin-form'

import { EditFieldDrawerDecorator, StoryRouter } from '~utils/storybook'

import { EditDropdown } from './EditDropdown'

const DEFAULT_DROPDOWN_FIELD: DropdownFieldBase = {
title: 'Storybook Dropdown',
description: 'Some description about Dropdown',
required: true,
disabled: false,
fieldType: BasicField.Dropdown,
fieldOptions: ['Option 1', 'Option 2', 'Option 3'],
globalId: 'unused',
}

export default {
title: 'Features/AdminForm/EditFieldDrawer/EditDropdown',
component: EditDropdown,
decorators: [
StoryRouter({
initialEntries: ['/61540ece3d4a6e50ac0cc6ff'],
path: '/:formId',
}),
EditFieldDrawerDecorator,
],
parameters: {
// Required so skeleton "animation" does not hide content.
chromatic: { pauseAnimationAtEnd: true },
msw: createFormBuilderMocks({}, 0),
},
args: {
field: DEFAULT_DROPDOWN_FIELD,
},
} as Meta<StoryArgs>

interface StoryArgs {
field: DropdownFieldBase
}

const Template: Story<StoryArgs> = ({ field }) => {
return <EditDropdown field={field} />
}

export const Default = Template.bind({})
Default.storyName = 'EditDropdown'
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { useMemo } from 'react'
import { FormControl } from '@chakra-ui/react'
import { extend, pick } from 'lodash'

import { DropdownFieldBase } from '~shared/types/field'

import { createBaseValidationRules } from '~utils/fieldValidation'
import FormErrorMessage from '~components/FormControl/FormErrorMessage'
import FormLabel from '~components/FormControl/FormLabel'
import Input from '~components/Input'
import Textarea from '~components/Textarea'
import Toggle from '~components/Toggle'

import {
SPLIT_TEXTAREA_TRANSFORM,
SPLIT_TEXTAREA_VALIDATION,
} from '../common/constants'
import { DrawerContentContainer } from '../common/DrawerContentContainer'
import { FormFieldDrawerActions } from '../common/FormFieldDrawerActions'
import { EditFieldProps } from '../common/types'
import { useEditFieldForm } from '../common/useEditFieldForm'

type EditDropdownProps = EditFieldProps<DropdownFieldBase>

const EDIT_DROPDOWN_FIELD_KEYS = ['title', 'description', 'required'] as const

type EditDropdownKeys = typeof EDIT_DROPDOWN_FIELD_KEYS[number]

type EditDropdownInputs = Pick<DropdownFieldBase, EditDropdownKeys> & {
fieldOptionsString: string // Differs from fieldOptions in DropdownFieldBase because input is a string. Will be converted to array using SPLIT_TEXTAREA_TRANSFORM
}

const transformDropdownFieldToEditForm = (
field: DropdownFieldBase,
): EditDropdownInputs => {
return {
...pick(field, EDIT_DROPDOWN_FIELD_KEYS),
fieldOptionsString: SPLIT_TEXTAREA_TRANSFORM.input(field.fieldOptions),
}
}

const transformDropdownEditFormToField = (
inputs: EditDropdownInputs,
originalField: DropdownFieldBase,
): DropdownFieldBase => {
return extend({}, originalField, inputs, {
fieldOptions: SPLIT_TEXTAREA_TRANSFORM.output(inputs.fieldOptionsString),
})
}

export const EditDropdown = ({ field }: EditDropdownProps): JSX.Element => {
const {
register,
formState: { errors },
isSaveEnabled,
buttonText,
handleUpdateField,
isLoading,
handleCancel,
} = useEditFieldForm<EditDropdownInputs, DropdownFieldBase>({
field,
transform: {
input: transformDropdownFieldToEditForm,
output: transformDropdownEditFormToField,
},
})

const requiredValidationRule = useMemo(
() => createBaseValidationRules({ required: true }),
[],
)

return (
<DrawerContentContainer>
<FormControl isRequired isReadOnly={isLoading} isInvalid={!!errors.title}>
<FormLabel>Question</FormLabel>
<Input autoFocus {...register('title', requiredValidationRule)} />
<FormErrorMessage>{errors?.title?.message}</FormErrorMessage>
</FormControl>
<FormControl isReadOnly={isLoading} isInvalid={!!errors.description}>
<FormLabel>Description</FormLabel>
<Textarea {...register('description')} />
<FormErrorMessage>{errors?.description?.message}</FormErrorMessage>
</FormControl>
<FormControl isReadOnly={isLoading}>
<Toggle {...register('required')} label="Required" />
</FormControl>
<FormControl
isRequired
isReadOnly={isLoading}
isInvalid={!!errors.fieldOptionsString}
>
<FormLabel>Options</FormLabel>
<Textarea
{...register('fieldOptionsString', {
validate: SPLIT_TEXTAREA_VALIDATION,
})}
/>
<FormErrorMessage>
{errors?.fieldOptionsString?.message}
</FormErrorMessage>
</FormControl>
<FormFieldDrawerActions
isLoading={isLoading}
isSaveEnabled={isSaveEnabled}
buttonText={buttonText}
handleClick={handleUpdateField}
handleCancel={handleCancel}
/>
</DrawerContentContainer>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { EditDropdown } from './EditDropdown'
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { Box, useDisclosure } from '@chakra-ui/react'
import { DecoratorFn, Meta, Story } from '@storybook/react'
import { Meta, Story } from '@storybook/react'

import { BasicField, EmailFieldBase } from '~shared/types'

import { createFormBuilderMocks } from '~/mocks/msw/handlers/admin-form'

import { StoryRouter } from '~utils/storybook'

import { BuilderAndDesignContext } from '~features/admin-form/create/builder-and-design/BuilderAndDesignContext'
import { CreatePageSidebarProvider } from '~features/admin-form/create/common/CreatePageSidebarContext'
import { EditFieldDrawerDecorator, StoryRouter } from '~utils/storybook'

import { EditEmail } from './EditEmail'

Expand All @@ -31,23 +27,6 @@ const DEFAULT_EMAIL_FIELD: EmailFieldBase = {
globalId: 'unused',
}

const EditFieldDrawerDecorator: DecoratorFn = (storyFn) => {
const deleteFieldModalDisclosure = useDisclosure()
return (
<Box maxW="33.25rem">
<CreatePageSidebarProvider>
<BuilderAndDesignContext.Provider
value={{
deleteFieldModalDisclosure,
}}
>
{storyFn()}
</BuilderAndDesignContext.Provider>
</CreatePageSidebarProvider>
</Box>
)
}

export default {
title: 'Features/AdminForm/EditFieldDrawer/EditEmail',
component: EditEmail,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import Textarea from '~components/Textarea'
import Toggle from '~components/Toggle'

import { useCreateTabForm } from '../../../../useCreateTabForm'
import { SPLIT_TEXTAREA_TRANSFORM } from '../common/constants'
import { DrawerContentContainer } from '../common/DrawerContentContainer'
import { FormFieldDrawerActions } from '../common/FormFieldDrawerActions'
import { EditFieldProps } from '../common/types'
import { useEditFieldForm } from '../common/useEditFieldForm'
import { SPLIT_TEXTAREA_TRANSFORM } from '../common/utils'

const EDIT_EMAIL_FIELD_KEYS = [
'title',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { Box, useDisclosure } from '@chakra-ui/react'
import { DecoratorFn, Meta, Story } from '@storybook/react'
import { Meta, Story } from '@storybook/react'

import { BasicField, HomenoFieldBase } from '~shared/types'

import { createFormBuilderMocks } from '~/mocks/msw/handlers/admin-form'

import { StoryRouter } from '~utils/storybook'

import { BuilderAndDesignContext } from '~features/admin-form/create/builder-and-design/BuilderAndDesignContext'
import { CreatePageSidebarProvider } from '~features/admin-form/create/common/CreatePageSidebarContext'
import { EditFieldDrawerDecorator, StoryRouter } from '~utils/storybook'

import { EditHomeno } from './EditHomeno'

Expand All @@ -22,23 +18,6 @@ const DEFAULT_HOMENO_FIELD: HomenoFieldBase = {
globalId: 'unused',
}

const EditFieldDrawerDecorator: DecoratorFn = (storyFn) => {
const deleteFieldModalDisclosure = useDisclosure()
return (
<Box maxW="33.25rem">
<CreatePageSidebarProvider>
<BuilderAndDesignContext.Provider
value={{
deleteFieldModalDisclosure,
}}
>
{storyFn()}
</BuilderAndDesignContext.Provider>
</CreatePageSidebarProvider>
</Box>
)
}

export default {
title: 'Features/AdminForm/EditFieldDrawer/EditHomeno',
component: EditHomeno,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import { Box, useDisclosure } from '@chakra-ui/react'
import { DecoratorFn, Meta, Story } from '@storybook/react'
import { Meta, Story } from '@storybook/react'

import {
BasicField,
LongTextFieldBase,
TextSelectedValidation,
} from '~shared/types'

import { StoryRouter } from '~utils/storybook'

import { BuilderAndDesignContext } from '~features/admin-form/create/builder-and-design/BuilderAndDesignContext'
import { CreatePageSidebarProvider } from '~features/admin-form/create/common/CreatePageSidebarContext'
import { EditFieldDrawerDecorator, StoryRouter } from '~utils/storybook'

import { EditLongText, EditLongTextProps } from './EditLongText'

Expand All @@ -27,23 +23,6 @@ const DEFAULT_LONGTEXT_FIELD: LongTextFieldBase = {
globalId: 'unused',
}

const EditFieldDrawerDecorator: DecoratorFn = (storyFn) => {
const deleteFieldModalDisclosure = useDisclosure()
return (
<Box maxW="33.25rem">
<CreatePageSidebarProvider>
<BuilderAndDesignContext.Provider
value={{
deleteFieldModalDisclosure,
}}
>
{storyFn()}
</BuilderAndDesignContext.Provider>
</CreatePageSidebarProvider>
</Box>
)
}

export default {
title: 'Features/AdminForm/EditFieldDrawer/EditLongText',
component: EditLongText,
Expand Down
Loading

0 comments on commit fe41313

Please sign in to comment.