Skip to content

Commit 03be58a

Browse files
Merge pull request #2124 from tim48-robot/fix/community-studies-sorting
fix sorting, check quick video
2 parents 4e9e842 + 3153716 commit 03be58a

3 files changed

Lines changed: 104 additions & 11 deletions

File tree

src/shared/components/tables/ListComponent.vue

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
:headers="headers"
44
:items="items"
55
:sort-by="sortBy || [{ key: 'updateDate', order: 'desc' }]"
6-
item-key="id"
6+
:item-value="itemValue"
77
density="comfortable"
88
class="rounded-lg"
99
elevation="2"
@@ -185,9 +185,13 @@ const { t } = useI18n()
185185
// Composables
186186
const typeRef = toRef(props, 'type')
187187
const showActionsRef = toRef(props, 'showActions')
188-
const { headers, getEmptyStateMessage } = useDataTableConfig(typeRef, t, {
189-
showActions: showActionsRef,
190-
})
188+
const { headers, getEmptyStateMessage, itemValue } = useDataTableConfig(
189+
typeRef,
190+
t,
191+
{
192+
showActions: showActionsRef,
193+
},
194+
)
191195
const {
192196
getItemTitle,
193197
getOwnerName,

src/shared/composables/useDataTableConfig.js

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,51 @@
11
import { computed, toRef, unref } from 'vue'
2+
import { getSessionStatus } from '@/shared/utils/sessionsUtils'
3+
4+
const toSortableTimestamp = (value) => {
5+
if (!value) return 0
6+
if (typeof value?.toMillis === 'function') return value.toMillis()
7+
8+
const timestamp = new Date(value).getTime()
9+
return Number.isNaN(timestamp) ? 0 : timestamp
10+
}
11+
12+
const getSessionItemValue = (item) =>
13+
[item.id, item.userDocId ?? item.email, item.email, item.testDate]
14+
.map((value) => encodeURIComponent(String(value ?? '')))
15+
.join(':')
16+
17+
const getSortableTitle = (item) =>
18+
item.header?.templateTitle ?? item.testTitle ?? item.title ?? item.email ?? ''
19+
20+
const getSortableOwner = (item, type) => {
21+
if (type === 'myTemplates') return ''
22+
if (type === 'publicTemplates') {
23+
return item.header?.templateAuthor?.userEmail ?? ''
24+
}
25+
26+
return item.testAdmin?.email ?? item.testAuthorEmail ?? ''
27+
}
28+
29+
const getSortableParticipantCount = (item) =>
30+
item.numberColaborators ?? item.cooperators?.length ?? 0
31+
32+
const getSortableCreationDate = (item, type) => {
33+
if (type === 'myTemplates' || type === 'publicTemplates') {
34+
return item.header?.creationDate ?? 0
35+
}
36+
37+
return item.creationDate ?? item.updateDate ?? 0
38+
}
239

340
export function useDataTableConfig(type, t, options = {}) {
441
const typeRef = toRef(type)
542

43+
const itemValue = (item) =>
44+
typeRef.value === 'sessions' ? getSessionItemValue(item) : item.id
45+
646
const headers = computed(() => {
47+
const currentType = typeRef.value
48+
749
const baseHeaders = [
850
{
951
title: t('common.table.type'),
@@ -15,8 +57,7 @@ export function useDataTableConfig(type, t, options = {}) {
1557
title: t('common.table.name'),
1658
key: 'name',
1759
sortable: true,
18-
value: (item) =>
19-
item.header?.templateTitle ?? item.testTitle ?? item.email,
60+
value: getSortableTitle,
2061
},
2162
{
2263
title: t('common.table.tags'),
@@ -28,45 +69,50 @@ export function useDataTableConfig(type, t, options = {}) {
2869
title: t('common.table.owner'),
2970
key: 'owner',
3071
sortable: true,
72+
value: (item) => getSortableOwner(item, currentType),
3173
},
3274
]
3375

34-
if (typeRef.value === 'sessions') {
76+
if (currentType === 'sessions') {
3577
baseHeaders.push({
3678
title: t('common.table.evaluator'),
3779
key: 'evaluator',
3880
sortable: true,
81+
value: (item) => item.email ?? '',
3982
})
4083
baseHeaders.push({
4184
title: t('common.table.status'),
4285
key: 'status',
4386
sortable: true,
87+
value: (item) => getSessionStatus(item.testDate).status,
4488
})
4589
baseHeaders.push({
4690
title: t('common.table.sessionDate'),
4791
key: 'testDate',
4892
sortable: true,
93+
value: (item) => toSortableTimestamp(item.testDate),
4994
})
5095
}
5196

5297
if (
53-
typeRef.value !== 'sessions' &&
54-
typeRef.value !== 'myTemplates' &&
55-
typeRef.value !== 'publicTemplates'
98+
currentType !== 'sessions' &&
99+
currentType !== 'myTemplates' &&
100+
currentType !== 'publicTemplates'
56101
) {
57102
baseHeaders.push({
58103
title: t('common.table.participants'),
59104
key: 'participants',
60105
sortable: true,
61106
align: 'center',
62-
value: (item) => item.numberColaborators ?? 0,
107+
value: getSortableParticipantCount,
63108
})
64109
}
65110

66111
baseHeaders.push({
67112
title: t('common.table.created'),
68113
key: 'creationDate',
69114
sortable: true,
115+
value: (item) => getSortableCreationDate(item, currentType),
70116
})
71117

72118
if (unref(options.showActions)) {
@@ -99,5 +145,6 @@ export function useDataTableConfig(type, t, options = {}) {
99145
return {
100146
headers,
101147
getEmptyStateMessage,
148+
itemValue,
102149
}
103150
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { ref } from 'vue'
2+
import { useDataTableConfig } from '@/shared/composables/useDataTableConfig'
3+
4+
describe('useDataTableConfig', () => {
5+
it('gives sessions unique row values and sortable derived columns', () => {
6+
const { headers, itemValue } = useDataTableConfig(
7+
ref('sessions'),
8+
(key) => key,
9+
)
10+
const firstSession = {
11+
id: 'halo-study',
12+
email: 'first@example.com',
13+
testDate: '2026-07-01T08:38:00.000Z',
14+
}
15+
const secondSession = {
16+
id: 'halo-study',
17+
email: 'second@example.com',
18+
testDate: '2026-07-01T08:38:00.000Z',
19+
}
20+
21+
expect(itemValue(firstSession)).not.toBe(itemValue(secondSession))
22+
23+
const statusHeader = headers.value.find(({ key }) => key === 'status')
24+
const sessionDateHeader = headers.value.find(
25+
({ key }) => key === 'testDate',
26+
)
27+
28+
expect(statusHeader.value({
29+
...firstSession,
30+
testDate: '2000-01-01T00:00:00.000Z',
31+
})).toBe('completed')
32+
expect(sessionDateHeader.value(firstSession)).toBe(
33+
new Date(firstSession.testDate).getTime(),
34+
)
35+
})
36+
37+
it('keeps study rows keyed by their document id', () => {
38+
const { itemValue } = useDataTableConfig(ref('myTests'), (key) => key)
39+
40+
expect(itemValue({ id: 'study-id' })).toBe('study-id')
41+
})
42+
})

0 commit comments

Comments
 (0)