@@ -13,9 +13,9 @@ import {
1313 mdiPhoneCheck ,
1414 mdiEmailCheckOutline ,
1515 mdiSquareEditOutline ,
16- mdiPhone ,
1716 mdiPlus ,
1817} from ' @mdi/js'
18+ import { parsePhoneNumberFromString } from ' libphonenumber-js'
1919import { computed , onBeforeUnmount , onMounted , ref , watch } from ' vue'
2020import type { EntitiesContact } from ' ~~/shared/types/api'
2121import { useContactsStore , type ContactInput } from ' ~/stores/contacts'
@@ -36,9 +36,14 @@ interface PropertyRow {
3636 value: string
3737}
3838
39+ interface PhoneNumberRow {
40+ value: string
41+ country: string
42+ }
43+
3944interface ContactForm {
4045 name: string
41- phoneNumbers: string []
46+ phoneNumbers: PhoneNumberRow []
4247 emails: string []
4348 properties: PropertyRow []
4449}
@@ -79,9 +84,9 @@ const pendingDelete = ref<EntitiesContact | null>(null)
7984
8085const form = ref <ContactForm >({
8186 name: ' ' ,
82- phoneNumbers: [' ' ],
87+ phoneNumbers: [{ value: ' ' , country: ' US ' } ],
8388 emails: [' ' ],
84- properties: [],
89+ properties: [{ key: ' ' , value: ' ' } ],
8590})
8691const formErrors = ref (new ErrorMessages ())
8792
@@ -106,9 +111,16 @@ const dialogTitle = computed(() =>
106111function emptyForm(): ContactForm {
107112 return {
108113 name: ' ' ,
109- phoneNumbers: [' ' ],
114+ phoneNumbers: [{ value: ' ' , country: ' US ' } ],
110115 emails: [' ' ],
111- properties: [],
116+ properties: [{ key: ' ' , value: ' ' }],
117+ }
118+ }
119+
120+ function phoneNumberRow(value = ' ' ): PhoneNumberRow {
121+ return {
122+ value ,
123+ country: parsePhoneNumberFromString (value )?.country ?? ' US' ,
112124 }
113125}
114126
@@ -121,15 +133,18 @@ function openAdd() {
121133
122134function openEdit(contact : EntitiesContact ) {
123135 editingId .value = contact .id
136+ const propertyEntries = Object .entries (contact .properties ?? {}).map (
137+ ([key , value ]) => ({ key , value }),
138+ )
124139 form .value = {
125140 name: contact .name ?? ' ' ,
126141 phoneNumbers: contact .phone_numbers ?.length
127- ? [ ... contact .phone_numbers ]
128- : [' ' ],
142+ ? contact .phone_numbers . map (( value ) => phoneNumberRow ( value ))
143+ : [phoneNumberRow () ],
129144 emails: contact .emails ?.length ? [... contact .emails ] : [' ' ],
130- properties: Object . entries ( contact . properties ?? {}). map (
131- ([ key , value ]) => ({ key , value }),
132- ) ,
145+ properties: propertyEntries . length
146+ ? propertyEntries
147+ : [{ key: ' ' , value: ' ' }] ,
133148 }
134149 formErrors .value = new ErrorMessages ()
135150 editDialog .value = true
@@ -147,13 +162,13 @@ function openImport() {
147162}
148163
149164function addPhoneNumber() {
150- form .value .phoneNumbers .push (' ' )
165+ form .value .phoneNumbers .push (phoneNumberRow () )
151166}
152167
153168function removePhoneNumber(index : number ) {
154169 form .value .phoneNumbers .splice (index , 1 )
155170 if (form .value .phoneNumbers .length === 0 ) {
156- form .value .phoneNumbers .push (' ' )
171+ form .value .phoneNumbers .push (phoneNumberRow () )
157172 }
158173}
159174
@@ -174,6 +189,9 @@ function addProperty() {
174189
175190function removeProperty(index : number ) {
176191 form .value .properties .splice (index , 1 )
192+ if (form .value .properties .length === 0 ) {
193+ form .value .properties .push ({ key: ' ' , value: ' ' })
194+ }
177195}
178196
179197function buildPayload(): ContactInput {
@@ -187,7 +205,7 @@ function buildPayload(): ContactInput {
187205 return {
188206 name: form .value .name .trim (),
189207 phone_numbers: form .value .phoneNumbers
190- .map ((value ) => value .trim ())
208+ .map (({ value } ) => value .trim ())
191209 .filter ((value ) => value .length > 0 ),
192210 emails: form .value .emails
193211 .map ((value ) => value .trim ())
@@ -202,7 +220,7 @@ function validateForm(): boolean {
202220 bag .add (' name' , ' The name is required.' )
203221 }
204222 const hasPhone = form .value .phoneNumbers .some (
205- (value ) => value .trim ().length > 0 ,
223+ ({ value } ) => value .trim ().length > 0 ,
206224 )
207225 if (! hasPhone ) {
208226 bag .add (' phone_numbers' , ' At least one phone number is required.' )
@@ -401,7 +419,7 @@ onBeforeUnmount(() => {
401419 v-model :items-per-page =" itemsPerPage "
402420 :headers =" headers "
403421 :header-props =" {
404- class: ' text-uppercase text-medium-emphasis' ,
422+ class: ' text-uppercase text-medium-emphasis bg-black ' ,
405423 } "
406424 :items =" contactsStore .contacts "
407425 :items-length =" contactsStore .total "
@@ -463,19 +481,23 @@ onBeforeUnmount(() => {
463481 </template >
464482
465483 <template #[` item.created_at ` ]=" { item } " >
466- <span
467- class =" text-medium-emphasis"
468- :title =" formatTimestamp(item.created_at)"
469- >{{ humanizeTimeShort(item.created_at) }}</span
470- >
484+ <VTooltip :text =" formatTimestamp (item .created_at )" >
485+ <template #activator =" { props } " >
486+ <span v-bind =" props" class =" text-medium-emphasis" >
487+ {{ humanizeTimeShort(item.created_at) }}
488+ </span >
489+ </template >
490+ </VTooltip >
471491 </template >
472492
473493 <template #[` item.updated_at ` ]=" { item } " >
474- <span
475- class =" text-medium-emphasis"
476- :title =" formatTimestamp(item.updated_at)"
477- >{{ humanizeTimeShort(item.updated_at) }}</span
478- >
494+ <VTooltip :text =" formatTimestamp (item .updated_at )" >
495+ <template #activator =" { props } " >
496+ <span v-bind =" props" class =" text-medium-emphasis" >
497+ {{ humanizeTimeShort(item.updated_at) }}
498+ </span >
499+ </template >
500+ </VTooltip >
479501 </template >
480502
481503 <template #[` item.actions ` ]=" { item } " >
@@ -596,13 +618,16 @@ onBeforeUnmount(() => {
596618 :key =" `phone-${index}`"
597619 class =" d-flex align-start ga-2"
598620 >
599- <VTextField
600- v-model =" form .phoneNumbers [index ]"
621+ <v-phone-input
622+ v-model =" phone.value"
623+ v-model:country =" phone.country"
601624 :label =" `Phone number ${index + 1}`"
602- placeholder="+18005550199"
625+ country-label =" Country"
626+ placeholder =" Phone number e.g 18005550199"
603627 variant =" outlined"
604628 density =" comfortable"
605- :prepend-inner-icon =" mdiPhone "
629+ color =" primary"
630+ persistent-placeholder
606631 :error =" index === 0 && formErrors.has('phone_numbers')"
607632 :error-messages ="
608633 index === 0 ? formErrors.get('phone_numbers') : []
@@ -667,12 +692,6 @@ onBeforeUnmount(() => {
667692 Add
668693 </VBtn >
669694 </div >
670- <p
671- v-if =" !form.properties.length"
672- class =" text-medium-emphasis text-body-2 mb-2"
673- >
674- Add custom key/value details such as company or address.
675- </p >
676695 <div
677696 v-for =" (property, index) in form.properties"
678697 :key =" `property-${index}`"
0 commit comments