2022-06-19 16:32:46 +02:00
|
|
|
import i18n from '@/i18n'
|
|
|
|
|
|
|
|
const { t, locale } = i18n.global
|
2024-03-18 21:34:43 +01:00
|
|
|
const NO_INDEX = 'NO_INDEX'
|
|
|
|
|
|
|
|
const numberComparator = (a, b) => a - b
|
|
|
|
const stringComparator = (a, b) => a.localeCompare(b, locale.value)
|
|
|
|
const dateComparator = (a, b) =>
|
|
|
|
new Date(a) - new Date(b) || (!a ? -1 : !b ? 1 : 0)
|
|
|
|
|
|
|
|
function createComparators(criteria) {
|
|
|
|
return criteria.map(({ field, type, order = 1 }) => {
|
|
|
|
switch (type) {
|
|
|
|
case String:
|
|
|
|
return (a, b) => stringComparator(a[field], b[field]) * order
|
|
|
|
case Number:
|
|
|
|
return (a, b) => numberComparator(a[field], b[field]) * order
|
|
|
|
case Date:
|
|
|
|
return (a, b) => dateComparator(a[field], b[field]) * order
|
2022-02-19 07:47:54 +01:00
|
|
|
}
|
2024-03-18 21:34:43 +01:00
|
|
|
})
|
2022-02-19 07:47:54 +01:00
|
|
|
}
|
|
|
|
|
2024-03-18 21:34:43 +01:00
|
|
|
const characterIndex = (string = '') => {
|
|
|
|
const value = string.charAt(0)
|
|
|
|
if (value.match(/\p{Letter}/gu)) {
|
|
|
|
return value.toUpperCase()
|
|
|
|
} else if (value.match(/\p{Number}/gu)) {
|
|
|
|
return '#'
|
2023-03-23 23:19:55 +01:00
|
|
|
}
|
2024-03-18 21:34:43 +01:00
|
|
|
return '⌘'
|
2023-03-23 23:19:55 +01:00
|
|
|
}
|
|
|
|
|
2024-03-31 21:50:33 +02:00
|
|
|
const numberIndex = (number) => {
|
|
|
|
Math.floor(number / 10)
|
2023-12-08 10:12:03 +01:00
|
|
|
}
|
|
|
|
|
2024-03-18 21:34:43 +01:00
|
|
|
const times = [
|
|
|
|
{ difference: NaN, text: () => t('grouped-list.undefined') },
|
|
|
|
{ difference: 86400000, text: () => t('grouped-list.today') },
|
|
|
|
{ difference: 604800000, text: () => t('grouped-list.last-week') },
|
|
|
|
{ difference: 2592000000, text: () => t('grouped-list.last-month') },
|
|
|
|
{ difference: Infinity, text: (date) => date.getFullYear() }
|
|
|
|
]
|
|
|
|
|
|
|
|
const timeIndex = (string) => {
|
|
|
|
const date = new Date(string)
|
|
|
|
const diff = new Date() - date
|
|
|
|
return times.find((item) => isNaN(diff) || diff < item.difference)?.text(date)
|
2022-02-19 07:47:54 +01:00
|
|
|
}
|
|
|
|
|
2024-03-18 21:34:43 +01:00
|
|
|
function createIndexer({ field, type = undefined } = {}) {
|
|
|
|
switch (type) {
|
|
|
|
case String:
|
|
|
|
return (item) => characterIndex(item[field])
|
|
|
|
case Number:
|
|
|
|
return (item) => item[field]
|
|
|
|
case Date:
|
|
|
|
return (item) => timeIndex(item[field])
|
|
|
|
case 'Digits':
|
|
|
|
return (item) => numberIndex(item[field])
|
|
|
|
default:
|
|
|
|
return (item) => NO_INDEX
|
2022-02-19 07:47:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-22 19:32:11 +01:00
|
|
|
export class GroupedList {
|
2024-03-18 21:34:43 +01:00
|
|
|
constructor({ items = [], total = 0, offset = 0, limit = -1 } = {}, options) {
|
2022-02-19 07:47:54 +01:00
|
|
|
this.items = items
|
|
|
|
this.total = total
|
|
|
|
this.offset = offset
|
|
|
|
this.limit = limit
|
|
|
|
this.count = items.length
|
2024-02-27 16:27:37 +01:00
|
|
|
this.indices = []
|
2024-03-18 21:34:43 +01:00
|
|
|
this.group(options)
|
2022-02-19 07:47:54 +01:00
|
|
|
}
|
|
|
|
|
2024-03-18 21:34:43 +01:00
|
|
|
group({ criteria = [], filters = [], index } = {}) {
|
|
|
|
const indexer = createIndexer(index)
|
2024-03-12 13:45:53 +01:00
|
|
|
const itemsFiltered = this.items.filter((item) =>
|
2024-03-18 21:34:43 +01:00
|
|
|
filters.every((filter) => filter(item))
|
2024-03-12 13:45:53 +01:00
|
|
|
)
|
2022-02-19 07:47:54 +01:00
|
|
|
this.count = itemsFiltered.length
|
|
|
|
// Sort item list
|
2024-03-18 21:34:43 +01:00
|
|
|
const comparators = createComparators(criteria)
|
|
|
|
const itemsSorted = itemsFiltered.sort((a, b) =>
|
|
|
|
comparators.reduce(
|
|
|
|
(comparison, comparator) => comparison || comparator(a, b),
|
|
|
|
0
|
|
|
|
)
|
2024-03-12 14:04:05 +01:00
|
|
|
)
|
2022-02-19 07:47:54 +01:00
|
|
|
// Group item list
|
2024-03-12 13:45:53 +01:00
|
|
|
this.itemsGrouped = itemsSorted.reduce((map, item) => {
|
2024-03-18 21:34:43 +01:00
|
|
|
const index = indexer(item)
|
|
|
|
map.set(index, [...(map.get(index) || []), item])
|
2024-03-12 13:45:53 +01:00
|
|
|
return map
|
|
|
|
}, new Map())
|
|
|
|
// Create index list
|
|
|
|
this.indices = Array.from(this.itemsGrouped.keys())
|
2022-02-19 07:47:54 +01:00
|
|
|
}
|
|
|
|
|
2023-12-12 21:20:41 +01:00
|
|
|
*generate() {
|
2024-03-18 21:34:43 +01:00
|
|
|
for (const [index, items] of this.itemsGrouped.entries()) {
|
|
|
|
if (index !== NO_INDEX) {
|
2023-12-12 21:20:41 +01:00
|
|
|
yield {
|
2024-03-26 12:04:04 +01:00
|
|
|
index,
|
2023-12-12 21:20:41 +01:00
|
|
|
isItem: false,
|
2024-03-26 12:04:04 +01:00
|
|
|
item: {},
|
|
|
|
itemId: index
|
2023-11-24 15:48:29 +01:00
|
|
|
}
|
2023-12-12 21:20:41 +01:00
|
|
|
}
|
2024-03-12 13:45:53 +01:00
|
|
|
for (const item of items) {
|
2023-12-12 21:20:41 +01:00
|
|
|
yield {
|
2024-03-26 12:04:04 +01:00
|
|
|
index,
|
2023-12-12 21:20:41 +01:00
|
|
|
isItem: true,
|
2024-03-26 12:04:04 +01:00
|
|
|
item,
|
|
|
|
itemId: item.id
|
2022-02-19 07:47:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-12-12 21:20:41 +01:00
|
|
|
|
|
|
|
[Symbol.iterator]() {
|
|
|
|
return this.generate()
|
|
|
|
}
|
2022-02-19 07:47:54 +01:00
|
|
|
}
|