️(frontend) backport phone number formatting to the backend

Use the Python port of Google's phone number library on the backend
instead of the JS one on the client. Saves 140Kb of unnecessary JS
and avoids a complex dynamic import that would have been required to
optimize loading.

The transformation is static: the phone number lives in the Django
settings, so the backend can format it once and pass the result to
the client. This avoids every client loading the 140Kb library and
re-computing the same information.

Moreover, within a single client, the transformation was previously
re-computed several times during a webapp lifecycle.
This commit is contained in:
lebaudantoine
2026-05-26 12:05:53 +02:00
committed by aleb_the_flash
parent 8984d863df
commit 7390673bfc
11 changed files with 242 additions and 48 deletions
-7
View File
@@ -30,7 +30,6 @@
"i18next-browser-languagedetector": "8.2.1",
"i18next-parser": "9.3.0",
"i18next-resources-to-backend": "1.2.1",
"libphonenumber-js": "1.12.10",
"livekit-client": "2.17.1",
"posthog-js": "1.342.1",
"react": "18.3.1",
@@ -8760,12 +8759,6 @@
"node": ">= 0.8.0"
}
},
"node_modules/libphonenumber-js": {
"version": "1.12.10",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.10.tgz",
"integrity": "sha512-E91vHJD61jekHHR/RF/E83T/CMoaLXT7cwYA75T4gim4FZjnM6hbJjVIGg7chqlSqRsSvQ3izGmOjHy1SQzcGQ==",
"license": "MIT"
},
"node_modules/lightningcss": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz",
-1
View File
@@ -36,7 +36,6 @@
"i18next-browser-languagedetector": "8.2.1",
"i18next-parser": "9.3.0",
"i18next-resources-to-backend": "1.2.1",
"libphonenumber-js": "1.12.10",
"livekit-client": "2.17.1",
"posthog-js": "1.342.1",
"react": "18.3.1",
+1 -1
View File
@@ -44,7 +44,7 @@ export interface ApiConfig {
}
telephony: {
enabled: boolean
phone_number?: string
international_phone_number?: string
default_country?: string
}
manifest_link?: string
@@ -1,20 +1,17 @@
import { useConfig } from '@/api/useConfig.ts'
import { useMemo } from 'react'
import { parseConfigPhoneNumber } from '../../utils/telephony'
import { useConfig } from '@/api/useConfig'
export const useTelephony = () => {
const { data } = useConfig()
const parsedPhoneNumber = useMemo(() => {
return parseConfigPhoneNumber(
data?.telephony?.phone_number,
data?.telephony?.default_country
)
}, [data?.telephony])
if (!data?.telephony?.enabled) {
return {
enabled: false,
}
}
return {
enabled: data?.telephony?.enabled && parsedPhoneNumber,
country: parsedPhoneNumber?.country,
internationalPhoneNumber: parsedPhoneNumber?.formatInternational(),
enabled: data?.telephony?.enabled,
country: data?.telephony.default_country,
internationalPhoneNumber: data?.telephony.international_phone_number,
}
}
@@ -1,23 +1,3 @@
import { CountryCode, parsePhoneNumberWithError } from 'libphonenumber-js'
export const parseConfigPhoneNumber = (
rawPhoneNumber?: string,
defaultCountry?: string
) => {
if (!rawPhoneNumber || !defaultCountry) {
return null
}
try {
return parsePhoneNumberWithError(
rawPhoneNumber,
defaultCountry as CountryCode
)
} catch (error) {
console.warn('Invalid phone number format:', rawPhoneNumber, error)
return null
}
}
export function formatPinCode(pinCode?: string) {
return pinCode && `${pinCode.replace(/(\d{3})(\d{3})(\d{4})/, '$1 $2 $3')}#`
}