Merge pull request #135 from abhinavxd/fix/contact-form-calling-code

Fix: Contact form displays countries with the same calling code incorrectly
This commit is contained in:
Abhinav Raut
2025-09-14 22:27:06 +05:30
committed by GitHub
15 changed files with 102 additions and 28 deletions

View File

@@ -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 {

View File

@@ -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

View File

@@ -184,6 +184,10 @@
@apply border shadow rounded;
}
.loading-fade {
@apply opacity-50 transition-opacity duration-300
}
// Scrollbar start
::-webkit-scrollbar {
width: 8px; /* Adjust width */

View File

@@ -8,7 +8,7 @@
:class="['w-full justify-between', buttonClass]"
>
<slot name="selected" :selected="selectedItem">{{ selectedLabel }}</slot>
<CaretSortIcon class="ml-2 h-4 w-4 shrink-0 opacity-50" />
<CaretSortIcon class="h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent class="p-0">

View File

@@ -41,8 +41,8 @@
<div class="flex flex-col flex-1">
<div class="flex items-end">
<FormField v-slot="{ componentField }" name="phone_number_calling_code">
<FormItem class="w-20">
<FormField v-slot="{ componentField }" name="phone_number_country_code">
<FormItem class="w-max">
<FormLabel class="flex items-center whitespace-nowrap">
{{ t('globals.terms.phoneNumber') }}
</FormLabel>
@@ -58,13 +58,18 @@
<div class="w-7 h-7 flex items-center justify-center">
<span v-if="item.emoji">{{ item.emoji }}</span>
</div>
<span class="text-sm">{{ item.label }} ({{ item.value }})</span>
<span class="text-sm">{{ item.label }} ({{ item.calling_code }})</span>
</div>
</template>
<template #selected="{ selected }">
<div class="flex items-center mb-1">
<span v-if="selected" class="text-xl leading-none">{{ selected.emoji }}</span>
<div class="flex items-center gap-1">
<span v-if="selected" class="text-lg">{{ selected.emoji }}</span>
<span
v-if="selected && selected.calling_code"
class="text-xs text-muted-foreground"
>({{ selected.calling_code }})</span
>
</div>
</template>
</ComboBox>
@@ -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
}))
</script>

View File

@@ -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({

View File

@@ -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}`
})
</script>

View File

@@ -5,7 +5,11 @@
<CustomBreadcrumb :links="breadcrumbLinks" />
</div>
<div v-if="contact" class="flex justify-center space-y-4 w-full">
<div
v-if="contact"
class="flex justify-center space-y-4 w-full"
:class="{ 'loading-fade': formLoading }"
>
<div class="flex flex-col w-full mt-12">
<div class="flex flex-col space-y-2">
<AvatarUpload
@@ -189,7 +193,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

View File

@@ -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"`

View File

@@ -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",

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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"`

View File

@@ -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,

View File

@@ -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)