generated from StanfordBDHG/NextJSTemplate
-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
# List users and patients ## ♻️ Current situation & Problem Users and patients need to be listed. ## ⚙️ Release Notes * Add features to DataTable * Create "Users" list page * Create "Patients list" page ## ✅ Testing Patients and users views will be covered with E2E tests later, hence drop in code coverage ### Code of Conduct & Contributing Guidelines By submitting creating this pull request, you agree to follow our [Code of Conduct](https://github.com/StanfordBDHG/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordBDHG/.github/blob/main/CONTRIBUTING.md): - [x] I agree to follow the [Code of Conduct](https://github.com/StanfordBDHG/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordBDHG/.github/blob/main/CONTRIBUTING.md).
- Loading branch information
1 parent
ceaa0ba
commit 720a0df
Showing
66 changed files
with
2,935 additions
and
415 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// | ||
// This source file is part of the Stanford Biodesign Digital Health ENGAGE-HF open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2023 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
'use client' | ||
import { Home, Users, Contact } from 'lucide-react' | ||
import { usePathname } from 'next/navigation' | ||
import { Role } from '@/modules/firebase/role' | ||
import { MenuItem } from '@stanfordbdhg/design-system/molecules/DashboardLayout' | ||
|
||
interface MenuLinksProps { | ||
role: Role | ||
} | ||
|
||
export const MenuLinks = ({ role }: MenuLinksProps) => { | ||
const pathname = usePathname() | ||
|
||
const hrefProps = (href: string) => ({ | ||
href, | ||
isActive: pathname === href, | ||
}) | ||
|
||
return ( | ||
<> | ||
<MenuItem {...hrefProps('/')} label="Home" icon={<Home />} /> | ||
{role === Role.admin && ( | ||
<MenuItem {...hrefProps('/users')} label="Users" icon={<Users />} /> | ||
)} | ||
<MenuItem | ||
{...hrefProps('/patients')} | ||
label="Patients" | ||
icon={<Contact />} | ||
/> | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// | ||
// This source file is part of the Stanford Biodesign Digital Health ENGAGE-HF open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2023 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
'use client' | ||
import { createColumnHelper } from '@tanstack/table-core' | ||
import { Pencil, Trash } from 'lucide-react' | ||
import { CopyText } from '@/packages/design-system/src/components/CopyText' | ||
import { | ||
DataTable, | ||
RowDropdownMenu, | ||
} from '@/packages/design-system/src/components/DataTable' | ||
import { DropdownMenuItem } from '@/packages/design-system/src/components/DropdownMenu' | ||
import type { Patient } from './page' | ||
|
||
const columnHelper = createColumnHelper<Patient>() | ||
|
||
const columns = [ | ||
columnHelper.accessor('uid', { | ||
header: 'Id', | ||
cell: (props) => ( | ||
<CopyText className="max-w-[7rem]">{props.getValue()}</CopyText> | ||
), | ||
}), | ||
columnHelper.accessor('displayName', { | ||
header: 'Name', | ||
cell: (props) => props.getValue() ?? '-', | ||
}), | ||
columnHelper.accessor('email', { header: 'Email' }), | ||
columnHelper.accessor('gender', { header: 'Gender' }), | ||
columnHelper.display({ | ||
id: 'actions', | ||
cell: () => ( | ||
// TODO: Actions | ||
<RowDropdownMenu> | ||
<DropdownMenuItem> | ||
<Pencil /> | ||
Edit | ||
</DropdownMenuItem> | ||
<DropdownMenuItem> | ||
<Trash /> | ||
Delete | ||
</DropdownMenuItem> | ||
</RowDropdownMenu> | ||
), | ||
}), | ||
] | ||
|
||
interface PatientsDataTableProps { | ||
data: Patient[] | ||
} | ||
|
||
export const PatientsTable = ({ data }: PatientsDataTableProps) => ( | ||
<DataTable columns={columns} data={data} entityName="patients" /> | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// | ||
// This source file is part of the Stanford Biodesign Digital Health ENGAGE-HF open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2023 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
import { getDocs, query, where } from 'firebase/firestore' | ||
import { Contact } from 'lucide-react' | ||
import { getAuthenticatedOnlyApp, getUserRole } from '@/modules/firebase/guards' | ||
import { Role } from '@/modules/firebase/role' | ||
import { mapUserData } from '@/modules/firebase/user' | ||
import { PageTitle } from '@/packages/design-system/src/molecules/DashboardLayout' | ||
import { PatientsTable } from './PatientsTable' | ||
import { DashboardLayout } from '../DashboardLayout' | ||
|
||
const getPatientsQuery = async () => { | ||
const { refs } = await getAuthenticatedOnlyApp() | ||
const userRole = await getUserRole() | ||
if (userRole.role === Role.admin) return refs.users() | ||
if (userRole.role === Role.owner) { | ||
const organizationIds = userRole.organizations.docs.map((doc) => doc.id) | ||
return query(refs.users(), where('organization', 'in', organizationIds)) | ||
} | ||
if (userRole.role === Role.clinician) { | ||
const organizationId = userRole.clinician.data().organization | ||
if (!organizationId) { | ||
// TODO: Check if there is any reason for organization not to be defined | ||
throw new Error('') | ||
} | ||
return query(refs.users(), where('organization', '==', organizationId)) | ||
} | ||
// Other roles can't reach this point, so this should never execute | ||
throw new Error() | ||
} | ||
|
||
const listPatients = async () => { | ||
const patientsQuery = await getPatientsQuery() | ||
const patients = await getDocs(patientsQuery) | ||
const userIdsToGet = patients.docs.map((patient) => patient.id) | ||
const patientsById = new Map( | ||
patients.docs.map( | ||
(patient) => [patient.id, { id: patient.id, ...patient.data() }] as const, | ||
), | ||
) | ||
|
||
return mapUserData(userIdsToGet, (authData, id) => { | ||
const patient = patientsById.get(id) | ||
if (!patient) { | ||
console.error(`No patient found for user id ${id}`) | ||
return null | ||
} | ||
return { | ||
uid: id, | ||
email: authData.email, | ||
displayName: authData.displayName, | ||
gender: patient.GenderIdentityKey, | ||
} | ||
}) | ||
} | ||
|
||
export type Patient = Awaited<ReturnType<typeof listPatients>>[number] | ||
|
||
const PatientsPage = async () => { | ||
const patients = await listPatients() | ||
|
||
return ( | ||
<DashboardLayout title={<PageTitle title="Patients" icon={<Contact />} />}> | ||
<PatientsTable data={patients} /> | ||
</DashboardLayout> | ||
) | ||
} | ||
|
||
export default PatientsPage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// | ||
// This source file is part of the Stanford Biodesign Digital Health ENGAGE-HF open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2023 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
'use client' | ||
import { createColumnHelper } from '@tanstack/table-core' | ||
import { Pencil, Trash } from 'lucide-react' | ||
import { CopyText } from '@/packages/design-system/src/components/CopyText' | ||
import { | ||
DataTable, | ||
RowDropdownMenu, | ||
} from '@/packages/design-system/src/components/DataTable' | ||
import { DropdownMenuItem } from '@/packages/design-system/src/components/DropdownMenu' | ||
import type { User } from './page' | ||
|
||
const columnHelper = createColumnHelper<User>() | ||
|
||
const columns = [ | ||
columnHelper.accessor('uid', { | ||
header: 'Id', | ||
cell: (props) => ( | ||
<CopyText className="max-w-[7rem]">{props.getValue()}</CopyText> | ||
), | ||
}), | ||
columnHelper.accessor('displayName', { | ||
header: 'Name', | ||
cell: (props) => props.getValue() ?? '-', | ||
}), | ||
columnHelper.accessor('email', { header: 'Email' }), | ||
columnHelper.accessor('role', { header: 'Role' }), | ||
columnHelper.display({ | ||
id: 'actions', | ||
cell: () => ( | ||
// TODO: Actions | ||
<RowDropdownMenu> | ||
<DropdownMenuItem> | ||
<Pencil /> | ||
Edit | ||
</DropdownMenuItem> | ||
<DropdownMenuItem> | ||
<Trash /> | ||
Delete | ||
</DropdownMenuItem> | ||
</RowDropdownMenu> | ||
), | ||
}), | ||
] | ||
|
||
interface UsersDataTableProps { | ||
data: User[] | ||
} | ||
|
||
export const UsersTable = ({ data }: UsersDataTableProps) => ( | ||
<DataTable columns={columns} data={data} entityName="users" /> | ||
) |
Oops, something went wrong.