Skip to content

Commit 13156ab

Browse files
AchoArnoldCopilot
andcommitted
feat(web): improve contact dialog fields
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 9284da6 commit 13156ab

1 file changed

Lines changed: 55 additions & 36 deletions

File tree

web/app/pages/contacts/index.vue

Lines changed: 55 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -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'
1919
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
2020
import type { EntitiesContact } from '~~/shared/types/api'
2121
import { 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+
3944
interface 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
8085
const form = ref<ContactForm>({
8186
name: '',
82-
phoneNumbers: [''],
87+
phoneNumbers: [{ value: '', country: 'US' }],
8388
emails: [''],
84-
properties: [],
89+
properties: [{ key: '', value: '' }],
8590
})
8691
const formErrors = ref(new ErrorMessages())
8792
@@ -106,9 +111,16 @@ const dialogTitle = computed(() =>
106111
function 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
122134
function 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
149164
function addPhoneNumber() {
150-
form.value.phoneNumbers.push('')
165+
form.value.phoneNumbers.push(phoneNumberRow())
151166
}
152167
153168
function 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
175190
function 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
179197
function 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

Comments
 (0)