Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature : Adding percentage option to Input Number #8481

Merged
merged 15 commits into from
Nov 14, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,5 @@ export const formatFieldMetadataItemAsFieldDefinition = ({
metadata: fieldDefintionMetadata,
type: field.type,
}),
settings: field.settings,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,6 @@ export const RecordBoardCard = ({
metadata: fieldDefinition.metadata,
type: fieldDefinition.type,
}),
settings: fieldDefinition.settings,
},
useUpdateRecord: useUpdateOneRecordHook,
hotkeyScope: InlineCellHotkeyScope.InlineCell,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { useNumberFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useNumberFieldDisplay';
import { NumberDisplay } from '@/ui/field/display/components/NumberDisplay';
import { formatNumber } from '~/utils/format/number';

export const NumberFieldDisplay = () => {
const { fieldValue, fieldDefinition } = useNumberFieldDisplay();
return (
<NumberDisplay
value={fieldValue}
decimals={fieldDefinition.settings?.decimals}
/>
);
const decimals = fieldDefinition.metadata.settings?.decimals;
const type = fieldDefinition.metadata.settings?.type;
const value =
type === 'percentage' && fieldValue
? `${formatNumber(Number(fieldValue) * 100, decimals)}%`
: fieldValue
? formatNumber(Number(fieldValue), decimals)
: null;
return <NumberDisplay value={value} decimals={decimals} />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
castAsNumberOrNull,
} from '~/utils/cast-as-number-or-null';

import { isNull } from '@sniptt/guards';
import { FieldContext } from '../../contexts/FieldContext';
import { usePersistField } from '../../hooks/usePersistField';
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
Expand All @@ -33,12 +34,23 @@ export const useNumberField = () => {
const persistField = usePersistField();

const persistNumberField = (newValue: string) => {
if (fieldDefinition?.metadata?.settings?.type === 'percentage') {
newValue = newValue.replaceAll('%', '');
if (!canBeCastAsNumberOrNull(newValue)) {
return;
}
const castedValue = castAsNumberOrNull(newValue);
if (!isNull(castedValue)) {
persistField(castedValue / 100);
return;
}
persistField(null);
return;
}
if (!canBeCastAsNumberOrNull(newValue)) {
return;
}

const castedValue = castAsNumberOrNull(newValue);

persistField(castedValue);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,4 @@ export type FieldDefinition<T extends FieldMetadata> = {
infoTooltipContent?: string;
defaultValue?: any;
editButtonIcon?: IconComponent;
settings?: {
decimals?: number;
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,20 @@ import { CurrencyCode } from './CurrencyCode';
export type FieldUuidMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldBooleanMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldTextMetadata = {
objectMetadataNameSingular?: string;
placeHolder: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldDateTimeMetadata = {
Expand All @@ -46,74 +49,90 @@ export type FieldNumberMetadata = {
fieldName: string;
placeHolder: string;
isPositive?: boolean;
settings?: {
decimals?: number;
type?: 'percentage' | 'number';
};
};

export type FieldLinkMetadata = {
objectMetadataNameSingular?: string;
placeHolder: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldLinksMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldCurrencyMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
placeHolder: string;
isPositive?: boolean;
settings?: Record<string, never>;
};

export type FieldFullNameMetadata = {
objectMetadataNameSingular?: string;
placeHolder: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldEmailMetadata = {
objectMetadataNameSingular?: string;
placeHolder: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldEmailsMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldPhoneMetadata = {
objectMetadataNameSingular?: string;
placeHolder: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldRatingMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldAddressMetadata = {
objectMetadataNameSingular?: string;
placeHolder: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldRawJsonMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
placeHolder: string;
settings?: Record<string, never>;
};

export type FieldRichTextMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldPositionMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldRelationMetadata = {
Expand All @@ -125,40 +144,47 @@ export type FieldRelationMetadata = {
relationType?: RelationDefinitionType;
targetFieldMetadataName?: string;
useEditButton?: boolean;
settings?: Record<string, never>;
};

export type FieldSelectMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
options: { label: string; color: ThemeColor; value: string }[];
isNullable: boolean;
settings?: Record<string, never>;
};

export type FieldMultiSelectMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
options: { label: string; color: ThemeColor; value: string }[];
settings?: Record<string, never>;
};

export type FieldActorMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldArrayMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
values: { label: string; value: string }[];
settings?: Record<string, never>;
};

export type FieldPhonesMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldTsVectorMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
settings?: Record<string, never>;
};

export type FieldMetadata =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { FieldInputDraftValue } from '@/object-record/record-field/types/FieldIn
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { isFieldCurrency } from '@/object-record/record-field/types/guards/isFieldCurrency';
import { isFieldCurrencyValue } from '@/object-record/record-field/types/guards/isFieldCurrencyValue';
import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber';
import { isFieldNumberValue } from '@/object-record/record-field/types/guards/isFieldNumberValue';
import { isFieldRawJson } from '@/object-record/record-field/types/guards/isFieldRawJson';
import { isFieldRawJsonValue } from '@/object-record/record-field/types/guards/isFieldRawJsonValue';
import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation';
Expand All @@ -12,7 +14,7 @@ import { isDefined } from '~/utils/isDefined';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';

type computeDraftValueFromFieldValueParams<FieldValue> = {
fieldDefinition: Pick<FieldDefinition<FieldMetadata>, 'type'>;
fieldDefinition: Pick<FieldDefinition<FieldMetadata>, 'type' | 'metadata'>;
fieldValue: FieldValue;
};

Expand Down Expand Up @@ -40,6 +42,18 @@ export const computeDraftValueFromFieldValue = <FieldValue>({
} as unknown as FieldInputDraftValue<FieldValue>;
}

if (
isFieldNumber(fieldDefinition) &&
isFieldNumberValue(fieldValue) &&
fieldDefinition.metadata.settings?.type === 'percentage'
) {
return (isUndefinedOrNull(fieldValue)
? ''
: (
fieldValue * 100
).toString()) as unknown as FieldInputDraftValue<FieldValue>;
}

if (isFieldRelation(fieldDefinition)) {
return computeEmptyDraftValue<FieldValue>({ fieldDefinition });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ import { z } from 'zod';

export const numberFieldDefaultValueSchema = z.object({
decimals: z.number().nullable(),
type: z.enum(['percentage', 'number']).nullable(),
});
Original file line number Diff line number Diff line change
Expand Up @@ -304,9 +304,6 @@ describe('useRecordData', () => {
},
},
position: expect.any(Number),
settings: {
displayAsRelativeDate: true,
},
showLabel: undefined,
size: 100,
type: 'DATE_TIME',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { z } from 'zod';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { numberFieldDefaultValueSchema } from '@/object-record/record-field/validation-schemas/numberFieldDefaultValueSchema';
import { SettingsDataModelFieldNumberDecimalsInput } from '@/settings/data-model/fields/forms/number/components/SettingsDataModelFieldNumberDecimalInput';
import { CardContent } from 'twenty-ui';
import { Select } from '@/ui/input/components/Select';
import styled from '@emotion/styled';
import { CardContent, IconNumber9, IconPercentage } from 'twenty-ui';
import { DEFAULT_DECIMAL_VALUE } from '~/utils/format/number';

export const settingsDataModelFieldNumberFormSchema = z.object({
Expand All @@ -15,6 +17,13 @@ export type SettingsDataModelFieldNumberFormValues = z.infer<
typeof settingsDataModelFieldNumberFormSchema
>;

const StyledFormCardTitle = styled.div`
color: ${({ theme }) => theme.font.color.light};
font-size: ${({ theme }) => theme.font.size.xs};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin-bottom: ${({ theme }) => theme.spacing(1)};
`;

type SettingsDataModelFieldNumberFormProps = {
disabled?: boolean;
fieldMetadataItem: Pick<
Expand All @@ -36,17 +45,43 @@ export const SettingsDataModelFieldNumberForm = ({
defaultValue={{
decimals:
fieldMetadataItem?.settings?.decimals ?? DEFAULT_DECIMAL_VALUE,
type: fieldMetadataItem?.settings?.type || 'number',
}}
control={control}
render={({ field: { onChange, value } }) => {
const count = value?.decimals ?? 0;
const type = value?.type ?? 'number';

return (
<SettingsDataModelFieldNumberDecimalsInput
value={count}
onChange={(value) => onChange({ decimals: value })}
disabled={disabled}
></SettingsDataModelFieldNumberDecimalsInput>
<>
<StyledFormCardTitle>Type</StyledFormCardTitle>
<Select
disabled={disabled}
dropdownId="selectNumberTypes"
options={[
{
label: 'Number',
value: 'number',
Icon: IconNumber9,
},
{
label: 'Percentage',
value: 'percentage',
Icon: IconPercentage,
},
]}
value={type}
onChange={(value) => onChange({ type: value, decimals: count })}
withSearchInput={false}
dropdownWidthAuto={true}
/>
<br />
<SettingsDataModelFieldNumberDecimalsInput
value={count}
onChange={(value) => onChange({ type: type, decimals: value })}
disabled={disabled}
/>
</>
);
}}
/>
Expand Down
Loading
Loading