fix: require explicit business form choices

This commit is contained in:
2026-07-02 18:59:42 -07:00
parent 12c3ca560c
commit 6efe3a6615
3 changed files with 165 additions and 121 deletions

View File

@@ -24,10 +24,6 @@ function getOrganizationRoles(roles: RoleDefinition[], organizationId: string):
return roles.filter((role) => role.scope === "organization" && role.organizationId === organizationId && role.isEnabled);
}
function getDefaultOrganizationId(organizations: Organization[]): string {
return organizations[0]?.id ?? "";
}
export function UserManagementClient({
canManageAccounts = false,
organizations,
@@ -36,7 +32,7 @@ export function UserManagementClient({
}: UserManagementClientProps): React.ReactElement {
const router = useRouter();
const [isCreateOpen, setIsCreateOpen] = useState(false);
const [selectedOrganizationId, setSelectedOrganizationId] = useState(() => getDefaultOrganizationId(organizations));
const [selectedOrganizationId, setSelectedOrganizationId] = useState("");
const [reviewRoleByRequestId, setReviewRoleByRequestId] = useState<Record<string, string>>({});
const [message, setMessage] = useState("");
const [isPending, setIsPending] = useState(false);
@@ -68,15 +64,22 @@ export function UserManagementClient({
}
setMessage("");
setIsPending(true);
const formData = new FormData(event.currentTarget);
const organizationId = String(formData.get("organizationId") ?? "");
const roleId = String(formData.get("roleId") ?? "");
if (!organizationId || !roleId) {
setMessage("请选择机构和角色");
return;
}
setIsPending(true);
const response = await fetch("/api/settings/accounts", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
organizationId: String(formData.get("organizationId") ?? ""),
roleId: String(formData.get("roleId") ?? ""),
organizationId,
roleId,
name: String(formData.get("name") ?? ""),
email: String(formData.get("email") ?? ""),
avatarUrl: String(formData.get("avatarUrl") ?? ""),
@@ -170,8 +173,7 @@ export function UserManagementClient({
<CardContent className="space-y-3">
{pendingJoinRequests.map((request) => {
const requestRoles = getOrganizationRoles(roles, request.organizationId);
const defaultRoleId = requestRoles.find((role) => role.key === "caregiver")?.id ?? requestRoles[0]?.id ?? "";
const selectedRoleId = reviewRoleByRequestId[request.id] ?? defaultRoleId;
const selectedRoleId = reviewRoleByRequestId[request.id] ?? "";
return (
<div key={request.id} className="rounded-md border p-3">
@@ -190,7 +192,10 @@ export function UserManagementClient({
onValueChange={(roleId) =>
setReviewRoleByRequestId((current) => ({ ...current, [request.id]: roleId }))
}
options={requestRoles.map((role) => ({ value: role.id, label: role.label }))}
options={[
{ value: "", label: "选择审批角色", disabled: true },
...requestRoles.map((role) => ({ value: role.id, label: role.label })),
]}
value={selectedRoleId}
/>
<Button
@@ -233,7 +238,11 @@ export function UserManagementClient({
aria-label="机构"
name="organizationId"
onValueChange={setSelectedOrganizationId}
options={organizations.map((organization) => ({ value: organization.id, label: organization.name }))}
options={[
{ value: "", label: "选择机构", disabled: true },
...organizations.map((organization) => ({ value: organization.id, label: organization.name })),
]}
required
value={selectedOrganizationId}
/>
</label>
@@ -242,11 +251,14 @@ export function UserManagementClient({
<span className="font-medium"></span>
<Select
aria-label="角色"
defaultValue={organizationRoles[0]?.id ?? ""}
defaultValue=""
disabled={organizationRoles.length === 0}
key={selectedOrganizationId}
name="roleId"
options={organizationRoles.map((role) => ({ value: role.id, label: role.label }))}
options={[
{ value: "", label: selectedOrganizationId ? "选择角色" : "先选择机构", disabled: true },
...organizationRoles.map((role) => ({ value: role.id, label: role.label })),
]}
required
/>
</label>
@@ -303,17 +315,14 @@ export function UserAccountActions({
}: UserAccountActionsProps): React.ReactElement {
const router = useRouter();
const [isEditOpen, setIsEditOpen] = useState(false);
const [selectedOrganizationId, setSelectedOrganizationId] = useState(
() => account.organizationId ?? getDefaultOrganizationId(organizations),
);
const [selectedOrganizationId, setSelectedOrganizationId] = useState(() => account.organizationId ?? "");
const [message, setMessage] = useState("");
const [isPending, setIsPending] = useState(false);
const organizationRoles = useMemo(
() => getOrganizationRoles(roles, selectedOrganizationId),
[roles, selectedOrganizationId],
);
const defaultRoleId =
organizationRoles.find((role) => role.key === account.role || role.id === account.role)?.id ?? organizationRoles[0]?.id ?? "";
const defaultRoleId = organizationRoles.find((role) => role.key === account.role || role.id === account.role)?.id ?? "";
const isCurrentAccount = account.id === currentAccountId;
async function updateAccount(payload: Record<string, string>): Promise<void> {
@@ -430,7 +439,10 @@ export function UserAccountActions({
aria-label="账号机构"
name="organizationId"
onValueChange={setSelectedOrganizationId}
options={organizations.map((organization) => ({ value: organization.id, label: organization.name }))}
options={[
{ value: "", label: "选择机构", disabled: true },
...organizations.map((organization) => ({ value: organization.id, label: organization.name })),
]}
value={selectedOrganizationId}
/>
</label>
@@ -442,7 +454,10 @@ export function UserAccountActions({
disabled={organizationRoles.length === 0}
key={selectedOrganizationId}
name="roleId"
options={organizationRoles.map((role) => ({ value: role.id, label: role.label }))}
options={[
{ value: "", label: selectedOrganizationId ? "选择角色" : "先选择机构", disabled: true },
...organizationRoles.map((role) => ({ value: role.id, label: role.label })),
]}
/>
</label>
</div>