80 lines
3.3 KiB
TypeScript
80 lines
3.3 KiB
TypeScript
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
|
// The sign-in page (spec §7): where a visitor lands when they need to be signed in, and where a
|
|
// failed sign-in ends (src/server/auth-response.ts). It says what went wrong in the person's
|
|
// language -- from a fixed set of codes, never from the provider's text -- and offers the way in the
|
|
// deployment has: its identity provider, or, in development with none, any e-mail address.
|
|
|
|
import { loadAuthConfig } from "@conusai-kit/auth"
|
|
import { redirect } from "next/navigation"
|
|
import type { ReactElement } from "react"
|
|
import { AUTH_ERROR_MESSAGES, parseAuthError, safeReturnTo } from "../../../src/server/auth-errors"
|
|
import { betterAuthFormLabels, MIN_PASSWORD_LENGTH } from "../../../src/server/better-auth" // kit:convex-better-auth
|
|
import { pageContext } from "../../../src/server/page"
|
|
import { BetterAuthForm } from "../../../src/ui/better-auth-form" // kit:convex-better-auth
|
|
import { StateView } from "../../../src/ui/state-view"
|
|
|
|
export const dynamic = "force-dynamic"
|
|
|
|
export default async function SignIn({
|
|
searchParams,
|
|
}: {
|
|
searchParams: Promise<{ error?: string; return_to?: string }>
|
|
}): Promise<ReactElement> {
|
|
const { error, return_to: returnToParam } = await searchParams
|
|
const { i18n, signedIn } = await pageContext()
|
|
const returnTo = safeReturnTo(returnToParam)
|
|
// Somebody who is already in has nothing to do here, unless they were sent back with an error.
|
|
const code = parseAuthError(error)
|
|
if (signedIn && !code) redirect(returnTo)
|
|
|
|
const config = loadAuthConfig()
|
|
const next = returnTo === "/" ? "" : `?return_to=${encodeURIComponent(returnTo)}`
|
|
const betterAuth = config.provider === "convex-better-auth" // kit:convex-better-auth
|
|
return (
|
|
<StateView title={i18n.message("signin.title")}>
|
|
{code ? (
|
|
<p className="app-error" role="alert">
|
|
{i18n.message(AUTH_ERROR_MESSAGES[code])}
|
|
</p>
|
|
) : (
|
|
<p>{i18n.message("signin.intro")}</p>
|
|
)}
|
|
{config.oidc ? (
|
|
<p>
|
|
<a href={`/auth/sign-in/start${next}`}>{i18n.message("signin.continue")}</a>
|
|
</p>
|
|
) : null}
|
|
{!config.oidc && config.devLogin ? (
|
|
<form method="get" action="/auth/dev-login">
|
|
<h2>{i18n.message("signin.devTitle")}</h2>
|
|
<p>{i18n.message("signin.devHelp")}</p>
|
|
{returnTo === "/" ? null : <input type="hidden" name="return_to" value={returnTo} />}
|
|
<label className="kit-field" htmlFor="dev-email">
|
|
{i18n.message("app.email")}
|
|
<input id="dev-email" name="email" type="email" required autoComplete="email" />
|
|
</label>
|
|
<button type="submit">{i18n.message("signin.devSubmit")}</button>
|
|
</form>
|
|
) : null}
|
|
{/* kit:convex-better-auth:begin */}
|
|
{betterAuth ? (
|
|
<>
|
|
<BetterAuthForm
|
|
mode="sign-in"
|
|
returnTo={returnTo}
|
|
minPasswordLength={MIN_PASSWORD_LENGTH}
|
|
labels={betterAuthFormLabels(i18n, "sign-in")}
|
|
/>
|
|
<p>
|
|
<a href={`/auth/sign-up${next}`}>{i18n.message("signin.account.toSignUp")}</a>
|
|
</p>
|
|
</>
|
|
) : null}
|
|
{/* kit:convex-better-auth:end */}
|
|
{!config.oidc && !config.devLogin && config.provider === "oidc" ? (
|
|
<p role="status">{i18n.message("signin.notConfigured")}</p>
|
|
) : null}
|
|
</StateView>
|
|
)
|
|
}
|