Skip to content

Commit 50c8d95

Browse files
committed
feat: sort addressbooks
Signed-off-by: Grigory Vodyanov <[email protected]>
1 parent 66f0ea1 commit 50c8d95

File tree

2 files changed

+88
-3
lines changed

2 files changed

+88
-3
lines changed

src/components/ContactDetails.vue

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,12 +400,12 @@ import PropertySelect from './Properties/PropertySelect.vue'
400400
import { generateUrl } from '@nextcloud/router'
401401
import { loadState } from '@nextcloud/initial-state'
402402
import isTalkEnabled from '../services/isTalkEnabled.js'
403-
import { reactive, toRaw } from 'vue'
403+
import { reactive, toRaw, defineComponent } from 'vue'
404404
import IsMobileMixin from '../mixins/IsMobileMixin.ts'
405405
406406
const { profileEnabled } = loadState('user_status', 'profileEnabled', false)
407407
408-
export default {
408+
export default defineComponent({
409409
name: 'ContactDetails',
410410
411411
components: {
@@ -1051,10 +1051,12 @@ export default {
10511051
})
10521052
await this.updateContact()
10531053
if (this.newAddressBook && this.newAddressBook !== this.contact.addressbook.id) {
1054+
this.updateAddressBookAccesses(this.newAddressBook)
10541055
this.moveContactToAddressbook(this.newAddressBook)
10551056
this.newAddressBook = null
10561057
}
10571058
this.editMode = false
1059+
await this.$store.commit('resortAddressbooks')
10581060
} catch (error) {
10591061
this.logger.error('error while saving contact', { error })
10601062
showError(t('contacts', 'Unable to update contact'))
@@ -1065,8 +1067,15 @@ export default {
10651067
})
10661068
}
10671069
},
1070+
1071+
updateAddressBookAccesses(newAddressBook) {
1072+
const accesses = JSON.parse(localStorage.getItem('addressbook-accesses') || '{}')
1073+
accesses[newAddressBook] = new Date()
1074+
1075+
localStorage.setItem('addressbook-accesses', JSON.stringify(accesses))
1076+
},
10681077
},
1069-
}
1078+
})
10701079
</script>
10711080
10721081
<style lang="scss" scoped>

src/store/addressbooks.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,72 @@ export function mapDavShareeToSharee(sharee) {
7070
}
7171
}
7272

73+
/**
74+
* Sorts addressbooks by rules:
75+
* 1. First group: Default personal addressbook ("contacts")
76+
* 2. Second group: Recently used (based on lastUsedAddressBooks) go second, ordered from newest to oldest
77+
* 3. Third group: Writeable enabled contacts, sorted by the amount of contacts they have, from more to less
78+
* 4. Fourth group: Read-only enabled contacts, sorted by the amount of contacts
79+
* 5. Fifth group: Disabled contacts, sorted by the amount of contacts
80+
*
81+
* @param {Array} addressbooks
82+
* @return {Array}
83+
*/
84+
export function sortAddressbooks(addressbooks) {
85+
const lastUsed = lastUsedAddressBooks(addressbooks)
86+
87+
return addressbooks
88+
.slice()
89+
.sort((a, b) => {
90+
const getContactCount = (ab) => Object.keys(ab.contacts || {}).length
91+
92+
const getPriorityGroup = (ab) => {
93+
if (ab.id === 'contacts') return 0
94+
if (ab.enabled === false) return 4
95+
if (lastUsed.includes(ab.id)) return 1
96+
if (ab.readOnly) return 3
97+
return 2
98+
}
99+
100+
const groupA = getPriorityGroup(a)
101+
const groupB = getPriorityGroup(b)
102+
103+
// First, sort by priority group
104+
if (groupA !== groupB) {
105+
return groupA - groupB
106+
}
107+
108+
// Within the same group, apply specific sorting rules
109+
if (groupA === 0) {
110+
return 0
111+
} else if (groupA === 1) {
112+
// Sort by position in lastUsed array (newest first)
113+
return lastUsed.indexOf(a.id) - lastUsed.indexOf(b.id)
114+
} else { // Groups 2, 3, 4 - sort by contact count (descending)
115+
const countA = getContactCount(a)
116+
const countB = getContactCount(b)
117+
118+
if (countA !== countB) {
119+
return countB - countA
120+
}
121+
122+
// If contact counts are equal, sort alphabetically by ID as tiebreaker
123+
return a.id.localeCompare(b.id)
124+
}
125+
})
126+
}
127+
128+
/**
129+
*
130+
*/
131+
function lastUsedAddressBooks() {
132+
const accesses = JSON.parse(localStorage.getItem('addressbook-accesses') || '{}')
133+
134+
return Object.entries(accesses)
135+
.sort(([, a], [, b]) => new Date(b) - new Date(a))
136+
.map(([id]) => id)
137+
}
138+
73139
const mutations = {
74140

75141
/**
@@ -218,6 +284,14 @@ const mutations = {
218284
sharee.writeable = !sharee.writeable
219285
},
220286

287+
/**
288+
* Needed to track indirect state changes for addressbook sorting
289+
*
290+
* @param state
291+
*/
292+
resortAddressbooks(state) {
293+
state.addressbooks = sortAddressbooks(state.addressbooks)
294+
},
221295
}
222296

223297
const getters = {
@@ -246,6 +320,8 @@ const actions = {
246320
context.commit('addAddressbook', addressbook)
247321
})
248322

323+
context.commit('resortAddressbooks')
324+
249325
return addressbooks
250326
},
251327

0 commit comments

Comments
 (0)