73 lines
3.2 KiB
TypeScript
73 lines
3.2 KiB
TypeScript
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
|
// The person's own account (joint contract §12): what the app keeps about them, the export of it, and
|
|
// the deletion of the account. The page is a user page, under `settings`, which is a reserved
|
|
// organization slug, so no organization's path can shadow it.
|
|
//
|
|
// The export and the deletion are the account module's procedures; this page only renders them, and
|
|
// the client host beside it ends the browser modules' context once a deletion answered. The analytics
|
|
// panel (ADR-049) erases or exports what the platform's own stores keep about the person's visits,
|
|
// through the account.analytics procedures: the deployment token stays on the server. With the fake
|
|
// platform its procedures answer "unavailable".
|
|
|
|
import { ACCOUNT_PATH, accountDeletionStatus } from "@app/modules/account/contract"
|
|
import { analyticsLabels, deletionLabels, exportLabels, pageLabels } from "@app/modules/account/ui"
|
|
import { loadAuthConfig } from "@conusai-kit/auth"
|
|
import { meGet } from "@conusai-kit/tenancy"
|
|
import { redirect } from "next/navigation"
|
|
import type { ReactElement } from "react"
|
|
import { orFallback, signInHref } from "../../../src/server/guard"
|
|
import { pageContext } from "../../../src/server/page"
|
|
import { AccountPanels } from "../../../src/ui/account"
|
|
|
|
export const dynamic = "force-dynamic"
|
|
|
|
/**
|
|
* Where a person signs in again to delete their account: straight to the provider (the sign-in page
|
|
* sends somebody already signed in away), or, in development, the dev login with their own address.
|
|
* Either opens a new session, whose sign-in is then recent.
|
|
*/
|
|
function reauthHref(email: string): string {
|
|
const back = `return_to=${encodeURIComponent(ACCOUNT_PATH)}`
|
|
const config = loadAuthConfig()
|
|
if (config.oidc) return `/auth/sign-in/start?${back}`
|
|
if (config.devLogin) return `/auth/dev-login?email=${encodeURIComponent(email)}&${back}`
|
|
return `/auth/sign-in?${back}`
|
|
}
|
|
|
|
export default async function AccountPage(): Promise<ReactElement> {
|
|
const { caller, i18n, signedIn, path } = await pageContext()
|
|
if (!signedIn) redirect(signInHref(path))
|
|
const t = (key: string, values?: Record<string, string | number>) => i18n.message(`account.${key}`, values)
|
|
const page = pageLabels(t)
|
|
const [me, status] = await orFallback(path, () =>
|
|
Promise.all([caller.call(meGet, undefined), caller.call(accountDeletionStatus, undefined)]),
|
|
)
|
|
const failed = i18n.message("app.failed")
|
|
return (
|
|
<main>
|
|
<h1>{page.title}</h1>
|
|
<p>{page.intro}</p>
|
|
<section aria-labelledby="account-profile">
|
|
<h2 id="account-profile">{page.profileHeading}</h2>
|
|
<dl>
|
|
<dt>{page.name}</dt>
|
|
<dd>{me.displayName}</dd>
|
|
<dt>{page.email}</dt>
|
|
<dd>{me.email}</dd>
|
|
</dl>
|
|
</section>
|
|
<AccountPanels
|
|
exportLabels={exportLabels(t, failed)}
|
|
analyticsLabels={analyticsLabels(t, failed)}
|
|
deletion={{
|
|
labels: deletionLabels(t, failed, status, me.email),
|
|
interactive: status.interactive,
|
|
recentSignIn: status.recentSignIn,
|
|
reauthHref: reauthHref(me.email),
|
|
deletion: status.deletion,
|
|
}}
|
|
/>
|
|
</main>
|
|
)
|
|
}
|