- src/i18n/server.ts: createI18nConfig factory consolidating the locale resolution chain (cookie → access_token preferred_language claim → Accept-Language → default). Reusable across apps; previously each frontend reimplemented it. - AdminShell: thread signoutPath + myProfileUrl (default https://my.gosec.internal/profile) into the navbar; render My Profile link alongside logout. - LogoutButton: replace two-step fetch+signOut+redirect with a plain anchor pointing at signoutPath — the NextAuth POST-only signout endpoint plus form-CSRF flow doesn't need client JS. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
46 lines
1.1 KiB
TypeScript
46 lines
1.1 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* Default flow: a plain anchor to `/api/auth/signout` (overridable via
|
|
* the `signoutPath` prop). The route handler runs RP-initiated logout
|
|
* in a single redirect — kills the NextAuth cookie, ends the Keycloak
|
|
* SSO session, lands on the app's signed-out page.
|
|
*
|
|
* Apps with a different shape (no `/api/auth/signout`, need to fire
|
|
* custom telemetry, etc.) pass `onSignOut` to replace the navigation
|
|
* with a button + custom handler.
|
|
*/
|
|
type LogoutButtonProps = {
|
|
label: string;
|
|
signoutPath?: string;
|
|
onSignOut?: () => void | Promise<void>;
|
|
};
|
|
|
|
export function LogoutButton({
|
|
label,
|
|
signoutPath = "/api/auth/signout",
|
|
onSignOut,
|
|
}: LogoutButtonProps) {
|
|
if (onSignOut) {
|
|
return (
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
void onSignOut();
|
|
}}
|
|
className="dropdown-item"
|
|
>
|
|
<i className="ph-sign-out me-2"></i>
|
|
{label}
|
|
</button>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<a href={signoutPath} className="dropdown-item">
|
|
<i className="ph-sign-out me-2"></i>
|
|
{label}
|
|
</a>
|
|
);
|
|
}
|