From 6f300bb073290ef0e037b68160e26c3758e0681e Mon Sep 17 00:00:00 2001 From: Abhinav Raut Date: Sun, 14 Sep 2025 19:36:30 +0530 Subject: [PATCH] Fix: Contact form displays countries with the same calling code incorrectly. For example, when a user selects the USA, the form also shows Canada, as both share the +1 calling code. Rename column from `phone_number_calling_code` to `phone_number_country_code`. Feat: Show the calling code alongside the country flag in the contact form for the selected country. Previously, only the flag was displayed. --- cmd/contacts.go | 12 ++--- cmd/upgrade.go | 1 + .../src/components/ui/combobox/ComboBox.vue | 2 +- frontend/src/features/contact/ContactForm.vue | 20 ++++--- frontend/src/features/contact/formSchema.js | 2 +- .../sidebar/ConversationSideBarContact.vue | 10 +++- .../src/views/contact/ContactDetailView.vue | 2 +- internal/conversation/models/models.go | 2 +- internal/conversation/queries.sql | 2 +- internal/migrations/v0.7.4.go | 53 +++++++++++++++++++ internal/user/contact.go | 2 +- internal/user/models/models.go | 2 +- internal/user/queries.sql | 6 +-- schema.sql | 4 +- 14 files changed, 93 insertions(+), 27 deletions(-) create mode 100644 internal/migrations/v0.7.4.go diff --git a/cmd/contacts.go b/cmd/contacts.go index 536fdb8..3f9e452 100644 --- a/cmd/contacts.go +++ b/cmd/contacts.go @@ -103,9 +103,9 @@ func handleUpdateContact(r *fastglue.Request) error { if v, ok := form.Value["phone_number"]; ok && len(v) > 0 { phoneNumber = string(v[0]) } - phoneNumberCallingCode := "" - if v, ok := form.Value["phone_number_calling_code"]; ok && len(v) > 0 { - phoneNumberCallingCode = string(v[0]) + phoneNumberCountryCode := "" + if v, ok := form.Value["phone_number_country_code"]; ok && len(v) > 0 { + phoneNumberCountryCode = string(v[0]) } avatarURL := "" if v, ok := form.Value["avatar_url"]; ok && len(v) > 0 { @@ -116,8 +116,8 @@ func handleUpdateContact(r *fastglue.Request) error { if avatarURL == "null" { avatarURL = "" } - if phoneNumberCallingCode == "null" { - phoneNumberCallingCode = "" + if phoneNumberCountryCode == "null" { + phoneNumberCountryCode = "" } if phoneNumber == "null" { phoneNumber = "" @@ -146,7 +146,7 @@ func handleUpdateContact(r *fastglue.Request) error { Email: null.StringFrom(email), AvatarURL: null.NewString(avatarURL, avatarURL != ""), PhoneNumber: null.NewString(phoneNumber, phoneNumber != ""), - PhoneNumberCallingCode: null.NewString(phoneNumberCallingCode, phoneNumberCallingCode != ""), + PhoneNumberCountryCode: null.NewString(phoneNumberCountryCode, phoneNumberCountryCode != ""), } if err := app.user.UpdateContact(id, contactToUpdate); err != nil { diff --git a/cmd/upgrade.go b/cmd/upgrade.go index 8e9ec50..b72e67e 100644 --- a/cmd/upgrade.go +++ b/cmd/upgrade.go @@ -35,6 +35,7 @@ var migList = []migFunc{ {"v0.5.0", migrations.V0_5_0}, {"v0.6.0", migrations.V0_6_0}, {"v0.7.0", migrations.V0_7_0}, + {"v0.7.4", migrations.V0_7_4}, } // upgrade upgrades the database to the current version by running SQL migration files diff --git a/frontend/src/components/ui/combobox/ComboBox.vue b/frontend/src/components/ui/combobox/ComboBox.vue index 9355cae..a52bcd5 100644 --- a/frontend/src/components/ui/combobox/ComboBox.vue +++ b/frontend/src/components/ui/combobox/ComboBox.vue @@ -8,7 +8,7 @@ :class="['w-full justify-between', buttonClass]" > {{ selectedLabel }} - + diff --git a/frontend/src/features/contact/ContactForm.vue b/frontend/src/features/contact/ContactForm.vue index 42645e2..201f505 100644 --- a/frontend/src/features/contact/ContactForm.vue +++ b/frontend/src/features/contact/ContactForm.vue @@ -41,8 +41,8 @@
- - + + {{ t('globals.terms.phoneNumber') }} @@ -58,13 +58,18 @@
{{ item.emoji }}
- {{ item.label }} ({{ item.value }}) + {{ item.label }} ({{ item.calling_code }})
@@ -116,7 +121,8 @@ const userStore = useUserStore() const allCountries = countries.map((country) => ({ label: country.name, - value: country.calling_code, - emoji: country.emoji + value: country.iso_2, + emoji: country.emoji, + calling_code: country.calling_code })) diff --git a/frontend/src/features/contact/formSchema.js b/frontend/src/features/contact/formSchema.js index 95fe9b8..6e87540 100644 --- a/frontend/src/features/contact/formSchema.js +++ b/frontend/src/features/contact/formSchema.js @@ -29,7 +29,7 @@ export const createFormSchema = (t) => z.object({ }) }) .nullable(), - phone_number_calling_code: z.string().optional().nullable(), + phone_number_country_code: z.string().optional().nullable(), avatar_url: z.string().optional().nullable(), email: z .string({ diff --git a/frontend/src/features/conversation/sidebar/ConversationSideBarContact.vue b/frontend/src/features/conversation/sidebar/ConversationSideBarContact.vue index f0fbd45..22dcc0b 100644 --- a/frontend/src/features/conversation/sidebar/ConversationSideBarContact.vue +++ b/frontend/src/features/conversation/sidebar/ConversationSideBarContact.vue @@ -58,6 +58,7 @@ import { ViewVerticalIcon } from '@radix-icons/vue' import { Button } from '@/components/ui/button' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { Mail, Phone, ExternalLink } from 'lucide-vue-next' +import countries from '@/constants/countries.js' import { useEmitter } from '@/composables/useEmitter' import { EMITTER_EVENTS } from '@/constants/emitterEvents.js' import { useConversationStore } from '@/stores/conversation' @@ -72,8 +73,13 @@ const { t } = useI18n() const userStore = useUserStore() const phoneNumber = computed(() => { - const callingCode = conversation.value?.contact?.phone_number_calling_code || '' + const countryCodeValue = conversation.value?.contact?.phone_number_country_code || '' const number = conversation.value?.contact?.phone_number || t('conversation.sidebar.notAvailable') - return callingCode ? `${callingCode} ${number}` : number + if (!countryCodeValue) return number + + // Lookup calling code + const country = countries.find((c) => c.iso_2 === countryCodeValue) + const callingCode = country ? country.calling_code : countryCodeValue + return `${callingCode} ${number}` }) diff --git a/frontend/src/views/contact/ContactDetailView.vue b/frontend/src/views/contact/ContactDetailView.vue index 3c1d557..3bc3ff2 100644 --- a/frontend/src/views/contact/ContactDetailView.vue +++ b/frontend/src/views/contact/ContactDetailView.vue @@ -189,7 +189,7 @@ async function onUpload(file) { formData.append('last_name', form.values.last_name) formData.append('email', form.values.email) formData.append('phone_number', form.values.phone_number) - formData.append('phone_number_calling_code', form.values.phone_number_calling_code) + formData.append('phone_number_country_code', form.values.phone_number_country_code) formData.append('enabled', form.values.enabled) const { data } = await api.updateContact(contact.value.id, formData) contact.value.avatar_url = data.avatar_url diff --git a/internal/conversation/models/models.go b/internal/conversation/models/models.go index 2732f06..d5a19e7 100644 --- a/internal/conversation/models/models.go +++ b/internal/conversation/models/models.go @@ -145,7 +145,7 @@ type ConversationContact struct { AvailabilityStatus string `db:"availability_status" json:"availability_status"` AvatarURL null.String `db:"avatar_url" json:"avatar_url"` PhoneNumber null.String `db:"phone_number" json:"phone_number"` - PhoneNumberCallingCode null.String `db:"phone_number_calling_code" json:"phone_number_calling_code"` + PhoneNumberCountryCode null.String `db:"phone_number_country_code" json:"phone_number_country_code"` CustomAttributes json.RawMessage `db:"custom_attributes" json:"custom_attributes"` Enabled bool `db:"enabled" json:"enabled"` LastActiveAt null.Time `db:"last_active_at" json:"last_active_at"` diff --git a/internal/conversation/queries.sql b/internal/conversation/queries.sql index f6cbcc9..bb0fbbe 100644 --- a/internal/conversation/queries.sql +++ b/internal/conversation/queries.sql @@ -140,7 +140,7 @@ SELECT ct.availability_status as "contact.availability_status", ct.avatar_url as "contact.avatar_url", ct.phone_number as "contact.phone_number", - ct.phone_number_calling_code as "contact.phone_number_calling_code", + ct.phone_number_country_code as "contact.phone_number_country_code", ct.custom_attributes as "contact.custom_attributes", ct.enabled as "contact.enabled", ct.last_active_at as "contact.last_active_at", diff --git a/internal/migrations/v0.7.4.go b/internal/migrations/v0.7.4.go new file mode 100644 index 0000000..f96ad45 --- /dev/null +++ b/internal/migrations/v0.7.4.go @@ -0,0 +1,53 @@ +package migrations + +import ( + "github.com/jmoiron/sqlx" + "github.com/knadh/koanf/v2" + "github.com/knadh/stuffbin" +) + +// V0_7_4 updates the database schema to v0.7.4. +func V0_7_4(db *sqlx.DB, fs stuffbin.FileSystem, ko *koanf.Koanf) error { + // Rename phone_number_calling_code to phone_number_country_code + // This column will now store country codes (US, CA, GB) instead of calling codes (+1, +44) + _, err := db.Exec(` + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'users' AND column_name = 'phone_number_country_code' + ) AND EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'users' AND column_name = 'phone_number_calling_code' + ) THEN + ALTER TABLE users + RENAME COLUMN phone_number_calling_code TO phone_number_country_code; + END IF; + END $$; + `) + if err != nil { + return err + } + + // Rename the constraint to match the new column name + _, err = db.Exec(` + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.constraint_column_usage + WHERE constraint_name = 'constraint_users_on_phone_number_country_code' + ) AND EXISTS ( + SELECT 1 FROM information_schema.constraint_column_usage + WHERE constraint_name = 'constraint_users_on_phone_number_calling_code' + ) THEN + ALTER TABLE users + RENAME CONSTRAINT constraint_users_on_phone_number_calling_code TO constraint_users_on_phone_number_country_code; + END IF; + END $$; + `) + if err != nil { + return err + } + + return nil +} \ No newline at end of file diff --git a/internal/user/contact.go b/internal/user/contact.go index b792175..e890849 100644 --- a/internal/user/contact.go +++ b/internal/user/contact.go @@ -29,7 +29,7 @@ func (u *Manager) CreateContact(user *models.User) error { // UpdateContact updates a contact in the database. func (u *Manager) UpdateContact(id int, user models.User) error { - if _, err := u.q.UpdateContact.Exec(id, user.FirstName, user.LastName, user.Email, user.AvatarURL, user.PhoneNumber, user.PhoneNumberCallingCode); err != nil { + if _, err := u.q.UpdateContact.Exec(id, user.FirstName, user.LastName, user.Email, user.AvatarURL, user.PhoneNumber, user.PhoneNumberCountryCode); err != nil { u.lo.Error("error updating user", "error", err) return envelope.NewError(envelope.GeneralError, u.i18n.Ts("globals.messages.errorUpdating", "name", "{globals.terms.contact}"), nil) } diff --git a/internal/user/models/models.go b/internal/user/models/models.go index 23ca469..610285a 100644 --- a/internal/user/models/models.go +++ b/internal/user/models/models.go @@ -53,7 +53,7 @@ type User struct { Email null.String `db:"email" json:"email"` Type string `db:"type" json:"type"` AvailabilityStatus string `db:"availability_status" json:"availability_status"` - PhoneNumberCallingCode null.String `db:"phone_number_calling_code" json:"phone_number_calling_code"` + PhoneNumberCountryCode null.String `db:"phone_number_country_code" json:"phone_number_country_code"` PhoneNumber null.String `db:"phone_number" json:"phone_number"` AvatarURL null.String `db:"avatar_url" json:"avatar_url"` Enabled bool `db:"enabled" json:"enabled"` diff --git a/internal/user/queries.sql b/internal/user/queries.sql index 4c0d285..8ba765c 100644 --- a/internal/user/queries.sql +++ b/internal/user/queries.sql @@ -39,7 +39,7 @@ SELECT u.availability_status, u.last_active_at, u.last_login_at, - u.phone_number_calling_code, + u.phone_number_country_code, u.phone_number, u.api_key, u.api_key_last_used_at, @@ -174,7 +174,7 @@ SET first_name = COALESCE($2, first_name), email = COALESCE($4, email), avatar_url = $5, phone_number = $6, - phone_number_calling_code = $7, + phone_number_country_code = $7, updated_at = now() WHERE id = $1 and type = 'contact'; @@ -233,7 +233,7 @@ SELECT u.availability_status, u.last_active_at, u.last_login_at, - u.phone_number_calling_code, + u.phone_number_country_code, u.phone_number, u.api_key, u.api_key_last_used_at, diff --git a/schema.sql b/schema.sql index c1822c4..6bdf520 100644 --- a/schema.sql +++ b/schema.sql @@ -129,7 +129,7 @@ CREATE TABLE users ( email TEXT NULL, first_name TEXT NOT NULL, last_name TEXT NULL, - phone_number_calling_code TEXT NULL, + phone_number_country_code TEXT NULL, phone_number TEXT NULL, country TEXT NULL, "password" VARCHAR(150) NULL, @@ -146,7 +146,7 @@ CREATE TABLE users ( api_key_last_used_at TIMESTAMPTZ NULL, CONSTRAINT constraint_users_on_country CHECK (LENGTH(country) <= 140), CONSTRAINT constraint_users_on_phone_number CHECK (LENGTH(phone_number) <= 20), - CONSTRAINT constraint_users_on_phone_number_calling_code CHECK (LENGTH(phone_number_calling_code) <= 10), + CONSTRAINT constraint_users_on_phone_number_country_code CHECK (LENGTH(phone_number_country_code) <= 10), CONSTRAINT constraint_users_on_email_length CHECK (LENGTH(email) <= 320), CONSTRAINT constraint_users_on_first_name CHECK (LENGTH(first_name) <= 140), CONSTRAINT constraint_users_on_last_name CHECK (LENGTH(last_name) <= 140)