feat: add sub fields for address (#13566)

https://github.com/user-attachments/assets/8fe9079d-9b66-4b42-8b11-ad713e9de666

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
Naifer
2025-08-02 22:43:39 +01:00
committed by GitHub
parent 4624739879
commit 2bda929984
20 changed files with 1138 additions and 112 deletions
@@ -1,19 +1,14 @@
import { isNonEmptyString } from '@sniptt/guards';
import { useAddressFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useAddressFieldDisplay';
import { TextDisplay } from '@/ui/field/display/components/TextDisplay';
import { formatAddressDisplay } from '~/utils/formatAddressDisplay';
export const AddressFieldDisplay = () => {
const { fieldValue } = useAddressFieldDisplay();
const { fieldValue, fieldDefinition } = useAddressFieldDisplay();
const settings = fieldDefinition.metadata.settings;
const content = [
fieldValue?.addressStreet1,
fieldValue?.addressStreet2,
fieldValue?.addressCity,
fieldValue?.addressCountry,
]
.filter(isNonEmptyString)
.join(', ');
const subFields =
settings && 'subFields' in settings ? settings.subFields : undefined;
return <TextDisplay text={content} />;
const parsedFieldValue = formatAddressDisplay(fieldValue, subFields);
return <TextDisplay text={parsedFieldValue} />;
};
@@ -25,7 +25,7 @@ export const AddressFieldInput = ({
onTab,
onShiftTab,
}: AddressFieldInputProps) => {
const { draftValue, setDraftValue } = useAddressField();
const { draftValue, setDraftValue, fieldDefinition } = useAddressField();
const persistField = usePersistField();
@@ -43,7 +43,10 @@ export const AddressFieldInput = ({
addressLng: newAddress?.addressLng ?? null,
};
};
const settings = fieldDefinition.metadata.settings;
const subFields =
settings && 'subFields' in settings ? settings.subFields : undefined;
const handleEnter = (newAddress: FieldAddressDraftValue) => {
onEnter?.(() => persistField(convertToAddress(newAddress)));
};
@@ -85,6 +88,7 @@ export const AddressFieldInput = ({
onChange={handleChange}
onTab={handleTab}
onShiftTab={handleShiftTab}
subFields={subFields}
/>
);
};
@@ -1,6 +1,7 @@
import { RATING_VALUES } from '@/object-record/record-field/meta-types/constants/RatingValues';
import { ZodHelperLiteral } from '@/object-record/record-field/types/ZodHelperLiteral';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { AllowedAddressSubField } from 'twenty-shared/src/types/AddressFieldsType';
import { ConnectedAccountProvider } from 'twenty-shared/types';
import { ThemeColor } from 'twenty-ui/theme';
import { z } from 'zod';
@@ -114,7 +115,9 @@ export type FieldRatingMetadata = BaseFieldMetadata & {
export type FieldAddressMetadata = BaseFieldMetadata & {
placeHolder: string;
settings?: null;
settings?: {
subFields?: AllowedAddressSubField[] | null;
};
};
export type FieldRawJsonMetadata = BaseFieldMetadata & {
@@ -1,5 +1,6 @@
import { z } from 'zod';
import { ALLOWED_ADDRESS_SUBFIELDS } from 'twenty-shared/src/types/AddressFieldsType';
import { FieldAddressValue } from '../FieldMetadata';
export const addressSchema = z.object({
@@ -17,3 +18,11 @@ export const isFieldAddressValue = (
fieldValue: unknown,
): fieldValue is FieldAddressValue =>
addressSchema.safeParse(fieldValue).success;
export const addressSettingsSchema = z.object({
subFields: z
.array(z.enum(ALLOWED_ADDRESS_SUBFIELDS))
.min(1)
.optional()
.nullable(),
});