From 2ee360918c10cc92c2865e1d77d2e4e5aa289656 Mon Sep 17 00:00:00 2001 From: QiShaoXuan Date: Tue, 2 Aug 2022 14:53:44 +0800 Subject: [PATCH] chore: abstracting callback functions to reduce the complexity of the jsx --- .../CreatePendantPanel.tsx | 134 +-------- .../UpdatePendantPanel.tsx | 153 +--------- .../pendant-operation-panel/hooks.ts | 265 ++++++++++++++++++ 3 files changed, 289 insertions(+), 263 deletions(-) create mode 100644 libs/components/editor-core/src/block-pendant/pendant-operation-panel/hooks.ts diff --git a/libs/components/editor-core/src/block-pendant/pendant-operation-panel/CreatePendantPanel.tsx b/libs/components/editor-core/src/block-pendant/pendant-operation-panel/CreatePendantPanel.tsx index ecd564dbbe..b9d29cebe7 100644 --- a/libs/components/editor-core/src/block-pendant/pendant-operation-panel/CreatePendantPanel.tsx +++ b/libs/components/editor-core/src/block-pendant/pendant-operation-panel/CreatePendantPanel.tsx @@ -1,17 +1,11 @@ -import React, { CSSProperties, useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; import { nanoid } from 'nanoid'; -import { - Input, - Option, - Select, - Tooltip, - message, -} from '@toeverything/components/ui'; +import { Input, Option, Select, Tooltip } from '@toeverything/components/ui'; import { HelpCenterIcon } from '@toeverything/components/icons'; import { AsyncBlock } from '../../editor'; import { IconMap, pendantOptions } from '../config'; -import { OptionType, PendantOptions, PendantTypes } from '../types'; +import { PendantOptions } from '../types'; import { PendantModifyPanel } from '../pendant-modify-panel'; import { StyledDivider, @@ -21,24 +15,13 @@ import { StyledPopoverSubTitle, StyledPopoverWrapper, } from '../StyledComponent'; -import { - genSelectOptionId, - InformationProperty, - useRecastBlock, - useRecastBlockMeta, - useSelectProperty, -} from '../../recast-block'; -import { - checkPendantForm, - genInitialOptions, - getOfficialSelected, - getPendantConfigByType, -} from '../utils'; -import { usePendant } from '../use-pendant'; +import { genInitialOptions, getPendantConfigByType } from '../utils'; +import { useOnCreateSure } from './hooks'; const upperFirst = (str: string) => { return `${str[0].toUpperCase()}${str.slice(1)}`; }; + export const CreatePendantPanel = ({ block, onSure, @@ -48,9 +31,7 @@ export const CreatePendantPanel = ({ }) => { const [selectedOption, setSelectedOption] = useState(); const [fieldName, setFieldName] = useState(''); - const { addProperty, removeProperty } = useRecastBlockMeta(); - const { createSelect } = useSelectProperty(); - const { setPendant } = usePendant(block); + const onCreateSure = useOnCreateSure({ block }); useEffect(() => { selectedOption && @@ -117,99 +98,13 @@ export const CreatePendantPanel = ({ getPendantConfigByType(selectedOption.type) )} iconConfig={getPendantConfigByType(selectedOption.type)} - // isStatusSelect={selectedOption.name === 'Status'} onSure={async (type, newPropertyItem, newValue) => { - const checkResult = checkPendantForm( + await onCreateSure({ type, - fieldName, newPropertyItem, - newValue - ); - - if (!checkResult.passed) { - await message.error(checkResult.message); - return; - } - - if ( - type === PendantTypes.MultiSelect || - type === PendantTypes.Select || - type === PendantTypes.Status - ) { - const newProperty = await createSelect({ - name: fieldName, - options: newPropertyItem, - type, - }); - - const selectedId = getOfficialSelected({ - isMulti: type === PendantTypes.MultiSelect, - options: newProperty.options, - tempOptions: newPropertyItem, - tempSelectedId: newValue, - }); - - await setPendant(newProperty, selectedId); - } else if (type === PendantTypes.Information) { - const emailOptions = genOptionWithId( - newPropertyItem.emailOptions - ); - - const phoneOptions = genOptionWithId( - newPropertyItem.phoneOptions - ); - - const locationOptions = genOptionWithId( - newPropertyItem.locationOptions - ); - - const newProperty = await addProperty({ - type, - name: fieldName, - emailOptions, - phoneOptions, - locationOptions, - } as Omit); - - await setPendant(newProperty, { - email: getOfficialSelected({ - isMulti: true, - options: emailOptions, - tempOptions: - newPropertyItem.emailOptions, - tempSelectedId: newValue.email, - }), - phone: getOfficialSelected({ - isMulti: true, - options: phoneOptions, - tempOptions: - newPropertyItem.phoneOptions, - tempSelectedId: newValue.phone, - }), - location: getOfficialSelected({ - isMulti: true, - options: locationOptions, - tempOptions: - newPropertyItem.locationOptions, - tempSelectedId: newValue.location, - }), - }); - } else { - // TODO: Color and background should use pendant config, but ui is not design now - const iconConfig = getPendantConfigByType(type); - // TODO: Color and background should be choose by user in the future - const newProperty = await addProperty({ - type: type, - name: fieldName, - background: - iconConfig.background as CSSProperties['background'], - color: iconConfig.color as CSSProperties['color'], - iconName: iconConfig.iconName, - }); - - await setPendant(newProperty, newValue); - } - + newValue, + fieldName, + }); onSure?.(); }} /> @@ -218,10 +113,3 @@ export const CreatePendantPanel = ({ ); }; - -const genOptionWithId = (options: OptionType[] = []) => { - return options.map((option: OptionType) => ({ - ...option, - id: genSelectOptionId(), - })); -}; diff --git a/libs/components/editor-core/src/block-pendant/pendant-operation-panel/UpdatePendantPanel.tsx b/libs/components/editor-core/src/block-pendant/pendant-operation-panel/UpdatePendantPanel.tsx index dd61c97b32..bb51054964 100644 --- a/libs/components/editor-core/src/block-pendant/pendant-operation-panel/UpdatePendantPanel.tsx +++ b/libs/components/editor-core/src/block-pendant/pendant-operation-panel/UpdatePendantPanel.tsx @@ -1,23 +1,13 @@ import { useState } from 'react'; +import { Input, Tooltip } from '@toeverything/components/ui'; +import { HelpCenterIcon } from '@toeverything/components/icons'; import { PendantModifyPanel } from '../pendant-modify-panel'; import type { AsyncBlock } from '../../editor'; import { - genSelectOptionId, - InformationProperty, - type MultiSelectProperty, type RecastBlockValue, type RecastMetaProperty, - type SelectOption, - type SelectProperty, - useRecastBlockMeta, - useSelectProperty, } from '../../recast-block'; -import { OptionType, PendantTypes, TempInformationType } from '../types'; -import { - getOfficialSelected, - getPendantConfigByType, - checkPendantForm, -} from '../utils'; +import { getPendantConfigByType } from '../utils'; import { usePendant } from '../use-pendant'; import { StyledPopoverWrapper, @@ -28,10 +18,8 @@ import { StyledPopoverSubTitle, } from '../StyledComponent'; import { IconMap, pendantOptions } from '../config'; -import { Input, message, Tooltip } from '@toeverything/components/ui'; -import { HelpCenterIcon } from '@toeverything/components/icons'; -type SelectPropertyType = MultiSelectProperty | SelectProperty; +import { useOnUpdateSure } from './hooks'; type Props = { value: RecastBlockValue; @@ -52,13 +40,12 @@ export const UpdatePendantPanel = ({ onCancel, titleEditable = false, }: Props) => { - const { updateSelect } = useSelectProperty(); - const { setPendant, removePendant } = usePendant(block); const pendantOption = pendantOptions.find(v => v.type === property.type); const iconConfig = getPendantConfigByType(property.type); + const { removePendant } = usePendant(block); const Icon = IconMap[iconConfig.iconName]; - const { updateProperty } = useRecastBlockMeta(); - const [fieldTitle, setFieldTitle] = useState(property.name); + const [fieldName, setFieldName] = useState(property.name); + const onUpdateSure = useOnUpdateSure({ block, property }); return ( @@ -76,10 +63,10 @@ export const UpdatePendantPanel = ({ Field Title {titleEditable ? ( { - setFieldTitle(e.target.value); + setFieldName(e.target.value); }} endAdornment={ @@ -110,126 +97,12 @@ export const UpdatePendantPanel = ({ property={property} type={property.type} onSure={async (type, newPropertyItem, newValue) => { - const checkResult = checkPendantForm( + await onUpdateSure({ type, - fieldTitle, newPropertyItem, - newValue - ); - - if (!checkResult.passed) { - await message.error(checkResult.message); - return; - } - - if ( - type === PendantTypes.MultiSelect || - type === PendantTypes.Select || - type === PendantTypes.Status - ) { - const newOptions = newPropertyItem as OptionType[]; - let selectProperty = property as SelectPropertyType; - const deleteOptionIds = selectProperty.options - .filter(o => { - return !newOptions.find(no => no.id === o.id); - }) - .map(o => o.id); - const addOptions = newOptions.filter( - o => typeof o.id === 'number' - ); - - const { addSelectOptions, removeSelectOptions } = - updateSelect(selectProperty); - - deleteOptionIds.length && - (selectProperty = (await removeSelectOptions( - ...deleteOptionIds - )) as SelectPropertyType); - - addOptions.length && - (selectProperty = (await addSelectOptions( - ...(addOptions as unknown as Omit< - SelectOption, - 'id' - >[]) - )) as SelectPropertyType); - - const selectedId = getOfficialSelected({ - isMulti: type === PendantTypes.MultiSelect, - options: selectProperty.options, - tempOptions: newPropertyItem, - tempSelectedId: newValue, - }); - - await setPendant(selectProperty, selectedId); - } else if (type === PendantTypes.Information) { - // const { emailOptions, phoneOptions, locationOptions } = - // property as InformationProperty; - const optionGroup = - newPropertyItem as TempInformationType; - - const emailOptions = optionGroup.emailOptions.map( - option => { - if (typeof option.id === 'number') { - option.id = genSelectOptionId(); - } - return option; - } - ); - const phoneOptions = optionGroup.phoneOptions.map( - option => { - if (typeof option.id === 'number') { - option.id = genSelectOptionId(); - } - return option; - } - ); - const locationOptions = optionGroup.locationOptions.map( - option => { - if (typeof option.id === 'number') { - option.id = genSelectOptionId(); - } - return option; - } - ); - - const newProperty = await updateProperty({ - ...property, - emailOptions, - phoneOptions, - locationOptions, - } as InformationProperty); - - await setPendant(newProperty, { - email: getOfficialSelected({ - isMulti: true, - options: emailOptions as SelectOption[], - tempOptions: newPropertyItem.emailOptions, - tempSelectedId: newValue.email, - }), - phone: getOfficialSelected({ - isMulti: true, - options: phoneOptions as SelectOption[], - tempOptions: newPropertyItem.phoneOptions, - tempSelectedId: newValue.phone, - }), - location: getOfficialSelected({ - isMulti: true, - options: locationOptions as SelectOption[], - tempOptions: newPropertyItem.locationOptions, - tempSelectedId: newValue.location, - }), - }); - } else { - await setPendant(property, newValue); - } - - if (fieldTitle !== property.name) { - await updateProperty({ - ...property, - name: fieldTitle, - }); - } + newValue, + fieldName, + }); onSure?.(); }} onDelete={ diff --git a/libs/components/editor-core/src/block-pendant/pendant-operation-panel/hooks.ts b/libs/components/editor-core/src/block-pendant/pendant-operation-panel/hooks.ts new file mode 100644 index 0000000000..83889962ac --- /dev/null +++ b/libs/components/editor-core/src/block-pendant/pendant-operation-panel/hooks.ts @@ -0,0 +1,265 @@ +import type { CSSProperties } from 'react'; +import { + genSelectOptionId, + type InformationProperty, + type MultiSelectProperty, + type RecastMetaProperty, + type SelectOption, + type SelectProperty, + useRecastBlockMeta, + useSelectProperty, +} from '../../recast-block'; +import { type AsyncBlock } from '../../editor'; +import { usePendant } from '../use-pendant'; +import { + type OptionType, + PendantTypes, + type TempInformationType, +} from '../types'; +import { + checkPendantForm, + getOfficialSelected, + getPendantConfigByType, +} from '../utils'; +import { message } from '@toeverything/components/ui'; + +type SelectPropertyType = MultiSelectProperty | SelectProperty; +type SureParams = { + fieldName: string; + type: PendantTypes; + newPropertyItem: any; + newValue: any; +}; + +const genOptionWithId = (options: OptionType[] = []) => { + return options.map((option: OptionType) => ({ + ...option, + id: genSelectOptionId(), + })); +}; +// Callback function for pendant create +export const useOnCreateSure = ({ block }: { block: AsyncBlock }) => { + const { addProperty } = useRecastBlockMeta(); + const { createSelect } = useSelectProperty(); + const { setPendant } = usePendant(block); + + return async ({ + type, + fieldName, + newPropertyItem, + newValue, + }: SureParams) => { + const checkResult = checkPendantForm( + type, + fieldName, + newPropertyItem, + newValue + ); + + if (!checkResult.passed) { + await message.error(checkResult.message); + return; + } + + if ( + type === PendantTypes.MultiSelect || + type === PendantTypes.Select || + type === PendantTypes.Status + ) { + const newProperty = await createSelect({ + name: fieldName, + options: newPropertyItem, + type, + }); + + const selectedId = getOfficialSelected({ + isMulti: type === PendantTypes.MultiSelect, + options: newProperty.options, + tempOptions: newPropertyItem, + tempSelectedId: newValue, + }); + + await setPendant(newProperty, selectedId); + } else if (type === PendantTypes.Information) { + const emailOptions = genOptionWithId(newPropertyItem.emailOptions); + + const phoneOptions = genOptionWithId(newPropertyItem.phoneOptions); + + const locationOptions = genOptionWithId( + newPropertyItem.locationOptions + ); + + const newProperty = await addProperty({ + type, + name: fieldName, + emailOptions, + phoneOptions, + locationOptions, + } as Omit); + + await setPendant(newProperty, { + email: getOfficialSelected({ + isMulti: true, + options: emailOptions, + tempOptions: newPropertyItem.emailOptions, + tempSelectedId: newValue.email, + }), + phone: getOfficialSelected({ + isMulti: true, + options: phoneOptions, + tempOptions: newPropertyItem.phoneOptions, + tempSelectedId: newValue.phone, + }), + location: getOfficialSelected({ + isMulti: true, + options: locationOptions, + tempOptions: newPropertyItem.locationOptions, + tempSelectedId: newValue.location, + }), + }); + } else { + // TODO: Color and background should use pendant config, but ui is not design now + const iconConfig = getPendantConfigByType(type); + // TODO: Color and background should be choose by user in the future + const newProperty = await addProperty({ + type: type, + name: fieldName, + background: + iconConfig.background as CSSProperties['background'], + color: iconConfig.color as CSSProperties['color'], + iconName: iconConfig.iconName, + }); + + await setPendant(newProperty, newValue); + } + }; +}; + +// Callback function for pendant update +export const useOnUpdateSure = ({ + block, + property, +}: { + block: AsyncBlock; + property: RecastMetaProperty; +}) => { + const { updateSelect } = useSelectProperty(); + const { setPendant } = usePendant(block); + const { updateProperty } = useRecastBlockMeta(); + + return async ({ + type, + fieldName, + newPropertyItem, + newValue, + }: SureParams) => { + const checkResult = checkPendantForm( + type, + fieldName, + newPropertyItem, + newValue + ); + + if (!checkResult.passed) { + await message.error(checkResult.message); + return; + } + + if ( + type === PendantTypes.MultiSelect || + type === PendantTypes.Select || + type === PendantTypes.Status + ) { + const newOptions = newPropertyItem as OptionType[]; + let selectProperty = property as SelectPropertyType; + const deleteOptionIds = selectProperty.options + .filter(o => { + return !newOptions.find(no => no.id === o.id); + }) + .map(o => o.id); + const addOptions = newOptions.filter(o => typeof o.id === 'number'); + + const { addSelectOptions, removeSelectOptions } = + updateSelect(selectProperty); + + deleteOptionIds.length && + (selectProperty = (await removeSelectOptions( + ...deleteOptionIds + )) as SelectPropertyType); + + addOptions.length && + (selectProperty = (await addSelectOptions( + ...(addOptions as unknown as Omit[]) + )) as SelectPropertyType); + + const selectedId = getOfficialSelected({ + isMulti: type === PendantTypes.MultiSelect, + options: selectProperty.options, + tempOptions: newPropertyItem, + tempSelectedId: newValue, + }); + + await setPendant(selectProperty, selectedId); + } else if (type === PendantTypes.Information) { + // const { emailOptions, phoneOptions, locationOptions } = + // property as InformationProperty; + const optionGroup = newPropertyItem as TempInformationType; + + const emailOptions = optionGroup.emailOptions.map(option => { + if (typeof option.id === 'number') { + option.id = genSelectOptionId(); + } + return option; + }); + const phoneOptions = optionGroup.phoneOptions.map(option => { + if (typeof option.id === 'number') { + option.id = genSelectOptionId(); + } + return option; + }); + const locationOptions = optionGroup.locationOptions.map(option => { + if (typeof option.id === 'number') { + option.id = genSelectOptionId(); + } + return option; + }); + + const newProperty = await updateProperty({ + ...property, + emailOptions, + phoneOptions, + locationOptions, + } as InformationProperty); + + await setPendant(newProperty, { + email: getOfficialSelected({ + isMulti: true, + options: emailOptions as SelectOption[], + tempOptions: newPropertyItem.emailOptions, + tempSelectedId: newValue.email, + }), + phone: getOfficialSelected({ + isMulti: true, + options: phoneOptions as SelectOption[], + tempOptions: newPropertyItem.phoneOptions, + tempSelectedId: newValue.phone, + }), + location: getOfficialSelected({ + isMulti: true, + options: locationOptions as SelectOption[], + tempOptions: newPropertyItem.locationOptions, + tempSelectedId: newValue.location, + }), + }); + } else { + await setPendant(property, newValue); + } + + if (fieldName !== property.name) { + await updateProperty({ + ...property, + name: fieldName, + }); + } + }; +};