// SPDX-FileCopyrightText: 2026 Progmasoft // SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 "use client"; import { type FormEvent, useId, useState } from "react"; import { localReturnUrl } from "@/lib/credentials"; import { getCredentialsMessages } from "@/lib/credentials-messages"; import { getMessages, type Locale } from "@/lib/localization"; interface SignInFormProps { locale: Locale; returnUrl: string; } /** * Signs in to Progmasoft OAuth. The cookie belongs to the OAuth host only; the * account holder then goes back to the authorization request that sent them. */ export function SignInForm({ locale, returnUrl }: SignInFormProps) { const { signIn, common } = getCredentialsMessages(locale); const { auth } = getMessages(locale); const formId = useId(); const [pending, setPending] = useState(false); const [message, setMessage] = useState(null); const [showPassword, setShowPassword] = useState(false); async function submit(event: FormEvent) { event.preventDefault(); setMessage(null); setPending(true); const form = new FormData(event.currentTarget); const response = await fetch("/api/v1/oauth/signin", { method: "POST", credentials: "same-origin", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: String(form.get("email") ?? ""), password: String(form.get("password") ?? ""), }), }).catch(() => null); if (response?.ok) { // A full navigation, so that /connect/authorize on the API receives the new cookie. window.location.assign(localReturnUrl(returnUrl)); return; } setPending(false); if (response?.status === 401) { // One message for every refusal: it does not tell registered addresses apart. setMessage(signIn.failed); } else { setMessage(common.unreachable); } } return (

{signIn.title}

{message && ( )}

{signIn.noAccount}{" "} {signIn.createAccount}

); }