From 44ac429533e8d763b0eddddfe97c8e2e0d132b8d Mon Sep 17 00:00:00 2001 From: Justyn Oh Date: Wed, 3 Aug 2022 15:26:15 +0800 Subject: [PATCH 1/5] feat: opacity for builder fields hidden by default --- .../BuilderAndDesignContent/BuilderFields.tsx | 5 ++++- .../FieldRow/FieldRowContainer.tsx | 3 +++ .../BuilderAndDesignContent/FormBuilder.tsx | 13 +++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/BuilderFields.tsx b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/BuilderFields.tsx index 5965119474..880d1d55f6 100644 --- a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/BuilderFields.tsx +++ b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/BuilderFields.tsx @@ -3,16 +3,18 @@ import { memo, useMemo } from 'react' import { AdminFormDto } from '~shared/types/form' import { augmentWithQuestionNo } from '~features/form/utils' +import { FieldIdSet } from '~features/logic/types' import FieldRow from './FieldRow' interface BuilderFieldsProps { fields: AdminFormDto['form_fields'] + visibleFieldIds: FieldIdSet isDraggingOver: boolean } export const BuilderFields = memo( - ({ fields, isDraggingOver }: BuilderFieldsProps) => { + ({ fields, visibleFieldIds, isDraggingOver }: BuilderFieldsProps) => { const fieldsWithQuestionNos = useMemo( () => augmentWithQuestionNo(fields), [fields], @@ -25,6 +27,7 @@ export const BuilderFields = memo( index={i} key={f._id} field={f} + isVisible={visibleFieldIds.has(f._id)} isDraggingOver={isDraggingOver} /> ))} 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 5585b98337..c44be1b592 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 @@ -68,12 +68,14 @@ import { SectionFieldRow } from './SectionFieldRow' export interface FieldRowContainerProps { field: FormFieldDto index: number + isVisible: boolean isDraggingOver: boolean } export const FieldRowContainer = ({ field, index, + isVisible, isDraggingOver, }: FieldRowContainerProps): JSX.Element => { const isMobile = useIsMobile() @@ -271,6 +273,7 @@ export const FieldRowContainer = ({ pb={{ base: '0.75rem', md: '1.5rem' }} w="100%" pointerEvents={isActive ? undefined : 'none'} + opacity={isActive || isVisible ? '100%' : '30%'} > diff --git a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/FormBuilder.tsx b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/FormBuilder.tsx index 2a07453a8a..6116e852ac 100644 --- a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/FormBuilder.tsx +++ b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/FormBuilder.tsx @@ -1,11 +1,14 @@ +import { useMemo } from 'react' import { Droppable } from 'react-beautiful-dnd' import { Box, Flex, FlexProps, Text } from '@chakra-ui/react' import Button from '~components/Button' +import { getVisibleFieldIds } from '~features/logic/utils' import { useBgColor } from '~features/public-form/components/PublicFormWrapper' import { useCreatePageSidebar } from '../../common/CreatePageSidebarContext' +import { useAdminFormLogic } from '../../logic/hooks/useAdminFormLogic' import { FIELD_LIST_DROP_ID } from '../constants' import { DndPlaceholderProps } from '../types' import { @@ -29,8 +32,17 @@ export const FormBuilder = ({ ...props }: FormBuilderProps): JSX.Element => { const { builderFields } = useBuilderFields() + const { formLogics } = useAdminFormLogic() const { handleBuilderClick } = useCreatePageSidebar() const setEditEndPage = useBuilderAndDesignStore(setToEditEndPageSelector) + const visibleFieldIds = useMemo( + () => + getVisibleFieldIds( + {}, // Assume form has no inputs yet. + { formFields: builderFields ?? [], formLogics: formLogics ?? [] }, + ), + [builderFields, formLogics], + ) const bg = useBgColor(useDesignColorTheme()) @@ -58,6 +70,7 @@ export const FormBuilder = ({ > {provided.placeholder} From be4e395da12ec856cf73a889d64a2912b8be9455 Mon Sep 17 00:00:00 2001 From: Justyn Oh Date: Wed, 3 Aug 2022 16:27:30 +0800 Subject: [PATCH 2/5] feat: add stories --- .../AdminFormCreatePage.stories.tsx | 12 ++++++++++ .../src/mocks/msw/handlers/admin-form/form.ts | 23 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/frontend/src/features/admin-form/AdminFormCreatePage.stories.tsx b/frontend/src/features/admin-form/AdminFormCreatePage.stories.tsx index c98ba5dfa4..cb9708bde6 100644 --- a/frontend/src/features/admin-form/AdminFormCreatePage.stories.tsx +++ b/frontend/src/features/admin-form/AdminFormCreatePage.stories.tsx @@ -12,6 +12,7 @@ import { import { createFormBuilderMocks, MOCK_FORM_FIELDS_WITH_MYINFO, + MOCK_FORM_LOGICS, } from '~/mocks/msw/handlers/admin-form' import { getFreeSmsQuota } from '~/mocks/msw/handlers/admin-form/twilio' import { getUser, MOCK_USER } from '~/mocks/msw/handlers/user' @@ -80,6 +81,17 @@ DesktopAllFields.parameters = { responseMode: FormResponseMode.Email, }), } + +export const DesktopAllFieldsFieldsHiddenByLogic = Template.bind({}) +DesktopAllFieldsFieldsHiddenByLogic.parameters = { + msw: buildMswRoutes({ + form_fields: MOCK_FORM_FIELDS_WITH_MYINFO, + form_logics: MOCK_FORM_LOGICS, + authType: FormAuthType.MyInfo, + responseMode: FormResponseMode.Email, + }), +} + export const DesktopLoading = Template.bind({}) DesktopLoading.parameters = { msw: buildMswRoutes({}, 'infinite'), diff --git a/frontend/src/mocks/msw/handlers/admin-form/form.ts b/frontend/src/mocks/msw/handlers/admin-form/form.ts index 63a9a714f8..8e31f6ae6a 100644 --- a/frontend/src/mocks/msw/handlers/admin-form/form.ts +++ b/frontend/src/mocks/msw/handlers/admin-form/form.ts @@ -11,7 +11,12 @@ import { RatingShape, TableFieldDto, } from '~shared/types/field' -import { FormLogic } from '~shared/types/form' +import { + FormLogic, + LogicConditionState, + LogicIfValue, + LogicType, +} from '~shared/types/form' import { AdminFormDto, AdminFormViewDto, @@ -546,6 +551,22 @@ export const MOCK_FORM_FIELDS_WITH_MYINFO = [ ...MOCK_MYINFO_FIELDS, ] +export const MOCK_FORM_LOGICS = [ + { + show: MOCK_FORM_FIELDS_WITH_MYINFO.map((f) => f._id), + _id: '620115f74ad4f00012900a8c', + logicType: LogicType.ShowFields as const, + conditions: [ + { + ifValueType: LogicIfValue.SingleSelect, + field: '5da04eb5e397fc0013f63c7e', + state: LogicConditionState.Equal, + value: 'Yes', + }, + ], + }, +] + export const createMockForm = ( props: Partial = {}, ): AdminFormViewDto => { From f975be3d01caf5299edb6847940851a3ee30ae42 Mon Sep 17 00:00:00 2001 From: Justyn Oh Date: Wed, 3 Aug 2022 16:28:46 +0800 Subject: [PATCH 3/5] chore: add comment regarding mocked logic --- frontend/src/mocks/msw/handlers/admin-form/form.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/mocks/msw/handlers/admin-form/form.ts b/frontend/src/mocks/msw/handlers/admin-form/form.ts index 8e31f6ae6a..b1940f99d8 100644 --- a/frontend/src/mocks/msw/handlers/admin-form/form.ts +++ b/frontend/src/mocks/msw/handlers/admin-form/form.ts @@ -552,6 +552,9 @@ export const MOCK_FORM_FIELDS_WITH_MYINFO = [ ] export const MOCK_FORM_LOGICS = [ + // Note: this logic is actually invalid since the if field cannot be a show + // field at the same time. But it's fine just for the purposes of displaying + // the hidden view. { show: MOCK_FORM_FIELDS_WITH_MYINFO.map((f) => f._id), _id: '620115f74ad4f00012900a8c', From 311a40538d0779a7b2207a919a9dc31c5dd7beae Mon Sep 17 00:00:00 2001 From: Justyn Oh Date: Wed, 3 Aug 2022 16:37:04 +0800 Subject: [PATCH 4/5] chore: rename story --- .../AdminFormCreatePage.stories.tsx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/src/features/admin-form/AdminFormCreatePage.stories.tsx b/frontend/src/features/admin-form/AdminFormCreatePage.stories.tsx index cb9708bde6..8015ba284a 100644 --- a/frontend/src/features/admin-form/AdminFormCreatePage.stories.tsx +++ b/frontend/src/features/admin-form/AdminFormCreatePage.stories.tsx @@ -82,16 +82,6 @@ DesktopAllFields.parameters = { }), } -export const DesktopAllFieldsFieldsHiddenByLogic = Template.bind({}) -DesktopAllFieldsFieldsHiddenByLogic.parameters = { - msw: buildMswRoutes({ - form_fields: MOCK_FORM_FIELDS_WITH_MYINFO, - form_logics: MOCK_FORM_LOGICS, - authType: FormAuthType.MyInfo, - responseMode: FormResponseMode.Email, - }), -} - export const DesktopLoading = Template.bind({}) DesktopLoading.parameters = { msw: buildMswRoutes({}, 'infinite'), @@ -122,3 +112,13 @@ MobileLoading.parameters = { ...getMobileViewParameters(), msw: buildMswRoutes({}, 'infinite'), } + +export const AllFieldsFieldsHiddenByLogic = Template.bind({}) +AllFieldsFieldsHiddenByLogic.parameters = { + msw: buildMswRoutes({ + form_fields: MOCK_FORM_FIELDS_WITH_MYINFO, + form_logics: MOCK_FORM_LOGICS, + authType: FormAuthType.MyInfo, + responseMode: FormResponseMode.Email, + }), +} From a0740f7dbe2b23feb317567ca769820d75618957 Mon Sep 17 00:00:00 2001 From: Justyn Oh Date: Fri, 5 Aug 2022 11:41:46 +0800 Subject: [PATCH 5/5] feat: add tooltips for hidden fields. --- .../BuilderAndDesignContent/BuilderFields.tsx | 2 +- .../FieldRow/FieldRowContainer.tsx | 219 +++++++++--------- 2 files changed, 114 insertions(+), 107 deletions(-) diff --git a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/BuilderFields.tsx b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/BuilderFields.tsx index 880d1d55f6..1e8c8d3b01 100644 --- a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/BuilderFields.tsx +++ b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignContent/BuilderFields.tsx @@ -27,7 +27,7 @@ export const BuilderFields = memo( index={i} key={f._id} field={f} - isVisible={visibleFieldIds.has(f._id)} + isHiddenByLogic={!visibleFieldIds.has(f._id)} isDraggingOver={isDraggingOver} /> ))} 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 c44be1b592..e1250ba623 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 @@ -19,6 +19,7 @@ import { BasicField, FormFieldDto } from '~shared/types/field' import { useIsMobile } from '~hooks/useIsMobile' import IconButton from '~components/IconButton' +import Tooltip from '~components/Tooltip' import { AttachmentField, CheckboxField, @@ -68,14 +69,14 @@ import { SectionFieldRow } from './SectionFieldRow' export interface FieldRowContainerProps { field: FormFieldDto index: number - isVisible: boolean + isHiddenByLogic: boolean isDraggingOver: boolean } export const FieldRowContainer = ({ field, index, - isVisible, + isHiddenByLogic, isDraggingOver, }: FieldRowContainerProps): JSX.Element => { const isMobile = useIsMobile() @@ -213,117 +214,123 @@ export const FieldRowContainer = ({ {...provided.draggableProps} ref={provided.innerRef} > - + + + - {isMobile ? ( - } - onClick={handleEditFieldClick} - /> - ) : null} - { - // Fields which are not yet created cannot be duplicated - stateData.state !== BuildFieldState.CreatingField && ( + + {isMobile ? ( } + variant="clear" + colorScheme="secondary" + aria-label="Edit field" + icon={} + onClick={handleEditFieldClick} /> - ) - } - } - onClick={handleDeleteClick} - isLoading={deleteFieldMutation.isLoading} - isDisabled={isAnyMutationLoading} - /> - - - - + ) : null} + { + // Fields which are not yet created cannot be duplicated + stateData.state !== BuildFieldState.CreatingField && ( + } + /> + ) + } + } + onClick={handleDeleteClick} + isLoading={deleteFieldMutation.isLoading} + isDisabled={isAnyMutationLoading} + /> + + + + + )}