Phone country code unique (#9035)

fix #8775
This commit is contained in:
Guillim
2024-12-19 16:42:18 +01:00
committed by GitHub
parent 3f58a41d2f
commit 360c34fd18
47 changed files with 878 additions and 132 deletions

View File

@ -30,6 +30,7 @@ export const PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS = `
phones {
primaryPhoneNumber
primaryPhoneCountryCode
primaryPhoneCallingCode
additionalPhones
}
position
@ -37,6 +38,7 @@ export const PERSON_FRAGMENT_WITH_DEPTH_ZERO_RELATIONS = `
whatsapp {
primaryPhoneNumber
primaryPhoneCountryCode
primaryPhoneCallingCode
additionalPhones
}
workPreference
@ -229,6 +231,7 @@ export const PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS = `
phones {
primaryPhoneNumber
primaryPhoneCountryCode
primaryPhoneCallingCode
additionalPhones
}
pointOfContactForOpportunities {
@ -305,6 +308,7 @@ export const PERSON_FRAGMENT_WITH_DEPTH_ONE_RELATIONS = `
whatsapp {
primaryPhoneNumber
primaryPhoneCountryCode
primaryPhoneCallingCode
additionalPhones
}
workPreference

View File

@ -38,6 +38,7 @@ export const responseData = {
},
phones: {
primaryPhoneCountryCode: '',
primaryPhoneCallingCode: '',
primaryPhoneNumber: '',
},
linkedinLink: {

View File

@ -43,6 +43,7 @@ export const responseData = {
},
phones: {
primaryPhoneCountryCode: '',
primaryPhoneCallingCode: '',
primaryPhoneNumber: '',
},
linkedinLink: {

View File

@ -178,6 +178,7 @@ const mocks: MockedResponse[] = [
phones {
primaryPhoneNumber
primaryPhoneCountryCode
primaryPhoneCallingCode
additionalPhones
}
position
@ -185,6 +186,7 @@ const mocks: MockedResponse[] = [
whatsapp {
primaryPhoneNumber
primaryPhoneCountryCode
primaryPhoneCallingCode
additionalPhones
}
workPreference
@ -332,6 +334,7 @@ const mocks: MockedResponse[] = [
phones {
primaryPhoneNumber
primaryPhoneCountryCode
primaryPhoneCallingCode
additionalPhones
}
position
@ -339,6 +342,7 @@ const mocks: MockedResponse[] = [
whatsapp {
primaryPhoneNumber
primaryPhoneCountryCode
primaryPhoneCallingCode
additionalPhones
}
workPreference

View File

@ -39,7 +39,8 @@ const mocks: MockedResponse[] = [
input: {
phones: {
primaryPhoneNumber: '123 456',
primaryPhoneCountryCode: '+1',
primaryPhoneCountryCode: 'US',
primaryPhoneCallingCode: '+1',
additionalPhones: [],
},
},
@ -134,7 +135,8 @@ describe('usePersistField', () => {
act(() => {
result.current.persistField({
primaryPhoneNumber: '123 456',
primaryPhoneCountryCode: '+1',
primaryPhoneCountryCode: 'US',
primaryPhoneCallingCode: '+1',
additionalPhones: [],
});
});

View File

@ -208,6 +208,7 @@ const mocks: MockedResponse[] = [
phones {
primaryPhoneNumber
primaryPhoneCountryCode
primaryPhoneCallingCode
additionalPhones
}
position
@ -215,6 +216,7 @@ const mocks: MockedResponse[] = [
whatsapp {
primaryPhoneNumber
primaryPhoneCountryCode
primaryPhoneCallingCode
additionalPhones
}
workPreference

View File

@ -9,12 +9,11 @@ import { TEXT_INPUT_STYLE } from 'twenty-ui';
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 { PhoneCountryPickerDropdownButton } from '@/ui/input/components/internal/phone/components/PhoneCountryPickerDropdownButton';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { stripSimpleQuotesFromString } from '~/utils/string/stripSimpleQuotesFromString';
export const DEFAULT_PHONE_COUNTRY_CODE = '1';
export const DEFAULT_PHONE_CALLING_CODE = '1';
const StyledCustomPhoneInput = styled(ReactPhoneNumberInput)`
font-family: ${({ theme }) => theme.font.family};
@ -60,22 +59,22 @@ export const PhonesFieldInput = ({
const phones = createPhonesFromFieldValue(fieldValue);
const defaultCallingCode =
stripSimpleQuotesFromString(
fieldDefinition?.defaultValue?.primaryPhoneCountryCode,
) ?? DEFAULT_PHONE_COUNTRY_CODE;
// TODO : improve once we store the real country code
const defaultCountry = useCountries().find(
(obj) => `+${obj.callingCode}` === defaultCallingCode,
)?.countryCode;
const defaultCountry = stripSimpleQuotesFromString(
fieldDefinition?.defaultValue?.primaryPhoneCountryCode,
);
const handlePersistPhones = (
updatedPhones: { number: string; callingCode: string }[],
updatedPhones: {
number: string;
countryCode: string;
callingCode: string;
}[],
) => {
const [nextPrimaryPhone, ...nextAdditionalPhones] = updatedPhones;
persistPhonesField({
primaryPhoneNumber: nextPrimaryPhone?.number ?? '',
primaryPhoneCountryCode: nextPrimaryPhone?.callingCode ?? '',
primaryPhoneCountryCode: nextPrimaryPhone?.countryCode ?? '',
primaryPhoneCallingCode: nextPrimaryPhone?.callingCode ?? '',
additionalPhones: nextAdditionalPhones,
});
};
@ -96,11 +95,13 @@ export const PhonesFieldInput = ({
return {
number: phone.nationalNumber,
callingCode: `+${phone.countryCallingCode}`,
countryCode: phone.country as string,
};
}
return {
number: '',
callingCode: '',
countryCode: '',
};
}}
renderItem={({

View File

@ -19,7 +19,8 @@ describe('createPhonesFromFieldValue test suite', () => {
it('should return an array with primary phone number if it is defined', () => {
const fieldValue: FieldPhonesValue = {
primaryPhoneNumber: '123456789',
primaryPhoneCountryCode: '+1',
primaryPhoneCountryCode: 'US',
primaryPhoneCallingCode: '+1',
additionalPhones: [],
};
const result = createPhonesFromFieldValue(fieldValue);
@ -27,6 +28,24 @@ describe('createPhonesFromFieldValue test suite', () => {
{
number: '123456789',
callingCode: '+1',
countryCode: 'US',
},
]);
});
it('should return an array with primary phone number if it is defined, even with incorrect callingCode', () => {
const fieldValue: FieldPhonesValue = {
primaryPhoneNumber: '123456789',
primaryPhoneCountryCode: 'US',
primaryPhoneCallingCode: '+33',
additionalPhones: [],
};
const result = createPhonesFromFieldValue(fieldValue);
expect(result).toEqual([
{
number: '123456789',
callingCode: '+33',
countryCode: 'US',
},
]);
});
@ -34,10 +53,11 @@ describe('createPhonesFromFieldValue test suite', () => {
it('should return an array with both primary and additional phones if they are defined', () => {
const fieldValue: FieldPhonesValue = {
primaryPhoneNumber: '123456789',
primaryPhoneCountryCode: '+1',
primaryPhoneCountryCode: 'US',
primaryPhoneCallingCode: '+1',
additionalPhones: [
{ number: '987654321', callingCode: '+44' },
{ number: '555555555', callingCode: '+33' },
{ number: '987654321', callingCode: '+44', countryCode: 'GB' },
{ number: '555555555', callingCode: '+33', countryCode: 'FR' },
],
};
const result = createPhonesFromFieldValue(fieldValue);
@ -45,9 +65,10 @@ describe('createPhonesFromFieldValue test suite', () => {
{
number: '123456789',
callingCode: '+1',
countryCode: 'US',
},
{ number: '987654321', callingCode: '+44' },
{ number: '555555555', callingCode: '+33' },
{ number: '987654321', callingCode: '+44', countryCode: 'GB' },
{ number: '555555555', callingCode: '+33', countryCode: 'FR' },
]);
});
@ -56,14 +77,14 @@ describe('createPhonesFromFieldValue test suite', () => {
primaryPhoneNumber: '',
primaryPhoneCountryCode: '',
additionalPhones: [
{ number: '987654321', callingCode: '+44' },
{ number: '555555555', callingCode: '+33' },
{ number: '987654321', callingCode: '+44', countryCode: 'GB' },
{ number: '555555555', callingCode: '+33', countryCode: 'FR' },
],
};
const result = createPhonesFromFieldValue(fieldValue);
expect(result).toEqual([
{ number: '987654321', callingCode: '+44' },
{ number: '555555555', callingCode: '+33' },
{ number: '987654321', callingCode: '+44', countryCode: 'GB' },
{ number: '555555555', callingCode: '+33', countryCode: 'FR' },
]);
});
@ -72,22 +93,34 @@ describe('createPhonesFromFieldValue test suite', () => {
primaryPhoneNumber: ' ',
primaryPhoneCountryCode: '',
additionalPhones: [
{ number: '987654321', callingCode: '+44' },
{ number: '555555555', callingCode: '+33' },
{ number: '987654321', callingCode: '+44', countryCode: 'GB' },
{ number: '555555555', callingCode: '+33', countryCode: 'FR' },
],
};
const result = createPhonesFromFieldValue(fieldValue);
expect(result).toEqual([
{ number: ' ', callingCode: '' },
{ number: '987654321', callingCode: '+44' },
{ number: '555555555', callingCode: '+33' },
{ number: ' ', callingCode: '', countryCode: '' },
{ number: '987654321', callingCode: '+44', countryCode: 'GB' },
{ number: '555555555', callingCode: '+33', countryCode: 'FR' },
]);
});
it('should return an empty array if only country code is defined', () => {
it('should return an empty array if only country and calling code are defined', () => {
const fieldValue: FieldPhonesValue = {
primaryPhoneNumber: '',
primaryPhoneCountryCode: '+33',
primaryPhoneCountryCode: 'FR',
primaryPhoneCallingCode: '+33',
additionalPhones: [],
};
const result = createPhonesFromFieldValue(fieldValue);
expect(result).toEqual([]);
});
it('should return an empty array if only calling code is defined', () => {
const fieldValue: FieldPhonesValue = {
primaryPhoneNumber: '',
primaryPhoneCallingCode: '+33',
primaryPhoneCountryCode: '',
additionalPhones: [],
};
const result = createPhonesFromFieldValue(fieldValue);

View File

@ -8,7 +8,10 @@ export const createPhonesFromFieldValue = (fieldValue: FieldPhonesValue) => {
fieldValue.primaryPhoneNumber
? {
number: fieldValue.primaryPhoneNumber,
callingCode: fieldValue.primaryPhoneCountryCode,
callingCode: fieldValue.primaryPhoneCallingCode
? fieldValue.primaryPhoneCallingCode
: fieldValue.primaryPhoneCountryCode,
countryCode: fieldValue.primaryPhoneCountryCode,
}
: null,
...(fieldValue.additionalPhones ?? []),

View File

@ -27,6 +27,7 @@ export type FieldDateTimeDraftValue = string;
export type FieldPhonesDraftValue = {
primaryPhoneNumber: string;
primaryPhoneCountryCode: string;
primaryPhoneCallingCode: string;
additionalPhones?: PhoneRecord[] | null;
};
export type FieldEmailsDraftValue = {

View File

@ -265,10 +265,15 @@ export type FieldActorValue = {
export type FieldArrayValue = string[];
export type PhoneRecord = { number: string; callingCode: string };
export type PhoneRecord = {
number: string;
callingCode: string;
countryCode: string;
};
export type FieldPhonesValue = {
primaryPhoneNumber: string;
primaryPhoneCountryCode: string;
primaryPhoneCallingCode?: string;
additionalPhones?: PhoneRecord[] | null;
};

View File

@ -5,8 +5,15 @@ import { FieldPhonesValue } from '../FieldMetadata';
export const phonesSchema = z.object({
primaryPhoneNumber: z.string(),
primaryPhoneCountryCode: z.string(),
primaryPhoneCallingCode: z.string(),
additionalPhones: z
.array(z.object({ number: z.string(), callingCode: z.string() }))
.array(
z.object({
number: z.string(),
callingCode: z.string(),
countryCode: z.string(),
}),
)
.nullable(),
}) satisfies z.ZodType<FieldPhonesValue>;

View File

@ -71,6 +71,9 @@ export const computeDraftValueFromFieldValue = <FieldValue>({
primaryPhoneCountryCode: stripSimpleQuotesFromString(
fieldDefinition?.defaultValue?.primaryPhoneCountryCode,
),
primaryPhoneCallingCode: stripSimpleQuotesFromString(
fieldDefinition?.defaultValue?.primaryPhoneCallingCode,
),
} as unknown as FieldInputDraftValue<FieldValue>;
}

View File

@ -21,6 +21,7 @@ const mockPerson = {
whatsapp: {
primaryPhoneNumber: '+1',
primaryPhoneCountryCode: '234-567-890',
primaryPhoneCallingCode: '+33',
additionalPhones: [],
},
linkedinLink: {

View File

@ -663,7 +663,8 @@ export const mockPerformance = {
id: '20202020-2d40-4e49-8df4-9c6a049191df',
email: 'lorie.vladim@google.com',
phones: {
primaryPhoneCountryCode: '+33',
primaryPhoneCountryCode: 'FR',
primaryPhoneCallingCode: '+33',
primaryPhoneNumber: '788901235',
},
linkedinLink: {

View File

@ -207,6 +207,7 @@ const companyMocks = [
phones {
primaryPhoneNumber
primaryPhoneCountryCode
primaryPhoneCallingCode
additionalPhones
}
position
@ -214,6 +215,7 @@ const companyMocks = [
whatsapp {
primaryPhoneNumber
primaryPhoneCountryCode
primaryPhoneCallingCode
additionalPhones
}
workPreference

View File

@ -95,6 +95,7 @@ export const generateEmptyFieldValue = (
return {
primaryPhoneNumber: '',
primaryPhoneCountryCode: '',
primaryPhoneCallingCode: '',
additionalPhones: null,
};
}