diff --git a/app/javascript/dashboard/components-next/Contacts/ContactLabels/ContactLabels.vue b/app/javascript/dashboard/components-next/Contacts/ContactLabels/ContactLabels.vue
index 6efe18a25..65405e39c 100644
--- a/app/javascript/dashboard/components-next/Contacts/ContactLabels/ContactLabels.vue
+++ b/app/javascript/dashboard/components-next/Contacts/ContactLabels/ContactLabels.vue
@@ -9,7 +9,7 @@ import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.v
const props = defineProps({
contactId: {
type: [String, Number],
- required: true,
+ default: null,
},
});
diff --git a/app/javascript/dashboard/components-next/Contacts/ContactsForm/ContactsForm.vue b/app/javascript/dashboard/components-next/Contacts/ContactsForm/ContactsForm.vue
index 38ae71e16..c6b302f42 100644
--- a/app/javascript/dashboard/components-next/Contacts/ContactsForm/ContactsForm.vue
+++ b/app/javascript/dashboard/components-next/Contacts/ContactsForm/ContactsForm.vue
@@ -121,10 +121,10 @@ const getFormBinding = key => {
// Example 2 (root): field = 'email' returns state.email = "john@example.com"
get: () => {
if (field === 'firstName' || field === 'lastName') {
- return state[field];
+ return state[field]?.toString() || '';
}
const [base, nested] = field.split('.');
- return nested ? state[base][nested] : state[base];
+ return (nested ? state[base][nested] : state[base])?.toString() || '';
},
// Set value in state and emit update
diff --git a/app/javascript/dashboard/components-next/Contacts/ContactsSidebar/ContactMerge.vue b/app/javascript/dashboard/components-next/Contacts/ContactsSidebar/ContactMerge.vue
new file mode 100644
index 000000000..da9345996
--- /dev/null
+++ b/app/javascript/dashboard/components-next/Contacts/ContactsSidebar/ContactMerge.vue
@@ -0,0 +1,206 @@
+
+
+
+
+
+
+ {{ t('CONTACTS_LAYOUT.SIDEBAR.MERGE.TITLE') }}
+
+
+ {{ t('CONTACTS_LAYOUT.SIDEBAR.MERGE.DESCRIPTION') }}
+
+
+
+
+
+
+
+ {{ t('CONTACTS_LAYOUT.SIDEBAR.MERGE.PRIMARY_HELP_LABEL') }}
+
+
+
+
+
+
+
+
+
+ {{ t('CONTACTS_LAYOUT.SIDEBAR.MERGE.PARENT_HELP_LABEL') }}
+
+
+
+
+
+
+ {{ selectedContact.name }}
+
+
+ {{ selectedContact.email }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/components-next/combobox/ComboBox.vue b/app/javascript/dashboard/components-next/combobox/ComboBox.vue
index 7fce6f64c..459091d83 100644
--- a/app/javascript/dashboard/components-next/combobox/ComboBox.vue
+++ b/app/javascript/dashboard/components-next/combobox/ComboBox.vue
@@ -43,7 +43,7 @@ const props = defineProps({
},
});
-const emit = defineEmits(['update:modelValue']);
+const emit = defineEmits(['update:modelValue', 'search']);
const { t } = useI18n();
@@ -125,6 +125,7 @@ watch(
:empty-state="emptyState"
:selected-values="selectedValue"
@update:search-value="search = $event"
+ @search="emit('search', $event)"
@select="selectOption"
/>
diff --git a/app/javascript/dashboard/components-next/combobox/ComboBoxDropdown.vue b/app/javascript/dashboard/components-next/combobox/ComboBoxDropdown.vue
index 4a0e3856c..e479aca2d 100644
--- a/app/javascript/dashboard/components-next/combobox/ComboBoxDropdown.vue
+++ b/app/javascript/dashboard/components-next/combobox/ComboBoxDropdown.vue
@@ -33,7 +33,7 @@ const props = defineProps({
},
});
-const emit = defineEmits(['update:searchValue', 'select']);
+const emit = defineEmits(['update:searchValue', 'select', 'search']);
const { t } = useI18n();
@@ -46,6 +46,11 @@ const isSelected = option => {
return option.value === props.selectedValues;
};
+const onInputSearch = event => {
+ emit('update:searchValue', event.target.value);
+ emit('search', event.target.value);
+};
+
defineExpose({
focus: () => searchInput.value?.focus(),
});
@@ -64,7 +69,7 @@ defineExpose({
type="search"
:placeholder="searchPlaceholder || t('COMBOBOX.SEARCH_PLACEHOLDER')"
class="w-full py-2 pl-10 pr-2 text-sm border-none rounded-t-md bg-n-solid-1 text-slate-900 dark:text-slate-50"
- @input="emit('update:searchValue', $event.target.value)"
+ @input="onInputSearch"
/>
uiFlags.value.isFetchingItem);
+const isMergingContact = computed(() => uiFlags.value.isMerging);
const selectedContact = computed(() => contact.value(route.params.contactId));
+const showSpinner = computed(
+ () => isFetchingItem.value || isMergingContact.value
+);
+
const { t } = useI18n();
const CONTACT_TABS_OPTIONS = [
@@ -89,7 +96,7 @@ onMounted(() => {
@go-to-contacts-list="goToContactsList"
>
@@ -110,6 +117,12 @@ onMounted(() => {
+