Files
teatea-pension/modules/settings/components/GlobalSettingsClient.tsx

159 lines
6.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { FormEvent, useState } from "react";
import { Globe2, Save, ShieldCheck } 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 { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import type { ApiResult } from "@/modules/core/server/api";
import type { SystemSettings } from "@/modules/core/types";
type GlobalSettingsClientProps = {
settings: SystemSettings;
};
export function GlobalSettingsClient({ settings }: GlobalSettingsClientProps): React.ReactElement {
const router = useRouter();
const [message, setMessage] = useState("");
const [isPending, setIsPending] = useState(false);
async function handleSubmit(event: FormEvent<HTMLFormElement>): Promise<void> {
event.preventDefault();
setMessage("");
setIsPending(true);
const formData = new FormData(event.currentTarget);
const response = await fetch("/api/settings/global", {
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") ?? ""),
oidcAvatarClaim: String(formData.get("oidcAvatarClaim") ?? ""),
oidcAutoProvision: formData.get("oidcAutoProvision") === "on",
}),
});
const result = (await response.json()) as ApiResult<{ settings: SystemSettings }>;
setIsPending(false);
if (!result.success) {
setMessage(result.reason);
return;
}
setMessage(result.reason);
router.refresh();
}
return (
<form className="grid gap-5 xl:grid-cols-[0.9fr_1.1fr]" onSubmit={handleSubmit}>
<Card>
<CardHeader>
<div className="flex items-center gap-2">
<Globe2 className="size-5 text-primary" aria-hidden="true" />
<CardTitle></CardTitle>
</div>
<CardDescription> OIDC </CardDescription>
</CardHeader>
<CardContent className="grid gap-4">
<label className="flex items-center justify-between gap-4 rounded-md border p-3 text-sm">
<span>
<span className="block font-medium"></span>
<span className="block text-xs text-muted-foreground">使</span>
</span>
<Checkbox aria-label="开放公开注册" defaultChecked={settings.registrationEnabled} name="registrationEnabled" />
</label>
<label className="flex items-center justify-between gap-4 rounded-md border p-3 text-sm">
<span>
<span className="block font-medium"> OIDC </span>
<span className="block text-xs text-muted-foreground"> OIDC </span>
</span>
<Checkbox aria-label="启用 OIDC 登录" defaultChecked={settings.oidcEnabled} name="oidcEnabled" />
</label>
<label className="flex items-center justify-between gap-4 rounded-md border p-3 text-sm">
<span>
<span className="block font-medium">OIDC </span>
<span className="block text-xs text-muted-foreground"> OIDC </span>
</span>
<Checkbox aria-label="OIDC 自动开户" defaultChecked={settings.oidcAutoProvision} name="oidcAutoProvision" />
</label>
</CardContent>
</Card>
<Card>
<CardHeader>
<div className="flex items-center gap-2">
<ShieldCheck className="size-5 text-primary" aria-hidden="true" />
<CardTitle>OIDC </CardTitle>
</div>
<CardDescription> OIDC issuerclientscope claim</CardDescription>
</CardHeader>
<CardContent className="grid gap-4">
<div className="grid gap-3 md:grid-cols-2">
<label className="grid gap-2 text-sm">
<span className="font-medium">Issuer URL</span>
<Input defaultValue={settings.oidcIssuerUrl} name="oidcIssuerUrl" placeholder="https://idp.example.com" />
</label>
<label className="grid gap-2 text-sm">
<span className="font-medium">Client ID</span>
<Input defaultValue={settings.oidcClientId} name="oidcClientId" />
</label>
</div>
<label className="grid gap-2 text-sm">
<span className="font-medium">Client Secret</span>
<Input
name="oidcClientSecret"
placeholder={settings.oidcHasClientSecret ? "已配置,留空则不修改" : "未配置"}
type="password"
/>
</label>
<div className="grid gap-3 md:grid-cols-2">
<label className="grid gap-2 text-sm">
<span className="font-medium">Scopes</span>
<Input defaultValue={settings.oidcScopes} name="oidcScopes" placeholder="openid profile email" />
</label>
<label className="grid gap-2 text-sm">
<span className="font-medium">Redirect URI</span>
<Input defaultValue={settings.oidcRedirectUri} name="oidcRedirectUri" placeholder="/api/auth/oidc/callback" />
</label>
</div>
<label className="grid gap-2 text-sm">
<span className="font-medium">Avatar Claim</span>
<Input defaultValue={settings.oidcAvatarClaim} name="oidcAvatarClaim" placeholder="picture" />
</label>
{message ? (
<p className="rounded-md bg-secondary px-3 py-2 text-sm text-secondary-foreground" role="status">
{message}
</p>
) : null}
<div className="flex items-center justify-between gap-3 border-t pt-4">
<Badge variant={settings.oidcEnabled ? "success" : "secondary"}>
{settings.oidcEnabled ? "OIDC 已启用" : "OIDC 未启用"}
</Badge>
<Button disabled={isPending} type="submit">
<Save className="size-4" aria-hidden="true" />
</Button>
</div>
</CardContent>
</Card>
</form>
);
}