From fe41313e73df6de37ce77cedbf426d568e54b472 Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Fri, 6 May 2022 18:10:03 +0800 Subject: [PATCH] feat(v2): allow creation of dropdown fields in admin form builder (#3817) * 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 --- .../FieldRow/FieldRowContainer.tsx | 3 + .../EditFieldDrawer/EditFieldDrawer.tsx | 3 + .../edit-fieldtype/EditCheckbox.tsx | 8 +- .../EditDecimal/EditDecimal.stories.tsx | 24 +--- .../EditDropdown/EditDropdown.stories.tsx | 50 ++++++++ .../EditDropdown/EditDropdown.tsx | 112 ++++++++++++++++++ .../edit-fieldtype/EditDropdown/index.ts | 1 + .../EditEmail/EditEmail.stories.tsx | 25 +--- .../edit-fieldtype/EditEmail/EditEmail.tsx | 2 +- .../EditHomeno/EditHomeno.stories.tsx | 25 +--- .../EditLongText/EditLongText.stories.tsx | 25 +--- .../EditMobile/EditMobile.stories.tsx | 25 +--- .../EditNumber/EditNumber.stories.tsx | 25 +--- .../edit-fieldtype/EditRadio.tsx | 8 +- .../EditShortText/EditShortText.stories.tsx | 25 +--- .../common/{utils.ts => constants.ts} | 3 - .../edit-fieldtype/common/useEditFieldForm.ts | 3 +- .../EditFieldDrawer/edit-fieldtype/index.ts | 1 + .../builder-and-design/utils/fieldCreation.ts | 7 ++ frontend/src/utils/storybook.tsx | 22 +++- 20 files changed, 222 insertions(+), 175 deletions(-) create mode 100644 frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditDropdown/EditDropdown.stories.tsx create mode 100644 frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditDropdown/EditDropdown.tsx create mode 100644 frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditDropdown/index.ts rename frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/common/{utils.ts => constants.ts} (81%) diff --git a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/FieldRow/FieldRowContainer.tsx b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/FieldRow/FieldRowContainer.tsx index cf30c88900..4b2d62a3fd 100644 --- a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/FieldRow/FieldRowContainer.tsx +++ b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/FieldRow/FieldRowContainer.tsx @@ -20,6 +20,7 @@ import IconButton from '~components/IconButton' import { CheckboxField, DecimalField, + DropdownField, EmailField, HomeNoField, LongTextField, @@ -310,6 +311,8 @@ const MemoFieldRow = memo(({ field, ...rest }: MemoFieldRowProps) => { return case BasicField.Decimal: return + case BasicField.Dropdown: + return case BasicField.Statement: return case BasicField.ShortText: diff --git a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/EditFieldDrawer.tsx b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/EditFieldDrawer.tsx index 69b0f15956..12cb265fe5 100644 --- a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/EditFieldDrawer.tsx +++ b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/EditFieldDrawer.tsx @@ -20,6 +20,7 @@ import { CreatePageDrawerCloseButton } from '../CreatePageDrawerCloseButton' import { EditCheckbox, EditDecimal, + EditDropdown, EditEmail, EditHeader, EditHomeno, @@ -131,6 +132,8 @@ export const MemoFieldDrawerContent = memo( switch (field.fieldType) { case BasicField.Checkbox: return + case BasicField.Dropdown: + return case BasicField.Mobile: return case BasicField.HomeNo: diff --git a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditCheckbox.tsx b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditCheckbox.tsx index a348316f8f..df6dde3cdc 100644 --- a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditCheckbox.tsx +++ b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditCheckbox.tsx @@ -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 diff --git a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditDecimal/EditDecimal.stories.tsx b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditDecimal/EditDecimal.stories.tsx index f98a4cd140..4225711c80 100644 --- a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditDecimal/EditDecimal.stories.tsx +++ b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditDecimal/EditDecimal.stories.tsx @@ -1,13 +1,10 @@ -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' @@ -15,23 +12,6 @@ const DEFAULT_DECIMAL_FIELD = getFieldCreationMeta( BasicField.Decimal, ) as DecimalFieldBase -const EditFieldDrawerDecorator: DecoratorFn = (storyFn) => { - const deleteFieldModalDisclosure = useDisclosure() - return ( - - - - {storyFn()} - - - - ) -} - export default { title: 'Features/AdminForm/EditFieldDrawer/EditDecimal', component: EditDecimal, diff --git a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditDropdown/EditDropdown.stories.tsx b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditDropdown/EditDropdown.stories.tsx new file mode 100644 index 0000000000..1da29e37e5 --- /dev/null +++ b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditDropdown/EditDropdown.stories.tsx @@ -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 + +interface StoryArgs { + field: DropdownFieldBase +} + +const Template: Story = ({ field }) => { + return +} + +export const Default = Template.bind({}) +Default.storyName = 'EditDropdown' diff --git a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditDropdown/EditDropdown.tsx b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditDropdown/EditDropdown.tsx new file mode 100644 index 0000000000..c8be561319 --- /dev/null +++ b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditDropdown/EditDropdown.tsx @@ -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 + +const EDIT_DROPDOWN_FIELD_KEYS = ['title', 'description', 'required'] as const + +type EditDropdownKeys = typeof EDIT_DROPDOWN_FIELD_KEYS[number] + +type EditDropdownInputs = Pick & { + 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({ + field, + transform: { + input: transformDropdownFieldToEditForm, + output: transformDropdownEditFormToField, + }, + }) + + const requiredValidationRule = useMemo( + () => createBaseValidationRules({ required: true }), + [], + ) + + return ( + + + Question + + {errors?.title?.message} + + + Description +