2525 { number: readOnlyMultiSelectedCount }) " />
2626 </NcDialog >
2727
28+ <NcModal v-if =" isMerging "
29+ :name =" t (' contacts' , ' Merge contacts' )"
30+ size="large"
31+ @close =" isMerging = false " >
32+ <Merging :contacts =" multiSelectedContacts " @finished =" finishContactMerging " />
33+ </NcModal >
34+
2835 <div class =" contacts-list__header" >
2936 <div class =" search-contacts-field" >
3037 <input v-model =" query" type =" text" :placeholder =" t('contacts', 'Search contacts …')" >
4552 @click .prevent =" attemptDeleteAllMultiSelected " >
4653 <IconDelete :size =" 16 " />
4754 </NcButton >
55+ <NcButton v-if =" ! isMergingLoading "
56+ type="tertiary"
57+ :disabled =" ! areTwoEditable "
58+ :title =" mergeActionTitle "
59+ :close-after-click =" true "
60+ @click .prevent =" initiateContactMerging " >
61+ <IconSetMerge :size =" 20 " />
62+ </NcButton >
63+ <NcLoadingIcon v-else :size =" 20 " />
4864 </div >
4965 </transition >
5066
5975</template >
6076
6177<script >
62- import { NcAppContentList as AppContentList , NcButton , NcDialog , NcNoteCard } from ' @nextcloud/vue'
78+ import { NcAppContentList as AppContentList , NcButton , NcDialog , NcNoteCard , NcModal , NcLoadingIcon } from ' @nextcloud/vue'
6379import ContactsListItem from ' ./ContactsList/ContactsListItem.vue'
6480import VirtualList from ' vue-virtual-scroll-list'
6581import IconSelect from ' vue-material-design-icons/CloseThick.vue'
6682import IconDelete from ' vue-material-design-icons/DeleteOutline.vue'
83+ import IconSetMerge from ' vue-material-design-icons/SetMerge.vue'
84+ import Merging from ' ./ContactsList/Merging.vue'
85+
6786// eslint-disable-next-line import/no-unresolved
6887import IconCancelRaw from ' @mdi/svg/svg/cancel.svg?raw'
6988// eslint-disable-next-line import/no-unresolved
@@ -79,7 +98,11 @@ export default {
7998 NcButton,
8099 IconSelect,
81100 IconDelete,
101+ IconSetMerge,
82102 NcDialog,
103+ NcModal,
104+ Merging,
105+ NcLoadingIcon,
83106 },
84107
85108 props: {
@@ -106,6 +129,7 @@ export default {
106129 ContactsListItem,
107130 query: ' ' ,
108131 multiSelectedContacts: new Map (),
132+ refreshKey: 0 , // used to force re-render of the list when search query changes, can be removed in vue3
109133 showDeleteConfirmationDialog: false ,
110134 buttons: [
111135 {
@@ -121,6 +145,8 @@ export default {
121145 },
122146 ],
123147 lastToggledIndex: undefined ,
148+ isMerging: false ,
149+ isMergingLoading: false ,
124150 }
125151 },
126152
@@ -159,11 +185,19 @@ export default {
159185 isAtLeastOneEditable () {
160186 return this .readOnlyMultiSelectedCount !== this .multiSelectedContacts .size
161187 },
188+ areTwoEditable () {
189+ return this .multiSelectedContacts .size - this .readOnlyMultiSelectedCount === 2
190+ },
162191 deleteActionTitle () {
163192 return this .isAtLeastOneEditable
164193 ? n (' contacts' , ' Delete {number} contact' , ' Delete {number} contacts' , this .multiSelectedContacts .size , { number: this .multiSelectedContacts .size })
165194 : t (' contacts' , ' Please select at least one editable contact to delete' )
166195 },
196+ mergeActionTitle () {
197+ return this .areTwoEditable
198+ ? t (' contacts' , ' Merge contacts' )
199+ : t (' contacts' , ' Please select two editable contacts to merge' )
200+ },
167201 },
168202
169203 watch: {
@@ -302,6 +336,30 @@ export default {
302336 this .unselectAllMultiSelected ()
303337 this .showDeleteConfirmationDialog = false
304338 },
339+
340+ async initiateContactMerging () {
341+ // For every contact in the multiSelectedContacts, we need to dispatch the load contact action
342+ this .isMergingLoading = true
343+ const contacts = Array .from (this .multiSelectedContacts .values ())
344+ for (const contact of contacts) {
345+ await this .$store .dispatch (' fetchFullContact' , { contact })
346+ }
347+
348+ this .isMergingLoading = false
349+ this .isMerging = true
350+ },
351+
352+ async finishContactMerging (mergedContact ) {
353+ // After merging, we need to update the contact in the store
354+ await this .$store .dispatch (' fetchFullContact' , { contact: mergedContact, forceReFetch: true })
355+
356+ this .unselectAllMultiSelected ()
357+ this .isMerging = false
358+
359+ await this .$router .push ({
360+ name: ' root' ,
361+ })
362+ },
305363 },
306364}
307365< / script>
0 commit comments