Rename Money/Url to Currency/Link and remove snake_case from composite fields (#2536)
* Rename Money/Url to Currency/Link * regenerate front types * renaming money/url field types * fix double text * fix tests * fix server tests * fix generate-target-column-map * fix currency convert * fix: tests --------- Co-authored-by: Jérémy Magrin <jeremy.magrin@gmail.com>
This commit is contained in:
@ -221,7 +221,7 @@ export type CreateRelationInput = {
|
||||
toObjectMetadataId: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export enum Currency {
|
||||
export enum CurrencyCode {
|
||||
Aed = 'AED',
|
||||
Afn = 'AFN',
|
||||
All = 'ALL',
|
||||
@ -457,16 +457,16 @@ export type FieldDeleteResponse = {
|
||||
/** Type of the field */
|
||||
export enum FieldMetadataType {
|
||||
Boolean = 'BOOLEAN',
|
||||
Currency = 'CURRENCY',
|
||||
Date = 'DATE',
|
||||
Email = 'EMAIL',
|
||||
Enum = 'ENUM',
|
||||
Money = 'MONEY',
|
||||
Link = 'LINK',
|
||||
Number = 'NUMBER',
|
||||
Phone = 'PHONE',
|
||||
Probability = 'PROBABILITY',
|
||||
Relation = 'RELATION',
|
||||
Text = 'TEXT',
|
||||
Url = 'URL',
|
||||
Uuid = 'UUID'
|
||||
}
|
||||
|
||||
@ -608,7 +608,7 @@ export type Person = {
|
||||
export type Pipeline = {
|
||||
__typename?: 'Pipeline';
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
currency: Currency;
|
||||
currency: CurrencyCode;
|
||||
icon: Scalars['String']['output'];
|
||||
id: Scalars['ID']['output'];
|
||||
name: Scalars['String']['output'];
|
||||
|
||||
@ -981,7 +981,7 @@ export type CreateRefreshTokenInput = {
|
||||
expiresAt: Scalars['DateTime'];
|
||||
};
|
||||
|
||||
export enum Currency {
|
||||
export enum CurrencyCode {
|
||||
Aed = 'AED',
|
||||
Afn = 'AFN',
|
||||
All = 'ALL',
|
||||
@ -1206,11 +1206,11 @@ export type EnumColorSchemeFilter = {
|
||||
notIn?: InputMaybe<Array<ColorScheme>>;
|
||||
};
|
||||
|
||||
export type EnumCurrencyFilter = {
|
||||
equals?: InputMaybe<Currency>;
|
||||
in?: InputMaybe<Array<Currency>>;
|
||||
not?: InputMaybe<NestedEnumCurrencyFilter>;
|
||||
notIn?: InputMaybe<Array<Currency>>;
|
||||
export type EnumCurrencyCodeFilter = {
|
||||
equals?: InputMaybe<CurrencyCode>;
|
||||
in?: InputMaybe<Array<CurrencyCode>>;
|
||||
not?: InputMaybe<NestedEnumCurrencyCodeFilter>;
|
||||
notIn?: InputMaybe<Array<CurrencyCode>>;
|
||||
};
|
||||
|
||||
export type EnumPipelineProgressableTypeFilter = {
|
||||
@ -1332,16 +1332,16 @@ export type FieldDeleteResponse = {
|
||||
/** Type of the field */
|
||||
export enum FieldMetadataType {
|
||||
Boolean = 'BOOLEAN',
|
||||
Currency = 'CURRENCY',
|
||||
Date = 'DATE',
|
||||
Email = 'EMAIL',
|
||||
Enum = 'ENUM',
|
||||
Money = 'MONEY',
|
||||
Link = 'LINK',
|
||||
Number = 'NUMBER',
|
||||
Phone = 'PHONE',
|
||||
Probability = 'PROBABILITY',
|
||||
Relation = 'RELATION',
|
||||
Text = 'TEXT',
|
||||
Url = 'URL',
|
||||
Uuid = 'UUID'
|
||||
}
|
||||
|
||||
@ -1770,11 +1770,11 @@ export type NestedEnumColorSchemeFilter = {
|
||||
notIn?: InputMaybe<Array<ColorScheme>>;
|
||||
};
|
||||
|
||||
export type NestedEnumCurrencyFilter = {
|
||||
equals?: InputMaybe<Currency>;
|
||||
in?: InputMaybe<Array<Currency>>;
|
||||
not?: InputMaybe<NestedEnumCurrencyFilter>;
|
||||
notIn?: InputMaybe<Array<Currency>>;
|
||||
export type NestedEnumCurrencyCodeFilter = {
|
||||
equals?: InputMaybe<CurrencyCode>;
|
||||
in?: InputMaybe<Array<CurrencyCode>>;
|
||||
not?: InputMaybe<NestedEnumCurrencyCodeFilter>;
|
||||
notIn?: InputMaybe<Array<CurrencyCode>>;
|
||||
};
|
||||
|
||||
export type NestedEnumPipelineProgressableTypeFilter = {
|
||||
@ -2093,7 +2093,7 @@ export type PersonWhereUniqueInput = {
|
||||
export type Pipeline = {
|
||||
__typename?: 'Pipeline';
|
||||
createdAt: Scalars['DateTime'];
|
||||
currency: Currency;
|
||||
currency: CurrencyCode;
|
||||
icon: Scalars['String'];
|
||||
id: Scalars['ID'];
|
||||
name: Scalars['String'];
|
||||
@ -2442,7 +2442,7 @@ export type PipelineWhereInput = {
|
||||
NOT?: InputMaybe<Array<PipelineWhereInput>>;
|
||||
OR?: InputMaybe<Array<PipelineWhereInput>>;
|
||||
createdAt?: InputMaybe<DateTimeFilter>;
|
||||
currency?: InputMaybe<EnumCurrencyFilter>;
|
||||
currency?: InputMaybe<EnumCurrencyCodeFilter>;
|
||||
icon?: InputMaybe<StringFilter>;
|
||||
id?: InputMaybe<StringFilter>;
|
||||
name?: InputMaybe<StringFilter>;
|
||||
|
||||
@ -6,7 +6,14 @@ import { FieldMetadataItem } from '../types/FieldMetadataItem';
|
||||
export const useMapFieldMetadataToGraphQLQuery = () => {
|
||||
const { objectMetadataItems } = useFindManyObjectMetadataItems();
|
||||
|
||||
const mapFieldMetadataToGraphQLQuery = (field: FieldMetadataItem): any => {
|
||||
const mapFieldMetadataToGraphQLQuery = (
|
||||
field: FieldMetadataItem,
|
||||
maxDepthForRelations: number = 1,
|
||||
): any => {
|
||||
if (maxDepthForRelations <= 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// TODO: parse
|
||||
const fieldType = field.type as FieldType;
|
||||
|
||||
@ -22,11 +29,6 @@ export const useMapFieldMetadataToGraphQLQuery = () => {
|
||||
] as FieldType[]
|
||||
).includes(fieldType);
|
||||
|
||||
const fieldIsURL = fieldType === 'URL' || fieldType === 'URL_V2';
|
||||
|
||||
const fieldIsMoneyAmount =
|
||||
fieldType === 'MONEY' || fieldType === 'MONEY_AMOUNT_V2';
|
||||
|
||||
if (fieldIsSimpleValue) {
|
||||
return field.name;
|
||||
} else if (
|
||||
@ -44,7 +46,9 @@ export const useMapFieldMetadataToGraphQLQuery = () => {
|
||||
id
|
||||
${(relationMetadataItem?.fields ?? [])
|
||||
.filter((field) => field.type !== 'RELATION')
|
||||
.map((field) => field.name)
|
||||
.map((field) =>
|
||||
mapFieldMetadataToGraphQLQuery(field, maxDepthForRelations - 1),
|
||||
)
|
||||
.join('\n')}
|
||||
}`;
|
||||
} else if (
|
||||
@ -64,25 +68,27 @@ export const useMapFieldMetadataToGraphQLQuery = () => {
|
||||
id
|
||||
${(relationMetadataItem?.fields ?? [])
|
||||
.filter((field) => field.type !== 'RELATION')
|
||||
.map((field) => field.name)
|
||||
.map((field) =>
|
||||
mapFieldMetadataToGraphQLQuery(field, maxDepthForRelations - 1),
|
||||
)
|
||||
.join('\n')}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
} else if (fieldIsURL) {
|
||||
} else if (fieldType === 'LINK') {
|
||||
return `
|
||||
${field.name}
|
||||
{
|
||||
text
|
||||
link
|
||||
label
|
||||
url
|
||||
}
|
||||
`;
|
||||
} else if (fieldIsMoneyAmount) {
|
||||
} else if (fieldType === 'CURRENCY') {
|
||||
return `
|
||||
${field.name}
|
||||
{
|
||||
amount
|
||||
currency
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@ -2,12 +2,12 @@ import { FieldType } from '@/ui/object/field/types/FieldType';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const parseFieldType = (fieldType: FieldMetadataType): FieldType => {
|
||||
if (fieldType === FieldMetadataType.Url) {
|
||||
return 'URL_V2';
|
||||
if (fieldType === FieldMetadataType.Link) {
|
||||
return 'LINK';
|
||||
}
|
||||
|
||||
if (fieldType === FieldMetadataType.Money) {
|
||||
return 'MONEY_AMOUNT_V2';
|
||||
if (fieldType === FieldMetadataType.Currency) {
|
||||
return 'CURRENCY';
|
||||
}
|
||||
|
||||
return fieldType as FieldType;
|
||||
|
||||
@ -4,11 +4,14 @@ import { v4 } from 'uuid';
|
||||
import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect';
|
||||
import { useFindOneObjectMetadataItem } from '@/object-metadata/hooks/useFindOneObjectMetadataItem';
|
||||
import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
|
||||
import { Currency, FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { CurrencyCode, FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
const defaultFieldValues: Record<FieldMetadataType, unknown> = {
|
||||
[FieldMetadataType.Money]: { amount: null, currency: Currency.Usd },
|
||||
[FieldMetadataType.Currency]: {
|
||||
amountMicros: null,
|
||||
currencyCode: CurrencyCode.Usd,
|
||||
},
|
||||
[FieldMetadataType.Boolean]: false,
|
||||
[FieldMetadataType.Date]: null,
|
||||
[FieldMetadataType.Email]: '',
|
||||
@ -18,7 +21,7 @@ const defaultFieldValues: Record<FieldMetadataType, unknown> = {
|
||||
[FieldMetadataType.Relation]: null,
|
||||
[FieldMetadataType.Phone]: '',
|
||||
[FieldMetadataType.Text]: '',
|
||||
[FieldMetadataType.Url]: { link: '', text: '' },
|
||||
[FieldMetadataType.Link]: { url: '', label: '' },
|
||||
[FieldMetadataType.Uuid]: '',
|
||||
};
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ export const Currency: Story = {
|
||||
args: {
|
||||
fieldIconKey: 'IconCurrencyDollar',
|
||||
fieldLabel: 'Amount',
|
||||
fieldType: FieldMetadataType.Money,
|
||||
fieldType: FieldMetadataType.Currency,
|
||||
},
|
||||
};
|
||||
|
||||
@ -61,7 +61,7 @@ export const Link: Story = {
|
||||
args: {
|
||||
fieldIconKey: 'IconWorldWww',
|
||||
fieldLabel: 'Website',
|
||||
fieldType: FieldMetadataType.Url,
|
||||
fieldType: FieldMetadataType.Link,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ import {
|
||||
IconTextSize,
|
||||
} from '@/ui/display/icon';
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { Currency, FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { CurrencyCode, FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
const defaultDateValue = new Date();
|
||||
defaultDateValue.setFullYear(defaultDateValue.getFullYear() + 2);
|
||||
@ -36,10 +36,10 @@ export const dataTypes: Record<
|
||||
Icon: IconNumbers,
|
||||
defaultValue: 2000,
|
||||
},
|
||||
[FieldMetadataType.Url]: {
|
||||
[FieldMetadataType.Link]: {
|
||||
label: 'Link',
|
||||
Icon: IconLink,
|
||||
defaultValue: { link: 'www.twenty.com', text: '' },
|
||||
defaultValue: { url: 'www.twenty.com', label: '' },
|
||||
},
|
||||
[FieldMetadataType.Boolean]: {
|
||||
label: 'True/False',
|
||||
@ -51,10 +51,10 @@ export const dataTypes: Record<
|
||||
Icon: IconCalendarEvent,
|
||||
defaultValue: defaultDateValue.toISOString(),
|
||||
},
|
||||
[FieldMetadataType.Money]: {
|
||||
[FieldMetadataType.Currency]: {
|
||||
label: 'Currency',
|
||||
Icon: IconCoins,
|
||||
defaultValue: { amount: 2000, currency: Currency.Usd },
|
||||
defaultValue: { amount: 2000, currency: CurrencyCode.Usd },
|
||||
},
|
||||
[FieldMetadataType.Relation]: { label: 'Relation', Icon: IconPlug },
|
||||
[FieldMetadataType.Email]: { label: 'Email', Icon: IconMail },
|
||||
|
||||
@ -6,30 +6,30 @@ import { isFieldUuid } from '@/ui/object/field/types/guards/isFieldUuid';
|
||||
|
||||
import { FieldContext } from '../contexts/FieldContext';
|
||||
import { ChipFieldDisplay } from '../meta-types/display/components/ChipFieldDisplay';
|
||||
import { CurrencyFieldDisplay } from '../meta-types/display/components/CurrencyFieldDisplay';
|
||||
import { DateFieldDisplay } from '../meta-types/display/components/DateFieldDisplay';
|
||||
import { DoubleTextChipFieldDisplay } from '../meta-types/display/components/DoubleTextChipFieldDisplay';
|
||||
import { DoubleTextFieldDisplay } from '../meta-types/display/components/DoubleTextFieldDisplay';
|
||||
import { EmailFieldDisplay } from '../meta-types/display/components/EmailFieldDisplay';
|
||||
import { MoneyAmountV2FieldDisplay } from '../meta-types/display/components/MoneyAmountV2FieldDisplay';
|
||||
import { LinkFieldDisplay } from '../meta-types/display/components/LinkFieldDisplay';
|
||||
import { MoneyFieldDisplay } from '../meta-types/display/components/MoneyFieldDisplay';
|
||||
import { NumberFieldDisplay } from '../meta-types/display/components/NumberFieldDisplay';
|
||||
import { PhoneFieldDisplay } from '../meta-types/display/components/PhoneFieldDisplay';
|
||||
import { TextFieldDisplay } from '../meta-types/display/components/TextFieldDisplay';
|
||||
import { URLFieldDisplay } from '../meta-types/display/components/URLFieldDisplay';
|
||||
import { URLV2FieldDisplay } from '../meta-types/display/components/URLV2FieldDisplay';
|
||||
import { isFieldChip } from '../types/guards/isFieldChip';
|
||||
import { isFieldCurrency } from '../types/guards/isFieldCurrency';
|
||||
import { isFieldDate } from '../types/guards/isFieldDate';
|
||||
import { isFieldDoubleText } from '../types/guards/isFieldDoubleText';
|
||||
import { isFieldDoubleTextChip } from '../types/guards/isFieldDoubleTextChip';
|
||||
import { isFieldEmail } from '../types/guards/isFieldEmail';
|
||||
import { isFieldLink } from '../types/guards/isFieldLink';
|
||||
import { isFieldMoney } from '../types/guards/isFieldMoney';
|
||||
import { isFieldMoneyAmountV2 } from '../types/guards/isFieldMoneyAmountV2';
|
||||
import { isFieldNumber } from '../types/guards/isFieldNumber';
|
||||
import { isFieldPhone } from '../types/guards/isFieldPhone';
|
||||
import { isFieldRelation } from '../types/guards/isFieldRelation';
|
||||
import { isFieldText } from '../types/guards/isFieldText';
|
||||
import { isFieldURL } from '../types/guards/isFieldURL';
|
||||
import { isFieldURLV2 } from '../types/guards/isFieldURLV2';
|
||||
|
||||
export const FieldDisplay = () => {
|
||||
const { fieldDefinition } = useContext(FieldContext);
|
||||
@ -52,10 +52,10 @@ export const FieldDisplay = () => {
|
||||
<MoneyFieldDisplay />
|
||||
) : isFieldURL(fieldDefinition) ? (
|
||||
<URLFieldDisplay />
|
||||
) : isFieldURLV2(fieldDefinition) ? (
|
||||
<URLV2FieldDisplay />
|
||||
) : isFieldMoneyAmountV2(fieldDefinition) ? (
|
||||
<MoneyAmountV2FieldDisplay />
|
||||
) : isFieldLink(fieldDefinition) ? (
|
||||
<LinkFieldDisplay />
|
||||
) : isFieldCurrency(fieldDefinition) ? (
|
||||
<CurrencyFieldDisplay />
|
||||
) : isFieldPhone(fieldDefinition) ? (
|
||||
<PhoneFieldDisplay />
|
||||
) : isFieldChip(fieldDefinition) ? (
|
||||
|
||||
@ -5,11 +5,12 @@ import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'
|
||||
import { FieldContext } from '../contexts/FieldContext';
|
||||
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 { DateFieldInput } from '../meta-types/input/components/DateFieldInput';
|
||||
import { DoubleTextChipFieldInput } from '../meta-types/input/components/DoubleTextChipFieldInput';
|
||||
import { DoubleTextFieldInput } from '../meta-types/input/components/DoubleTextFieldInput';
|
||||
import { EmailFieldInput } from '../meta-types/input/components/EmailFieldInput';
|
||||
import { MoneyAmountV2FieldInput } from '../meta-types/input/components/MoneyAmountV2FieldInput';
|
||||
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 { PhoneFieldInput } from '../meta-types/input/components/PhoneFieldInput';
|
||||
@ -17,23 +18,22 @@ import { ProbabilityFieldInput } from '../meta-types/input/components/Probabilit
|
||||
import { RelationFieldInput } from '../meta-types/input/components/RelationFieldInput';
|
||||
import { TextFieldInput } from '../meta-types/input/components/TextFieldInput';
|
||||
import { URLFieldInput } from '../meta-types/input/components/URLFieldInput';
|
||||
import { URLV2FieldInput } from '../meta-types/input/components/URLV2FieldInput';
|
||||
import { FieldInputEvent } from '../types/FieldInputEvent';
|
||||
import { isFieldBoolean } from '../types/guards/isFieldBoolean';
|
||||
import { isFieldChip } from '../types/guards/isFieldChip';
|
||||
import { isFieldCurrency } from '../types/guards/isFieldCurrency';
|
||||
import { isFieldDate } from '../types/guards/isFieldDate';
|
||||
import { isFieldDoubleText } from '../types/guards/isFieldDoubleText';
|
||||
import { isFieldDoubleTextChip } from '../types/guards/isFieldDoubleTextChip';
|
||||
import { isFieldEmail } from '../types/guards/isFieldEmail';
|
||||
import { isFieldLink } from '../types/guards/isFieldLink';
|
||||
import { isFieldMoney } from '../types/guards/isFieldMoney';
|
||||
import { isFieldMoneyAmountV2 } from '../types/guards/isFieldMoneyAmountV2';
|
||||
import { isFieldNumber } from '../types/guards/isFieldNumber';
|
||||
import { isFieldPhone } from '../types/guards/isFieldPhone';
|
||||
import { isFieldProbability } from '../types/guards/isFieldProbability';
|
||||
import { isFieldRelation } from '../types/guards/isFieldRelation';
|
||||
import { isFieldText } from '../types/guards/isFieldText';
|
||||
import { isFieldURL } from '../types/guards/isFieldURL';
|
||||
import { isFieldURLV2 } from '../types/guards/isFieldURLV2';
|
||||
|
||||
type FieldInputProps = {
|
||||
onSubmit?: FieldInputEvent;
|
||||
@ -102,16 +102,16 @@ export const FieldInput = ({
|
||||
onTab={onTab}
|
||||
onShiftTab={onShiftTab}
|
||||
/>
|
||||
) : isFieldURLV2(fieldDefinition) ? (
|
||||
<URLV2FieldInput
|
||||
) : isFieldLink(fieldDefinition) ? (
|
||||
<LinkFieldInput
|
||||
onEnter={onEnter}
|
||||
onEscape={onEscape}
|
||||
onClickOutside={onClickOutside}
|
||||
onTab={onTab}
|
||||
onShiftTab={onShiftTab}
|
||||
/>
|
||||
) : isFieldMoneyAmountV2(fieldDefinition) ? (
|
||||
<MoneyAmountV2FieldInput
|
||||
) : isFieldCurrency(fieldDefinition) ? (
|
||||
<CurrencyFieldInput
|
||||
onEnter={onEnter}
|
||||
onEscape={onEscape}
|
||||
onClickOutside={onClickOutside}
|
||||
|
||||
@ -7,6 +7,8 @@ import { isFieldBoolean } from '../types/guards/isFieldBoolean';
|
||||
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 { isFieldCurrencyValue } from '../types/guards/isFieldCurrencyValue';
|
||||
import { isFieldDate } from '../types/guards/isFieldDate';
|
||||
import { isFieldDateValue } from '../types/guards/isFieldDateValue';
|
||||
import { isFieldDoubleText } from '../types/guards/isFieldDoubleText';
|
||||
@ -15,9 +17,9 @@ import { isFieldDoubleTextChipValue } from '../types/guards/isFieldDoubleTextChi
|
||||
import { isFieldDoubleTextValue } from '../types/guards/isFieldDoubleTextValue';
|
||||
import { isFieldEmail } from '../types/guards/isFieldEmail';
|
||||
import { isFieldEmailValue } from '../types/guards/isFieldEmailValue';
|
||||
import { isFieldLink } from '../types/guards/isFieldLink';
|
||||
import { isFieldLinkValue } from '../types/guards/isFieldLinkValue';
|
||||
import { isFieldMoney } from '../types/guards/isFieldMoney';
|
||||
import { isFieldMoneyAmountV2 } from '../types/guards/isFieldMoneyAmountV2';
|
||||
import { isFieldMoneyAmountV2Value } from '../types/guards/isFieldMoneyAmountV2Value';
|
||||
import { isFieldMoneyValue } from '../types/guards/isFieldMoneyValue';
|
||||
import { isFieldNumber } from '../types/guards/isFieldNumber';
|
||||
import { isFieldNumberValue } from '../types/guards/isFieldNumberValue';
|
||||
@ -30,8 +32,6 @@ import { isFieldRelationValue } from '../types/guards/isFieldRelationValue';
|
||||
import { isFieldText } from '../types/guards/isFieldText';
|
||||
import { isFieldTextValue } from '../types/guards/isFieldTextValue';
|
||||
import { isFieldURL } from '../types/guards/isFieldURL';
|
||||
import { isFieldURLV2 } from '../types/guards/isFieldURLV2';
|
||||
import { isFieldURLV2Value } from '../types/guards/isFieldURLV2Value';
|
||||
import { isFieldURLValue } from '../types/guards/isFieldURLValue';
|
||||
|
||||
export const usePersistField = () => {
|
||||
@ -73,8 +73,8 @@ export const usePersistField = () => {
|
||||
const fieldIsURL =
|
||||
isFieldURL(fieldDefinition) && isFieldURLValue(valueToPersist);
|
||||
|
||||
const fieldIsURLV2 =
|
||||
isFieldURLV2(fieldDefinition) && isFieldURLV2Value(valueToPersist);
|
||||
const fieldIsLink =
|
||||
isFieldLink(fieldDefinition) && isFieldLinkValue(valueToPersist);
|
||||
|
||||
const fieldIsBoolean =
|
||||
isFieldBoolean(fieldDefinition) &&
|
||||
@ -90,9 +90,9 @@ export const usePersistField = () => {
|
||||
const fieldIsMoney =
|
||||
isFieldMoney(fieldDefinition) && isFieldMoneyValue(valueToPersist);
|
||||
|
||||
const fieldIsMoneyAmountV2 =
|
||||
isFieldMoneyAmountV2(fieldDefinition) &&
|
||||
isFieldMoneyAmountV2Value(valueToPersist);
|
||||
const fieldIsCurrency =
|
||||
isFieldCurrency(fieldDefinition) &&
|
||||
isFieldCurrencyValue(valueToPersist);
|
||||
|
||||
const fieldIsPhone =
|
||||
isFieldPhone(fieldDefinition) && isFieldPhoneValue(valueToPersist);
|
||||
@ -169,8 +169,8 @@ export const usePersistField = () => {
|
||||
fieldIsMoney ||
|
||||
fieldIsDate ||
|
||||
fieldIsPhone ||
|
||||
fieldIsURLV2 ||
|
||||
fieldIsMoneyAmountV2
|
||||
fieldIsLink ||
|
||||
fieldIsCurrency
|
||||
) {
|
||||
const fieldName = fieldDefinition.metadata.fieldName;
|
||||
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
import { useCurrencyField } from '../../hooks/useCurrencyField';
|
||||
import { CurrencyDisplay } from '../content-display/components/CurrencyDisplay';
|
||||
|
||||
export const CurrencyFieldDisplay = () => {
|
||||
const { fieldValue } = useCurrencyField();
|
||||
|
||||
return <CurrencyDisplay value={fieldValue} />;
|
||||
};
|
||||
@ -0,0 +1,8 @@
|
||||
import { useLinkField } from '../../hooks/useLinkField';
|
||||
import { LinkDisplay } from '../content-display/components/LinkDisplay';
|
||||
|
||||
export const LinkFieldDisplay = () => {
|
||||
const { fieldValue } = useLinkField();
|
||||
|
||||
return <LinkDisplay value={fieldValue} />;
|
||||
};
|
||||
@ -1,8 +0,0 @@
|
||||
import { useMoneyAmountV2Field } from '../../hooks/useMoneyAmountV2Field';
|
||||
import { MoneyAmountV2Display } from '../content-display/components/MoneyAmountV2Display';
|
||||
|
||||
export const MoneyAmountV2FieldDisplay = () => {
|
||||
const { fieldValue } = useMoneyAmountV2Field();
|
||||
|
||||
return <MoneyAmountV2Display value={fieldValue} />;
|
||||
};
|
||||
@ -1,8 +0,0 @@
|
||||
import { useURLV2Field } from '../../hooks/useURLV2Field';
|
||||
import { URLV2Display } from '../content-display/components/URLDisplayV2';
|
||||
|
||||
export const URLV2FieldDisplay = () => {
|
||||
const { fieldValue } = useURLV2Field();
|
||||
|
||||
return <URLV2Display value={fieldValue} />;
|
||||
};
|
||||
@ -0,0 +1,18 @@
|
||||
import { FieldCurrencyValue } from '@/ui/object/field/types/FieldMetadata';
|
||||
import { convertCurrencyMicrosToCurrency } from '~/utils/convert-currency-amount';
|
||||
|
||||
import { EllipsisDisplay } from './EllipsisDisplay';
|
||||
|
||||
type CurrencyDisplayProps = {
|
||||
value?: FieldCurrencyValue;
|
||||
};
|
||||
|
||||
// TODO: convert currencyCode to currency symbol
|
||||
export const CurrencyDisplay = ({ value }: CurrencyDisplayProps) => {
|
||||
return (
|
||||
<EllipsisDisplay>
|
||||
{convertCurrencyMicrosToCurrency(value?.amountMicros)}{' '}
|
||||
{value?.currencyCode}
|
||||
</EllipsisDisplay>
|
||||
);
|
||||
};
|
||||
@ -6,7 +6,7 @@ import {
|
||||
LinkType,
|
||||
SocialLink,
|
||||
} from '@/ui/navigation/link/components/SocialLink';
|
||||
import { FieldURLV2Value } from '@/ui/object/field/types/FieldMetadata';
|
||||
import { FieldLinkValue } from '@/ui/object/field/types/FieldMetadata';
|
||||
|
||||
import { EllipsisDisplay } from './EllipsisDisplay';
|
||||
|
||||
@ -20,8 +20,8 @@ const StyledRawLink = styled(RoundedLink)`
|
||||
}
|
||||
`;
|
||||
|
||||
type URLV2DisplayProps = {
|
||||
value?: FieldURLV2Value;
|
||||
type LinkDisplayProps = {
|
||||
value?: FieldLinkValue;
|
||||
};
|
||||
|
||||
const checkUrlType = (url: string) => {
|
||||
@ -39,18 +39,18 @@ const checkUrlType = (url: string) => {
|
||||
return LinkType.Url;
|
||||
};
|
||||
|
||||
export const URLV2Display = ({ value }: URLV2DisplayProps) => {
|
||||
export const LinkDisplay = ({ value }: LinkDisplayProps) => {
|
||||
const handleClick = (event: MouseEvent<HTMLElement>) => {
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
const absoluteUrl = value?.link
|
||||
? value.link.startsWith('http')
|
||||
? value.link
|
||||
: 'https://' + value.link
|
||||
const absoluteUrl = value?.url
|
||||
? value.url.startsWith('http')
|
||||
? value.url
|
||||
: 'https://' + value.url
|
||||
: '';
|
||||
|
||||
const displayedValue = value?.text || value?.link || '';
|
||||
const displayedValue = value?.label || value?.url || '';
|
||||
|
||||
const type = checkUrlType(absoluteUrl);
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
import { FieldMoneyAmountV2Value } from '@/ui/object/field/types/FieldMetadata';
|
||||
|
||||
import { EllipsisDisplay } from './EllipsisDisplay';
|
||||
|
||||
type MoneyAmountV2DisplayProps = {
|
||||
value?: FieldMoneyAmountV2Value;
|
||||
};
|
||||
|
||||
export const MoneyAmountV2Display = ({ value }: MoneyAmountV2DisplayProps) => {
|
||||
return (
|
||||
<EllipsisDisplay>
|
||||
{value?.amount} {value?.currency}
|
||||
</EllipsisDisplay>
|
||||
);
|
||||
};
|
||||
@ -5,19 +5,19 @@ import { FieldContext } from '../../contexts/FieldContext';
|
||||
import { useFieldInitialValue } from '../../hooks/useFieldInitialValue';
|
||||
import { usePersistField } from '../../hooks/usePersistField';
|
||||
import { entityFieldsFamilySelector } from '../../states/selectors/entityFieldsFamilySelector';
|
||||
import { FieldMoneyAmountV2Value } from '../../types/FieldMetadata';
|
||||
import { FieldCurrencyValue } from '../../types/FieldMetadata';
|
||||
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
|
||||
import { isFieldMoneyAmountV2 } from '../../types/guards/isFieldMoneyAmountV2';
|
||||
import { isFieldMoneyAmountV2Value } from '../../types/guards/isFieldMoneyAmountV2Value';
|
||||
import { isFieldCurrency } from '../../types/guards/isFieldCurrency';
|
||||
import { isFieldCurrencyValue } from '../../types/guards/isFieldCurrencyValue';
|
||||
|
||||
export const useMoneyAmountV2Field = () => {
|
||||
export const useCurrencyField = () => {
|
||||
const { entityId, fieldDefinition, hotkeyScope } = useContext(FieldContext);
|
||||
|
||||
assertFieldMetadata('MONEY_AMOUNT_V2', isFieldMoneyAmountV2, fieldDefinition);
|
||||
assertFieldMetadata('CURRENCY', isFieldCurrency, fieldDefinition);
|
||||
|
||||
const fieldName = fieldDefinition.metadata.fieldName;
|
||||
|
||||
const [fieldValue, setFieldValue] = useRecoilState<FieldMoneyAmountV2Value>(
|
||||
const [fieldValue, setFieldValue] = useRecoilState<FieldCurrencyValue>(
|
||||
entityFieldsFamilySelector({
|
||||
entityId: entityId,
|
||||
fieldName: fieldName,
|
||||
@ -26,8 +26,8 @@ export const useMoneyAmountV2Field = () => {
|
||||
|
||||
const persistField = usePersistField();
|
||||
|
||||
const persistMoneyAmountV2Field = (newValue: FieldMoneyAmountV2Value) => {
|
||||
if (!isFieldMoneyAmountV2Value(newValue)) {
|
||||
const persistCurrencyField = (newValue: FieldCurrencyValue) => {
|
||||
if (!isFieldCurrencyValue(newValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -36,11 +36,11 @@ export const useMoneyAmountV2Field = () => {
|
||||
|
||||
const fieldInitialValue = useFieldInitialValue();
|
||||
|
||||
const initialValue: FieldMoneyAmountV2Value = fieldInitialValue?.isEmpty
|
||||
? { amount: 0, currency: '' }
|
||||
const initialValue: FieldCurrencyValue = fieldInitialValue?.isEmpty
|
||||
? { amountMicros: 0, currencyCode: '' }
|
||||
: !isNaN(Number(fieldInitialValue?.value))
|
||||
? { amount: Number(fieldInitialValue?.value), currency: '' }
|
||||
: { amount: 0, currency: '' } ?? fieldValue;
|
||||
? { amountMicros: Number(fieldInitialValue?.value), currencyCode: '' }
|
||||
: { amountMicros: 0, currencyCode: '' } ?? fieldValue;
|
||||
|
||||
return {
|
||||
fieldDefinition,
|
||||
@ -48,6 +48,6 @@ export const useMoneyAmountV2Field = () => {
|
||||
initialValue,
|
||||
setFieldValue,
|
||||
hotkeyScope,
|
||||
persistMoneyAmountV2Field,
|
||||
persistCurrencyField,
|
||||
};
|
||||
};
|
||||
@ -5,19 +5,19 @@ import { FieldContext } from '../../contexts/FieldContext';
|
||||
import { useFieldInitialValue } from '../../hooks/useFieldInitialValue';
|
||||
import { usePersistField } from '../../hooks/usePersistField';
|
||||
import { entityFieldsFamilySelector } from '../../states/selectors/entityFieldsFamilySelector';
|
||||
import { FieldURLV2Value } from '../../types/FieldMetadata';
|
||||
import { FieldLinkValue } from '../../types/FieldMetadata';
|
||||
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
|
||||
import { isFieldURLV2 } from '../../types/guards/isFieldURLV2';
|
||||
import { isFieldURLV2Value } from '../../types/guards/isFieldURLV2Value';
|
||||
import { isFieldLink } from '../../types/guards/isFieldLink';
|
||||
import { isFieldLinkValue } from '../../types/guards/isFieldLinkValue';
|
||||
|
||||
export const useURLV2Field = () => {
|
||||
export const useLinkField = () => {
|
||||
const { entityId, fieldDefinition, hotkeyScope } = useContext(FieldContext);
|
||||
|
||||
assertFieldMetadata('URL_V2', isFieldURLV2, fieldDefinition);
|
||||
assertFieldMetadata('LINK', isFieldLink, fieldDefinition);
|
||||
|
||||
const fieldName = fieldDefinition.metadata.fieldName;
|
||||
|
||||
const [fieldValue, setFieldValue] = useRecoilState<FieldURLV2Value>(
|
||||
const [fieldValue, setFieldValue] = useRecoilState<FieldLinkValue>(
|
||||
entityFieldsFamilySelector({
|
||||
entityId: entityId,
|
||||
fieldName: fieldName,
|
||||
@ -26,16 +26,16 @@ export const useURLV2Field = () => {
|
||||
|
||||
const fieldInitialValue = useFieldInitialValue();
|
||||
|
||||
const initialValue: FieldURLV2Value = fieldInitialValue?.isEmpty
|
||||
? { link: '', text: '' }
|
||||
const initialValue: FieldLinkValue = fieldInitialValue?.isEmpty
|
||||
? { url: '', label: '' }
|
||||
: fieldInitialValue?.value
|
||||
? { link: fieldInitialValue.value, text: '' }
|
||||
? { url: fieldInitialValue.value, label: '' }
|
||||
: fieldValue;
|
||||
|
||||
const persistField = usePersistField();
|
||||
|
||||
const persistURLField = (newValue: FieldURLV2Value) => {
|
||||
if (!isFieldURLV2Value(newValue)) {
|
||||
const persistLinkField = (newValue: FieldLinkValue) => {
|
||||
if (!isFieldLinkValue(newValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -48,6 +48,6 @@ export const useURLV2Field = () => {
|
||||
initialValue,
|
||||
setFieldValue,
|
||||
hotkeyScope,
|
||||
persistURLField,
|
||||
persistLinkField,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,94 @@
|
||||
import { TextInput } from '@/ui/object/field/meta-types/input/components/internal/TextInput';
|
||||
import { convertCurrencyToCurrencyMicros } from '~/utils/convert-currency-amount';
|
||||
|
||||
import { useCurrencyField } from '../../hooks/useCurrencyField';
|
||||
|
||||
import { FieldInputOverlay } from './internal/FieldInputOverlay';
|
||||
import { FieldInputEvent } from './DateFieldInput';
|
||||
|
||||
export type CurrencyFieldInputProps = {
|
||||
onClickOutside?: FieldInputEvent;
|
||||
onEnter?: FieldInputEvent;
|
||||
onEscape?: FieldInputEvent;
|
||||
onTab?: FieldInputEvent;
|
||||
onShiftTab?: FieldInputEvent;
|
||||
};
|
||||
|
||||
export const CurrencyFieldInput = ({
|
||||
onEnter,
|
||||
onEscape,
|
||||
onClickOutside,
|
||||
onTab,
|
||||
onShiftTab,
|
||||
}: CurrencyFieldInputProps) => {
|
||||
const { hotkeyScope, initialValue, persistCurrencyField } =
|
||||
useCurrencyField();
|
||||
|
||||
const handleEnter = (newValue: string) => {
|
||||
onEnter?.(() =>
|
||||
persistCurrencyField({
|
||||
amountMicros:
|
||||
convertCurrencyToCurrencyMicros(parseFloat(newValue)) ?? 0,
|
||||
currencyCode: initialValue.currencyCode,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const handleEscape = (newValue: string) => {
|
||||
onEscape?.(() =>
|
||||
persistCurrencyField({
|
||||
amountMicros:
|
||||
convertCurrencyToCurrencyMicros(parseFloat(newValue)) ?? 0,
|
||||
currencyCode: initialValue.currencyCode,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const handleClickOutside = (
|
||||
event: MouseEvent | TouchEvent,
|
||||
newValue: string,
|
||||
) => {
|
||||
onClickOutside?.(() =>
|
||||
persistCurrencyField({
|
||||
amountMicros:
|
||||
convertCurrencyToCurrencyMicros(parseFloat(newValue)) ?? 0,
|
||||
currencyCode: initialValue.currencyCode,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const handleTab = (newValue: string) => {
|
||||
onTab?.(() =>
|
||||
persistCurrencyField({
|
||||
amountMicros:
|
||||
convertCurrencyToCurrencyMicros(parseFloat(newValue)) ?? 0,
|
||||
currencyCode: initialValue.currencyCode,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const handleShiftTab = (newValue: string) => {
|
||||
onShiftTab?.(() =>
|
||||
persistCurrencyField({
|
||||
amountMicros:
|
||||
convertCurrencyToCurrencyMicros(parseFloat(newValue)) ?? 0,
|
||||
currencyCode: initialValue.currencyCode,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<FieldInputOverlay>
|
||||
<TextInput
|
||||
value={initialValue.amountMicros?.toString() ?? ''}
|
||||
placeholder="Currency"
|
||||
onClickOutside={handleClickOutside}
|
||||
onEnter={handleEnter}
|
||||
onEscape={handleEscape}
|
||||
onShiftTab={handleShiftTab}
|
||||
onTab={handleTab}
|
||||
hotkeyScope={hotkeyScope}
|
||||
/>
|
||||
</FieldInputOverlay>
|
||||
);
|
||||
};
|
||||
@ -1,11 +1,11 @@
|
||||
import { FieldDoubleText } from '../../../types/FieldDoubleText';
|
||||
import { useURLV2Field } from '../../hooks/useURLV2Field';
|
||||
import { useLinkField } from '../../hooks/useLinkField';
|
||||
|
||||
import { DoubleTextInput } from './internal/DoubleTextInput';
|
||||
import { FieldInputOverlay } from './internal/FieldInputOverlay';
|
||||
import { FieldInputEvent } from './DateFieldInput';
|
||||
|
||||
export type URLV2FieldInputProps = {
|
||||
export type LinkFieldInputProps = {
|
||||
onClickOutside?: FieldInputEvent;
|
||||
onEnter?: FieldInputEvent;
|
||||
onEscape?: FieldInputEvent;
|
||||
@ -13,29 +13,29 @@ export type URLV2FieldInputProps = {
|
||||
onShiftTab?: FieldInputEvent;
|
||||
};
|
||||
|
||||
export const URLV2FieldInput = ({
|
||||
export const LinkFieldInput = ({
|
||||
onEnter,
|
||||
onEscape,
|
||||
onClickOutside,
|
||||
onTab,
|
||||
onShiftTab,
|
||||
}: URLV2FieldInputProps) => {
|
||||
const { initialValue, hotkeyScope, persistURLField } = useURLV2Field();
|
||||
}: LinkFieldInputProps) => {
|
||||
const { initialValue, hotkeyScope, persistLinkField } = useLinkField();
|
||||
|
||||
const handleEnter = (newURL: FieldDoubleText) => {
|
||||
onEnter?.(() =>
|
||||
persistURLField({
|
||||
link: newURL.firstValue,
|
||||
text: newURL.secondValue,
|
||||
persistLinkField({
|
||||
url: newURL.firstValue,
|
||||
label: newURL.secondValue,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const handleEscape = (newURL: FieldDoubleText) => {
|
||||
onEscape?.(() =>
|
||||
persistURLField({
|
||||
link: newURL.firstValue,
|
||||
text: newURL.secondValue,
|
||||
persistLinkField({
|
||||
url: newURL.firstValue,
|
||||
label: newURL.secondValue,
|
||||
}),
|
||||
);
|
||||
};
|
||||
@ -45,27 +45,27 @@ export const URLV2FieldInput = ({
|
||||
newURL: FieldDoubleText,
|
||||
) => {
|
||||
onClickOutside?.(() =>
|
||||
persistURLField({
|
||||
link: newURL.firstValue,
|
||||
text: newURL.secondValue,
|
||||
persistLinkField({
|
||||
url: newURL.firstValue,
|
||||
label: newURL.secondValue,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const handleTab = (newURL: FieldDoubleText) => {
|
||||
onTab?.(() =>
|
||||
persistURLField({
|
||||
link: newURL.firstValue,
|
||||
text: newURL.secondValue,
|
||||
persistLinkField({
|
||||
url: newURL.firstValue,
|
||||
label: newURL.secondValue,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const handleShiftTab = (newURL: FieldDoubleText) => {
|
||||
onShiftTab?.(() =>
|
||||
persistURLField({
|
||||
link: newURL.firstValue,
|
||||
text: newURL.secondValue,
|
||||
persistLinkField({
|
||||
url: newURL.firstValue,
|
||||
label: newURL.secondValue,
|
||||
}),
|
||||
);
|
||||
};
|
||||
@ -73,9 +73,9 @@ export const URLV2FieldInput = ({
|
||||
return (
|
||||
<FieldInputOverlay>
|
||||
<DoubleTextInput
|
||||
firstValue={initialValue.link}
|
||||
secondValue={initialValue.text}
|
||||
firstValuePlaceholder={'Link'}
|
||||
firstValue={initialValue.url}
|
||||
secondValue={initialValue.label}
|
||||
firstValuePlaceholder={'Url'}
|
||||
secondValuePlaceholder={'Label'}
|
||||
hotkeyScope={hotkeyScope}
|
||||
onClickOutside={handleClickOutside}
|
||||
@ -1,93 +0,0 @@
|
||||
import { DoubleTextInput } from '@/ui/object/field/meta-types/input/components/internal/DoubleTextInput';
|
||||
|
||||
import { usePersistField } from '../../../hooks/usePersistField';
|
||||
import { FieldDoubleText } from '../../../types/FieldDoubleText';
|
||||
import { useMoneyAmountV2Field } from '../../hooks/useMoneyAmountV2Field';
|
||||
|
||||
import { FieldInputOverlay } from './internal/FieldInputOverlay';
|
||||
import { FieldInputEvent } from './DateFieldInput';
|
||||
|
||||
export type MoneyAmountV2FieldInputProps = {
|
||||
onClickOutside?: FieldInputEvent;
|
||||
onEnter?: FieldInputEvent;
|
||||
onEscape?: FieldInputEvent;
|
||||
onTab?: FieldInputEvent;
|
||||
onShiftTab?: FieldInputEvent;
|
||||
};
|
||||
|
||||
export const MoneyAmountV2FieldInput = ({
|
||||
onEnter,
|
||||
onEscape,
|
||||
onClickOutside,
|
||||
onTab,
|
||||
onShiftTab,
|
||||
}: MoneyAmountV2FieldInputProps) => {
|
||||
const { hotkeyScope, initialValue } = useMoneyAmountV2Field();
|
||||
|
||||
const persistField = usePersistField();
|
||||
|
||||
const handleEnter = (newDoubleText: FieldDoubleText) => {
|
||||
onEnter?.(() =>
|
||||
persistField({
|
||||
amount: parseFloat(newDoubleText.firstValue),
|
||||
currency: newDoubleText.secondValue,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const handleEscape = (newDoubleText: FieldDoubleText) => {
|
||||
onEscape?.(() =>
|
||||
persistField({
|
||||
amount: parseFloat(newDoubleText.firstValue),
|
||||
currency: newDoubleText.secondValue,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const handleClickOutside = (
|
||||
event: MouseEvent | TouchEvent,
|
||||
newDoubleText: FieldDoubleText,
|
||||
) => {
|
||||
onClickOutside?.(() =>
|
||||
persistField({
|
||||
amount: parseFloat(newDoubleText.firstValue),
|
||||
currency: newDoubleText.secondValue,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const handleTab = (newDoubleText: FieldDoubleText) => {
|
||||
onTab?.(() =>
|
||||
persistField({
|
||||
amount: parseFloat(newDoubleText.firstValue),
|
||||
currency: newDoubleText.secondValue,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const handleShiftTab = (newDoubleText: FieldDoubleText) => {
|
||||
onShiftTab?.(() =>
|
||||
persistField({
|
||||
amount: parseFloat(newDoubleText.firstValue),
|
||||
currency: newDoubleText.secondValue,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<FieldInputOverlay>
|
||||
<DoubleTextInput
|
||||
firstValue={initialValue.amount?.toString() ?? ''}
|
||||
secondValue={initialValue.currency ?? ''}
|
||||
firstValuePlaceholder="Amount"
|
||||
secondValuePlaceholder="Currency"
|
||||
onClickOutside={handleClickOutside}
|
||||
onEnter={handleEnter}
|
||||
onEscape={handleEscape}
|
||||
onShiftTab={handleShiftTab}
|
||||
onTab={handleTab}
|
||||
hotkeyScope={hotkeyScope}
|
||||
/>
|
||||
</FieldInputOverlay>
|
||||
);
|
||||
};
|
||||
@ -7,12 +7,14 @@ import { FieldDefinition } from '../../types/FieldDefinition';
|
||||
import { FieldMetadata } from '../../types/FieldMetadata';
|
||||
import { isFieldBoolean } from '../../types/guards/isFieldBoolean';
|
||||
import { isFieldChip } from '../../types/guards/isFieldChip';
|
||||
import { isFieldCurrency } from '../../types/guards/isFieldCurrency';
|
||||
import { isFieldCurrencyValue } from '../../types/guards/isFieldCurrencyValue';
|
||||
import { isFieldDate } from '../../types/guards/isFieldDate';
|
||||
import { isFieldDoubleTextChip } from '../../types/guards/isFieldDoubleTextChip';
|
||||
import { isFieldEmail } from '../../types/guards/isFieldEmail';
|
||||
import { isFieldLink } from '../../types/guards/isFieldLink';
|
||||
import { isFieldLinkValue } from '../../types/guards/isFieldLinkValue';
|
||||
import { isFieldMoney } from '../../types/guards/isFieldMoney';
|
||||
import { isFieldMoneyAmountV2 } from '../../types/guards/isFieldMoneyAmountV2';
|
||||
import { isFieldMoneyAmountV2Value } from '../../types/guards/isFieldMoneyAmountV2Value';
|
||||
import { isFieldNumber } from '../../types/guards/isFieldNumber';
|
||||
import { isFieldPhone } from '../../types/guards/isFieldPhone';
|
||||
import { isFieldProbability } from '../../types/guards/isFieldProbability';
|
||||
@ -20,8 +22,6 @@ import { isFieldRelation } from '../../types/guards/isFieldRelation';
|
||||
import { isFieldRelationValue } from '../../types/guards/isFieldRelationValue';
|
||||
import { isFieldText } from '../../types/guards/isFieldText';
|
||||
import { isFieldURL } from '../../types/guards/isFieldURL';
|
||||
import { isFieldURLV2 } from '../../types/guards/isFieldURLV2';
|
||||
import { isFieldURLV2Value } from '../../types/guards/isFieldURLV2Value';
|
||||
import { entityFieldsFamilyState } from '../entityFieldsFamilyState';
|
||||
|
||||
const isValueEmpty = (value: unknown) => !assertNotNull(value) || value === '';
|
||||
@ -98,21 +98,21 @@ export const isEntityFieldEmptyFamilySelector = selectorFamily({
|
||||
);
|
||||
}
|
||||
|
||||
if (isFieldMoneyAmountV2(fieldDefinition)) {
|
||||
if (isFieldCurrency(fieldDefinition)) {
|
||||
const fieldName = fieldDefinition.metadata.fieldName;
|
||||
const fieldValue = get(entityFieldsFamilyState(entityId))?.[fieldName];
|
||||
|
||||
return (
|
||||
!isFieldMoneyAmountV2Value(fieldValue) ||
|
||||
isValueEmpty(fieldValue?.amount)
|
||||
!isFieldCurrencyValue(fieldValue) ||
|
||||
isValueEmpty(fieldValue?.amountMicros)
|
||||
);
|
||||
}
|
||||
|
||||
if (isFieldURLV2(fieldDefinition)) {
|
||||
if (isFieldLink(fieldDefinition)) {
|
||||
const fieldName = fieldDefinition.metadata.fieldName;
|
||||
const fieldValue = get(entityFieldsFamilyState(entityId))?.[fieldName];
|
||||
|
||||
return !isFieldURLV2Value(fieldValue) || isValueEmpty(fieldValue?.link);
|
||||
return !isFieldLinkValue(fieldValue) || isValueEmpty(fieldValue?.url);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
|
||||
@ -21,7 +21,7 @@ export type FieldURLMetadata = {
|
||||
fieldName: string;
|
||||
};
|
||||
|
||||
export type FieldURLV2Metadata = {
|
||||
export type FieldLinkMetadata = {
|
||||
placeHolder: string;
|
||||
fieldName: string;
|
||||
};
|
||||
@ -42,7 +42,7 @@ export type FieldMoneyMetadata = {
|
||||
isPositive?: boolean;
|
||||
};
|
||||
|
||||
export type FieldMoneyAmountV2Metadata = {
|
||||
export type FieldCurrencyMetadata = {
|
||||
fieldName: string;
|
||||
placeHolder: string;
|
||||
isPositive?: boolean;
|
||||
@ -91,22 +91,22 @@ export type FieldBooleanMetadata = {
|
||||
};
|
||||
|
||||
export type FieldMetadata =
|
||||
| FieldUuidMetadata
|
||||
| FieldTextMetadata
|
||||
| FieldRelationMetadata
|
||||
| FieldBooleanMetadata
|
||||
| FieldChipMetadata
|
||||
| FieldCurrencyMetadata
|
||||
| FieldDateMetadata
|
||||
| FieldDoubleTextChipMetadata
|
||||
| FieldDoubleTextMetadata
|
||||
| FieldPhoneMetadata
|
||||
| FieldURLMetadata
|
||||
| FieldURLV2Metadata
|
||||
| FieldNumberMetadata
|
||||
| FieldMoneyMetadata
|
||||
| FieldMoneyAmountV2Metadata
|
||||
| FieldEmailMetadata
|
||||
| FieldDateMetadata
|
||||
| FieldLinkMetadata
|
||||
| FieldMoneyMetadata
|
||||
| FieldNumberMetadata
|
||||
| FieldPhoneMetadata
|
||||
| FieldProbabilityMetadata
|
||||
| FieldBooleanMetadata;
|
||||
| FieldRelationMetadata
|
||||
| FieldTextMetadata
|
||||
| FieldURLMetadata
|
||||
| FieldUuidMetadata;
|
||||
|
||||
export type FieldTextValue = string;
|
||||
export type FieldUUidValue = string;
|
||||
@ -115,10 +115,10 @@ export type FieldChipValue = string;
|
||||
export type FieldDateValue = string | null;
|
||||
export type FieldPhoneValue = string;
|
||||
export type FieldURLValue = string;
|
||||
export type FieldURLV2Value = { link: string; text: string };
|
||||
export type FieldLinkValue = { url: string; label: string };
|
||||
export type FieldNumberValue = number | null;
|
||||
export type FieldMoneyValue = number | null;
|
||||
export type FieldMoneyAmountV2Value = { currency: string; amount: number };
|
||||
export type FieldCurrencyValue = { currencyCode: string; amountMicros: number };
|
||||
|
||||
export type FieldEmailValue = string;
|
||||
export type FieldProbabilityValue = number;
|
||||
|
||||
@ -11,8 +11,8 @@ export type FieldType =
|
||||
| 'DATE'
|
||||
| 'PHONE'
|
||||
| 'URL'
|
||||
| 'URL_V2'
|
||||
| 'LINK'
|
||||
| 'PROBABILITY'
|
||||
| 'MONEY_AMOUNT_V2'
|
||||
| 'CURRENCY'
|
||||
| 'MONEY_AMOUNT'
|
||||
| 'MONEY';
|
||||
|
||||
@ -2,12 +2,13 @@ import { FieldDefinition } from '../FieldDefinition';
|
||||
import {
|
||||
FieldBooleanMetadata,
|
||||
FieldChipMetadata,
|
||||
FieldCurrencyMetadata,
|
||||
FieldDateMetadata,
|
||||
FieldDoubleTextChipMetadata,
|
||||
FieldDoubleTextMetadata,
|
||||
FieldEmailMetadata,
|
||||
FieldLinkMetadata,
|
||||
FieldMetadata,
|
||||
FieldMoneyAmountV2Metadata,
|
||||
FieldMoneyMetadata,
|
||||
FieldNumberMetadata,
|
||||
FieldPhoneMetadata,
|
||||
@ -15,45 +16,44 @@ import {
|
||||
FieldRelationMetadata,
|
||||
FieldTextMetadata,
|
||||
FieldURLMetadata,
|
||||
FieldURLV2Metadata,
|
||||
FieldUuidMetadata,
|
||||
} from '../FieldMetadata';
|
||||
import { FieldType } from '../FieldType';
|
||||
|
||||
type AssertFieldMetadataFunction = <
|
||||
E extends FieldType,
|
||||
T extends E extends 'TEXT'
|
||||
? FieldTextMetadata
|
||||
: E extends 'UUID'
|
||||
? FieldUuidMetadata
|
||||
: E extends 'RELATION'
|
||||
? FieldRelationMetadata
|
||||
T extends E extends 'BOOLEAN'
|
||||
? FieldBooleanMetadata
|
||||
: E extends 'CHIP'
|
||||
? FieldChipMetadata
|
||||
: E extends 'DOUBLE_TEXT_CHIP'
|
||||
? FieldDoubleTextChipMetadata
|
||||
: E extends 'DOUBLE_TEXT'
|
||||
? FieldDoubleTextMetadata
|
||||
: E extends 'NUMBER'
|
||||
? FieldNumberMetadata
|
||||
: E extends 'EMAIL'
|
||||
? FieldEmailMetadata
|
||||
: E extends 'BOOLEAN'
|
||||
? FieldBooleanMetadata
|
||||
: E extends 'CURRENCY'
|
||||
? FieldCurrencyMetadata
|
||||
: E extends 'DATE'
|
||||
? FieldDateMetadata
|
||||
: E extends 'PHONE'
|
||||
? FieldPhoneMetadata
|
||||
: E extends 'URL'
|
||||
? FieldURLMetadata
|
||||
: E extends 'URL_V2'
|
||||
? FieldURLV2Metadata
|
||||
: E extends 'PROBABILITY'
|
||||
? FieldProbabilityMetadata
|
||||
: E extends 'DOUBLE_TEXT'
|
||||
? FieldDoubleTextMetadata
|
||||
: E extends 'DOUBLE_TEXT_CHIP'
|
||||
? FieldDoubleTextChipMetadata
|
||||
: E extends 'EMAIL'
|
||||
? FieldEmailMetadata
|
||||
: E extends 'LINK'
|
||||
? FieldLinkMetadata
|
||||
: E extends 'MONEY_AMOUNT'
|
||||
? FieldMoneyMetadata
|
||||
: E extends 'MONEY_AMOUNT_V2'
|
||||
? FieldMoneyAmountV2Metadata
|
||||
: E extends 'NUMBER'
|
||||
? FieldNumberMetadata
|
||||
: E extends 'PHONE'
|
||||
? FieldPhoneMetadata
|
||||
: E extends 'PROBABILITY'
|
||||
? FieldProbabilityMetadata
|
||||
: E extends 'RELATION'
|
||||
? FieldRelationMetadata
|
||||
: E extends 'TEXT'
|
||||
? FieldTextMetadata
|
||||
: E extends 'URL'
|
||||
? FieldURLMetadata
|
||||
: E extends 'UUID'
|
||||
? FieldUuidMetadata
|
||||
: never,
|
||||
>(
|
||||
fieldType: E,
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
import { FieldDefinition } from '../FieldDefinition';
|
||||
import { FieldCurrencyMetadata, FieldMetadata } from '../FieldMetadata';
|
||||
|
||||
export const isFieldCurrency = (
|
||||
field: FieldDefinition<FieldMetadata>,
|
||||
): field is FieldDefinition<FieldCurrencyMetadata> => field.type === 'CURRENCY';
|
||||
@ -0,0 +1,13 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { FieldCurrencyValue } from '../FieldMetadata';
|
||||
|
||||
const currencySchema = z.object({
|
||||
currencyCode: z.string(),
|
||||
amountMicros: z.number(),
|
||||
});
|
||||
|
||||
export const isFieldCurrencyValue = (
|
||||
fieldValue: unknown,
|
||||
): fieldValue is FieldCurrencyValue =>
|
||||
currencySchema.safeParse(fieldValue).success;
|
||||
@ -0,0 +1,6 @@
|
||||
import { FieldDefinition } from '../FieldDefinition';
|
||||
import { FieldLinkMetadata, FieldMetadata } from '../FieldMetadata';
|
||||
|
||||
export const isFieldLink = (
|
||||
field: FieldDefinition<FieldMetadata>,
|
||||
): field is FieldDefinition<FieldLinkMetadata> => field.type === 'LINK';
|
||||
@ -0,0 +1,13 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { FieldLinkValue } from '../FieldMetadata';
|
||||
|
||||
const linkSchema = z.object({
|
||||
url: z.string(),
|
||||
label: z.string(),
|
||||
});
|
||||
|
||||
// TODO: add zod
|
||||
export const isFieldLinkValue = (
|
||||
fieldValue: unknown,
|
||||
): fieldValue is FieldLinkValue => linkSchema.safeParse(fieldValue).success;
|
||||
@ -1,7 +0,0 @@
|
||||
import { FieldDefinition } from '../FieldDefinition';
|
||||
import { FieldMetadata, FieldMoneyAmountV2Metadata } from '../FieldMetadata';
|
||||
|
||||
export const isFieldMoneyAmountV2 = (
|
||||
field: FieldDefinition<FieldMetadata>,
|
||||
): field is FieldDefinition<FieldMoneyAmountV2Metadata> =>
|
||||
field.type === 'MONEY_AMOUNT_V2';
|
||||
@ -1,13 +0,0 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { FieldMoneyAmountV2Value } from '../FieldMetadata';
|
||||
|
||||
const moneyAmountV2Schema = z.object({
|
||||
currency: z.string(),
|
||||
amount: z.number(),
|
||||
});
|
||||
|
||||
export const isFieldMoneyAmountV2Value = (
|
||||
fieldValue: unknown,
|
||||
): fieldValue is FieldMoneyAmountV2Value =>
|
||||
moneyAmountV2Schema.safeParse(fieldValue).success;
|
||||
@ -1,6 +0,0 @@
|
||||
import { FieldDefinition } from '../FieldDefinition';
|
||||
import { FieldMetadata, FieldURLV2Metadata } from '../FieldMetadata';
|
||||
|
||||
export const isFieldURLV2 = (
|
||||
field: FieldDefinition<FieldMetadata>,
|
||||
): field is FieldDefinition<FieldURLV2Metadata> => field.type === 'URL_V2';
|
||||
@ -1,13 +0,0 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { FieldURLV2Value } from '../FieldMetadata';
|
||||
|
||||
const urlV2Schema = z.object({
|
||||
link: z.string(),
|
||||
text: z.string(),
|
||||
});
|
||||
|
||||
// TODO: add zod
|
||||
export const isFieldURLV2Value = (
|
||||
fieldValue: unknown,
|
||||
): fieldValue is FieldURLV2Value => urlV2Schema.safeParse(fieldValue).success;
|
||||
30
front/src/utils/convert-currency-amount.ts
Normal file
30
front/src/utils/convert-currency-amount.ts
Normal file
@ -0,0 +1,30 @@
|
||||
export const convertCurrencyToCurrencyMicros = (
|
||||
currencyAmount: number | undefined,
|
||||
) => {
|
||||
if (!currencyAmount) {
|
||||
return undefined;
|
||||
}
|
||||
const currencyAmountAsNumber = +currencyAmount;
|
||||
if (isNaN(currencyAmountAsNumber)) {
|
||||
throw new Error(`Cannot convert ${currencyAmount} to micros`);
|
||||
}
|
||||
const currencyAmountAsMicros = currencyAmountAsNumber * 1000000;
|
||||
if (currencyAmountAsMicros % 1 !== 0) {
|
||||
throw new Error(`Cannot convert ${currencyAmount} to micros`);
|
||||
}
|
||||
return currencyAmountAsMicros;
|
||||
};
|
||||
|
||||
export const convertCurrencyMicrosToCurrency = (
|
||||
currencyAmountMicros: number | undefined,
|
||||
) => {
|
||||
if (!currencyAmountMicros) {
|
||||
return undefined;
|
||||
}
|
||||
const currencyAmountMicrosAsNumber = +currencyAmountMicros;
|
||||
if (isNaN(currencyAmountMicrosAsNumber)) {
|
||||
throw new Error(`Cannot convert ${currencyAmountMicros} to currency`);
|
||||
}
|
||||
const currencyAmount = currencyAmountMicrosAsNumber / 1000000;
|
||||
return currencyAmount;
|
||||
};
|
||||
@ -0,0 +1,15 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- The `currency` column on the `pipelines` table would be dropped and recreated. This will lead to data loss if there is data in the column.
|
||||
|
||||
*/
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CurrencyCode" AS ENUM ('AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BOV', 'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BZD', 'CAD', 'CDF', 'CHF', 'CLF', 'CLP', 'CNY', 'COP', 'COU', 'CRC', 'CUC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'GBP', 'GEL', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'INR', 'IQD', 'IRR', 'ISK', 'JMD', 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KMF', 'KPW', 'KRW', 'KWD', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRO', 'MRU', 'MUR', 'MVR', 'MWK', 'MXN', 'MXV', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDD', 'SDG', 'SEK', 'SGD', 'SHP', 'SLL', 'SOS', 'SRD', 'SSP', 'STD', 'STN', 'SVC', 'SYP', 'SZL', 'THB', 'TJS', 'TMM', 'TMT', 'TND', 'TOP', 'TRY', 'TTD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VEF', 'VES', 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XOF', 'XPF', 'XSU', 'XUA', 'YER', 'ZAR', 'ZMW', 'ZWL');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "pipelines" DROP COLUMN "currency",
|
||||
ADD COLUMN "currency" "CurrencyCode" NOT NULL DEFAULT 'USD';
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "Currency";
|
||||
@ -446,7 +446,7 @@ model ActivityTarget {
|
||||
}
|
||||
|
||||
// All of the world's currently active currencies based on the ISO 4217 standard
|
||||
enum Currency {
|
||||
enum CurrencyCode {
|
||||
AED
|
||||
AFN
|
||||
ALL
|
||||
@ -615,6 +615,8 @@ enum Currency {
|
||||
ZAR
|
||||
ZMW
|
||||
ZWL
|
||||
|
||||
@@map("CurrencyCode")
|
||||
}
|
||||
|
||||
model Pipeline {
|
||||
@ -640,7 +642,7 @@ model Pipeline {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
currency Currency @default(USD)
|
||||
currency CurrencyCode @default(USD)
|
||||
|
||||
@@map("pipelines")
|
||||
}
|
||||
|
||||
@ -27,8 +27,8 @@ export enum FieldMetadataType {
|
||||
NUMBER = 'NUMBER',
|
||||
PROBABILITY = 'PROBABILITY',
|
||||
ENUM = 'ENUM',
|
||||
URL = 'URL',
|
||||
MONEY = 'MONEY',
|
||||
LINK = 'LINK',
|
||||
CURRENCY = 'CURRENCY',
|
||||
RELATION = 'RELATION',
|
||||
}
|
||||
|
||||
|
||||
@ -23,21 +23,21 @@ export type FieldMetadataDynamicDefaultValue =
|
||||
| { type: 'uuid' }
|
||||
| { type: 'now' };
|
||||
|
||||
interface FieldMetadataDefaultValueUrl {
|
||||
text: string;
|
||||
link: string;
|
||||
interface FieldMetadataDefaultValueLink {
|
||||
label: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface FieldMetadataDefaultValueMoney {
|
||||
amount: number;
|
||||
currency: string;
|
||||
interface FieldMetadataDefaultValueCurrency {
|
||||
amountMicros: number;
|
||||
currencyCode: string;
|
||||
}
|
||||
|
||||
type AllFieldMetadataDefaultValueTypes =
|
||||
| FieldMetadataScalarDefaultValue
|
||||
| FieldMetadataDynamicDefaultValue
|
||||
| FieldMetadataDefaultValueUrl
|
||||
| FieldMetadataDefaultValueMoney;
|
||||
| FieldMetadataDefaultValueLink
|
||||
| FieldMetadataDefaultValueCurrency;
|
||||
|
||||
type FieldMetadataDefaultValueMapping = {
|
||||
[FieldMetadataType.UUID]: FieldMetadataDefaultValueString;
|
||||
@ -49,8 +49,8 @@ type FieldMetadataDefaultValueMapping = {
|
||||
[FieldMetadataType.NUMBER]: FieldMetadataDefaultValueNumber;
|
||||
[FieldMetadataType.PROBABILITY]: FieldMetadataDefaultValueNumber;
|
||||
[FieldMetadataType.ENUM]: FieldMetadataDefaultValueString;
|
||||
[FieldMetadataType.URL]: FieldMetadataDefaultValueUrl;
|
||||
[FieldMetadataType.MONEY]: FieldMetadataDefaultValueMoney;
|
||||
[FieldMetadataType.LINK]: FieldMetadataDefaultValueLink;
|
||||
[FieldMetadataType.CURRENCY]: FieldMetadataDefaultValueCurrency;
|
||||
};
|
||||
|
||||
type DefaultValueByFieldMetadata<T extends FieldMetadataType | 'default'> = [
|
||||
|
||||
@ -4,14 +4,14 @@ export interface FieldMetadataTargetColumnMapValue {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface FieldMetadataTargetColumnMapUrl {
|
||||
text: string;
|
||||
link: string;
|
||||
export interface FieldMetadataTargetColumnMapLink {
|
||||
label: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface FieldMetadataTargetColumnMapMoney {
|
||||
amount: string;
|
||||
currency: string;
|
||||
export interface FieldMetadataTargetColumnMapCurrency {
|
||||
amountMicros: string;
|
||||
currencyCode: string;
|
||||
}
|
||||
|
||||
type AllFieldMetadataTypes = {
|
||||
@ -19,8 +19,8 @@ type AllFieldMetadataTypes = {
|
||||
};
|
||||
|
||||
type FieldMetadataTypeMapping = {
|
||||
[FieldMetadataType.URL]: FieldMetadataTargetColumnMapUrl;
|
||||
[FieldMetadataType.MONEY]: FieldMetadataTargetColumnMapMoney;
|
||||
[FieldMetadataType.LINK]: FieldMetadataTargetColumnMapLink;
|
||||
[FieldMetadataType.CURRENCY]: FieldMetadataTargetColumnMapCurrency;
|
||||
};
|
||||
|
||||
type TypeByFieldMetadata<T extends FieldMetadataType | 'default'> =
|
||||
|
||||
@ -19,46 +19,49 @@ describe('convertFieldMetadataToColumnActions', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('should convert URL field metadata to column actions', () => {
|
||||
it('should convert LINK field metadata to column actions', () => {
|
||||
const fieldMetadata = {
|
||||
type: FieldMetadataType.URL,
|
||||
targetColumnMap: { text: 'url_text', link: 'url_link' },
|
||||
defaultValue: { text: 'http://example.com', link: 'Example' },
|
||||
type: FieldMetadataType.LINK,
|
||||
targetColumnMap: { label: 'linkLabel', url: 'linkURL' },
|
||||
defaultValue: { label: 'http://example.com', url: 'Example' },
|
||||
} as any;
|
||||
const columnActions = convertFieldMetadataToColumnActions(fieldMetadata);
|
||||
expect(columnActions).toEqual([
|
||||
{
|
||||
action: 'CREATE',
|
||||
columnName: 'url_text',
|
||||
columnName: 'linkLabel',
|
||||
columnType: 'varchar',
|
||||
defaultValue: "'http://example.com'",
|
||||
},
|
||||
{
|
||||
action: 'CREATE',
|
||||
columnName: 'url_link',
|
||||
columnName: 'linkURL',
|
||||
columnType: 'varchar',
|
||||
defaultValue: "'Example'",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should convert MONEY field metadata to column actions', () => {
|
||||
it('should convert CURRENCY field metadata to column actions', () => {
|
||||
const fieldMetadata = {
|
||||
type: FieldMetadataType.MONEY,
|
||||
targetColumnMap: { amount: 'money_amount', currency: 'money_currency' },
|
||||
defaultValue: { amount: 100, currency: 'USD' },
|
||||
type: FieldMetadataType.CURRENCY,
|
||||
targetColumnMap: {
|
||||
amountMicros: 'moneyAmountMicros',
|
||||
currencyCode: 'moneyCurrencyCode',
|
||||
},
|
||||
defaultValue: { amountMicros: 100 * 1_000_000, currencyCode: 'USD' },
|
||||
} as any;
|
||||
const columnActions = convertFieldMetadataToColumnActions(fieldMetadata);
|
||||
expect(columnActions).toEqual([
|
||||
{
|
||||
action: 'CREATE',
|
||||
columnName: 'money_amount',
|
||||
columnName: 'moneyAmountMicros',
|
||||
columnType: 'integer',
|
||||
defaultValue: 100,
|
||||
defaultValue: 100 * 1_000_000,
|
||||
},
|
||||
{
|
||||
action: 'CREATE',
|
||||
columnName: 'money_currency',
|
||||
columnName: 'moneyCurrencyCode',
|
||||
columnType: 'varchar',
|
||||
defaultValue: "'USD'",
|
||||
},
|
||||
|
||||
@ -12,21 +12,21 @@ describe('generateTargetColumnMap', () => {
|
||||
);
|
||||
expect(textMap).toEqual({ value: 'name' });
|
||||
|
||||
const urlMap = generateTargetColumnMap(
|
||||
FieldMetadataType.URL,
|
||||
const linkMap = generateTargetColumnMap(
|
||||
FieldMetadataType.LINK,
|
||||
false,
|
||||
'website',
|
||||
);
|
||||
expect(urlMap).toEqual({ text: 'website_text', link: 'website_link' });
|
||||
expect(linkMap).toEqual({ label: 'websiteLabel', url: 'websiteUrl' });
|
||||
|
||||
const moneyMap = generateTargetColumnMap(
|
||||
FieldMetadataType.MONEY,
|
||||
const currencyMap = generateTargetColumnMap(
|
||||
FieldMetadataType.CURRENCY,
|
||||
true,
|
||||
'price',
|
||||
);
|
||||
expect(moneyMap).toEqual({
|
||||
amount: '_price_amount',
|
||||
currency: '_price_currency',
|
||||
expect(currencyMap).toEqual({
|
||||
amountMicros: '_priceAmountMicros',
|
||||
currencyCode: '_priceCurrencyCode',
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -8,7 +8,9 @@ describe('serializeDefaultValue', () => {
|
||||
});
|
||||
|
||||
it('should handle uuid dynamic default value', () => {
|
||||
expect(serializeDefaultValue({ type: 'uuid' })).toBe('uuid_generate_v4()');
|
||||
expect(serializeDefaultValue({ type: 'uuid' })).toBe(
|
||||
'public.uuid_generate_v4()',
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle now dynamic default value', () => {
|
||||
|
||||
@ -124,44 +124,44 @@ describe('validateDefaultValueBasedOnType', () => {
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
// URL type
|
||||
it('should validate URL default value', () => {
|
||||
// LINK type
|
||||
it('should validate LINK default value', () => {
|
||||
expect(
|
||||
validateDefaultValueBasedOnType(
|
||||
{ text: 'http://example.com', link: 'Example' },
|
||||
FieldMetadataType.URL,
|
||||
{ label: 'http://example.com', url: 'Example' },
|
||||
FieldMetadataType.LINK,
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid URL default value', () => {
|
||||
it('should return false for invalid LINK default value', () => {
|
||||
expect(
|
||||
validateDefaultValueBasedOnType(
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error Just for testing purposes
|
||||
{ text: 123, link: {} },
|
||||
FieldMetadataType.URL,
|
||||
{ label: 123, url: {} },
|
||||
FieldMetadataType.LINK,
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
// MONEY type
|
||||
it('should validate MONEY default value', () => {
|
||||
// CURRENCY type
|
||||
it('should validate CURRENCY default value', () => {
|
||||
expect(
|
||||
validateDefaultValueBasedOnType(
|
||||
{ amount: 100, currency: 'USD' },
|
||||
FieldMetadataType.MONEY,
|
||||
{ amountMicros: 100, currencyCode: 'USD' },
|
||||
FieldMetadataType.CURRENCY,
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid MONEY default value', () => {
|
||||
it('should return false for invalid CURRENCY default value', () => {
|
||||
expect(
|
||||
validateDefaultValueBasedOnType(
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error Just for testing purposes
|
||||
{ amount: '100', currency: 'USD' },
|
||||
FieldMetadataType.MONEY,
|
||||
{ amountMicros: '100', currencyCode: 'USD' },
|
||||
FieldMetadataType.CURRENCY,
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
@ -85,41 +85,41 @@ export function convertFieldMetadataToColumnActions(
|
||||
},
|
||||
];
|
||||
}
|
||||
case FieldMetadataType.URL: {
|
||||
case FieldMetadataType.LINK: {
|
||||
const defaultValue =
|
||||
fieldMetadata.defaultValue as FieldMetadataDefaultValue<FieldMetadataType.URL>;
|
||||
fieldMetadata.defaultValue as FieldMetadataDefaultValue<FieldMetadataType.LINK>;
|
||||
|
||||
return [
|
||||
{
|
||||
action: TenantMigrationColumnActionType.CREATE,
|
||||
columnName: fieldMetadata.targetColumnMap.text,
|
||||
columnName: fieldMetadata.targetColumnMap.label,
|
||||
columnType: 'varchar',
|
||||
defaultValue: serializeDefaultValue(defaultValue?.text),
|
||||
defaultValue: serializeDefaultValue(defaultValue?.label),
|
||||
},
|
||||
{
|
||||
action: TenantMigrationColumnActionType.CREATE,
|
||||
columnName: fieldMetadata.targetColumnMap.link,
|
||||
columnName: fieldMetadata.targetColumnMap.url,
|
||||
columnType: 'varchar',
|
||||
defaultValue: serializeDefaultValue(defaultValue?.link),
|
||||
defaultValue: serializeDefaultValue(defaultValue?.url),
|
||||
},
|
||||
];
|
||||
}
|
||||
case FieldMetadataType.MONEY: {
|
||||
case FieldMetadataType.CURRENCY: {
|
||||
const defaultValue =
|
||||
fieldMetadata.defaultValue as FieldMetadataDefaultValue<FieldMetadataType.MONEY>;
|
||||
fieldMetadata.defaultValue as FieldMetadataDefaultValue<FieldMetadataType.CURRENCY>;
|
||||
|
||||
return [
|
||||
{
|
||||
action: TenantMigrationColumnActionType.CREATE,
|
||||
columnName: fieldMetadata.targetColumnMap.amount,
|
||||
columnName: fieldMetadata.targetColumnMap.amountMicros,
|
||||
columnType: 'integer',
|
||||
defaultValue: serializeDefaultValue(defaultValue?.amount),
|
||||
defaultValue: serializeDefaultValue(defaultValue?.amountMicros),
|
||||
},
|
||||
{
|
||||
action: TenantMigrationColumnActionType.CREATE,
|
||||
columnName: fieldMetadata.targetColumnMap.currency,
|
||||
columnName: fieldMetadata.targetColumnMap.currencyCode,
|
||||
columnType: 'varchar',
|
||||
defaultValue: serializeDefaultValue(defaultValue?.currency),
|
||||
defaultValue: serializeDefaultValue(defaultValue?.currencyCode),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@ -29,15 +29,15 @@ export function generateTargetColumnMap(
|
||||
return {
|
||||
value: columnName,
|
||||
};
|
||||
case FieldMetadataType.URL:
|
||||
case FieldMetadataType.LINK:
|
||||
return {
|
||||
text: `${columnName}_text`,
|
||||
link: `${columnName}_link`,
|
||||
label: `${columnName}Label`,
|
||||
url: `${columnName}Url`,
|
||||
};
|
||||
case FieldMetadataType.MONEY:
|
||||
case FieldMetadataType.CURRENCY:
|
||||
return {
|
||||
amount: `${columnName}_amount`,
|
||||
currency: `${columnName}_currency`,
|
||||
amountMicros: `${columnName}AmountMicros`,
|
||||
currencyCode: `${columnName}CurrencyCode`,
|
||||
};
|
||||
default:
|
||||
throw new BadRequestException(`Unknown type ${type}`);
|
||||
|
||||
@ -13,7 +13,7 @@ export const serializeDefaultValue = (
|
||||
if (typeof defaultValue === 'object' && 'type' in defaultValue) {
|
||||
switch (defaultValue.type) {
|
||||
case 'uuid':
|
||||
return 'uuid_generate_v4()';
|
||||
return 'public.uuid_generate_v4()';
|
||||
case 'now':
|
||||
return 'now()';
|
||||
default:
|
||||
|
||||
@ -54,22 +54,22 @@ export const validateDefaultValueBasedOnType = (
|
||||
defaultValue.value instanceof Date
|
||||
);
|
||||
|
||||
case FieldMetadataType.URL:
|
||||
case FieldMetadataType.LINK:
|
||||
return (
|
||||
typeof defaultValue === 'object' &&
|
||||
'text' in defaultValue &&
|
||||
typeof defaultValue.text === 'string' &&
|
||||
'link' in defaultValue &&
|
||||
typeof defaultValue.link === 'string'
|
||||
'label' in defaultValue &&
|
||||
typeof defaultValue.label === 'string' &&
|
||||
'url' in defaultValue &&
|
||||
typeof defaultValue.url === 'string'
|
||||
);
|
||||
|
||||
case FieldMetadataType.MONEY:
|
||||
case FieldMetadataType.CURRENCY:
|
||||
return (
|
||||
typeof defaultValue === 'object' &&
|
||||
'amount' in defaultValue &&
|
||||
typeof defaultValue.amount === 'number' &&
|
||||
'currency' in defaultValue &&
|
||||
typeof defaultValue.currency === 'string'
|
||||
'amountMicros' in defaultValue &&
|
||||
typeof defaultValue.amountMicros === 'number' &&
|
||||
'currencyCode' in defaultValue &&
|
||||
typeof defaultValue.currencyCode === 'string'
|
||||
);
|
||||
|
||||
default:
|
||||
|
||||
@ -75,7 +75,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
isNullable: true,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
// isSystem: true,
|
||||
isSystem: true,
|
||||
workspaceId: record.workspaceId,
|
||||
},
|
||||
{
|
||||
|
||||
@ -53,7 +53,7 @@ const personMetadata = {
|
||||
{
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.URL,
|
||||
type: FieldMetadataType.LINK,
|
||||
name: 'linkedinUrl',
|
||||
label: 'Linkedin',
|
||||
targetColumnMap: {
|
||||
@ -66,7 +66,7 @@ const personMetadata = {
|
||||
{
|
||||
isCustom: false,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.URL,
|
||||
type: FieldMetadataType.LINK,
|
||||
name: 'xUrl',
|
||||
label: 'X',
|
||||
targetColumnMap: {
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
import { ObjectMetadataInterface } from 'src/tenant/schema-builder/interfaces/object-metadata.interface';
|
||||
import { FieldMetadataInterface } from 'src/tenant/schema-builder/interfaces/field-metadata.interface';
|
||||
|
||||
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||
|
||||
export const currencyObjectDefinition = {
|
||||
id: FieldMetadataType.CURRENCY.toString(),
|
||||
nameSingular: 'currency',
|
||||
namePlural: 'currency',
|
||||
labelSingular: 'Currency',
|
||||
labelPlural: 'Currency',
|
||||
targetTableName: '',
|
||||
fields: [
|
||||
{
|
||||
id: 'amountMicros',
|
||||
type: FieldMetadataType.NUMBER,
|
||||
objectMetadataId: FieldMetadataType.CURRENCY.toString(),
|
||||
name: 'amountMicros',
|
||||
label: 'AmountMicros',
|
||||
targetColumnMap: { value: 'amountMicros' },
|
||||
isNullable: true,
|
||||
} satisfies FieldMetadataInterface,
|
||||
{
|
||||
id: 'currencyCode',
|
||||
type: FieldMetadataType.TEXT,
|
||||
objectMetadataId: FieldMetadataType.CURRENCY.toString(),
|
||||
name: 'currencyCode',
|
||||
label: 'Currency Code',
|
||||
targetColumnMap: { value: 'currencyCode' },
|
||||
isNullable: true,
|
||||
} satisfies FieldMetadataInterface,
|
||||
],
|
||||
fromRelations: [],
|
||||
toRelations: [],
|
||||
} satisfies ObjectMetadataInterface;
|
||||
@ -0,0 +1,35 @@
|
||||
import { ObjectMetadataInterface } from 'src/tenant/schema-builder/interfaces/object-metadata.interface';
|
||||
import { FieldMetadataInterface } from 'src/tenant/schema-builder/interfaces/field-metadata.interface';
|
||||
|
||||
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||
|
||||
export const linkObjectDefinition = {
|
||||
id: FieldMetadataType.LINK.toString(),
|
||||
nameSingular: 'link',
|
||||
namePlural: 'link',
|
||||
labelSingular: 'Link',
|
||||
labelPlural: 'Link',
|
||||
targetTableName: '',
|
||||
fields: [
|
||||
{
|
||||
id: 'label',
|
||||
type: FieldMetadataType.TEXT,
|
||||
objectMetadataId: FieldMetadataType.LINK.toString(),
|
||||
name: 'label',
|
||||
label: 'Label',
|
||||
targetColumnMap: { value: 'label' },
|
||||
isNullable: true,
|
||||
} satisfies FieldMetadataInterface,
|
||||
{
|
||||
id: 'url',
|
||||
type: FieldMetadataType.TEXT,
|
||||
objectMetadataId: FieldMetadataType.LINK.toString(),
|
||||
name: 'url',
|
||||
label: 'Url',
|
||||
targetColumnMap: { value: 'url' },
|
||||
isNullable: true,
|
||||
} satisfies FieldMetadataInterface,
|
||||
],
|
||||
fromRelations: [],
|
||||
toRelations: [],
|
||||
} satisfies ObjectMetadataInterface;
|
||||
@ -1,34 +0,0 @@
|
||||
import { ObjectMetadataInterface } from 'src/tenant/schema-builder/interfaces/object-metadata.interface';
|
||||
import { FieldMetadataInterface } from 'src/tenant/schema-builder/interfaces/field-metadata.interface';
|
||||
|
||||
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||
|
||||
export const moneyObjectDefinition = {
|
||||
id: FieldMetadataType.MONEY.toString(),
|
||||
nameSingular: 'Money',
|
||||
namePlural: 'Money',
|
||||
labelSingular: 'Money',
|
||||
labelPlural: 'Money',
|
||||
targetTableName: 'money',
|
||||
fields: [
|
||||
{
|
||||
id: 'amount',
|
||||
type: FieldMetadataType.NUMBER,
|
||||
objectMetadataId: FieldMetadataType.MONEY.toString(),
|
||||
name: 'amount',
|
||||
label: 'Amount',
|
||||
targetColumnMap: { value: 'amount' },
|
||||
isNullable: true,
|
||||
} satisfies FieldMetadataInterface,
|
||||
{
|
||||
id: 'currency',
|
||||
type: FieldMetadataType.TEXT,
|
||||
objectMetadataId: FieldMetadataType.MONEY.toString(),
|
||||
name: 'currency',
|
||||
label: 'Currency',
|
||||
targetColumnMap: { value: 'currency' },
|
||||
} satisfies FieldMetadataInterface,
|
||||
],
|
||||
fromRelations: [],
|
||||
toRelations: [],
|
||||
} satisfies ObjectMetadataInterface;
|
||||
@ -1,33 +0,0 @@
|
||||
import { ObjectMetadataInterface } from 'src/tenant/schema-builder/interfaces/object-metadata.interface';
|
||||
import { FieldMetadataInterface } from 'src/tenant/schema-builder/interfaces/field-metadata.interface';
|
||||
|
||||
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||
|
||||
export const urlObjectDefinition = {
|
||||
id: FieldMetadataType.URL.toString(),
|
||||
nameSingular: 'Url',
|
||||
namePlural: 'Url',
|
||||
labelSingular: 'Url',
|
||||
labelPlural: 'Url',
|
||||
targetTableName: 'url',
|
||||
fields: [
|
||||
{
|
||||
id: 'text',
|
||||
type: FieldMetadataType.TEXT,
|
||||
objectMetadataId: FieldMetadataType.URL.toString(),
|
||||
name: 'text',
|
||||
label: 'Text',
|
||||
targetColumnMap: { value: 'text' },
|
||||
} satisfies FieldMetadataInterface,
|
||||
{
|
||||
id: 'link',
|
||||
type: FieldMetadataType.TEXT,
|
||||
objectMetadataId: FieldMetadataType.URL.toString(),
|
||||
name: 'link',
|
||||
label: 'Link',
|
||||
targetColumnMap: { value: 'link' },
|
||||
} satisfies FieldMetadataInterface,
|
||||
],
|
||||
fromRelations: [],
|
||||
toRelations: [],
|
||||
} satisfies ObjectMetadataInterface;
|
||||
@ -52,7 +52,7 @@ export class TypeMapperService {
|
||||
const numberScalar =
|
||||
numberScalarMode === 'float' ? GraphQLFloat : GraphQLInt;
|
||||
|
||||
// URL and MONEY are handled in the factories because they are objects
|
||||
// LINK and CURRENCY are handled in the factories because they are objects
|
||||
const typeScalarMapping = new Map<FieldMetadataType, GraphQLScalarType>([
|
||||
[FieldMetadataType.UUID, GraphQLID],
|
||||
[FieldMetadataType.TEXT, GraphQLString],
|
||||
@ -78,7 +78,7 @@ export class TypeMapperService {
|
||||
const numberScalar =
|
||||
numberScalarMode === 'float' ? FloatFilterType : IntFilterType;
|
||||
|
||||
// URL and MONEY are handled in the factories because they are objects
|
||||
// LINK and CURRENCY are handled in the factories because they are objects
|
||||
const typeFilterMapping = new Map<
|
||||
FieldMetadataType,
|
||||
GraphQLInputObjectType | GraphQLScalarType<boolean, boolean>
|
||||
@ -100,7 +100,7 @@ export class TypeMapperService {
|
||||
mapToOrderByType(
|
||||
fieldMetadataType: FieldMetadataType,
|
||||
): GraphQLInputType | undefined {
|
||||
// URL and MONEY are handled in the factories because they are objects
|
||||
// LINK and CURRENCY are handled in the factories because they are objects
|
||||
const typeOrderByMapping = new Map<FieldMetadataType, GraphQLEnumType>([
|
||||
[FieldMetadataType.UUID, OrderByDirectionType],
|
||||
[FieldMetadataType.TEXT, OrderByDirectionType],
|
||||
|
||||
@ -14,8 +14,8 @@ import {
|
||||
} from './factories/input-type-definition.factory';
|
||||
import { getFieldMetadataType } from './utils/get-field-metadata-type.util';
|
||||
import { BuildSchemaOptions } from './interfaces/build-schema-optionts.interface';
|
||||
import { moneyObjectDefinition } from './object-definitions/money.object-definition';
|
||||
import { urlObjectDefinition } from './object-definitions/url.object-definition';
|
||||
import { currencyObjectDefinition } from './object-definitions/currency.object-definition';
|
||||
import { linkObjectDefinition } from './object-definitions/link.object-definition';
|
||||
import { ObjectMetadataInterface } from './interfaces/object-metadata.interface';
|
||||
import { FieldMetadataInterface } from './interfaces/field-metadata.interface';
|
||||
import { FilterTypeDefinitionFactory } from './factories/filter-type-definition.factory';
|
||||
@ -61,8 +61,8 @@ export class TypeDefinitionsGenerator {
|
||||
|
||||
private generateStaticObjectTypeDefs(options: BuildSchemaOptions) {
|
||||
const staticObjectMetadataCollection = [
|
||||
moneyObjectDefinition,
|
||||
urlObjectDefinition,
|
||||
currencyObjectDefinition,
|
||||
linkObjectDefinition,
|
||||
];
|
||||
|
||||
this.logger.log(
|
||||
|
||||
Reference in New Issue
Block a user