// SPDX-FileCopyrightText: 2026 Progmasoft // SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 "use client"; import { useEffect, useState } from "react"; import { callOAuthApi, oauthScopes, signInPath, type ConsentView, type OAuthScope, } from "@/lib/credentials"; import { format, getCredentialsMessages } from "@/lib/credentials-messages"; import type { Locale } from "@/lib/localization"; type ConsentState = | { kind: "loading" } | { kind: "invalid" } | { kind: "failed" } | { kind: "ready"; consent: ConsentView }; /** * The consent page. `/connect/authorize` sends the account holder here with * the parameters of the request; the decision is posted back there as a plain * form, so the browser follows the redirection to the application. */ export function ConsentPanel({ locale, parameters, }: { locale: Locale; parameters: [string, string][]; }) { const { consent: text, scopes, common } = getCredentialsMessages(locale); const [state, setState] = useState({ kind: "loading" }); const query = new URLSearchParams(parameters).toString(); useEffect(() => { const controller = new AbortController(); void callOAuthApi(`/consent?${query}`, { signal: controller.signal, }).then((result) => { if (result.kind === "signedOut") { window.location.replace(signInPath(`/connect/authorize?${query}`)); } else if (result.kind === "ok") { setState({ kind: "ready", consent: result.value }); } else { setState({ kind: result.kind === "refused" ? "invalid" : "failed" }); } }); return () => controller.abort(); }, [query]); if (state.kind === "loading") { return

{common.loading}

; } if (state.kind !== "ready") { return (
{state.kind === "invalid" ? text.invalid : common.unreachable}
); } const { consent } = state; const granted = consent.scopes.filter((scope): scope is OAuthScope => oauthScopes.includes(scope as OAuthScope), ); return (
{parameters.map(([name, value], index) => ( ))}

{format(text.title, { name: consent.displayName })}

{consent.homepage ? ( {consent.homepage} ) : ( {consent.clientId} )} {consent.owner && ( <> ยท {format(text.registeredBy, { owner: consent.owner })} )}

{format(text.wants, { name: consent.displayName })}

  • {scopes.account}
  • {granted.map((scope) => (
  • {scopes[scope]}
  • ))}

{format(text.returnTo, { origin: consent.returnTo })}{" "} {format(text.signedInAs, { name: consent.accountName })}{" "} {text.withdrawLater}

); }