Owner: Engineering Team | Last Updated: 2026-01-30 | Status: Current
The Settings page provides users with centralized control over their profile, security, subscription, usage tracking, referrals, and account lifecycle. It is rendered by the SettingsLayout component, which orchestrates all settings sections with Framer Motion animations and applies conditional display logic based on user state.
Route: /[locale]/settings (inside the (dashboard) route group)
Main component: SettingsLayout.tsx
Component exports (from the settings index file):
export { SettingsLayout } from './SettingsLayout'
export { Subscription } from './Subscription'
export { Usage } from './Usage'
export { ReferralProgram } from './ReferralProgram'
export { PersonalInformation } from './PersonalInformation'
export { Security } from './Security'
export { ProfilePhoto } from './ProfilePhoto'
The SettingsLayout component renders the following sections in order. Each section is a standalone component located in components/partials/settings/.
Component: PersonalInformation.tsx
Allows users to update their first name and last name.
| Detail | Value |
|---|---|
| Form library | Formik |
| HTTP method | PATCH via axios.patch |
| Endpoint | /api/user/account/ |
| Fields | First name, Last name |
The form submits a PATCH request to update only the changed name fields on the user profile.
Component: ProfilePhoto.tsx
Handles avatar upload and removal.
| Detail | Value |
|---|---|
| Max file size | 5 MB |
| Allowed file types | jpeg, png, webp, gif |
| Upload format | FormData (multipart) |
| Endpoint | PATCH /api/user/account/ |
The component constructs a FormData payload for multipart file upload to the backend. Users can also remove their existing avatar.
Validation rules:
Component: Security.tsx
Provides password change functionality for users who authenticate with email and password.
| Detail | Value |
|---|---|
| Visibility condition | session.user.has_password must be true |
| Validation library | Yup |
| Password strength | Visual progress bar indicator |
Conditional display: This section is hidden for users who signed up exclusively via Google or Facebook OAuth (i.e., accounts where has_password is false). Only users with an email/password credential see the password change form.
The form includes a password strength indicator rendered as a progress bar that updates in real time as the user types a new password.
Two-factor authentication is available for email/password accounts only.
| Detail | Value |
|---|---|
| Type | TOTP (Time-based One-Time Password) |
| State indicator | session.user.totp (boolean) |
| Setup flow | QR code generation followed by verification code entry |
Flow:
session.user.totp is set to true upon successful verification.Users who authenticated exclusively via social providers (Google/Facebook) without a password do not have access to this feature.
Component directory: change-email/ (subdirectory within settings components)
Implements a multi-step email change flow.
| Detail | Value |
|---|---|
| Endpoint | POST /api/user/update-user-email/ |
| Flow type | Multi-step with email verification |
Flow:
The email is not updated until the new address is verified.
Component: Subscription.tsx
Displays the user's current subscription plan, word limits, and provides subscription management actions.
| Detail | Value |
|---|---|
| Billing portal endpoint | GET /api/user/billing-portal?update=&utm_source= |
| Auth | Authorization header required |
| Upgrade UI | UpgradeModal component |
Features:
UpgradeModal for plan upgrades.Component: Usage.tsx
Tracks and displays word usage with visual progress bars.
| Detail | Value |
|---|---|
| Visual | Progress bars for word consumption |
| Data shown | Words used, bonus words (from referrals), billing cycle dates |
Plan-specific UI:
Bonus words earned through the referral program are displayed separately.
Component: UsageLocked.tsx
An alternative usage display shown when the user's subscription has been downgraded.
| Detail | Value |
|---|---|
| Display condition | User subscription is in a downgraded state |
| Replaces | Usage component |
The SettingsLayout component conditionally renders either UsageLocked or Usage based on the user's downgrade status.
Component: ReferralProgram.tsx
Displays the user's referral link and earned referral rewards.
| Detail | Value |
|---|---|
| Feature | Copy-to-clipboard referral link sharing |
| Reward display | Earned words counter (e.g., "0 / 1,000") |
| Visibility condition | Hidden if referral program has expired |
Conditional display: The SettingsLayout checks whether the referral program has expired. If expired, this entire section is hidden from the settings page.
Component directory: account-deletion/ (subdirectory within settings components)
Implements a multi-step account deletion flow with a confirmation dialog.
Flow:
Component directory: pause-flow/ (subdirectory within settings components)
A complex pause/unpause subscription flow implemented as a multi-step wizard.
| Detail | Value |
|---|---|
| Steps | 10-step wizard |
| Actions | Pause subscription, Unpause subscription |
This flow guides users through a detailed process before pausing their subscription, likely including retention offers and confirmation steps across the 10 wizard steps.
The SettingsLayout component applies the following conditional rendering rules:
| Condition | Behavior |
|---|---|
| User subscription is downgraded | Renders UsageLocked instead of Usage |
| Referral program is expired | Hides the ReferralProgram section entirely |
User has no password (!session.user.has_password) |
Hides the Security (password change) section |
| Animation | All sections animate using Framer Motion |
| Endpoint | Method | Purpose |
|---|---|---|
/api/user/account/ |
GET |
Load user profile data |
/api/user/account/ |
PATCH |
Update profile fields (name, avatar) |
/api/user/update-user-email/ |
POST |
Initiate email change with verification |
/api/user/add-to-klaviyo/ |
POST |
Add user to Klaviyo marketing list |
/api/user/billing-portal |
GET |
Generate Stripe billing portal URL (query params: update, utm_source; requires auth header) |
/api/user/billing-portal-redirect/ |
GET |
Redirect user to Stripe billing portal |
SettingsLayout.tsx
├── PersonalInformation.tsx
├── ProfilePhoto.tsx
├── Security.tsx (hidden if no password)
├── change-email/ (subdirectory, multi-step)
├── Subscription.tsx
│ └── UpgradeModal
├── Usage.tsx (or UsageLocked.tsx if downgraded)
├── ReferralProgram.tsx (hidden if expired)
├── account-deletion/ (subdirectory, multi-step)
└── pause-flow/ (subdirectory, 10-step wizard)
| Library | Usage |
|---|---|
| Formik | Form state management for PersonalInformation |
| Yup | Schema validation for password change in Security |
| axios | HTTP requests (axios.patch for profile updates) |
| Framer Motion | Section entrance/exit animations in SettingsLayout |
| Stripe (via billing portal API) | Subscription management in Subscription |
| Date | Author | Change |
|---|---|---|
| 2026-01-30 | Admin | Comprehensive rewrite with full section documentation, API endpoints, conditional logic, and component architecture |
| 2026-01-30 | Admin | Initial creation |
Prev: Web App - Payments | Up: WalterWrites