Fix phone not reactive (#8918)

Fixin reactivity on the multi items phone component (add/delete/edit
phones)

<img width="325" alt="Screenshot 2024-12-06 at 11 03 34"
src="https://github.com/user-attachments/assets/96ddaf82-19ae-4a09-aa45-04caad2f0af1">

---------

Co-authored-by: khuddite <khuddite@gmail.com>
Co-authored-by: Weiko <deniaud.corentin@gmail.com>
This commit is contained in:
Guillim 2024-12-06 14:45:14 +01:00 committed by GitHub
parent 36fb14179b
commit 14b7bcf262
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 116 additions and 17 deletions

View File

@ -2,13 +2,13 @@ import { usePhonesField } from '@/object-record/record-field/meta-types/hooks/us
import { PhonesFieldMenuItem } from '@/object-record/record-field/meta-types/input/components/PhonesFieldMenuItem'; import { PhonesFieldMenuItem } from '@/object-record/record-field/meta-types/input/components/PhonesFieldMenuItem';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { E164Number, parsePhoneNumber } from 'libphonenumber-js'; import { E164Number, parsePhoneNumber } from 'libphonenumber-js';
import { useMemo } from 'react';
import ReactPhoneNumberInput from 'react-phone-number-input'; import ReactPhoneNumberInput from 'react-phone-number-input';
import 'react-phone-number-input/style.css'; import 'react-phone-number-input/style.css';
import { TEXT_INPUT_STYLE, isDefined } from 'twenty-ui'; import { TEXT_INPUT_STYLE } from 'twenty-ui';
import { MultiItemFieldInput } from './MultiItemFieldInput'; import { MultiItemFieldInput } from './MultiItemFieldInput';
import { createPhonesFromFieldValue } from '@/object-record/record-field/meta-types/input/utils/phonesUtils';
import { useCountries } from '@/ui/input/components/internal/hooks/useCountries'; import { useCountries } from '@/ui/input/components/internal/hooks/useCountries';
import { PhoneCountryPickerDropdownButton } from '@/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton'; import { PhoneCountryPickerDropdownButton } from '@/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton';
import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldMetadataType } from '~/generated-metadata/graphql';
@ -52,23 +52,10 @@ type PhonesFieldInputProps = {
}; };
export const PhonesFieldInput = ({ onCancel }: PhonesFieldInputProps) => { export const PhonesFieldInput = ({ onCancel }: PhonesFieldInputProps) => {
const { persistPhonesField, hotkeyScope, draftValue, fieldDefinition } = const { persistPhonesField, hotkeyScope, fieldDefinition, fieldValue } =
usePhonesField(); usePhonesField();
const phones = useMemo<{ number: string; callingCode: string }[]>(() => { const phones = createPhonesFromFieldValue(fieldValue);
if (!isDefined(draftValue)) {
return [];
}
return [
draftValue.primaryPhoneNumber
? {
number: draftValue.primaryPhoneNumber,
callingCode: draftValue.primaryPhoneCountryCode,
}
: null,
...(draftValue.additionalPhones ?? []),
].filter(isDefined);
}, [draftValue]);
const defaultCallingCode = const defaultCallingCode =
stripSimpleQuotesFromString( stripSimpleQuotesFromString(

View File

@ -0,0 +1,96 @@
import { FieldPhonesValue } from '@/object-record/record-field/types/FieldMetadata';
import { createPhonesFromFieldValue } from '../phonesUtils';
describe('createPhonesFromFieldValue test suite', () => {
it('should return an empty array if fieldValue is undefined', () => {
const result = createPhonesFromFieldValue(
undefined as unknown as FieldPhonesValue,
);
expect(result).toEqual([]);
});
it('should return an empty array if fieldValue is null', () => {
const result = createPhonesFromFieldValue(
null as unknown as FieldPhonesValue,
);
expect(result).toEqual([]);
});
it('should return an array with primary phone number if it is defined', () => {
const fieldValue: FieldPhonesValue = {
primaryPhoneNumber: '123456789',
primaryPhoneCountryCode: '+1',
additionalPhones: [],
};
const result = createPhonesFromFieldValue(fieldValue);
expect(result).toEqual([
{
number: '123456789',
callingCode: '+1',
},
]);
});
it('should return an array with both primary and additional phones if they are defined', () => {
const fieldValue: FieldPhonesValue = {
primaryPhoneNumber: '123456789',
primaryPhoneCountryCode: '+1',
additionalPhones: [
{ number: '987654321', callingCode: '+44' },
{ number: '555555555', callingCode: '+33' },
],
};
const result = createPhonesFromFieldValue(fieldValue);
expect(result).toEqual([
{
number: '123456789',
callingCode: '+1',
},
{ number: '987654321', callingCode: '+44' },
{ number: '555555555', callingCode: '+33' },
]);
});
it('should return an array with additional phones if they are defined while no primary phone defined', () => {
const fieldValue: FieldPhonesValue = {
primaryPhoneNumber: '',
primaryPhoneCountryCode: '',
additionalPhones: [
{ number: '987654321', callingCode: '+44' },
{ number: '555555555', callingCode: '+33' },
],
};
const result = createPhonesFromFieldValue(fieldValue);
expect(result).toEqual([
{ number: '987654321', callingCode: '+44' },
{ number: '555555555', callingCode: '+33' },
]);
});
it('should return an array with both primary and additional phones if they are defined, with primary as an extra space', () => {
const fieldValue: FieldPhonesValue = {
primaryPhoneNumber: ' ',
primaryPhoneCountryCode: '',
additionalPhones: [
{ number: '987654321', callingCode: '+44' },
{ number: '555555555', callingCode: '+33' },
],
};
const result = createPhonesFromFieldValue(fieldValue);
expect(result).toEqual([
{ number: ' ', callingCode: '' },
{ number: '987654321', callingCode: '+44' },
{ number: '555555555', callingCode: '+33' },
]);
});
it('should return an empty array if only country code is defined', () => {
const fieldValue: FieldPhonesValue = {
primaryPhoneNumber: '',
primaryPhoneCountryCode: '+33',
additionalPhones: [],
};
const result = createPhonesFromFieldValue(fieldValue);
expect(result).toEqual([]);
});
});

View File

@ -0,0 +1,16 @@
import { FieldPhonesValue } from '@/object-record/record-field/types/FieldMetadata';
import { isDefined } from 'twenty-ui';
export const createPhonesFromFieldValue = (fieldValue: FieldPhonesValue) => {
return !isDefined(fieldValue)
? []
: [
fieldValue.primaryPhoneNumber
? {
number: fieldValue.primaryPhoneNumber,
callingCode: fieldValue.primaryPhoneCountryCode,
}
: null,
...(fieldValue.additionalPhones ?? []),
].filter(isDefined);
};