Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 25 additions & 31 deletions apps/web/src/routes/_app/admin/groups/index.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { useState } from 'react';

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

import { PageHeader } from '@/components/PageHeader';
import { useDeleteGroupMutation } from '@/hooks/useDeleteGroupMutation';
import { groupsQueryOptions, useGroupsQuery } from '@/hooks/useGroupsQuery';
import { useSearch } from '@/hooks/useSearch';

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

return (
<Sheet open={Boolean(selectedGroup)} onOpenChange={() => setSelectedGroup(null)}>
Expand All @@ -27,47 +25,43 @@ const RouteComponent = () => {
})}
</Heading>
</PageHeader>
<div className="mb-3 flex gap-3">
<SearchBar
className="grow"
placeholder={t({
en: 'Search by Group Name',
fr: 'Recherche par nom de groupe'
})}
value={searchTerm}
onValueChange={setSearchTerm}
/>
<Button asChild variant="outline">
<Link to="/admin/groups/create">
{t({
en: 'Add Group',
fr: 'Ajouter un groupe'
})}
</Link>
</Button>
</div>
<ClientTable<Group>
<DataTable
columns={[
{
field: 'name',
label: t('common.groupName')
accessorKey: 'name',
header: t('common.groupName')
},
{
field: ({ type }) => {
accessorKey: 'type',
cell: (ctx) => {
const type = ctx.getValue() as Group['type'];
if (type === 'CLINICAL') {
return t('common.clinical');
} else if (type === 'RESEARCH') {
return t('common.research');
}
return type satisfies never;
},
label: t('common.groupType')
header: t('common.groupType')
}
]}
data={filteredData}
entriesPerPage={15}
minRows={15}
onEntryClick={setSelectedGroup}
data={groupsQuery.data}
rowActions={[
{
label: t('common.manage'),
onSelect: setSelectedGroup
}
]}
togglesComponent={() => (
<Button asChild variant="outline">
<Link to="/admin/groups/create">
{t({
en: 'Add Group',
fr: 'Ajouter un groupe'
})}
</Link>
</Button>
)}
/>
<Sheet.Content>
<Sheet.Header>
Expand Down
65 changes: 25 additions & 40 deletions apps/web/src/routes/_app/admin/users/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,7 @@ import React, { useEffect, useMemo, useState } from 'react';

import { isAllUndefined, snakeToCamelCase } from '@douglasneuroinformatics/libjs';
import { estimatePasswordStrength } from '@douglasneuroinformatics/libpasswd';
import {
Button,
ClientTable,
Dialog,
Form,
Heading,
SearchBar,
Sheet
} from '@douglasneuroinformatics/libui/components';
import { Button, DataTable, Dialog, Form, Heading, Sheet } from '@douglasneuroinformatics/libui/components';
import { useTranslation } from '@douglasneuroinformatics/libui/hooks';
import type { FormTypes } from '@opendatacapture/runtime-core';
import { $UserPermission } from '@opendatacapture/schemas/core';
Expand All @@ -24,7 +16,6 @@ import { PageHeader } from '@/components/PageHeader';
import { WithFallback } from '@/components/WithFallback';
import { useDeleteUserMutation } from '@/hooks/useDeleteUserMutation';
import { groupsQueryOptions, useGroupsQuery } from '@/hooks/useGroupsQuery';
import { useSearch } from '@/hooks/useSearch';
import { useUpdateUserMutation } from '@/hooks/useUpdateUserMutation';
import { usersQueryOptions, useUsersQuery } from '@/hooks/useUsersQuery';
import { useAppStore } from '@/store';
Expand Down Expand Up @@ -276,7 +267,6 @@ const RouteComponent = () => {
const deleteUserMutation = useDeleteUserMutation();
const updateUserMutation = useUpdateUserMutation();
const [selectedUser, setSelectedUser] = useState<null | User>(null);
const { filteredData, searchTerm, setSearchTerm } = useSearch(usersQuery.data ?? [], 'username');

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

Expand Down Expand Up @@ -307,34 +297,16 @@ const RouteComponent = () => {
})}
</Heading>
</PageHeader>
<div className="mb-3 flex gap-3">
<SearchBar
className="grow"
data-testid="admin-users-search"
placeholder={t({
en: 'Search by Username',
fr: "Recherche par nom d'utilisateur"
})}
value={searchTerm}
onValueChange={setSearchTerm}
/>
<Button variant="outline">
<Link to="/admin/users/create">
{t({
en: 'Add User',
fr: 'Ajouter un utilisateur'
})}
</Link>
</Button>
</div>
<ClientTable<User>
<DataTable
columns={[
{
field: 'username',
label: t('common.username')
accessorKey: 'username',
header: t('common.username')
},
{
field: ({ basePermissionLevel }) => {
accessorKey: 'basePermissionLevel',
cell: (ctx) => {
const basePermissionLevel = ctx.getValue() as User['basePermissionLevel'];
if (!basePermissionLevel) {
return t({
en: 'None',
Expand All @@ -343,14 +315,27 @@ const RouteComponent = () => {
}
return t(`common.${snakeToCamelCase(basePermissionLevel)}`);
},
label: t('common.basePermissionLevel')
header: t('common.basePermissionLevel')
}
]}
data={filteredData}
data={usersQuery.data}
data-testid="admin-users-table"
entriesPerPage={15}
minRows={15}
onEntryClick={setSelectedUser}
rowActions={[
{
label: t('common.manage'),
onSelect: setSelectedUser
}
]}
togglesComponent={() => (
<Button variant="outline">
<Link to="/admin/users/create">
{t({
en: 'Add User',
fr: 'Ajouter un utilisateur'
})}
</Link>
</Button>
)}
/>
<Sheet.Content className="flex flex-col p-0" data-testid="admin-user-edit-sheet">
<Sheet.Header className="px-6 pt-6">
Expand Down
9 changes: 4 additions & 5 deletions apps/web/src/routes/_app/datahub/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const Filters: React.FC<{ table: TanstackTable.Table<Subject> }> = ({ table }) =

const columns = table.getAllColumns();

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

const sexColumn = columns.find((column) => column.id === 'sex')!;
Expand Down Expand Up @@ -311,7 +311,7 @@ const MasterDataTable: React.FC<{
id: 'subjectId'
},
{
accessorFn: (subject) => subject.dateOfBirth,
accessorKey: 'dateOfBirth',
cell: (ctx) => {
const value = ctx.getValue() as Date | null | undefined;
return value ? toBasicISOString(value) : 'NULL';
Expand All @@ -327,8 +327,7 @@ const MasterDataTable: React.FC<{
}
return true;
},
header: t('core.identificationData.dateOfBirth.label'),
id: 'date-of-birth'
header: t('core.identificationData.dateOfBirth.label')
},
{
accessorFn: (subject) => subject.sex ?? null,
Expand Down Expand Up @@ -358,7 +357,7 @@ const MasterDataTable: React.FC<{
value: ['MALE', 'FEMALE', null] satisfies SexFilter
},
{
id: 'date-of-birth',
id: 'dateOfBirth',
value: {
allowNull: true,
max: null,
Expand Down
16 changes: 12 additions & 4 deletions apps/web/src/translations/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@
"en": "Insufficient password strength",
"fr": "Mot de passe trop faible"
},
"manage": {
"en": "Manage",
"fr": "Gérer"
},
"method": {
"en": "Method",
"fr": "Méthode"
Expand All @@ -85,6 +89,10 @@
"en": "Password",
"fr": "Mot de passe"
},
"passwordsMustMatch": {
"en": "Passwords Must Match",
"fr": "Les mots de passe doivent correspondre"
},
"personalInfo": {
"en": "Personal Information",
"fr": "Renseignements personnels"
Expand All @@ -101,10 +109,6 @@
"en": "Standard",
"fr": "Standard"
},
"passwordsMustMatch": {
"en": "Passwords Must Match",
"fr": "Les mots de passe doivent correspondre"
},
"subjectIdentification": {
"description": {
"en": "The following items are used to compute a unique identifier that enables consistent cross-session identification.",
Expand Down Expand Up @@ -154,5 +158,9 @@
"usernameExists": {
"en": "Username already exists",
"fr": "Le nom d'utilisateur existe déjà"
},
"view": {
"en": "View",
"fr": "Voir"
}
}
8 changes: 4 additions & 4 deletions apps/web/src/translations/layout.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,6 @@
"en": "Data Hub",
"fr": "Centre de données"
},
"upload": {
"en": "Upload Data",
"fr": "Téléverser les données"
},
"endSession": {
"en": "End Current Session",
"fr": "Terminer la session en cours"
Expand All @@ -66,6 +62,10 @@
"en": "Start Session",
"fr": "Commencer une session"
},
"upload": {
"en": "Upload Data",
"fr": "Téléverser les données"
},
"viewCurrentSubject": {
"en": "View Current Subject",
"fr": "Voir le client actuel"
Expand Down