"use client"; import { FormEvent, useState } from "react"; import { Copy, LinkIcon, Save, Send } from "lucide-react"; import { useRouter } from "next/navigation"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import type { ApiResult } from "@/modules/core/server/api"; import type { Organization, OrganizationInvitation, RoleDefinition } from "@/modules/core/types"; type OrganizationDetailClientProps = { invitations: OrganizationInvitation[]; organization: Organization; roles: RoleDefinition[]; }; function getInviteHref(token: string): string { return `/register?invite=${encodeURIComponent(token)}`; } export function OrganizationDetailClient({ invitations, organization, roles, }: OrganizationDetailClientProps): React.ReactElement { const router = useRouter(); const [settingsMessage, setSettingsMessage] = useState(""); const [inviteMessage, setInviteMessage] = useState(""); const [isPending, setIsPending] = useState(false); const organizationRoles = roles.filter((role) => role.scope === "organization" && role.organizationId === organization.id && role.isEnabled); const defaultRoleId = organizationRoles.find((role) => role.key === "caregiver")?.id ?? organizationRoles[0]?.id ?? ""; async function handleSettingsSubmit(event: FormEvent): Promise { event.preventDefault(); setSettingsMessage(""); setIsPending(true); const formData = new FormData(event.currentTarget); const response = await fetch(`/api/organizations/${organization.id}`, { method: "PATCH", headers: { "content-type": "application/json" }, body: JSON.stringify({ registrationEnabled: formData.get("registrationEnabled") === "on", oidcEnabled: formData.get("oidcEnabled") === "on", oidcIssuerUrl: String(formData.get("oidcIssuerUrl") ?? ""), oidcClientId: String(formData.get("oidcClientId") ?? ""), oidcClientSecret: String(formData.get("oidcClientSecret") ?? ""), oidcScopes: String(formData.get("oidcScopes") ?? ""), oidcRedirectUri: String(formData.get("oidcRedirectUri") ?? ""), oidcAutoProvision: formData.get("oidcAutoProvision") === "on", }), }); const result = (await response.json()) as ApiResult<{ organization: Organization }>; setIsPending(false); if (!result.success) { setSettingsMessage(result.reason); return; } setSettingsMessage(result.reason); router.refresh(); } async function handleInviteSubmit(event: FormEvent): Promise { event.preventDefault(); setInviteMessage(""); setIsPending(true); const formData = new FormData(event.currentTarget); const response = await fetch(`/api/organizations/${organization.id}/invitations`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ email: String(formData.get("email") ?? ""), roleId: String(formData.get("roleId") ?? ""), }), }); const result = (await response.json()) as ApiResult<{ invitation: OrganizationInvitation }>; setIsPending(false); if (!result.success) { setInviteMessage(result.reason); return; } setInviteMessage(`${result.reason}:${getInviteHref(result.invitation.token)}`); event.currentTarget.reset(); router.refresh(); } return (
机构访问配置 控制公开注册、OIDC 登录入口和自动开户策略。
{settingsMessage ? (

{settingsMessage}

) : null}
机构邀请 生成邀请链接后发送给成员;可限定邮箱,也可生成通用邀请。
{inviteMessage ? (

{inviteMessage}

) : null}
{invitations.map((invitation) => ( ))} {invitations.length === 0 ? ( ) : null}
对象 角色 状态 有效期 链接
{invitation.email || "通用邀请"} {invitation.roleLabel} {invitation.status} {new Date(invitation.expiresAt).toLocaleString("zh-CN")}
暂无邀请
); }