Refactor types to remove unused types and add FullNameFieldInput (#2590)

This commit is contained in:
Charles Bochet
2023-11-20 13:40:22 +01:00
committed by GitHub
parent eb64baa62e
commit b6665f880d
42 changed files with 101 additions and 1846 deletions

View File

@ -9,29 +9,19 @@ import { isFieldLink } from '@/ui/object/field/types/guards/isFieldLink';
import { isFieldUuid } from '@/ui/object/field/types/guards/isFieldUuid'; import { isFieldUuid } from '@/ui/object/field/types/guards/isFieldUuid';
import { FieldContext } from '../contexts/FieldContext'; import { FieldContext } from '../contexts/FieldContext';
import { ChipFieldDisplay } from '../meta-types/display/components/ChipFieldDisplay';
import { CurrencyFieldDisplay } from '../meta-types/display/components/CurrencyFieldDisplay'; import { CurrencyFieldDisplay } from '../meta-types/display/components/CurrencyFieldDisplay';
import { DateFieldDisplay } from '../meta-types/display/components/DateFieldDisplay'; import { DateFieldDisplay } from '../meta-types/display/components/DateFieldDisplay';
import { DoubleTextChipFieldDisplay } from '../meta-types/display/components/DoubleTextChipFieldDisplay';
import { EmailFieldDisplay } from '../meta-types/display/components/EmailFieldDisplay'; import { EmailFieldDisplay } from '../meta-types/display/components/EmailFieldDisplay';
import { EnumFieldDisplay } from '../meta-types/display/components/EnumFieldDisplay';
import { MoneyFieldDisplay } from '../meta-types/display/components/MoneyFieldDisplay';
import { NumberFieldDisplay } from '../meta-types/display/components/NumberFieldDisplay'; import { NumberFieldDisplay } from '../meta-types/display/components/NumberFieldDisplay';
import { PhoneFieldDisplay } from '../meta-types/display/components/PhoneFieldDisplay'; import { PhoneFieldDisplay } from '../meta-types/display/components/PhoneFieldDisplay';
import { TextFieldDisplay } from '../meta-types/display/components/TextFieldDisplay'; import { TextFieldDisplay } from '../meta-types/display/components/TextFieldDisplay';
import { URLFieldDisplay } from '../meta-types/display/components/URLFieldDisplay';
import { isFieldChip } from '../types/guards/isFieldChip';
import { isFieldCurrency } from '../types/guards/isFieldCurrency'; import { isFieldCurrency } from '../types/guards/isFieldCurrency';
import { isFieldDate } from '../types/guards/isFieldDate'; import { isFieldDate } from '../types/guards/isFieldDate';
import { isFieldDoubleTextChip } from '../types/guards/isFieldDoubleTextChip';
import { isFieldEmail } from '../types/guards/isFieldEmail'; import { isFieldEmail } from '../types/guards/isFieldEmail';
import { isFieldEnum } from '../types/guards/isFieldEnum';
import { isFieldMoney } from '../types/guards/isFieldMoney';
import { isFieldNumber } from '../types/guards/isFieldNumber'; import { isFieldNumber } from '../types/guards/isFieldNumber';
import { isFieldPhone } from '../types/guards/isFieldPhone'; import { isFieldPhone } from '../types/guards/isFieldPhone';
import { isFieldRelation } from '../types/guards/isFieldRelation'; import { isFieldRelation } from '../types/guards/isFieldRelation';
import { isFieldText } from '../types/guards/isFieldText'; import { isFieldText } from '../types/guards/isFieldText';
import { isFieldURL } from '../types/guards/isFieldURL';
export const FieldDisplay = () => { export const FieldDisplay = () => {
const { fieldDefinition } = useContext(FieldContext); const { fieldDefinition } = useContext(FieldContext);
@ -50,10 +40,6 @@ export const FieldDisplay = () => {
<DateFieldDisplay /> <DateFieldDisplay />
) : isFieldNumber(fieldDefinition) ? ( ) : isFieldNumber(fieldDefinition) ? (
<NumberFieldDisplay /> <NumberFieldDisplay />
) : isFieldMoney(fieldDefinition) ? (
<MoneyFieldDisplay />
) : isFieldURL(fieldDefinition) ? (
<URLFieldDisplay />
) : isFieldLink(fieldDefinition) ? ( ) : isFieldLink(fieldDefinition) ? (
<LinkFieldDisplay /> <LinkFieldDisplay />
) : isFieldCurrency(fieldDefinition) ? ( ) : isFieldCurrency(fieldDefinition) ? (
@ -62,12 +48,6 @@ export const FieldDisplay = () => {
<FullNameFieldDisplay /> <FullNameFieldDisplay />
) : isFieldPhone(fieldDefinition) ? ( ) : isFieldPhone(fieldDefinition) ? (
<PhoneFieldDisplay /> <PhoneFieldDisplay />
) : isFieldChip(fieldDefinition) ? (
<ChipFieldDisplay />
) : isFieldDoubleTextChip(fieldDefinition) ? (
<DoubleTextChipFieldDisplay />
) : isFieldEnum(fieldDefinition) ? (
<EnumFieldDisplay />
) : ( ) : (
<></> <></>
)} )}

View File

@ -1,37 +1,31 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { FullNameFieldInput } from '@/ui/object/field/meta-types/input/components/FullNameFieldInput';
import { isFieldFullName } from '@/ui/object/field/types/guards/isFieldFullName';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { FieldContext } from '../contexts/FieldContext'; import { FieldContext } from '../contexts/FieldContext';
import { BooleanFieldInput } from '../meta-types/input/components/BooleanFieldInput'; import { BooleanFieldInput } from '../meta-types/input/components/BooleanFieldInput';
import { ChipFieldInput } from '../meta-types/input/components/ChipFieldInput';
import { CurrencyFieldInput } from '../meta-types/input/components/CurrencyFieldInput'; import { CurrencyFieldInput } from '../meta-types/input/components/CurrencyFieldInput';
import { DateFieldInput } from '../meta-types/input/components/DateFieldInput'; import { DateFieldInput } from '../meta-types/input/components/DateFieldInput';
import { DoubleTextChipFieldInput } from '../meta-types/input/components/DoubleTextChipFieldInput';
import { EmailFieldInput } from '../meta-types/input/components/EmailFieldInput'; import { EmailFieldInput } from '../meta-types/input/components/EmailFieldInput';
import { LinkFieldInput } from '../meta-types/input/components/LinkFieldInput'; import { LinkFieldInput } from '../meta-types/input/components/LinkFieldInput';
import { MoneyFieldInput } from '../meta-types/input/components/MoneyFieldInput';
import { NumberFieldInput } from '../meta-types/input/components/NumberFieldInput'; import { NumberFieldInput } from '../meta-types/input/components/NumberFieldInput';
import { PhoneFieldInput } from '../meta-types/input/components/PhoneFieldInput'; import { PhoneFieldInput } from '../meta-types/input/components/PhoneFieldInput';
import { ProbabilityFieldInput } from '../meta-types/input/components/ProbabilityFieldInput'; import { ProbabilityFieldInput } from '../meta-types/input/components/ProbabilityFieldInput';
import { RelationFieldInput } from '../meta-types/input/components/RelationFieldInput'; import { RelationFieldInput } from '../meta-types/input/components/RelationFieldInput';
import { TextFieldInput } from '../meta-types/input/components/TextFieldInput'; import { TextFieldInput } from '../meta-types/input/components/TextFieldInput';
import { URLFieldInput } from '../meta-types/input/components/URLFieldInput';
import { FieldInputEvent } from '../types/FieldInputEvent'; import { FieldInputEvent } from '../types/FieldInputEvent';
import { isFieldBoolean } from '../types/guards/isFieldBoolean'; import { isFieldBoolean } from '../types/guards/isFieldBoolean';
import { isFieldChip } from '../types/guards/isFieldChip';
import { isFieldCurrency } from '../types/guards/isFieldCurrency'; import { isFieldCurrency } from '../types/guards/isFieldCurrency';
import { isFieldDate } from '../types/guards/isFieldDate'; import { isFieldDate } from '../types/guards/isFieldDate';
import { isFieldDoubleTextChip } from '../types/guards/isFieldDoubleTextChip';
import { isFieldEmail } from '../types/guards/isFieldEmail'; import { isFieldEmail } from '../types/guards/isFieldEmail';
import { isFieldLink } from '../types/guards/isFieldLink'; import { isFieldLink } from '../types/guards/isFieldLink';
import { isFieldMoney } from '../types/guards/isFieldMoney';
import { isFieldNumber } from '../types/guards/isFieldNumber'; import { isFieldNumber } from '../types/guards/isFieldNumber';
import { isFieldPhone } from '../types/guards/isFieldPhone'; import { isFieldPhone } from '../types/guards/isFieldPhone';
import { isFieldProbability } from '../types/guards/isFieldProbability'; import { isFieldProbability } from '../types/guards/isFieldProbability';
import { isFieldRelation } from '../types/guards/isFieldRelation'; import { isFieldRelation } from '../types/guards/isFieldRelation';
import { isFieldText } from '../types/guards/isFieldText'; import { isFieldText } from '../types/guards/isFieldText';
import { isFieldURL } from '../types/guards/isFieldURL';
type FieldInputProps = { type FieldInputProps = {
onSubmit?: FieldInputEvent; onSubmit?: FieldInputEvent;
@ -76,6 +70,14 @@ export const FieldInput = ({
onTab={onTab} onTab={onTab}
onShiftTab={onShiftTab} onShiftTab={onShiftTab}
/> />
) : isFieldFullName(fieldDefinition) ? (
<FullNameFieldInput
onEnter={onEnter}
onEscape={onEscape}
onClickOutside={onClickOutside}
onTab={onTab}
onShiftTab={onShiftTab}
/>
) : isFieldDate(fieldDefinition) ? ( ) : isFieldDate(fieldDefinition) ? (
<DateFieldInput <DateFieldInput
onEnter={onEnter} onEnter={onEnter}
@ -92,14 +94,6 @@ export const FieldInput = ({
onTab={onTab} onTab={onTab}
onShiftTab={onShiftTab} onShiftTab={onShiftTab}
/> />
) : isFieldURL(fieldDefinition) ? (
<URLFieldInput
onEnter={onEnter}
onEscape={onEscape}
onClickOutside={onClickOutside}
onTab={onTab}
onShiftTab={onShiftTab}
/>
) : isFieldLink(fieldDefinition) ? ( ) : isFieldLink(fieldDefinition) ? (
<LinkFieldInput <LinkFieldInput
onEnter={onEnter} onEnter={onEnter}
@ -128,30 +122,6 @@ export const FieldInput = ({
<BooleanFieldInput onSubmit={onSubmit} /> <BooleanFieldInput onSubmit={onSubmit} />
) : isFieldProbability(fieldDefinition) ? ( ) : isFieldProbability(fieldDefinition) ? (
<ProbabilityFieldInput onSubmit={onSubmit} /> <ProbabilityFieldInput onSubmit={onSubmit} />
) : isFieldChip(fieldDefinition) ? (
<ChipFieldInput
onEnter={onEnter}
onEscape={onEscape}
onClickOutside={onClickOutside}
onTab={onTab}
onShiftTab={onShiftTab}
/>
) : isFieldDoubleTextChip(fieldDefinition) ? (
<DoubleTextChipFieldInput
onEnter={onEnter}
onEscape={onEscape}
onClickOutside={onClickOutside}
onTab={onTab}
onShiftTab={onShiftTab}
/>
) : isFieldMoney(fieldDefinition) ? (
<MoneyFieldInput
onEnter={onEnter}
onEscape={onEscape}
onClickOutside={onClickOutside}
onTab={onTab}
onShiftTab={onShiftTab}
/>
) : ( ) : (
<></> <></>
)} )}

View File

@ -5,9 +5,9 @@ import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { FieldContext } from '../contexts/FieldContext'; import { FieldContext } from '../contexts/FieldContext';
import { isFieldEmail } from '../types/guards/isFieldEmail'; import { isFieldEmail } from '../types/guards/isFieldEmail';
import { isFieldLink } from '../types/guards/isFieldLink';
import { isFieldPhone } from '../types/guards/isFieldPhone'; import { isFieldPhone } from '../types/guards/isFieldPhone';
import { isFieldRelation } from '../types/guards/isFieldRelation'; import { isFieldRelation } from '../types/guards/isFieldRelation';
import { isFieldURL } from '../types/guards/isFieldURL';
export const useGetButtonIcon = (): IconComponent | undefined => { export const useGetButtonIcon = (): IconComponent | undefined => {
const { fieldDefinition } = useContext(FieldContext); const { fieldDefinition } = useContext(FieldContext);
@ -15,7 +15,7 @@ export const useGetButtonIcon = (): IconComponent | undefined => {
if (!fieldDefinition) return undefined; if (!fieldDefinition) return undefined;
if ( if (
isFieldURL(fieldDefinition) || isFieldLink(fieldDefinition) ||
isFieldEmail(fieldDefinition) || isFieldEmail(fieldDefinition) ||
isFieldPhone(fieldDefinition) || isFieldPhone(fieldDefinition) ||
isFieldRelation(fieldDefinition) isFieldRelation(fieldDefinition)

View File

@ -11,8 +11,8 @@ export const useIsFieldEmpty = () => {
isEntityFieldEmptyFamilySelector({ isEntityFieldEmptyFamilySelector({
fieldDefinition: { fieldDefinition: {
type: fieldDefinition.type, type: fieldDefinition.type,
metadata: { ...fieldDefinition.metadata, mainIdentifierMapper: null },
}, },
fieldName: fieldDefinition.metadata.fieldName,
entityId, entityId,
}), }),
); );

View File

@ -1,26 +1,21 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback } from 'recoil';
import { isFieldFullName } from '@/ui/object/field/types/guards/isFieldFullName';
import { isFieldFullNameValue } from '@/ui/object/field/types/guards/isFieldFullNameValue';
import { FieldContext } from '../contexts/FieldContext'; import { FieldContext } from '../contexts/FieldContext';
import { entityFieldsFamilySelector } from '../states/selectors/entityFieldsFamilySelector'; import { entityFieldsFamilySelector } from '../states/selectors/entityFieldsFamilySelector';
import { isFieldBoolean } from '../types/guards/isFieldBoolean'; import { isFieldBoolean } from '../types/guards/isFieldBoolean';
import { isFieldBooleanValue } from '../types/guards/isFieldBooleanValue'; import { isFieldBooleanValue } from '../types/guards/isFieldBooleanValue';
import { isFieldChip } from '../types/guards/isFieldChip';
import { isFieldChipValue } from '../types/guards/isFieldChipValue';
import { isFieldCurrency } from '../types/guards/isFieldCurrency'; import { isFieldCurrency } from '../types/guards/isFieldCurrency';
import { isFieldCurrencyValue } from '../types/guards/isFieldCurrencyValue'; import { isFieldCurrencyValue } from '../types/guards/isFieldCurrencyValue';
import { isFieldDate } from '../types/guards/isFieldDate'; import { isFieldDate } from '../types/guards/isFieldDate';
import { isFieldDateValue } from '../types/guards/isFieldDateValue'; import { isFieldDateValue } from '../types/guards/isFieldDateValue';
import { isFieldDoubleText } from '../types/guards/isFieldDoubleText';
import { isFieldDoubleTextChip } from '../types/guards/isFieldDoubleTextChip';
import { isFieldDoubleTextChipValue } from '../types/guards/isFieldDoubleTextChipValue';
import { isFieldDoubleTextValue } from '../types/guards/isFieldDoubleTextValue';
import { isFieldEmail } from '../types/guards/isFieldEmail'; import { isFieldEmail } from '../types/guards/isFieldEmail';
import { isFieldEmailValue } from '../types/guards/isFieldEmailValue'; import { isFieldEmailValue } from '../types/guards/isFieldEmailValue';
import { isFieldLink } from '../types/guards/isFieldLink'; import { isFieldLink } from '../types/guards/isFieldLink';
import { isFieldLinkValue } from '../types/guards/isFieldLinkValue'; import { isFieldLinkValue } from '../types/guards/isFieldLinkValue';
import { isFieldMoney } from '../types/guards/isFieldMoney';
import { isFieldMoneyValue } from '../types/guards/isFieldMoneyValue';
import { isFieldNumber } from '../types/guards/isFieldNumber'; import { isFieldNumber } from '../types/guards/isFieldNumber';
import { isFieldNumberValue } from '../types/guards/isFieldNumberValue'; import { isFieldNumberValue } from '../types/guards/isFieldNumberValue';
import { isFieldPhone } from '../types/guards/isFieldPhone'; import { isFieldPhone } from '../types/guards/isFieldPhone';
@ -31,8 +26,6 @@ import { isFieldRelation } from '../types/guards/isFieldRelation';
import { isFieldRelationValue } from '../types/guards/isFieldRelationValue'; import { isFieldRelationValue } from '../types/guards/isFieldRelationValue';
import { isFieldText } from '../types/guards/isFieldText'; import { isFieldText } from '../types/guards/isFieldText';
import { isFieldTextValue } from '../types/guards/isFieldTextValue'; import { isFieldTextValue } from '../types/guards/isFieldTextValue';
import { isFieldURL } from '../types/guards/isFieldURL';
import { isFieldURLValue } from '../types/guards/isFieldURLValue';
export const usePersistField = () => { export const usePersistField = () => {
const { const {
@ -50,17 +43,6 @@ export const usePersistField = () => {
isFieldRelation(fieldDefinition) && isFieldRelation(fieldDefinition) &&
isFieldRelationValue(valueToPersist); isFieldRelationValue(valueToPersist);
const fieldIsChip =
isFieldChip(fieldDefinition) && isFieldChipValue(valueToPersist);
const fieldIsDoubleText =
isFieldDoubleText(fieldDefinition) &&
isFieldDoubleTextValue(valueToPersist);
const fieldIsDoubleTextChip =
isFieldDoubleTextChip(fieldDefinition) &&
isFieldDoubleTextChipValue(valueToPersist);
const fieldIsText = const fieldIsText =
isFieldText(fieldDefinition) && isFieldTextValue(valueToPersist); isFieldText(fieldDefinition) && isFieldTextValue(valueToPersist);
@ -70,9 +52,6 @@ export const usePersistField = () => {
const fieldIsDate = const fieldIsDate =
isFieldDate(fieldDefinition) && isFieldDateValue(valueToPersist); isFieldDate(fieldDefinition) && isFieldDateValue(valueToPersist);
const fieldIsURL =
isFieldURL(fieldDefinition) && isFieldURLValue(valueToPersist);
const fieldIsLink = const fieldIsLink =
isFieldLink(fieldDefinition) && isFieldLinkValue(valueToPersist); isFieldLink(fieldDefinition) && isFieldLinkValue(valueToPersist);
@ -87,13 +66,14 @@ export const usePersistField = () => {
const fieldIsNumber = const fieldIsNumber =
isFieldNumber(fieldDefinition) && isFieldNumberValue(valueToPersist); isFieldNumber(fieldDefinition) && isFieldNumberValue(valueToPersist);
const fieldIsMoney =
isFieldMoney(fieldDefinition) && isFieldMoneyValue(valueToPersist);
const fieldIsCurrency = const fieldIsCurrency =
isFieldCurrency(fieldDefinition) && isFieldCurrency(fieldDefinition) &&
isFieldCurrencyValue(valueToPersist); isFieldCurrencyValue(valueToPersist);
const fieldIsFullName =
isFieldFullName(fieldDefinition) &&
isFieldFullNameValue(valueToPersist);
const fieldIsPhone = const fieldIsPhone =
isFieldPhone(fieldDefinition) && isFieldPhoneValue(valueToPersist); isFieldPhone(fieldDefinition) && isFieldPhoneValue(valueToPersist);
@ -115,62 +95,17 @@ export const usePersistField = () => {
}, },
}, },
}); });
} else if (fieldIsChip) {
const fieldName = fieldDefinition.metadata.contentFieldName;
set(
entityFieldsFamilySelector({ entityId, fieldName }),
valueToPersist,
);
updateEntity?.({
variables: {
where: { id: entityId },
data: {
[fieldName]: valueToPersist,
},
},
});
} else if (fieldIsDoubleText || fieldIsDoubleTextChip) {
set(
entityFieldsFamilySelector({
entityId,
fieldName: fieldDefinition.metadata.firstValueFieldName,
}),
valueToPersist.firstValue,
);
set(
entityFieldsFamilySelector({
entityId,
fieldName: fieldDefinition.metadata.secondValueFieldName,
}),
valueToPersist.secondValue,
);
updateEntity?.({
variables: {
where: { id: entityId },
data: {
[fieldDefinition.metadata.firstValueFieldName]:
valueToPersist.firstValue,
[fieldDefinition.metadata.secondValueFieldName]:
valueToPersist.secondValue,
},
},
});
} else if ( } else if (
fieldIsText || fieldIsText ||
fieldIsBoolean || fieldIsBoolean ||
fieldIsURL ||
fieldIsEmail || fieldIsEmail ||
fieldIsProbability || fieldIsProbability ||
fieldIsNumber || fieldIsNumber ||
fieldIsMoney ||
fieldIsDate || fieldIsDate ||
fieldIsPhone || fieldIsPhone ||
fieldIsLink || fieldIsLink ||
fieldIsCurrency fieldIsCurrency ||
fieldIsFullName
) { ) {
const fieldName = fieldDefinition.metadata.fieldName; const fieldName = fieldDefinition.metadata.fieldName;

View File

@ -40,7 +40,7 @@ export const useToggleEditOnlyInput = () => {
}); });
} else { } else {
throw new Error( throw new Error(
`Invalid value to toggle for type : ${fieldDefinition.type}, type may not be implemented in useToggleEditOnlyInput.`, `Invalid value to toggle for type : ${fieldDefinition}, type may not be implemented in useToggleEditOnlyInput.`,
); );
} }
}, },

View File

@ -1,14 +1,10 @@
import { useChipField } from '../../hooks/useChipField';
import { ChipDisplay } from '../content-display/components/ChipDisplay';
export const ChipFieldDisplay = () => { export const ChipFieldDisplay = () => {
const { avatarFieldValue, contentFieldValue, entityId } = useChipField(); // const { avatarFieldValue, contentFieldValue, entityId } = useChipField();
// return (
return ( // <ChipDisplay
<ChipDisplay // displayName={contentFieldValue}
displayName={contentFieldValue} // avatarUrlValue={avatarFieldValue}
avatarUrlValue={avatarFieldValue} // entityId={entityId}
entityId={entityId} // />
/> // );
);
}; };

View File

@ -1,17 +1,11 @@
import { useDoubleTextChipField } from '../../hooks/useDoubleTextChipField';
import { ChipDisplay } from '../content-display/components/ChipDisplay';
export const DoubleTextChipFieldDisplay = () => { export const DoubleTextChipFieldDisplay = () => {
const { avatarUrl, firstValue, secondValue, entityId } = // const {} = useFullNameField();
useDoubleTextChipField(); // const content = [firstValue, secondValue].filter(Boolean).join(' ');
// return (
const content = [firstValue, secondValue].filter(Boolean).join(' '); // <ChipDisplay
// displayName={content}
return ( // avatarUrlValue={avatarUrl}
<ChipDisplay // entityId={entityId}
displayName={content} // />
avatarUrlValue={avatarUrl} // );
entityId={entityId}
/>
);
}; };

View File

@ -1,9 +0,0 @@
import { Tag } from '@/ui/display/tag/components/Tag';
import { useEnumField } from '../../hooks/useEnumField';
export const EnumFieldDisplay = () => {
const { fieldValue } = useEnumField();
return <Tag color={fieldValue.color} text={fieldValue.text} />;
};

View File

@ -1,8 +0,0 @@
import { useMoneyField } from '../../hooks/useMoneyField';
import { MoneyDisplay } from '../content-display/components/MoneyDisplay';
export const MoneyFieldDisplay = () => {
const { fieldValue } = useMoneyField();
return <MoneyDisplay value={fieldValue} />;
};

View File

@ -1,9 +0,0 @@
import { URLDisplay } from '@/ui/object/field/meta-types/display/content-display/components/URLDisplay';
import { useURLField } from '../../hooks/useURLField';
export const URLFieldDisplay = () => {
const { fieldValue } = useURLField();
return <URLDisplay value={fieldValue} />;
};

View File

@ -1,57 +0,0 @@
import { useEffect } from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { FieldContext } from '../../../../contexts/FieldContext';
import { FieldEnumValue } from '../../../../types/FieldMetadata';
import { useEnumField } from '../../../hooks/useEnumField';
import { EnumFieldDisplay } from '../EnumFieldDisplay';
const EnumFieldValueSetterEffect = ({ value }: { value: FieldEnumValue }) => {
const { setFieldValue } = useEnumField();
useEffect(() => {
setFieldValue(value);
}, [setFieldValue, value]);
return null;
};
const meta: Meta = {
title: 'UI/Data/Field/Display/EnumFieldDisplay',
decorators: [
(Story, { args }) => (
<FieldContext.Provider
value={{
entityId: '',
isMainIdentifier: false,
fieldDefinition: {
fieldMetadataId: 'enum',
label: 'Enum',
iconName: 'IconTag',
type: 'ENUM',
metadata: {
fieldName: 'Enum',
},
},
hotkeyScope: 'hotkey-scope',
}}
>
<EnumFieldValueSetterEffect value={args.value} />
<Story />
</FieldContext.Provider>
),
ComponentDecorator,
],
component: EnumFieldDisplay,
args: {
value: { color: 'purple', text: 'Lorem ipsum' },
},
};
export default meta;
type Story = StoryObj<typeof EnumFieldDisplay>;
export const Default: Story = {};

View File

@ -1,68 +0,0 @@
import { useEffect } from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { FieldContext } from '../../../../contexts/FieldContext';
import { useMoneyField } from '../../../hooks/useMoneyField';
import { MoneyFieldDisplay } from '../MoneyFieldDisplay';
const MoneyFieldValueSetterEffect = ({ value }: { value: number }) => {
const { setFieldValue } = useMoneyField();
useEffect(() => {
setFieldValue(value);
}, [setFieldValue, value]);
return null;
};
const meta: Meta = {
title: 'UI/Data/Field/Display/MoneyFieldDisplay',
decorators: [
(Story, { args }) => (
<FieldContext.Provider
value={{
entityId: '',
isMainIdentifier: false,
fieldDefinition: {
fieldMetadataId: 'money',
label: 'Money',
type: 'MONEY_AMOUNT',
iconName: 'Icon123',
metadata: {
fieldName: 'Amount',
placeHolder: 'Amount',
isPositive: true,
},
},
hotkeyScope: 'hotkey-scope',
useUpdateEntityMutation: () => [() => undefined, undefined],
}}
>
<MoneyFieldValueSetterEffect value={args.value} />
<Story />
</FieldContext.Provider>
),
ComponentDecorator,
],
component: MoneyFieldDisplay,
args: {
value: 100,
},
};
export default meta;
type Story = StoryObj<typeof MoneyFieldDisplay>;
export const Default: Story = {};
export const Elipsis: Story = {
args: {
value: 1e100,
},
parameters: {
container: { width: 100 },
},
};

View File

@ -1,66 +0,0 @@
import { useEffect } from 'react';
import { MemoryRouter } from 'react-router';
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { FieldContext } from '../../../../contexts/FieldContext';
import { useURLField } from '../../../hooks/useURLField';
import { URLFieldDisplay } from '../URLFieldDisplay';
const URLFieldValueSetterEffect = ({ value }: { value: string }) => {
const { setFieldValue } = useURLField();
useEffect(() => {
setFieldValue(value);
}, [setFieldValue, value]);
return null;
};
const meta: Meta = {
title: 'UI/Data/Field/Display/URLFieldDisplay',
decorators: [
(Story, { args }) => (
<FieldContext.Provider
value={{
entityId: '',
isMainIdentifier: false,
fieldDefinition: {
fieldMetadataId: 'URL',
label: 'URL',
type: 'URL',
iconName: 'IconLink',
metadata: {
fieldName: 'URL',
placeHolder: 'URL',
},
},
hotkeyScope: 'hotkey-scope',
}}
>
<MemoryRouter>
<URLFieldValueSetterEffect value={args.value} />
<Story />
</MemoryRouter>
</FieldContext.Provider>
),
ComponentDecorator,
],
component: URLFieldDisplay,
args: {
value: 'https://github.com/twentyhq',
},
};
export default meta;
type Story = StoryObj<typeof URLFieldDisplay>;
export const Default: Story = {};
export const Elipsis: Story = {
parameters: {
container: { width: 200 },
},
};

View File

@ -1,55 +0,0 @@
import { useContext } from 'react';
import { useRecoilState } from 'recoil';
import { FieldContext } from '../../contexts/FieldContext';
import { useFieldInitialValue } from '../../hooks/useFieldInitialValue';
import { entityFieldsFamilySelector } from '../../states/selectors/entityFieldsFamilySelector';
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
import { isFieldChip } from '../../types/guards/isFieldChip';
export const useChipField = () => {
const { entityId, fieldDefinition, hotkeyScope } = useContext(FieldContext);
assertFieldMetadata('CHIP', isFieldChip, fieldDefinition);
const contentFieldName = fieldDefinition.metadata.contentFieldName;
const avatarUrlFieldName = fieldDefinition.metadata.urlFieldName;
const [contentFieldValue, setContentFieldValue] = useRecoilState<string>(
entityFieldsFamilySelector({
entityId: entityId,
fieldName: contentFieldName,
}),
);
const [avatarFieldValue, setAvatarFieldValue] = useRecoilState<string>(
entityFieldsFamilySelector({
entityId: entityId,
fieldName: avatarUrlFieldName,
}),
);
const fieldInitialValue = useFieldInitialValue();
const initialContentValue = fieldInitialValue?.isEmpty
? ''
: fieldInitialValue?.value ?? contentFieldValue;
const initialAvatarValue = fieldInitialValue?.isEmpty
? ''
: fieldInitialValue?.value
? ''
: avatarFieldValue;
return {
fieldDefinition,
contentFieldValue,
initialContentValue,
setContentFieldValue,
avatarFieldValue,
initialAvatarValue,
setAvatarFieldValue,
entityId,
hotkeyScope,
};
};

View File

@ -1,75 +0,0 @@
import { useContext } from 'react';
import { useRecoilState } from 'recoil';
import { FieldContext } from '../../contexts/FieldContext';
import { useFieldInitialValue } from '../../hooks/useFieldInitialValue';
import { entityFieldsFamilySelector } from '../../states/selectors/entityFieldsFamilySelector';
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
import { isFieldDoubleTextChip } from '../../types/guards/isFieldDoubleTextChip';
export const useDoubleTextChipField = () => {
const { entityId, fieldDefinition, hotkeyScope } = useContext(FieldContext);
assertFieldMetadata(
'DOUBLE_TEXT_CHIP',
isFieldDoubleTextChip,
fieldDefinition,
);
const [firstValue, setFirstValue] = useRecoilState<string>(
entityFieldsFamilySelector({
entityId: entityId,
fieldName: fieldDefinition.metadata.firstValueFieldName,
}),
);
const [secondValue, setSecondValue] = useRecoilState<string>(
entityFieldsFamilySelector({
entityId: entityId,
fieldName: fieldDefinition.metadata.secondValueFieldName,
}),
);
const [avatarUrl, setAvatarUrl] = useRecoilState<string>(
entityFieldsFamilySelector({
entityId: entityId,
fieldName: fieldDefinition.metadata.avatarUrlFieldName,
}),
);
const fullValue = [firstValue, secondValue].filter(Boolean).join(' ');
const fieldInitialValue = useFieldInitialValue();
const initialFirstValue = fieldInitialValue?.isEmpty
? ''
: fieldInitialValue?.value ?? firstValue;
const initialSecondValue = fieldInitialValue?.isEmpty
? ''
: fieldInitialValue?.value
? ''
: secondValue;
const initialAvatarUrl = fieldInitialValue?.isEmpty
? ''
: fieldInitialValue?.value
? ''
: avatarUrl;
return {
fieldDefinition,
avatarUrl,
setAvatarUrl,
secondValue,
setSecondValue,
firstValue,
setFirstValue,
fullValue,
entityId,
hotkeyScope,
initialAvatarUrl,
initialFirstValue,
initialSecondValue,
};
};

View File

@ -1,47 +0,0 @@
import { useContext } from 'react';
import { useRecoilState } from 'recoil';
import { FieldEnumValue } from '@/ui/object/field/types/FieldMetadata';
import { ThemeColor } from '@/ui/theme/constants/colors';
import { FieldContext } from '../../contexts/FieldContext';
import { useFieldInitialValue } from '../../hooks/useFieldInitialValue';
import { entityFieldsFamilySelector } from '../../states/selectors/entityFieldsFamilySelector';
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
import { isFieldEnum } from '../../types/guards/isFieldEnum';
import { isFieldEnumValue } from '../../types/guards/isFieldEnumValue';
export const useEnumField = () => {
const { entityId, fieldDefinition, hotkeyScope } = useContext(FieldContext);
assertFieldMetadata('ENUM', isFieldEnum, fieldDefinition);
const { fieldName } = fieldDefinition.metadata;
const [fieldValue, setFieldValue] = useRecoilState<FieldEnumValue>(
entityFieldsFamilySelector({
entityId: entityId,
fieldName: fieldName,
}),
);
const fieldEnumValue = isFieldEnumValue(fieldValue)
? fieldValue
: { color: 'green' as ThemeColor, text: '' };
const fieldInitialValue = useFieldInitialValue();
const initialValue = {
color: 'green' as ThemeColor,
text: fieldInitialValue?.isEmpty
? ''
: fieldInitialValue?.value ?? fieldEnumValue?.text ?? '',
};
return {
fieldDefinition,
fieldValue: fieldEnumValue,
initialValue,
setFieldValue,
hotkeyScope,
};
};

View File

@ -1,58 +0,0 @@
import { useContext } from 'react';
import { useRecoilState } from 'recoil';
import {
canBeCastAsIntegerOrNull,
castAsIntegerOrNull,
} from '~/utils/cast-as-integer-or-null';
import { FieldContext } from '../../contexts/FieldContext';
import { useFieldInitialValue } from '../../hooks/useFieldInitialValue';
import { usePersistField } from '../../hooks/usePersistField';
import { entityFieldsFamilySelector } from '../../states/selectors/entityFieldsFamilySelector';
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
import { isFieldMoney } from '../../types/guards/isFieldMoney';
export const useMoneyField = () => {
const { entityId, fieldDefinition, hotkeyScope } = useContext(FieldContext);
assertFieldMetadata('MONEY_AMOUNT', isFieldMoney, fieldDefinition);
const fieldName = fieldDefinition.metadata.fieldName;
const [fieldValue, setFieldValue] = useRecoilState<number | null>(
entityFieldsFamilySelector({
entityId: entityId,
fieldName: fieldName,
}),
);
const persistField = usePersistField();
const persistMoneyField = (newValue: string) => {
if (!canBeCastAsIntegerOrNull(newValue)) {
return;
}
const castedValue = castAsIntegerOrNull(newValue);
persistField(castedValue);
};
const fieldInitialValue = useFieldInitialValue();
const initialValue = fieldInitialValue?.isEmpty
? null
: !isNaN(Number(fieldInitialValue?.value))
? Number(fieldInitialValue?.value)
: null ?? fieldValue;
return {
fieldDefinition,
fieldValue,
initialValue,
setFieldValue,
hotkeyScope,
persistMoneyField,
};
};

View File

@ -1,53 +0,0 @@
import { useContext } from 'react';
import { useRecoilState } from 'recoil';
import { isURL } from '~/utils/is-url';
import { FieldContext } from '../../contexts/FieldContext';
import { useFieldInitialValue } from '../../hooks/useFieldInitialValue';
import { usePersistField } from '../../hooks/usePersistField';
import { entityFieldsFamilySelector } from '../../states/selectors/entityFieldsFamilySelector';
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
import { isFieldURL } from '../../types/guards/isFieldURL';
import { isFieldURLValue } from '../../types/guards/isFieldURLValue';
export const useURLField = () => {
const { entityId, fieldDefinition, hotkeyScope } = useContext(FieldContext);
assertFieldMetadata('URL', isFieldURL, fieldDefinition);
const fieldName = fieldDefinition.metadata.fieldName;
const [fieldValue, setFieldValue] = useRecoilState<string>(
entityFieldsFamilySelector({
entityId: entityId,
fieldName: fieldName,
}),
);
const fieldUrlValue = isFieldURLValue(fieldValue) ? fieldValue : '';
const fieldInitialValue = useFieldInitialValue();
const initialValue = fieldInitialValue?.isEmpty
? ''
: fieldInitialValue?.value ?? fieldUrlValue;
const persistField = usePersistField();
const persistURLField = (newValue: string) => {
if (!isURL(newValue) && newValue !== '') {
return;
}
persistField(newValue);
};
return {
fieldDefinition,
fieldValue: fieldUrlValue,
initialValue,
setFieldValue,
hotkeyScope,
persistURLField,
};
};

View File

@ -1,66 +0,0 @@
import { TextInput } from '@/ui/object/field/meta-types/input/components/internal/TextInput';
import { usePersistField } from '../../../hooks/usePersistField';
import { useChipField } from '../../hooks/useChipField';
import { FieldInputOverlay } from './internal/FieldInputOverlay';
import { FieldInputEvent } from './DateFieldInput';
export type ChipFieldInputProps = {
onClickOutside?: FieldInputEvent;
onEnter?: FieldInputEvent;
onEscape?: FieldInputEvent;
onTab?: FieldInputEvent;
onShiftTab?: FieldInputEvent;
};
export const ChipFieldInput = ({
onEnter,
onEscape,
onClickOutside,
onTab,
onShiftTab,
}: ChipFieldInputProps) => {
const { fieldDefinition, initialContentValue, hotkeyScope } = useChipField();
const persistField = usePersistField();
const handleEnter = (newText: string) => {
onEnter?.(() => persistField(newText));
};
const handleEscape = (newText: string) => {
onEscape?.(() => persistField(newText));
};
const handleClickOutside = (
event: MouseEvent | TouchEvent,
newText: string,
) => {
onClickOutside?.(() => persistField(newText));
};
const handleTab = (newText: string) => {
onTab?.(() => persistField(newText));
};
const handleShiftTab = (newText: string) => {
onShiftTab?.(() => persistField(newText));
};
return (
<FieldInputOverlay>
<TextInput
placeholder={fieldDefinition.metadata.placeHolder}
autoFocus
value={initialContentValue}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
onShiftTab={handleShiftTab}
onTab={handleTab}
hotkeyScope={hotkeyScope}
/>
</FieldInputOverlay>
);
};

View File

@ -1,13 +1,13 @@
import { useFullNameField } from '@/ui/object/field/meta-types/hooks/useFullNameField';
import { DoubleTextInput } from '@/ui/object/field/meta-types/input/components/internal/DoubleTextInput'; import { DoubleTextInput } from '@/ui/object/field/meta-types/input/components/internal/DoubleTextInput';
import { FieldDoubleText } from '@/ui/object/field/types/FieldDoubleText'; import { FieldDoubleText } from '@/ui/object/field/types/FieldDoubleText';
import { usePersistField } from '../../../hooks/usePersistField'; import { usePersistField } from '../../../hooks/usePersistField';
import { useDoubleTextChipField } from '../../hooks/useDoubleTextChipField';
import { FieldInputOverlay } from './internal/FieldInputOverlay'; import { FieldInputOverlay } from './internal/FieldInputOverlay';
import { FieldInputEvent } from './DateFieldInput'; import { FieldInputEvent } from './DateFieldInput';
export type DoubleTextChipFieldInputProps = { export type FullNameFieldInputProps = {
onClickOutside?: FieldInputEvent; onClickOutside?: FieldInputEvent;
onEnter?: FieldInputEvent; onEnter?: FieldInputEvent;
onEscape?: FieldInputEvent; onEscape?: FieldInputEvent;
@ -15,52 +15,53 @@ export type DoubleTextChipFieldInputProps = {
onShiftTab?: FieldInputEvent; onShiftTab?: FieldInputEvent;
}; };
export const DoubleTextChipFieldInput = ({ export const FullNameFieldInput = ({
onEnter, onEnter,
onEscape, onEscape,
onClickOutside, onClickOutside,
onTab, onTab,
onShiftTab, onShiftTab,
}: DoubleTextChipFieldInputProps) => { }: FullNameFieldInputProps) => {
const { const { hotkeyScope, initialValue } = useFullNameField();
fieldDefinition,
initialFirstValue,
initialSecondValue,
hotkeyScope,
} = useDoubleTextChipField();
const persistField = usePersistField(); const persistField = usePersistField();
const convertToFullName = (newDoubleText: FieldDoubleText) => {
return {
firstName: newDoubleText.firstValue,
lastName: newDoubleText.secondValue,
};
};
const handleEnter = (newDoubleText: FieldDoubleText) => { const handleEnter = (newDoubleText: FieldDoubleText) => {
onEnter?.(() => persistField(newDoubleText)); onEnter?.(() => persistField(convertToFullName(newDoubleText)));
}; };
const handleEscape = (newDoubleText: FieldDoubleText) => { const handleEscape = (newDoubleText: FieldDoubleText) => {
onEscape?.(() => persistField(newDoubleText)); onEscape?.(() => persistField(convertToFullName(newDoubleText)));
}; };
const handleClickOutside = ( const handleClickOutside = (
event: MouseEvent | TouchEvent, event: MouseEvent | TouchEvent,
newDoubleText: FieldDoubleText, newDoubleText: FieldDoubleText,
) => { ) => {
onClickOutside?.(() => persistField(newDoubleText)); onClickOutside?.(() => persistField(convertToFullName(newDoubleText)));
}; };
const handleTab = (newDoubleText: FieldDoubleText) => { const handleTab = (newDoubleText: FieldDoubleText) => {
onTab?.(() => persistField(newDoubleText)); onTab?.(() => persistField(convertToFullName(newDoubleText)));
}; };
const handleShiftTab = (newDoubleText: FieldDoubleText) => { const handleShiftTab = (newDoubleText: FieldDoubleText) => {
onShiftTab?.(() => persistField(newDoubleText)); onShiftTab?.(() => persistField(convertToFullName(newDoubleText)));
}; };
return ( return (
<FieldInputOverlay> <FieldInputOverlay>
<DoubleTextInput <DoubleTextInput
firstValue={initialFirstValue} firstValue={initialValue.firstName}
secondValue={initialSecondValue} secondValue={initialValue.lastName}
firstValuePlaceholder={fieldDefinition.metadata.firstValuePlaceholder} firstValuePlaceholder={'First name'}
secondValuePlaceholder={fieldDefinition.metadata.secondValuePlaceholder} secondValuePlaceholder={'Last name'}
onClickOutside={handleClickOutside} onClickOutside={handleClickOutside}
onEnter={handleEnter} onEnter={handleEnter}
onEscape={handleEscape} onEscape={handleEscape}

View File

@ -1,65 +0,0 @@
import { TextInput } from '@/ui/object/field/meta-types/input/components/internal/TextInput';
import { useMoneyField } from '../../hooks/useMoneyField';
import { FieldInputOverlay } from './internal/FieldInputOverlay';
export type FieldInputEvent = (persist: () => void) => void;
export type MoneyFieldInputProps = {
onClickOutside?: FieldInputEvent;
onEnter?: FieldInputEvent;
onEscape?: FieldInputEvent;
onTab?: FieldInputEvent;
onShiftTab?: FieldInputEvent;
};
export const MoneyFieldInput = ({
onEnter,
onEscape,
onClickOutside,
onTab,
onShiftTab,
}: MoneyFieldInputProps) => {
const { fieldDefinition, hotkeyScope, persistMoneyField, initialValue } =
useMoneyField();
const handleEnter = (newText: string) => {
onEnter?.(() => persistMoneyField(newText));
};
const handleEscape = (newText: string) => {
onEscape?.(() => persistMoneyField(newText));
};
const handleClickOutside = (
event: MouseEvent | TouchEvent,
newText: string,
) => {
onClickOutside?.(() => persistMoneyField(newText));
};
const handleTab = (newText: string) => {
onTab?.(() => persistMoneyField(newText));
};
const handleShiftTab = (newText: string) => {
onShiftTab?.(() => persistMoneyField(newText));
};
return (
<FieldInputOverlay>
<TextInput
placeholder={fieldDefinition.metadata.placeHolder}
autoFocus
value={initialValue?.toLocaleString() ?? ''}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
onShiftTab={handleShiftTab}
onTab={handleTab}
hotkeyScope={hotkeyScope}
/>
</FieldInputOverlay>
);
};

View File

@ -1,64 +0,0 @@
import { TextInput } from '@/ui/object/field/meta-types/input/components/internal/TextInput';
import { useURLField } from '../../hooks/useURLField';
import { FieldInputOverlay } from './internal/FieldInputOverlay';
import { FieldInputEvent } from './DateFieldInput';
export type URLFieldInputProps = {
onClickOutside?: FieldInputEvent;
onEnter?: FieldInputEvent;
onEscape?: FieldInputEvent;
onTab?: FieldInputEvent;
onShiftTab?: FieldInputEvent;
};
export const URLFieldInput = ({
onEnter,
onEscape,
onClickOutside,
onTab,
onShiftTab,
}: URLFieldInputProps) => {
const { fieldDefinition, initialValue, hotkeyScope, persistURLField } =
useURLField();
const handleEnter = (newText: string) => {
onEnter?.(() => persistURLField(newText));
};
const handleEscape = (newText: string) => {
onEscape?.(() => persistURLField(newText));
};
const handleClickOutside = (
event: MouseEvent | TouchEvent,
newText: string,
) => {
onClickOutside?.(() => persistURLField(newText));
};
const handleTab = (newText: string) => {
onTab?.(() => persistURLField(newText));
};
const handleShiftTab = (newText: string) => {
onShiftTab?.(() => persistURLField(newText));
};
return (
<FieldInputOverlay>
<TextInput
placeholder={fieldDefinition.metadata.placeHolder}
autoFocus
value={initialValue}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
onShiftTab={handleShiftTab}
onTab={handleTab}
hotkeyScope={hotkeyScope}
/>
</FieldInputOverlay>
);
};

View File

@ -1,176 +0,0 @@
import { useEffect } from 'react';
import { expect, jest } from '@storybook/jest';
import { Decorator, Meta, StoryObj } from '@storybook/react';
import { userEvent, waitFor, within } from '@storybook/testing-library';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
import { useChipField } from '../../../hooks/useChipField';
import { ChipFieldInput, ChipFieldInputProps } from '../ChipFieldInput';
const ChipFieldValueSetterEffect = ({ value }: { value: string }) => {
const { setContentFieldValue } = useChipField();
useEffect(() => {
setContentFieldValue(value);
}, [setContentFieldValue, value]);
return <></>;
};
type ChipFieldInputWithContextProps = ChipFieldInputProps & {
value: string;
entityId?: string;
};
const ChipFieldInputWithContext = ({
entityId,
value,
onEnter,
onEscape,
onClickOutside,
onTab,
onShiftTab,
}: ChipFieldInputWithContextProps) => {
const setHotKeyScope = useSetHotkeyScope();
useEffect(() => {
setHotKeyScope('hotkey-scope');
}, [setHotKeyScope]);
return (
<div>
<FieldContextProvider
fieldDefinition={{
fieldMetadataId: 'chip',
label: 'Chip',
type: 'CHIP',
iconName: 'Icon123',
metadata: {
contentFieldName: 'name',
urlFieldName: 'xURL',
placeHolder: 'X URL',
},
}}
entityId={entityId}
>
<ChipFieldValueSetterEffect value={value} />
<ChipFieldInput
onEnter={onEnter}
onEscape={onEscape}
onClickOutside={onClickOutside}
onTab={onTab}
onShiftTab={onShiftTab}
/>
</FieldContextProvider>
<div data-testid="data-field-input-click-outside-div" />
</div>
);
};
const enterJestFn = jest.fn();
const escapeJestfn = jest.fn();
const clickOutsideJestFn = jest.fn();
const tabJestFn = jest.fn();
const shiftTabJestFn = jest.fn();
const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) {
enterJestFn.mockClear();
escapeJestfn.mockClear();
clickOutsideJestFn.mockClear();
tabJestFn.mockClear();
shiftTabJestFn.mockClear();
}
return <Story />;
};
const meta: Meta = {
title: 'UI/Data/Field/Input/ChipFieldInput',
component: ChipFieldInputWithContext,
args: {
value: 'chip',
onEnter: enterJestFn,
onEscape: escapeJestfn,
onClickOutside: clickOutsideJestFn,
onTab: tabJestFn,
onShiftTab: shiftTabJestFn,
},
argTypes: {
onEnter: { control: false },
onEscape: { control: false },
onClickOutside: { control: false },
onTab: { control: false },
onShiftTab: { control: false },
},
parameters: {
clearMocks: true,
},
decorators: [clearMocksDecorator],
};
export default meta;
type Story = StoryObj<typeof ChipFieldInputWithContext>;
export const Default: Story = {};
export const Enter: Story = {
play: async () => {
expect(enterJestFn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{enter}');
expect(enterJestFn).toHaveBeenCalledTimes(1);
});
},
};
export const Escape: Story = {
play: async () => {
expect(escapeJestfn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{esc}');
expect(escapeJestfn).toHaveBeenCalledTimes(1);
});
},
};
export const ClickOutside: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(clickOutsideJestFn).toHaveBeenCalledTimes(0);
const emptyDiv = canvas.getByTestId('data-field-input-click-outside-div');
await waitFor(() => {
userEvent.click(emptyDiv);
expect(clickOutsideJestFn).toHaveBeenCalledTimes(1);
});
},
};
export const Tab: Story = {
play: async () => {
expect(tabJestFn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{tab}');
expect(tabJestFn).toHaveBeenCalledTimes(1);
});
},
};
export const ShiftTab: Story = {
play: async () => {
expect(shiftTabJestFn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{shift>}{tab}');
expect(shiftTabJestFn).toHaveBeenCalledTimes(1);
});
},
};

View File

@ -1,194 +0,0 @@
import { useEffect } from 'react';
import { expect, jest } from '@storybook/jest';
import { Decorator, Meta, StoryObj } from '@storybook/react';
import { userEvent, waitFor, within } from '@storybook/testing-library';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
import { useDoubleTextChipField } from '../../../hooks/useDoubleTextChipField';
import {
DoubleTextChipFieldInput,
DoubleTextChipFieldInputProps,
} from '../DoubleTextChipFieldInput';
const DoubleTextChipFieldValueSetterEffect = ({
firstValue,
secondValue,
}: {
firstValue: string;
secondValue: string;
}) => {
const { setFirstValue, setSecondValue } = useDoubleTextChipField();
useEffect(() => {
setFirstValue(firstValue);
setSecondValue(secondValue);
}, [firstValue, secondValue, setFirstValue, setSecondValue]);
return <></>;
};
type DoubleTextChipFieldInputWithContextProps =
DoubleTextChipFieldInputProps & {
firstValue: string;
secondValue: string;
entityId?: string;
};
const DoubleTextChipFieldInputWithContext = ({
entityId,
firstValue,
secondValue,
onClickOutside,
onEnter,
onEscape,
onTab,
onShiftTab,
}: DoubleTextChipFieldInputWithContextProps) => {
const setHotKeyScope = useSetHotkeyScope();
useEffect(() => {
setHotKeyScope('hotkey-scope');
}, [setHotKeyScope]);
return (
<div>
<FieldContextProvider
fieldDefinition={{
fieldMetadataId: 'double-text-chip',
label: 'Double-Text-Chip',
type: 'DOUBLE_TEXT_CHIP',
iconName: 'IconUser',
metadata: {
firstValueFieldName: 'First-text',
firstValuePlaceholder: 'First-text',
secondValueFieldName: 'Second-text',
secondValuePlaceholder: 'Second-text',
avatarUrlFieldName: 'avatarUrl',
fieldName: '',
},
}}
entityId={entityId}
>
<DoubleTextChipFieldValueSetterEffect
{...{ firstValue, secondValue }}
/>
<DoubleTextChipFieldInput
onEnter={onEnter}
onEscape={onEscape}
onClickOutside={onClickOutside}
onTab={onTab}
onShiftTab={onShiftTab}
/>
</FieldContextProvider>
<div data-testid="data-field-input-click-outside-div" />
</div>
);
};
const enterJestFn = jest.fn();
const escapeJestfn = jest.fn();
const clickOutsideJestFn = jest.fn();
const tabJestFn = jest.fn();
const shiftTabJestFn = jest.fn();
const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) {
enterJestFn.mockClear();
escapeJestfn.mockClear();
clickOutsideJestFn.mockClear();
tabJestFn.mockClear();
shiftTabJestFn.mockClear();
}
return <Story />;
};
const meta: Meta = {
title: 'UI/Data/Field/Input/DoubleTextChipFieldInput',
component: DoubleTextChipFieldInputWithContext,
args: {
firstValue: 'first value',
secondValue: 'second value',
onEnter: enterJestFn,
onEscape: escapeJestfn,
onClickOutside: clickOutsideJestFn,
onTab: tabJestFn,
onShiftTab: shiftTabJestFn,
},
argTypes: {
onEnter: { control: false },
onEscape: { control: false },
onClickOutside: { control: false },
onTab: { control: false },
onShiftTab: { control: false },
},
parameters: {
clearMocks: true,
},
decorators: [clearMocksDecorator],
};
export default meta;
type Story = StoryObj<typeof DoubleTextChipFieldInputWithContext>;
export const Default: Story = {};
export const Enter: Story = {
play: async () => {
expect(enterJestFn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{enter}');
expect(enterJestFn).toHaveBeenCalledTimes(1);
});
},
};
export const Escape: Story = {
play: async () => {
expect(escapeJestfn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{esc}');
expect(escapeJestfn).toHaveBeenCalledTimes(1);
});
},
};
export const ClickOutside: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(clickOutsideJestFn).toHaveBeenCalledTimes(0);
const emptyDiv = canvas.getByTestId('data-field-input-click-outside-div');
await waitFor(() => {
userEvent.click(emptyDiv);
expect(clickOutsideJestFn).toHaveBeenCalledTimes(1);
});
},
};
export const Tab: Story = {
play: async () => {
expect(tabJestFn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{tab}');
expect(tabJestFn).toHaveBeenCalledTimes(1);
});
},
};
export const ShiftTab: Story = {
play: async () => {
expect(shiftTabJestFn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{shift>}{tab}');
expect(shiftTabJestFn).toHaveBeenCalledTimes(1);
});
},
};

View File

@ -1,176 +0,0 @@
import { useEffect } from 'react';
import { expect, jest } from '@storybook/jest';
import { Decorator, Meta, StoryObj } from '@storybook/react';
import { userEvent, waitFor, within } from '@storybook/testing-library';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
import { useMoneyField } from '../../../hooks/useMoneyField';
import { MoneyFieldInput, MoneyFieldInputProps } from '../MoneyFieldInput';
const MoneyFieldValueSetterEffect = ({ value }: { value: number }) => {
const { setFieldValue } = useMoneyField();
useEffect(() => {
setFieldValue(value);
}, [setFieldValue, value]);
return <></>;
};
type MoneyFieldInputWithContextProps = MoneyFieldInputProps & {
value: number;
entityId?: string;
};
const MoneyFieldInputWithContext = ({
entityId,
value,
onEnter,
onEscape,
onClickOutside,
onTab,
onShiftTab,
}: MoneyFieldInputWithContextProps) => {
const setHotKeyScope = useSetHotkeyScope();
useEffect(() => {
setHotKeyScope('hotkey-scope');
}, [setHotKeyScope]);
return (
<div>
<FieldContextProvider
fieldDefinition={{
fieldMetadataId: 'moneyAmount',
label: 'MoneyAmout',
type: 'MONEY_AMOUNT',
iconName: 'Icon123',
metadata: {
fieldName: 'moneyAmount',
placeHolder: 'Enter Amount',
},
}}
entityId={entityId}
>
<MoneyFieldValueSetterEffect value={value} />
<MoneyFieldInput
onEnter={onEnter}
onEscape={onEscape}
onClickOutside={onClickOutside}
onTab={onTab}
onShiftTab={onShiftTab}
/>
</FieldContextProvider>
<div data-testid="data-field-input-click-outside-div" />
</div>
);
};
const enterJestFn = jest.fn();
const escapeJestfn = jest.fn();
const clickOutsideJestFn = jest.fn();
const tabJestFn = jest.fn();
const shiftTabJestFn = jest.fn();
const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) {
enterJestFn.mockClear();
escapeJestfn.mockClear();
clickOutsideJestFn.mockClear();
tabJestFn.mockClear();
shiftTabJestFn.mockClear();
}
return <Story />;
};
const meta: Meta = {
title: 'UI/Data/Field/Input/MoneyFieldInput',
component: MoneyFieldInputWithContext,
args: {
value: 1000,
isPositive: true,
onEnter: enterJestFn,
onEscape: escapeJestfn,
onClickOutside: clickOutsideJestFn,
onTab: tabJestFn,
onShiftTab: shiftTabJestFn,
},
argTypes: {
onEnter: { control: false },
onEscape: { control: false },
onClickOutside: { control: false },
onTab: { control: false },
onShiftTab: { control: false },
},
decorators: [clearMocksDecorator],
parameters: {
clearMocks: true,
},
};
export default meta;
type Story = StoryObj<typeof MoneyFieldInputWithContext>;
export const Default: Story = {};
export const Enter: Story = {
play: async () => {
expect(enterJestFn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{enter}');
expect(enterJestFn).toHaveBeenCalledTimes(1);
});
},
};
export const Escape: Story = {
play: async () => {
expect(escapeJestfn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{esc}');
expect(escapeJestfn).toHaveBeenCalledTimes(1);
});
},
};
export const ClickOutside: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(clickOutsideJestFn).toHaveBeenCalledTimes(0);
const emptyDiv = canvas.getByTestId('data-field-input-click-outside-div');
await waitFor(() => {
userEvent.click(emptyDiv);
expect(clickOutsideJestFn).toHaveBeenCalledTimes(1);
});
},
};
export const Tab: Story = {
play: async () => {
expect(tabJestFn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{tab}');
expect(tabJestFn).toHaveBeenCalledTimes(1);
});
},
};
export const ShiftTab: Story = {
play: async () => {
expect(shiftTabJestFn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{shift>}{tab}');
expect(shiftTabJestFn).toHaveBeenCalledTimes(1);
});
},
};

View File

@ -1,175 +0,0 @@
import { useEffect } from 'react';
import { expect, jest } from '@storybook/jest';
import { Decorator, Meta, StoryObj } from '@storybook/react';
import { userEvent, waitFor, within } from '@storybook/testing-library';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
import { useURLField } from '../../../hooks/useURLField';
import { URLFieldInput, URLFieldInputProps } from '../URLFieldInput';
const URLFieldValueSetterEffect = ({ value }: { value: string }) => {
const { setFieldValue } = useURLField();
useEffect(() => {
setFieldValue(value);
}, [setFieldValue, value]);
return <></>;
};
type URLFieldInputWithContextProps = URLFieldInputProps & {
value: string;
entityId?: string;
};
const URLFieldInputWithContext = ({
entityId,
value,
onEnter,
onEscape,
onClickOutside,
onTab,
onShiftTab,
}: URLFieldInputWithContextProps) => {
const setHotKeyScope = useSetHotkeyScope();
useEffect(() => {
setHotKeyScope('hotkey-scope');
}, [setHotKeyScope]);
return (
<div>
<FieldContextProvider
fieldDefinition={{
fieldMetadataId: 'url',
label: 'URL',
type: 'URL',
iconName: 'IconLink',
metadata: {
fieldName: 'URL',
placeHolder: 'Enter URL',
},
}}
entityId={entityId}
>
<URLFieldValueSetterEffect value={value} />
<URLFieldInput
onEnter={onEnter}
onEscape={onEscape}
onClickOutside={onClickOutside}
onTab={onTab}
onShiftTab={onShiftTab}
/>
</FieldContextProvider>
<div data-testid="data-field-input-click-outside-div" />
</div>
);
};
const enterJestFn = jest.fn();
const escapeJestfn = jest.fn();
const clickOutsideJestFn = jest.fn();
const tabJestFn = jest.fn();
const shiftTabJestFn = jest.fn();
const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) {
enterJestFn.mockClear();
escapeJestfn.mockClear();
clickOutsideJestFn.mockClear();
tabJestFn.mockClear();
shiftTabJestFn.mockClear();
}
return <Story />;
};
const meta: Meta = {
title: 'UI/Data/Field/Input/URLFieldInput',
component: URLFieldInputWithContext,
args: {
value: 'https://username.domain',
onEnter: enterJestFn,
onEscape: escapeJestfn,
onClickOutside: clickOutsideJestFn,
onTab: tabJestFn,
onShiftTab: shiftTabJestFn,
},
argTypes: {
onEnter: { control: false },
onEscape: { control: false },
onClickOutside: { control: false },
onTab: { control: false },
onShiftTab: { control: false },
},
decorators: [clearMocksDecorator],
parameters: {
clearMocks: true,
},
};
export default meta;
type Story = StoryObj<typeof URLFieldInputWithContext>;
export const Default: Story = {};
export const Enter: Story = {
play: async () => {
expect(enterJestFn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{enter}');
expect(enterJestFn).toHaveBeenCalledTimes(1);
});
},
};
export const Escape: Story = {
play: async () => {
expect(escapeJestfn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{esc}');
expect(escapeJestfn).toHaveBeenCalledTimes(1);
});
},
};
export const ClickOutside: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(clickOutsideJestFn).toHaveBeenCalledTimes(0);
const emptyDiv = canvas.getByTestId('data-field-input-click-outside-div');
await waitFor(() => {
userEvent.click(emptyDiv);
expect(clickOutsideJestFn).toHaveBeenCalledTimes(1);
});
},
};
export const Tab: Story = {
play: async () => {
expect(tabJestFn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{tab}');
expect(tabJestFn).toHaveBeenCalledTimes(1);
});
},
};
export const ShiftTab: Story = {
play: async () => {
expect(shiftTabJestFn).toHaveBeenCalledTimes(0);
await waitFor(() => {
userEvent.keyboard('{shift>}{tab}');
expect(shiftTabJestFn).toHaveBeenCalledTimes(1);
});
},
};

View File

@ -8,22 +8,18 @@ import { assertNotNull } from '~/utils/assert';
import { FieldDefinition } from '../../types/FieldDefinition'; import { FieldDefinition } from '../../types/FieldDefinition';
import { FieldMetadata } from '../../types/FieldMetadata'; import { FieldMetadata } from '../../types/FieldMetadata';
import { isFieldBoolean } from '../../types/guards/isFieldBoolean'; import { isFieldBoolean } from '../../types/guards/isFieldBoolean';
import { isFieldChip } from '../../types/guards/isFieldChip';
import { isFieldCurrency } from '../../types/guards/isFieldCurrency'; import { isFieldCurrency } from '../../types/guards/isFieldCurrency';
import { isFieldCurrencyValue } from '../../types/guards/isFieldCurrencyValue'; import { isFieldCurrencyValue } from '../../types/guards/isFieldCurrencyValue';
import { isFieldDate } from '../../types/guards/isFieldDate'; import { isFieldDate } from '../../types/guards/isFieldDate';
import { isFieldDoubleTextChip } from '../../types/guards/isFieldDoubleTextChip';
import { isFieldEmail } from '../../types/guards/isFieldEmail'; import { isFieldEmail } from '../../types/guards/isFieldEmail';
import { isFieldLink } from '../../types/guards/isFieldLink'; import { isFieldLink } from '../../types/guards/isFieldLink';
import { isFieldLinkValue } from '../../types/guards/isFieldLinkValue'; import { isFieldLinkValue } from '../../types/guards/isFieldLinkValue';
import { isFieldMoney } from '../../types/guards/isFieldMoney';
import { isFieldNumber } from '../../types/guards/isFieldNumber'; import { isFieldNumber } from '../../types/guards/isFieldNumber';
import { isFieldPhone } from '../../types/guards/isFieldPhone'; import { isFieldPhone } from '../../types/guards/isFieldPhone';
import { isFieldProbability } from '../../types/guards/isFieldProbability'; import { isFieldProbability } from '../../types/guards/isFieldProbability';
import { isFieldRelation } from '../../types/guards/isFieldRelation'; import { isFieldRelation } from '../../types/guards/isFieldRelation';
import { isFieldRelationValue } from '../../types/guards/isFieldRelationValue'; import { isFieldRelationValue } from '../../types/guards/isFieldRelationValue';
import { isFieldText } from '../../types/guards/isFieldText'; import { isFieldText } from '../../types/guards/isFieldText';
import { isFieldURL } from '../../types/guards/isFieldURL';
import { entityFieldsFamilyState } from '../entityFieldsFamilyState'; import { entityFieldsFamilyState } from '../entityFieldsFamilyState';
const isValueEmpty = (value: unknown) => !assertNotNull(value) || value === ''; const isValueEmpty = (value: unknown) => !assertNotNull(value) || value === '';
@ -32,27 +28,24 @@ export const isEntityFieldEmptyFamilySelector = selectorFamily({
key: 'isEntityFieldEmptyFamilySelector', key: 'isEntityFieldEmptyFamilySelector',
get: ({ get: ({
fieldDefinition, fieldDefinition,
fieldName,
entityId, entityId,
}: { }: {
fieldDefinition: Pick<FieldDefinition<FieldMetadata>, 'type'> & { fieldDefinition: Pick<FieldDefinition<FieldMetadata>, 'type'>;
metadata: Omit<FieldMetadata, 'mainIdentifierMapper'>; fieldName: string;
};
entityId: string; entityId: string;
}) => { }) => {
return ({ get }) => { return ({ get }) => {
if ( if (
isFieldUuid(fieldDefinition) || isFieldUuid(fieldDefinition) ||
isFieldText(fieldDefinition) || isFieldText(fieldDefinition) ||
isFieldURL(fieldDefinition) ||
isFieldDate(fieldDefinition) || isFieldDate(fieldDefinition) ||
isFieldNumber(fieldDefinition) || isFieldNumber(fieldDefinition) ||
isFieldProbability(fieldDefinition) || isFieldProbability(fieldDefinition) ||
isFieldMoney(fieldDefinition) ||
isFieldEmail(fieldDefinition) || isFieldEmail(fieldDefinition) ||
isFieldBoolean(fieldDefinition) || isFieldBoolean(fieldDefinition) ||
isFieldPhone(fieldDefinition) isFieldPhone(fieldDefinition)
) { ) {
const fieldName = fieldDefinition.metadata.fieldName;
const fieldValue = get(entityFieldsFamilyState(entityId))?.[ const fieldValue = get(entityFieldsFamilyState(entityId))?.[
fieldName fieldName
] as string | number | boolean | null; ] as string | number | boolean | null;
@ -61,46 +54,12 @@ export const isEntityFieldEmptyFamilySelector = selectorFamily({
} }
if (isFieldRelation(fieldDefinition)) { if (isFieldRelation(fieldDefinition)) {
const fieldName = fieldDefinition.metadata.fieldName;
const fieldValue = get(entityFieldsFamilyState(entityId))?.[fieldName]; const fieldValue = get(entityFieldsFamilyState(entityId))?.[fieldName];
return isFieldRelationValue(fieldValue) && isValueEmpty(fieldValue); return isFieldRelationValue(fieldValue) && isValueEmpty(fieldValue);
} }
if (isFieldChip(fieldDefinition)) {
const contentFieldName = fieldDefinition.metadata.contentFieldName;
const contentFieldValue = get(entityFieldsFamilyState(entityId))?.[
contentFieldName
] as string | null;
return isValueEmpty(contentFieldValue);
}
if (isFieldDoubleTextChip(fieldDefinition)) {
const firstValueFieldName =
fieldDefinition.metadata.firstValueFieldName;
const secondValueFieldName =
fieldDefinition.metadata.secondValueFieldName;
const contentFieldFirstValue = get(entityFieldsFamilyState(entityId))?.[
firstValueFieldName
] as string | null;
const contentFieldSecondValue = get(
entityFieldsFamilyState(entityId),
)?.[secondValueFieldName] as string | null;
return (
isValueEmpty(contentFieldFirstValue) &&
isValueEmpty(contentFieldSecondValue)
);
}
if (isFieldCurrency(fieldDefinition)) { if (isFieldCurrency(fieldDefinition)) {
const fieldName = fieldDefinition.metadata.fieldName;
const fieldValue = get(entityFieldsFamilyState(entityId))?.[fieldName]; const fieldValue = get(entityFieldsFamilyState(entityId))?.[fieldName];
return ( return (
@ -110,7 +69,6 @@ export const isEntityFieldEmptyFamilySelector = selectorFamily({
} }
if (isFieldFullName(fieldDefinition)) { if (isFieldFullName(fieldDefinition)) {
const fieldName = fieldDefinition.metadata.fieldName;
const fieldValue = get(entityFieldsFamilyState(entityId))?.[fieldName]; const fieldValue = get(entityFieldsFamilyState(entityId))?.[fieldName];
return ( return (
@ -120,7 +78,6 @@ export const isEntityFieldEmptyFamilySelector = selectorFamily({
} }
if (isFieldLink(fieldDefinition)) { if (isFieldLink(fieldDefinition)) {
const fieldName = fieldDefinition.metadata.fieldName;
const fieldValue = get(entityFieldsFamilyState(entityId))?.[fieldName]; const fieldValue = get(entityFieldsFamilyState(entityId))?.[fieldName];
return !isFieldLinkValue(fieldValue) || isValueEmpty(fieldValue?.url); return !isFieldLinkValue(fieldValue) || isValueEmpty(fieldValue?.url);

View File

@ -1,9 +1,11 @@
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect'; import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
import { MainIdentifierMapper } from '@/ui/object/field/types/MainIdentifierMapper'; import { MainIdentifierMapper } from '@/ui/object/field/types/MainIdentifierMapper';
import { ThemeColor } from '@/ui/theme/constants/colors';
export type FieldUuidMetadata = { export type FieldUuidMetadata = {
placeHolder: string; fieldName: string;
};
export type FieldBooleanMetadata = {
fieldName: string; fieldName: string;
}; };
@ -12,22 +14,8 @@ export type FieldTextMetadata = {
fieldName: string; fieldName: string;
}; };
export type FieldPhoneMetadata = {
placeHolder: string;
fieldName: string;
};
export type FieldURLMetadata = {
placeHolder: string;
fieldName: string;
};
export type FieldLinkMetadata = {
placeHolder: string;
fieldName: string;
};
export type FieldDateMetadata = { export type FieldDateMetadata = {
placeHolder: string;
fieldName: string; fieldName: string;
}; };
@ -37,10 +25,9 @@ export type FieldNumberMetadata = {
isPositive?: boolean; isPositive?: boolean;
}; };
export type FieldMoneyMetadata = { export type FieldLinkMetadata = {
fieldName: string;
placeHolder: string; placeHolder: string;
isPositive?: boolean; fieldName: string;
}; };
export type FieldCurrencyMetadata = { export type FieldCurrencyMetadata = {
@ -49,13 +36,23 @@ export type FieldCurrencyMetadata = {
isPositive?: boolean; isPositive?: boolean;
}; };
export type FieldFullnameMetadata = { export type FieldFullNameMetadata = {
placeHolder: string;
fieldName: string; fieldName: string;
}; };
export type FieldEmailMetadata = { export type FieldEmailMetadata = {
fieldName: string;
placeHolder: string; placeHolder: string;
fieldName: string;
};
export type FieldPhoneMetadata = {
placeHolder: string;
fieldName: string;
};
export type FieldProbabilityMetadata = {
fieldName: string;
}; };
export type FieldDefinitionRelationType = export type FieldDefinitionRelationType =
@ -74,85 +71,31 @@ export type FieldRelationMetadata = {
objectMetadataNamePlural: string; objectMetadataNamePlural: string;
}; };
export type FieldChipMetadata = {
contentFieldName: string;
urlFieldName: string;
placeHolder: string;
};
export type FieldDoubleTextMetadata = {
firstValueFieldName: string;
firstValuePlaceholder: string;
secondValueFieldName: string;
secondValuePlaceholder: string;
};
export type FieldDoubleTextChipMetadata = {
firstValueFieldName: string;
firstValuePlaceholder: string;
secondValueFieldName: string;
secondValuePlaceholder: string;
avatarUrlFieldName: string;
};
export type FieldProbabilityMetadata = {
fieldName: string;
};
export type FieldBooleanMetadata = {
fieldName: string;
};
export type FieldEnumMetadata = {
fieldName: string;
};
export type FieldMetadata = export type FieldMetadata =
| FieldBooleanMetadata | FieldBooleanMetadata
| FieldChipMetadata
| FieldCurrencyMetadata
| FieldDateMetadata
| FieldDoubleTextChipMetadata
| FieldDoubleTextMetadata
| FieldEmailMetadata
| FieldLinkMetadata
| FieldMoneyMetadata
| FieldNumberMetadata | FieldNumberMetadata
| FieldPhoneMetadata | FieldDateMetadata
| FieldProbabilityMetadata
| FieldEnumMetadata
| FieldRelationMetadata
| FieldTextMetadata | FieldTextMetadata
| FieldURLMetadata | FieldUuidMetadata
| FieldUuidMetadata; | FieldCurrencyMetadata
| FieldLinkMetadata
| FieldPhoneMetadata
| FieldEmailMetadata
| FieldProbabilityMetadata
| FieldRelationMetadata
| FieldFullNameMetadata;
export type FieldTextValue = string; export type FieldTextValue = string;
export type FieldUUidValue = string; export type FieldUUidValue = string;
export type FieldChipValue = string;
export type FieldDateValue = string | null; export type FieldDateValue = string | null;
export type FieldPhoneValue = string;
export type FieldURLValue = string;
export type FieldLinkValue = { url: string; label: string };
export type FieldNumberValue = number | null; export type FieldNumberValue = number | null;
export type FieldMoneyValue = number | null;
export type FieldCurrencyValue = { currencyCode: string; amountMicros: number };
export type FieldFullNameValue = { firstName: string; lastName: string };
export type FieldEmailValue = string;
export type FieldProbabilityValue = number;
export type FieldBooleanValue = boolean; export type FieldBooleanValue = boolean;
export type FieldDoubleTextValue = { export type FieldPhoneValue = string;
firstValue: string; export type FieldEmailValue = string;
secondValue: string; export type FieldLinkValue = { url: string; label: string };
}; export type FieldCurrencyValue = { currencyCode: string; amountMicros: number };
export type FieldFullNameValue = { firstName: string; lastName: string };
export type FieldDoubleTextChipValue = { export type FieldProbabilityValue = number;
firstValue: string;
secondValue: string;
};
export type FieldRelationValue = EntityForSelect | null; export type FieldRelationValue = EntityForSelect | null;
export type FieldEnumValue = { color: ThemeColor; text: string };

View File

@ -1,23 +1,17 @@
import { FieldDefinition } from '../FieldDefinition'; import { FieldDefinition } from '../FieldDefinition';
import { import {
FieldBooleanMetadata, FieldBooleanMetadata,
FieldChipMetadata,
FieldCurrencyMetadata, FieldCurrencyMetadata,
FieldDateMetadata, FieldDateMetadata,
FieldDoubleTextChipMetadata,
FieldDoubleTextMetadata,
FieldEmailMetadata, FieldEmailMetadata,
FieldEnumMetadata, FieldFullNameMetadata,
FieldFullnameMetadata,
FieldLinkMetadata, FieldLinkMetadata,
FieldMetadata, FieldMetadata,
FieldMoneyMetadata,
FieldNumberMetadata, FieldNumberMetadata,
FieldPhoneMetadata, FieldPhoneMetadata,
FieldProbabilityMetadata, FieldProbabilityMetadata,
FieldRelationMetadata, FieldRelationMetadata,
FieldTextMetadata, FieldTextMetadata,
FieldURLMetadata,
FieldUuidMetadata, FieldUuidMetadata,
} from '../FieldMetadata'; } from '../FieldMetadata';
import { FieldType } from '../FieldType'; import { FieldType } from '../FieldType';
@ -26,26 +20,16 @@ type AssertFieldMetadataFunction = <
E extends FieldType, E extends FieldType,
T extends E extends 'BOOLEAN' T extends E extends 'BOOLEAN'
? FieldBooleanMetadata ? FieldBooleanMetadata
: E extends 'CHIP'
? FieldChipMetadata
: E extends 'CURRENCY' : E extends 'CURRENCY'
? FieldCurrencyMetadata ? FieldCurrencyMetadata
: E extends 'FULL_NAME' : E extends 'FULL_NAME'
? FieldFullnameMetadata ? FieldFullNameMetadata
: E extends 'DATE' : E extends 'DATE'
? FieldDateMetadata ? FieldDateMetadata
: E extends 'DOUBLE_TEXT'
? FieldDoubleTextMetadata
: E extends 'DOUBLE_TEXT_CHIP'
? FieldDoubleTextChipMetadata
: E extends 'EMAIL' : E extends 'EMAIL'
? FieldEmailMetadata ? FieldEmailMetadata
: E extends 'LINK' : E extends 'LINK'
? FieldLinkMetadata ? FieldLinkMetadata
: E extends 'MONEY_AMOUNT'
? FieldMoneyMetadata
: E extends 'ENUM'
? FieldEnumMetadata
: E extends 'NUMBER' : E extends 'NUMBER'
? FieldNumberMetadata ? FieldNumberMetadata
: E extends 'PHONE' : E extends 'PHONE'
@ -56,8 +40,6 @@ type AssertFieldMetadataFunction = <
? FieldRelationMetadata ? FieldRelationMetadata
: E extends 'TEXT' : E extends 'TEXT'
? FieldTextMetadata ? FieldTextMetadata
: E extends 'URL'
? FieldURLMetadata
: E extends 'UUID' : E extends 'UUID'
? FieldUuidMetadata ? FieldUuidMetadata
: never, : never,

View File

@ -1,6 +0,0 @@
import { FieldDefinition } from '../FieldDefinition';
import { FieldChipMetadata, FieldMetadata } from '../FieldMetadata';
export const isFieldChip = (
field: Pick<FieldDefinition<FieldMetadata>, 'type'>,
): field is FieldDefinition<FieldChipMetadata> => field.type === 'CHIP';

View File

@ -1,8 +0,0 @@
import { isString } from '@sniptt/guards';
import { FieldChipValue } from '../FieldMetadata';
// TODO: add zod
export const isFieldChipValue = (
fieldValue: unknown,
): fieldValue is FieldChipValue => isString(fieldValue);

View File

@ -1,7 +0,0 @@
import { FieldDefinition } from '../FieldDefinition';
import { FieldDoubleTextMetadata, FieldMetadata } from '../FieldMetadata';
export const isFieldDoubleText = (
field: Pick<FieldDefinition<FieldMetadata>, 'type'>,
): field is FieldDefinition<FieldDoubleTextMetadata> =>
field.type === 'DOUBLE_TEXT';

View File

@ -1,7 +0,0 @@
import { FieldDefinition } from '../FieldDefinition';
import { FieldDoubleTextChipMetadata, FieldMetadata } from '../FieldMetadata';
export const isFieldDoubleTextChip = (
field: Pick<FieldDefinition<FieldMetadata>, 'type'>,
): field is FieldDefinition<FieldDoubleTextChipMetadata> =>
field.type === 'DOUBLE_TEXT_CHIP';

View File

@ -1,9 +0,0 @@
import { FieldDoubleTextChipValue } from '../FieldMetadata';
import { DoubleTextTypeResolver } from '../resolvers/DoubleTextTypeResolver';
export const isFieldDoubleTextChipValue = (
fieldValue: unknown,
): fieldValue is FieldDoubleTextChipValue =>
fieldValue !== null &&
fieldValue !== undefined &&
DoubleTextTypeResolver.safeParse(fieldValue).success;

View File

@ -1,10 +0,0 @@
import { FieldDoubleTextValue } from '../FieldMetadata';
import { DoubleTextTypeResolver } from '../resolvers/DoubleTextTypeResolver';
// TODO: add zod
export const isFieldDoubleTextValue = (
fieldValue: unknown,
): fieldValue is FieldDoubleTextValue =>
fieldValue !== null &&
fieldValue !== undefined &&
DoubleTextTypeResolver.safeParse(fieldValue).success;

View File

@ -1,6 +0,0 @@
import { FieldDefinition } from '../FieldDefinition';
import { FieldEnumMetadata, FieldMetadata } from '../FieldMetadata';
export const isFieldEnum = (
field: Pick<FieldDefinition<FieldMetadata>, 'type'>,
): field is FieldDefinition<FieldEnumMetadata> => field.type === 'ENUM';

View File

@ -1,7 +1,7 @@
import { FieldDefinition } from '../FieldDefinition'; import { FieldDefinition } from '../FieldDefinition';
import { FieldCurrencyMetadata, FieldMetadata } from '../FieldMetadata'; import { FieldFullNameMetadata, FieldMetadata } from '../FieldMetadata';
export const isFieldFullName = ( export const isFieldFullName = (
field: Pick<FieldDefinition<FieldMetadata>, 'type'>, field: Pick<FieldDefinition<FieldMetadata>, 'type'>,
): field is FieldDefinition<FieldCurrencyMetadata> => ): field is FieldDefinition<FieldFullNameMetadata> =>
field.type === 'FULL_NAME'; field.type === 'FULL_NAME';

View File

@ -1,7 +0,0 @@
import { FieldDefinition } from '../FieldDefinition';
import { FieldMetadata, FieldMoneyMetadata } from '../FieldMetadata';
export const isFieldMoney = (
field: Pick<FieldDefinition<FieldMetadata>, 'type'>,
): field is FieldDefinition<FieldMoneyMetadata> =>
field.type === 'MONEY_AMOUNT';

View File

@ -1,8 +0,0 @@
import { isNull, isNumber } from '@sniptt/guards';
import { FieldMoneyValue } from '../FieldMetadata';
// TODO: add zod
export const isFieldMoneyValue = (
fieldValue: unknown,
): fieldValue is FieldMoneyValue => isNull(fieldValue) || isNumber(fieldValue);

View File

@ -1,6 +0,0 @@
import { FieldDefinition } from '../FieldDefinition';
import { FieldMetadata, FieldURLMetadata } from '../FieldMetadata';
export const isFieldURL = (
field: Pick<FieldDefinition<FieldMetadata>, 'type'>,
): field is FieldDefinition<FieldURLMetadata> => field.type === 'URL';

View File

@ -1,8 +0,0 @@
import { isString } from '@sniptt/guards';
import { FieldURLValue } from '../FieldMetadata';
// TODO: add zod
export const isFieldURLValue = (
fieldValue: unknown,
): fieldValue is FieldURLValue => isString(fieldValue);