User Preferences
This document describes how user preferences (theme, locale, timezone) are read and
written across the frontend apps, using the shared auth bundle. It replaces the
information originally shared ad-hoc in
phpreaction-frontend-account-crud-react-v2#6 ,
verified and updated against the actual implementation in phpreaction-frontend-account-react.
Overview
user_preferences is part of the User object returned by
getUserInformations() (@phpcreation/frontend-auth-authorization-flow-react-nextjs-bundle).
Any app that renders a UserProvider with that user gets read access to preferences
through useUser(), anywhere in the component tree. Writing preferences goes through
the Account API and is only implemented in the account app today.
Reading preferences
1. Fetch the user server-side (layout)
import { getUserInformations } from "@phpcreation/frontend-auth-authorization-flow-react-nextjs-bundle/utils";
const user = await getUserInformations(
tenant?.name || "demo1",
true, // getGravatar
undefined, // idToken — auto-read from the id_token cookie server-side
undefined, // userToken — auto-read from the currentUser cookie server-side
true, // getFromCache
);2. Wrap the app with UserProvider
import { UserProvider } from "@phpcreation/frontend-auth-authorization-flow-react-nextjs-bundle/contexts";
<UserProvider user={user}>{children}</UserProvider>;3. Read user_preferences anywhere with useUser()
import { useUser } from "@phpcreation/frontend-auth-authorization-flow-react-nextjs-bundle/contexts";
const { user } = useUser();
user?.user_preferences?.theme; // "light" | "dark" | "system"
user?.user_preferences?.locale; // "fr" | "en"
user?.user_preferences?.timezone; // e.g. "America/New_York"user_preferences can be empty/undefined for a given key — always provide a fallback
(theme defaults to "system", locale to "fr", timezone to the browser’s guessed
timezone).
Real usage in phpreaction-frontend-account-react
| Where | What it reads |
|---|---|
src/app/[locale]/layout.tsx | user_preferences.theme — passed as ThemeProvider’s defaultTheme |
src/components/LayoutClient/index.tsx | user_preferences.locale / .timezone — passed to the Footer |
src/hooks/usePreferences.tsx | all three, as the form’s defaultValues |
Writing preferences
Only the account app currently exposes a form to update preferences
(/[locale]/preferences). Other apps should read via useUser() but should not
attempt to write preferences themselves — send users to the account app’s preferences
page instead.
Form → hook → server action → API
// src/hooks/usePreferences.tsx
const handleSubmit = async (data) => {
const newData = {
preferences: {
theme: data.theme,
locale: data.locale,
timezone: data.timezone,
},
};
const preferences = await editUserPreferences(tenant, newData);
if (preferences.ok) {
setTheme(data.theme);
await getNewUser(tenant, true); // refresh the UserProvider's context
router.replace(`/${data.locale}`);
}
};// src/app/[locale]/preferences/actions.ts
export async function editUserPreferences(tenant, body) {
await checkRequireAuth();
return callAccountApi(
"PATCH",
tenant,
"users/preferences/update",
"",
JSON.stringify(body),
true,
);
}The endpoint is PATCH /api/v1/users/preferences/update. An earlier version of
this documentation (and of the API Calls page) referenced
PATCH /api/v1/users/{id}/preferences, which does not match the current
implementation — that reference has been corrected.
After a successful save, getNewUser(tenant, true) is called to force-refresh the
UserProvider context so the rest of the app immediately reflects the new
preferences (no full reload needed), then the user is redirected to the new locale’s
URL.
Related
- Form:
src/containers/Preferences/index.tsx - Hook:
src/hooks/usePreferences.tsx - Server action:
src/app/[locale]/preferences/actions.ts - API reference: API Calls
- Source discussion: phpreaction-frontend-account-crud-react-v2#6