66<template >
77 <div class =" batch" >
88 <div class =" batch__title" >
9- <h3 >{{ t('contacts', 'Add contacts to groups') }}</h3 >
9+ <h3 v-if =" mode === 'grouping'" >
10+ {{ t('contacts', 'Add contacts to groups') }}
11+ </h3 >
12+ <h3 v-if =" mode === 'ab'" >
13+ {{ t('contacts', 'Move contacts to addressbook') }}
14+ </h3 >
1015 </div >
1116
12- <NcSelect v-model =" selectedGroups"
17+ <NcSelect v-if =" mode === 'grouping'"
18+ v-model =" selectedGroups"
1319 :input-label =" t('contacts', 'Select groups')"
1420 :multiple =" true"
1521 :options =" groupOptions" />
1622
23+ <!-- Addressbook selector for move mode -->
24+ <NcSelect v-if =" mode === 'ab'"
25+ v-model =" selectedAddressesBook"
26+ :input-label =" t('contacts', 'Select addressbook')"
27+ :options =" addressbookOptions" />
28+
1729 <h6 >{{ t('contacts', 'Selected contacts') }}</h6 >
1830 <NcNoteCard v-if =" amountOfReadOnlyContacts > 0" type =" info" >
19- {{ t('contacts', 'Please note that {count} contact{p} readonly and will not be added to groups. If you want to include them all you can create a Team instead .', { count: amountOfReadOnlyContacts, p: amountOfReadOnlyContacts === 1 ? ' is' : 's are' }) }}
31+ {{ t('contacts', 'Please note that {count} contact{p} readonly and will not be modified .', { count: amountOfReadOnlyContacts, p: amountOfReadOnlyContacts === 1 ? ' is' : 's are' }) }}
2032 </NcNoteCard >
2133
2234 <div class =" contacts-list" >
2638 :index =" index"
2739 :source =" contact"
2840 :reload-bus =" reloadBus"
29- :title =" contact.addressbook.canModifyCard ? '' : t('contacts', 'This contact is read-only and cannot be added to groups. Try creating a Team instead .')"
41+ :title =" contact.addressbook.canModifyCard ? '' : t('contacts', 'This contact is read-only and cannot be modified .')"
3042 :is-static =" true" />
3143 </div >
3244 </div >
3345
34- <NcButton v-if =" contacts.length > 9" variant =" secondary" @click =" showAllContacts = !showAllContacts" >
35- <template #icon >
36- <IconPlus :size =" 20" />
37- </template >
38- {{ t('contacts', showAllContacts ? 'Show less' : 'Show all') }}
39- </NcButton >
40-
41- <div class =" batch__footer" >
42- <NcButton variant =" primary" :disabled =" selectedGroups.length === 0" @click =" submit" >
43- <template #icon >
44- <IconAccountPlus :size =" 20" />
45- </template >
46- {{ t('contacts', 'Add') }}
47- </NcButton >
46+ <NcButton v-if =" contacts.length > 9"
47+ variant =" secondary"
48+ @click =" showAllContacts = !showAllContacts" >
49+ <template #icon >
50+ <IconPlus :size =" 20" />
51+ </template >
52+ {{ t('contacts', showAllContacts ? 'Show less' : 'Show all') }}
53+ </NcButton >
54+
55+ <div class =" batch__footer" >
56+ <NcButton v-if =" mode === 'grouping'"
57+ variant =" primary"
58+ :disabled =" selectedGroups.length === 0"
59+ @click =" submit" >
60+ <template #icon >
61+ <IconAccountPlus :size =" 20" />
62+ </template >
63+ {{ t('contacts', 'Add') }}
64+ </NcButton >
65+ <NcButton v-if =" mode === 'ab'"
66+ variant =" primary"
67+ :disabled =" !selectedAddressesBook"
68+ @click =" submit" >
69+ <template #icon >
70+ <IconBookArrow :size =" 20" />
71+ </template >
72+ {{ t('contacts', 'Move') }}
73+ </NcButton >
4874 </div >
4975 </div >
5076</template >
@@ -54,6 +80,7 @@ import ContactsListItem from './ContactsListItem.vue'
5480import { NcButton , NcSelect , NcNoteCard } from ' @nextcloud/vue'
5581import IconPlus from ' vue-material-design-icons/Plus.vue'
5682import IconAccountPlus from ' vue-material-design-icons/AccountMultiplePlusOutline.vue'
83+ import IconBookArrow from ' vue-material-design-icons/BookArrowRightOutline.vue'
5784import appendContactToGroup from ' ../../services/appendContactToGroup.js'
5885
5986export default {
@@ -65,6 +92,7 @@ export default {
6592 NcSelect,
6693 IconPlus,
6794 IconAccountPlus,
95+ IconBookArrow,
6896 NcNoteCard,
6997 },
7098
@@ -73,13 +101,21 @@ export default {
73101 type: Array ,
74102 required: true ,
75103 },
104+ mode: {
105+ type: String ,
106+ required: false ,
107+ default: ' grouping' ,
108+ },
76109 },
77110
111+ emits: [' submit' ],
112+
78113 data () {
79114 return {
80115 reloadBus: null ,
81116 showAllContacts: false ,
82117 selectedGroups: [],
118+ selectedAddressesBook: null ,
83119 }
84120 },
85121
@@ -99,17 +135,33 @@ export default {
99135 amountOfReadOnlyContacts () {
100136 return this .contacts .filter (contact => ! contact .addressbook .canModifyCard ).length
101137 },
138+ addressbookOptions () {
139+ // Provide only enabled, writable addressbooks to move to
140+ return this .$store .getters .getAddressbooks
141+ .filter (ab => ! ab .readOnly && ab .enabled )
142+ .map (ab => ({ label: ab .displayName || ab .label || ab .addressbook , value: ab .id || ab .addressbook }))
143+ },
102144 },
103145
104146 methods: {
105- async submit () {
147+ submit () {
148+ if (this .mode === ' grouping' ) {
149+ this .group ()
150+ }
151+
152+ if (this .mode === ' ab' ) {
153+ this .moveToAddressbook ()
154+ }
155+ },
156+
157+ async group () {
106158 const allGroups = this .$store .getters .getGroups
107159
108160 // Add to groups
109- this .selectedGroups .forEach (groupName => {
110- const group = allGroups .find (g => g .name === groupName )
161+ this .selectedGroups .forEach (selectedGroup => {
162+ const group = allGroups .find (g => g .name === selectedGroup . value )
111163 if (! group) {
112- console .error (' Cannot add contact to an undefined group' , groupName )
164+ console .error (' Cannot add contact to an undefined group' , selectedGroup )
113165 return
114166 }
115167 this .contacts .forEach (contact => {
@@ -127,6 +179,31 @@ export default {
127179
128180 this .$emit (' submit' )
129181 },
182+
183+ async moveToAddressbook () {
184+ if (! this .selectedAddressesBook ) return
185+ const addressbook = this .$store .getters .getAddressbooks .find (ab => ab .id === this .selectedAddressesBook .value )
186+ if (! addressbook) {
187+ console .error (' Selected addressbook not found' , this .selectedAddressesBook )
188+ return
189+ }
190+
191+ const movePromises = this .contacts .map (async (contact ) => {
192+ if (! contact .addressbook .canModifyCard || contact .addressbook .id === addressbook .id ) {
193+ return null
194+ }
195+ try {
196+ await this .$store .dispatch (' moveContactToAddressbook' , { contact, addressbook })
197+ return contact
198+ } catch (error) {
199+ console .error (' Failed to move contact' , contact, error)
200+ return null
201+ }
202+ })
203+
204+ await Promise .all (movePromises)
205+ this .$emit (' submit' )
206+ },
130207 },
131208}
132209 </script >
0 commit comments