// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0 // Members, their roles and the organization's open invitations (spec ยง3.2). Every change is a // procedure call: the role scale, the "nobody grants a role above their own" rule and the last // owner's protection are kit-tenancy's, not this page's. What this page decides is only who is shown // the controls: administrators, who hold `tenancy.member.invite` and `tenancy.member.manage`. import { invitationList, memberList, ORG_ROLES } from "@conusai-kit/tenancy" import type { ReactElement } from "react" import { orFallback } from "../../../src/server/guard" import { holdsAtLeast, pageContext } from "../../../src/server/page" import { InviteMember } from "../../../src/ui/invite-member" import { ProcedureForm } from "../../../src/ui/procedure-form" export const dynamic = "force-dynamic" export default async function Members({ params }: { params: Promise<{ org: string }> }): Promise { const { org } = await params const page = await pageContext() const { caller, i18n, path } = page const { members } = await orFallback(path, () => caller.call(memberList, { org })) const administers = await holdsAtLeast(page, org, "admin") const { invitations } = administers ? await orFallback(path, () => caller.call(invitationList, { org })) : { invitations: [] } const roleLabel = (role: string): string => i18n.message(`roles.${role}`) const roleOptions = ORG_ROLES.map((role) => ({ value: role, label: roleLabel(role) })) return ( <>

{i18n.message("app.members")}

{i18n.message("app.memberCount", { count: members.length })}

{members.map((member) => ( ))}
{i18n.message("app.name")} {i18n.message("app.email")} {i18n.message("app.role")}
{member.displayName} {member.email} {roleLabel(member.role)}
{administers ? ( <>

{i18n.message("app.invite")}

{i18n.message("members.openInvitations")}

{invitations.length === 0 ? (

{i18n.message("members.noInvitations")}

) : ( {invitations.map((invitation) => ( ))}
{i18n.message("app.email")} {i18n.message("app.role")} {i18n.message("members.invitedBy")} {i18n.message("members.expires")}
{invitation.email} {roleLabel(invitation.role)} {invitation.inviter.displayName} {i18n.date(new Date(invitation.expiresAt))}
)}

{i18n.message("members.changeRole")}