119 lines
3.7 KiB
TypeScript
119 lines
3.7 KiB
TypeScript
import { AppShell } from "@/components/app-shell"
|
|
import { SiteHeader } from "@/components/site-header"
|
|
import { prisma } from "@/lib/prisma"
|
|
import { DEFAULT_TENANT_ID } from "@/lib/constants"
|
|
import { requireStaffSession } from "@/lib/auth-server"
|
|
import { AdminUsersWorkspace, type AdminAccount } from "@/components/admin/users/admin-users-workspace"
|
|
import { fetchCompaniesByTenant, normalizeCompany } from "@/server/company-service"
|
|
|
|
export const runtime = "nodejs"
|
|
export const dynamic = "force-dynamic"
|
|
|
|
export default async function AdminUsersPage({
|
|
searchParams,
|
|
}: { searchParams: Promise<Record<string, string | string[] | undefined>> }) {
|
|
const session = await requireStaffSession()
|
|
const tenantId = session.user.tenantId ?? DEFAULT_TENANT_ID
|
|
const params = await searchParams
|
|
const autoOpenCreateUser = params.quick === "new-user"
|
|
|
|
const users = await prisma.user.findMany({
|
|
where: {
|
|
tenantId,
|
|
role: { in: ["MANAGER", "COLLABORATOR"] },
|
|
},
|
|
include: {
|
|
company: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
},
|
|
},
|
|
manager: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
email: true,
|
|
},
|
|
},
|
|
},
|
|
orderBy: { createdAt: "desc" },
|
|
})
|
|
|
|
const emails = users.map((user: (typeof users)[number]) => user.email)
|
|
const authUsers = await prisma.authUser.findMany({
|
|
where: { email: { in: emails } },
|
|
select: { id: true, email: true, updatedAt: true, createdAt: true },
|
|
})
|
|
|
|
const sessions = await prisma.authSession.findMany({
|
|
where: {
|
|
userId: {
|
|
in: authUsers.map((auth: (typeof authUsers)[number]) => auth.id),
|
|
},
|
|
},
|
|
orderBy: { updatedAt: "desc" },
|
|
select: { userId: true, updatedAt: true },
|
|
})
|
|
|
|
const sessionByUserId = new Map<string, Date>()
|
|
for (const sessionRow of sessions) {
|
|
if (!sessionByUserId.has(sessionRow.userId)) {
|
|
sessionByUserId.set(sessionRow.userId, sessionRow.updatedAt)
|
|
}
|
|
}
|
|
|
|
const authByEmail = new Map<string, { id: string; updatedAt: Date; createdAt: Date }>()
|
|
for (const authUser of authUsers) {
|
|
authByEmail.set(authUser.email.toLowerCase(), {
|
|
id: authUser.id,
|
|
updatedAt: authUser.updatedAt,
|
|
createdAt: authUser.createdAt,
|
|
})
|
|
}
|
|
|
|
const accounts: AdminAccount[] = users.map((user: (typeof users)[number]) => {
|
|
const auth = authByEmail.get(user.email.toLowerCase())
|
|
const lastSeenAt = auth ? sessionByUserId.get(auth.id) ?? auth.updatedAt : null
|
|
return {
|
|
id: user.id,
|
|
email: user.email,
|
|
name: user.name ?? user.email,
|
|
role: user.role === "MANAGER" ? "MANAGER" : "COLLABORATOR",
|
|
companyId: user.companyId ?? null,
|
|
companyName: user.company?.name ?? null,
|
|
jobTitle: user.jobTitle ?? null,
|
|
managerId: user.managerId ?? null,
|
|
managerName: user.manager?.name ?? null,
|
|
managerEmail: user.manager?.email ?? null,
|
|
tenantId: user.tenantId,
|
|
createdAt: user.createdAt.toISOString(),
|
|
updatedAt: user.updatedAt.toISOString(),
|
|
authUserId: auth?.id ?? null,
|
|
lastSeenAt: lastSeenAt ? lastSeenAt.toISOString() : null,
|
|
}
|
|
})
|
|
|
|
const companiesRaw = await fetchCompaniesByTenant(tenantId)
|
|
const companies = companiesRaw.map(normalizeCompany)
|
|
|
|
return (
|
|
<AppShell
|
|
header={
|
|
<SiteHeader
|
|
title="Usuários"
|
|
lead="Gerencie acessos de gestores/colaboradores e mantenha contatos, unidades e contratos atualizados."
|
|
/>
|
|
}
|
|
>
|
|
<div className="mx-auto w-full max-w-7xl px-4 pb-12 lg:px-8">
|
|
<AdminUsersWorkspace
|
|
initialAccounts={accounts}
|
|
companies={companies}
|
|
tenantId={tenantId}
|
|
autoOpenCreate={autoOpenCreateUser}
|
|
/>
|
|
</div>
|
|
</AppShell>
|
|
)
|
|
}
|