Files
template-app/apps/web/app/settings/account/page.tsx
T

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>
)
}