Skip to content

Commit 7ea307c

Browse files
authored
Merge pull request #1278 from joshunrau/data-table
implement data table on admin pages
2 parents e498899 + 1b13faf commit 7ea307c

File tree

5 files changed

+70
-84
lines changed

5 files changed

+70
-84
lines changed

apps/web/src/routes/_app/admin/groups/index.tsx

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
import { useState } from 'react';
22

3-
import { Button, ClientTable, Heading, SearchBar, Sheet } from '@douglasneuroinformatics/libui/components';
3+
import { Button, DataTable, Heading, Sheet } from '@douglasneuroinformatics/libui/components';
44
import { useTranslation } from '@douglasneuroinformatics/libui/hooks';
55
import type { Group } from '@opendatacapture/schemas/group';
66
import { createFileRoute, Link } from '@tanstack/react-router';
77

88
import { PageHeader } from '@/components/PageHeader';
99
import { useDeleteGroupMutation } from '@/hooks/useDeleteGroupMutation';
1010
import { groupsQueryOptions, useGroupsQuery } from '@/hooks/useGroupsQuery';
11-
import { useSearch } from '@/hooks/useSearch';
1211

1312
const RouteComponent = () => {
1413
const { t } = useTranslation();
1514
const groupsQuery = useGroupsQuery();
1615
const deleteGroupMutation = useDeleteGroupMutation();
1716
const [selectedGroup, setSelectedGroup] = useState<Group | null>(null);
18-
const { filteredData, searchTerm, setSearchTerm } = useSearch(groupsQuery.data ?? [], 'name');
1917

2018
return (
2119
<Sheet open={Boolean(selectedGroup)} onOpenChange={() => setSelectedGroup(null)}>
@@ -27,47 +25,43 @@ const RouteComponent = () => {
2725
})}
2826
</Heading>
2927
</PageHeader>
30-
<div className="mb-3 flex gap-3">
31-
<SearchBar
32-
className="grow"
33-
placeholder={t({
34-
en: 'Search by Group Name',
35-
fr: 'Recherche par nom de groupe'
36-
})}
37-
value={searchTerm}
38-
onValueChange={setSearchTerm}
39-
/>
40-
<Button asChild variant="outline">
41-
<Link to="/admin/groups/create">
42-
{t({
43-
en: 'Add Group',
44-
fr: 'Ajouter un groupe'
45-
})}
46-
</Link>
47-
</Button>
48-
</div>
49-
<ClientTable<Group>
28+
<DataTable
5029
columns={[
5130
{
52-
field: 'name',
53-
label: t('common.groupName')
31+
accessorKey: 'name',
32+
header: t('common.groupName')
5433
},
5534
{
56-
field: ({ type }) => {
35+
accessorKey: 'type',
36+
cell: (ctx) => {
37+
const type = ctx.getValue() as Group['type'];
5738
if (type === 'CLINICAL') {
5839
return t('common.clinical');
5940
} else if (type === 'RESEARCH') {
6041
return t('common.research');
6142
}
6243
return type satisfies never;
6344
},
64-
label: t('common.groupType')
45+
header: t('common.groupType')
6546
}
6647
]}
67-
data={filteredData}
68-
entriesPerPage={15}
69-
minRows={15}
70-
onEntryClick={setSelectedGroup}
48+
data={groupsQuery.data}
49+
rowActions={[
50+
{
51+
label: t('common.manage'),
52+
onSelect: setSelectedGroup
53+
}
54+
]}
55+
togglesComponent={() => (
56+
<Button asChild variant="outline">
57+
<Link to="/admin/groups/create">
58+
{t({
59+
en: 'Add Group',
60+
fr: 'Ajouter un groupe'
61+
})}
62+
</Link>
63+
</Button>
64+
)}
7165
/>
7266
<Sheet.Content>
7367
<Sheet.Header>

apps/web/src/routes/_app/admin/users/index.tsx

Lines changed: 25 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,7 @@ import React, { useEffect, useMemo, useState } from 'react';
22

33
import { isAllUndefined, snakeToCamelCase } from '@douglasneuroinformatics/libjs';
44
import { estimatePasswordStrength } from '@douglasneuroinformatics/libpasswd';
5-
import {
6-
Button,
7-
ClientTable,
8-
Dialog,
9-
Form,
10-
Heading,
11-
SearchBar,
12-
Sheet
13-
} from '@douglasneuroinformatics/libui/components';
5+
import { Button, DataTable, Dialog, Form, Heading, Sheet } from '@douglasneuroinformatics/libui/components';
146
import { useTranslation } from '@douglasneuroinformatics/libui/hooks';
157
import type { FormTypes } from '@opendatacapture/runtime-core';
168
import { $UserPermission } from '@opendatacapture/schemas/core';
@@ -24,7 +16,6 @@ import { PageHeader } from '@/components/PageHeader';
2416
import { WithFallback } from '@/components/WithFallback';
2517
import { useDeleteUserMutation } from '@/hooks/useDeleteUserMutation';
2618
import { groupsQueryOptions, useGroupsQuery } from '@/hooks/useGroupsQuery';
27-
import { useSearch } from '@/hooks/useSearch';
2819
import { useUpdateUserMutation } from '@/hooks/useUpdateUserMutation';
2920
import { usersQueryOptions, useUsersQuery } from '@/hooks/useUsersQuery';
3021
import { useAppStore } from '@/store';
@@ -276,7 +267,6 @@ const RouteComponent = () => {
276267
const deleteUserMutation = useDeleteUserMutation();
277268
const updateUserMutation = useUpdateUserMutation();
278269
const [selectedUser, setSelectedUser] = useState<null | User>(null);
279-
const { filteredData, searchTerm, setSearchTerm } = useSearch(usersQuery.data ?? [], 'username');
280270

281271
const [data, setData] = useState<null | UpdateUserFormInputData>(null);
282272

@@ -307,34 +297,16 @@ const RouteComponent = () => {
307297
})}
308298
</Heading>
309299
</PageHeader>
310-
<div className="mb-3 flex gap-3">
311-
<SearchBar
312-
className="grow"
313-
data-testid="admin-users-search"
314-
placeholder={t({
315-
en: 'Search by Username',
316-
fr: "Recherche par nom d'utilisateur"
317-
})}
318-
value={searchTerm}
319-
onValueChange={setSearchTerm}
320-
/>
321-
<Button variant="outline">
322-
<Link to="/admin/users/create">
323-
{t({
324-
en: 'Add User',
325-
fr: 'Ajouter un utilisateur'
326-
})}
327-
</Link>
328-
</Button>
329-
</div>
330-
<ClientTable<User>
300+
<DataTable
331301
columns={[
332302
{
333-
field: 'username',
334-
label: t('common.username')
303+
accessorKey: 'username',
304+
header: t('common.username')
335305
},
336306
{
337-
field: ({ basePermissionLevel }) => {
307+
accessorKey: 'basePermissionLevel',
308+
cell: (ctx) => {
309+
const basePermissionLevel = ctx.getValue() as User['basePermissionLevel'];
338310
if (!basePermissionLevel) {
339311
return t({
340312
en: 'None',
@@ -343,14 +315,27 @@ const RouteComponent = () => {
343315
}
344316
return t(`common.${snakeToCamelCase(basePermissionLevel)}`);
345317
},
346-
label: t('common.basePermissionLevel')
318+
header: t('common.basePermissionLevel')
347319
}
348320
]}
349-
data={filteredData}
321+
data={usersQuery.data}
350322
data-testid="admin-users-table"
351-
entriesPerPage={15}
352-
minRows={15}
353-
onEntryClick={setSelectedUser}
323+
rowActions={[
324+
{
325+
label: t('common.manage'),
326+
onSelect: setSelectedUser
327+
}
328+
]}
329+
togglesComponent={() => (
330+
<Button variant="outline">
331+
<Link to="/admin/users/create">
332+
{t({
333+
en: 'Add User',
334+
fr: 'Ajouter un utilisateur'
335+
})}
336+
</Link>
337+
</Button>
338+
)}
354339
/>
355340
<Sheet.Content className="flex flex-col p-0" data-testid="admin-user-edit-sheet">
356341
<Sheet.Header className="px-6 pt-6">

apps/web/src/routes/_app/datahub/index.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const Filters: React.FC<{ table: TanstackTable.Table<Subject> }> = ({ table }) =
4141

4242
const columns = table.getAllColumns();
4343

44-
const dobColumn = columns.find((column) => column.id === 'date-of-birth')!;
44+
const dobColumn = columns.find((column) => column.id === 'dateOfBirth')!;
4545
const dobFilter = dobColumn.getFilterValue() as DateFilter;
4646

4747
const sexColumn = columns.find((column) => column.id === 'sex')!;
@@ -311,7 +311,7 @@ const MasterDataTable: React.FC<{
311311
id: 'subjectId'
312312
},
313313
{
314-
accessorFn: (subject) => subject.dateOfBirth,
314+
accessorKey: 'dateOfBirth',
315315
cell: (ctx) => {
316316
const value = ctx.getValue() as Date | null | undefined;
317317
return value ? toBasicISOString(value) : 'NULL';
@@ -327,8 +327,7 @@ const MasterDataTable: React.FC<{
327327
}
328328
return true;
329329
},
330-
header: t('core.identificationData.dateOfBirth.label'),
331-
id: 'date-of-birth'
330+
header: t('core.identificationData.dateOfBirth.label')
332331
},
333332
{
334333
accessorFn: (subject) => subject.sex ?? null,
@@ -358,7 +357,7 @@ const MasterDataTable: React.FC<{
358357
value: ['MALE', 'FEMALE', null] satisfies SexFilter
359358
},
360359
{
361-
id: 'date-of-birth',
360+
id: 'dateOfBirth',
362361
value: {
363362
allowNull: true,
364363
max: null,

apps/web/src/translations/common.json

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@
7777
"en": "Insufficient password strength",
7878
"fr": "Mot de passe trop faible"
7979
},
80+
"manage": {
81+
"en": "Manage",
82+
"fr": "Gérer"
83+
},
8084
"method": {
8185
"en": "Method",
8286
"fr": "Méthode"
@@ -85,6 +89,10 @@
8589
"en": "Password",
8690
"fr": "Mot de passe"
8791
},
92+
"passwordsMustMatch": {
93+
"en": "Passwords Must Match",
94+
"fr": "Les mots de passe doivent correspondre"
95+
},
8896
"personalInfo": {
8997
"en": "Personal Information",
9098
"fr": "Renseignements personnels"
@@ -101,10 +109,6 @@
101109
"en": "Standard",
102110
"fr": "Standard"
103111
},
104-
"passwordsMustMatch": {
105-
"en": "Passwords Must Match",
106-
"fr": "Les mots de passe doivent correspondre"
107-
},
108112
"subjectIdentification": {
109113
"description": {
110114
"en": "The following items are used to compute a unique identifier that enables consistent cross-session identification.",
@@ -154,5 +158,9 @@
154158
"usernameExists": {
155159
"en": "Username already exists",
156160
"fr": "Le nom d'utilisateur existe déjà"
161+
},
162+
"view": {
163+
"en": "View",
164+
"fr": "Voir"
157165
}
158166
}

apps/web/src/translations/layout.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@
5050
"en": "Data Hub",
5151
"fr": "Centre de données"
5252
},
53-
"upload": {
54-
"en": "Upload Data",
55-
"fr": "Téléverser les données"
56-
},
5753
"endSession": {
5854
"en": "End Current Session",
5955
"fr": "Terminer la session en cours"
@@ -66,6 +62,10 @@
6662
"en": "Start Session",
6763
"fr": "Commencer une session"
6864
},
65+
"upload": {
66+
"en": "Upload Data",
67+
"fr": "Téléverser les données"
68+
},
6969
"viewCurrentSubject": {
7070
"en": "View Current Subject",
7171
"fr": "Voir le client actuel"

0 commit comments

Comments
 (0)