diff --git a/app/(dashboard)/users/[id]/EditUserForm.tsx b/app/(dashboard)/users/[id]/EditUserForm.tsx
new file mode 100644
index 00000000..31aa12ae
--- /dev/null
+++ b/app/(dashboard)/users/[id]/EditUserForm.tsx
@@ -0,0 +1,123 @@
+'use client'
+import { Role } from '@/modules/firebase/role'
+import { Button } from '@/packages/design-system/src/components/Button'
+import { Input } from '@/packages/design-system/src/components/Input'
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/packages/design-system/src/components/Select'
+import type { Data } from './page'
+import { useUser } from '@/modules/firebase/UserProvider'
+import { Field } from '@/packages/design-system/src/forms/Field'
+import { useForm } from '@/packages/design-system/src/forms/useForm'
+import { editUserFormSchema } from './utils'
+
+interface EditUserDialogFormProps {
+ data: Data
+}
+
+export const EditUserForm = ({ data }: EditUserDialogFormProps) => {
+ const authUser = useUser()
+ const form = useForm({
+ formSchema: editUserFormSchema,
+ defaultValues: {
+ email: data.authUser.email ?? '',
+ displayName: data.authUser.displayName ?? '',
+ role: data.role.role,
+ organizationId: data.user?.organization,
+ invitationCode: data.user?.invitationCode,
+ },
+ })
+
+ const handleSubmit = form.handleSubmit((data) => {
+ console.log(data)
+ })
+
+ return (
+
+ )
+}
diff --git a/app/(dashboard)/users/[id]/actions.tsx b/app/(dashboard)/users/[id]/actions.tsx
new file mode 100644
index 00000000..0e7753be
--- /dev/null
+++ b/app/(dashboard)/users/[id]/actions.tsx
@@ -0,0 +1,10 @@
+'use server'
+import { revalidatePath } from 'next/cache'
+import { type z } from 'zod'
+import { type editUserFormSchema } from '@/app/(dashboard)/users/[id]/utils'
+import { getAuthenticatedOnlyApp } from '@/modules/firebase/guards'
+import { routes } from '@/modules/routes'
+
+export const editUser = async (payload: z.infer) => {
+ const { callables } = await getAuthenticatedOnlyApp()
+}
diff --git a/app/(dashboard)/users/[id]/page.tsx b/app/(dashboard)/users/[id]/page.tsx
new file mode 100644
index 00000000..f10cda0d
--- /dev/null
+++ b/app/(dashboard)/users/[id]/page.tsx
@@ -0,0 +1,67 @@
+//
+// 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 { Users } from 'lucide-react'
+import { notFound } from 'next/navigation'
+import { EditUserForm } from './EditUserForm'
+import {
+ allowRoles,
+ getAuthenticatedOnlyApp,
+ getUserRole,
+} from '@/modules/firebase/guards'
+import { Role } from '@/modules/firebase/role'
+import { mapAuthData } from '@/modules/firebase/user'
+import { getDocData, getDocsData } from '@/modules/firebase/utils'
+import { getUserName } from '@/packages/design-system/src/modules/auth/user'
+import { PageTitle } from '@/packages/design-system/src/molecules/DashboardLayout'
+import { DashboardLayout } from '../../DashboardLayout'
+
+const getData = async (userId: string) => {
+ const { refs, docRefs } = await getAuthenticatedOnlyApp()
+ const organizations = await getDocsData(refs.organizations())
+ const user = await getDocData(docRefs.user(userId))
+ const allAuthData = await mapAuthData([userId], (data, id) => ({
+ id,
+ ...data,
+ }))
+ const authUser = allAuthData.at(0)
+
+ if (!authUser) {
+ notFound()
+ }
+ return {
+ user,
+ organizations,
+ authUser,
+ role: await getUserRole(userId),
+ }
+}
+
+export type Data = Awaited>
+
+const UserPage = async ({ params }: { params: { id: string } }) => {
+ await allowRoles([Role.admin, Role.owner])
+ const data = await getData(params.id)
+
+ return (
+ }
+ />
+ }
+ >
+
+
+
+
+ )
+}
+
+export default UserPage
diff --git a/app/(dashboard)/users/[id]/utils.ts b/app/(dashboard)/users/[id]/utils.ts
new file mode 100644
index 00000000..88ab6c50
--- /dev/null
+++ b/app/(dashboard)/users/[id]/utils.ts
@@ -0,0 +1,10 @@
+import { z } from 'zod'
+import { Role } from '@/modules/firebase/role'
+
+export const editUserFormSchema = z.object({
+ email: z.string().min(1, 'Email is required'),
+ displayName: z.string(),
+ invitationCode: z.string().optional(),
+ organizationId: z.string().optional(),
+ role: z.nativeEnum(Role),
+})