Skip to content

feat: add profile settings page with display name and avatar preference - #196

Merged
ayoub3bidi merged 5 commits into
developfrom
feature/profile-settings
Jul 2, 2026
Merged

feat: add profile settings page with display name and avatar preference#196
ayoub3bidi merged 5 commits into
developfrom
feature/profile-settings

Conversation

@ayoub3bidi

@ayoub3bidi ayoub3bidi commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Contribution workflow

  • Base branch is develop: This PR targets develop, not main.
  • Guidelines and docs: I have read CONTRIBUTING.md and the docs relevant to my change (DEVELOPMENT.md, ARCHITECTURE.md as needed).
  • This template: I kept the PR template structure and filled in the sections below that apply to this change.

Description

Implements the private /settings/profile route introduced in the auth contracts for v0.5.0. Users can now update their display name and choose between their Google avatar or a generated DiceBear avatar. The page is protected behind RequireAuth and all writes are scoped by Supabase RLS — only display_name and avatar_preference are client-writable.

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🎨 Style/UI improvement
  • ⚡ Performance improvement
  • 🧪 Test addition or improvement
  • 🔧 Chore (maintenance, dependencies, etc.)

Related Issues

Fixes #

Changes Made

  • Add RequireAuth guard component — redirects unauthenticated users to /
  • Add ProfileSettingsPage with display name editing (trim + validation) and avatar preference toggle (google vs generated DiceBear)
  • Add tabbed settings layout (Profile active; Notifications, Connections as disabled placeholders) with max-w-4xl page width
  • Add updateProfile() to profileService and expose refreshProfile() from AuthContext so the UI can reload after save
  • Update resolveUserAvatar to respect avatar_preference and prefer saved display_name
  • Add /settings/profile route with RequireAuth in main.jsx
  • Add "Account settings" navigation item in UserMenu
  • Add Supabase migration granting UPDATE (display_name, avatar_preference) to the authenticated role
  • Add i18n keys for profile and settings_tabs namespaces in en, fr, and ar
  • Update AGENTS.md and docs/AGENTS_REFERENCE.md with profile settings contracts
  • Fix Prettier formatting and react-hooks/exhaustive-deps warning in ProfileSettingsPage

Algorithm Details (if applicable)

N/A

Testing

  • All existing tests pass (pnpm test:run)
  • New tests added for new functionality
  • Manual testing completed
  • Cross-browser testing (if UI changes)

Test Results

Test Files  135 passed (135)
     Tests  1673 passed (1673)
  Duration  12.17s

New test coverage added:

  • profileService.test.js — 6 tests covering getProfile, updateProfile, trim/validation, and error paths
  • ProfileSettingsPage.test.jsx — 5 tests covering render, prefill from profile row, prefill from OAuth metadata, save success, and save error toast
  • AuthProvider.test.jsx — additional coverage for refreshProfile()
  • resolveUserAvatar.test.js — extended to cover avatar_preference logic
  • UserMenu.test.jsx — extended to cover "Account settings" navigation item

Screenshots/GIFs

Before After
No profile settings page /settings/profile with display name editor and avatar selector

Code Quality

  • Code follows the project's coding standards
  • ESLint passes (pnpm lint)
  • Prettier formatting applied (pnpm format)
  • No console errors or warnings
  • Code is properly documented with JSDoc (if applicable)

Performance Impact

  • No performance impact

Accessibility

  • Keyboard navigation works correctly
  • Screen reader compatibility maintained
  • Color contrast meets WCAG guidelines
  • Focus indicators are visible

Breaking Changes

  • None

Checklist

  • I have completed the Contribution workflow checklist at the top of this template
  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

Additional Notes

The VisualizerApp.jsx pre-existing react-hooks/exhaustive-deps warning (openFeature) is out of scope for this PR and was present before this branch.

Summary by CodeRabbit

  • New Features
    • Added a protected profile settings page for signed-in users to update their display name and choose an avatar preference (Google vs generated).
    • Added a settings entry to the account menu and a dedicated /settings/profile route with automatic page title translation.
  • Bug Fixes
    • Improved avatar rendering and display-name behavior to respect the saved profile value and avatar preference.
    • Enhanced auth/UX with a loading/redirect guard for protected pages.
  • Chores
    • Updated documentation, translations, and expanded test coverage for the new profile/settings flow.

- Add RequireAuth guard component for protected routes
- Add ProfileSettingsPage with display name editing and avatar preference toggle (google vs generated DiceBear)
- Add updateProfile() to profileService with trim/validation
- Add avatar_preference column to profiles table with RLS-granted client UPDATE
- Expose refreshProfile() in AuthContext for profile reload after save
- Update resolveUserAvatar to respect avatar preference and prioritize saved display name
- Add /settings/profile route with RequireAuth in main.jsx
- Add 'Account settings' menu item in UserMenu with navigation
- Add i18n translations for profile namespace in en/fr/ar
- Add profileService.test.js (6 tests) and ProfileSettingsPage.test.jsx (4 tests)
- Update AGENTS.md and AGENTS_REFERENCE.md with profile settings contracts
- Widen page from max-w-xl to max-w-4xl for comfortable spacing
- Replace 'Profile settings' title with 'Settings' heading
- Add tab bar with Profile (active), Notifications, Appearance, Privacy, Connected Accounts (disabled placeholders)
- Add settings_tabs i18n namespace in en/fr/ar
- Add test for tab bar rendering and disabled state
@netlify

netlify Bot commented Jul 2, 2026

Copy link
Copy Markdown

Deploy Preview for dev-bayanflow ready!

Name Link
🔨 Latest commit 3fbc9b1
🔍 Latest deploy log https://app.netlify.com/projects/dev-bayanflow/deploys/6a46a0a3faf3fc00080c5a35
😎 Deploy Preview https://deploy-preview-196--dev-bayanflow.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added documentation Improvements or additions to documentation style Improve styling, design, and animation tests labels Jul 2, 2026
@ayoub3bidi ayoub3bidi self-assigned this Jul 2, 2026
@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.10112% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/pages/ProfileSettingsPage.jsx 98.86% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

Preview for Bayan Flow Staging ready!

Name Link
🔨 Latest commit 3fbc9b1
🔍 Latest deploy log https://github.com/ayoub3bidi/bayan-flow/actions/runs/28609432139
😎 Deploy Preview https://pr-196-bayan-flow-staging.ayoub3bidi.workers.dev
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

Preview alias pr-196 on the staging worker. Updates automatically with new commits.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an authenticated /settings/profile page for editing display name and avatar preference, with route guarding, profile update plumbing, avatar resolution changes, Supabase schema/access updates, menu navigation, translations, and documentation updates.

Changes

Profile Settings Feature

Layer / File(s) Summary
Database schema and profile service contract
supabase/migrations/20260630120000_profiles_profile_settings.sql, src/services/profileService.js, src/services/profileService.test.js, src/test/supabaseMock.js
Adds avatar_preference, column-scoped update rules, updateProfile, and matching service tests and Supabase mock support.
Avatar resolution and display name precedence
src/utils/resolveUserAvatar.js, src/utils/resolveUserAvatar.test.js
Adds avatar-preference-aware generated avatar resolution and changes display-name precedence to prefer saved profile values.
AuthContext refreshProfile and avatarPreference wiring
src/contexts/AuthContextDefinition.js, src/contexts/AuthProvider.jsx, src/contexts/AuthProvider.test.jsx
Exposes refreshProfile, passes avatar preference into avatar resolution, and updates context tests for generated avatars and refresh-driven reloads.
RequireAuth guard and route registration
src/components/RequireAuth.jsx, src/main.jsx, src/components/DocumentTitle.jsx, src/components/UserMenu.jsx, src/components/UserMenu.test.jsx
Adds the auth guard, registers /settings/profile, maps its title, and adds a settings menu entry with test coverage.
ProfileSettingsPage implementation and tests
src/pages/ProfileSettingsPage.jsx, src/pages/ProfileSettingsPage.test.jsx
Implements the profile settings page, including loading, editing, avatar toggling, saving, refresh, toasts, and test coverage.
Docs, translations, and theme tokens
AGENTS.md, docs/AGENTS_REFERENCE.md, src/i18n/locales/*/translation.json, src/index.css
Updates route/profile documentation, locale strings for auth/profile/settings UI, and dark theme primary color tokens.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ProfileSettingsPage
  participant profileService
  participant Supabase
  participant AuthProvider

  User->>ProfileSettingsPage: opens /settings/profile
  ProfileSettingsPage->>profileService: getProfile(userId)
  profileService->>Supabase: select profile row
  Supabase-->>profileService: profile row
  profileService-->>ProfileSettingsPage: display_name, avatar_preference
  User->>ProfileSettingsPage: edits name / toggles avatar
  ProfileSettingsPage->>profileService: updateProfile(userId, patch)
  profileService->>Supabase: update profiles (scoped columns)
  Supabase-->>profileService: updated row
  profileService-->>ProfileSettingsPage: success
  ProfileSettingsPage->>AuthProvider: refreshProfile()
  AuthProvider-->>ProfileSettingsPage: updated context
  ProfileSettingsPage-->>User: success toast
Loading

Possibly related PRs

  • ayoub3bidi/bayan-flow#192: Establishes the shared auth/profile plumbing (resolveUserAvatar, AuthProvider, profiles table/RLS) that this PR extends with avatar_preference support.

Suggested labels: config

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: a new profile settings page for editing display name and avatar preference.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/profile-settings

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed: dependency version conflict. Check your lock file or package.json.


Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (4)
src/utils/resolveUserAvatar.js (1)

61-89: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate seed-derivation logic.

The (email ?? 'bayan-flow').trim() || 'bayan-flow' expression is now duplicated between the new generated-preference branch (Lines 69-70) and the existing fallback branch (Line 84).

♻️ Extract shared seed helper
+function resolveAvatarSeed(email) {
+  return (email ?? 'bayan-flow').trim() || 'bayan-flow';
+}
+
 export function resolveUserAvatar({
   metadataUrl,
   profileUrl,
   email,
   size = 64,
   avatarPreference = 'google',
 }) {
   if (avatarPreference === 'generated') {
-    const seed = (email ?? 'bayan-flow').trim() || 'bayan-flow';
+    const seed = resolveAvatarSeed(email);
     return {
       src: generateAvatarDataUri(seed, size),
       source: 'generated',
     };
   }

   if (isHttpUrl(metadataUrl)) {
     return { src: metadataUrl.trim(), source: 'google' };
   }

   if (isHttpUrl(profileUrl)) {
     return { src: profileUrl.trim(), source: 'profile' };
   }

-  const seed = (email ?? 'bayan-flow').trim() || 'bayan-flow';
+  const seed = resolveAvatarSeed(email);
   return {
     src: generateAvatarDataUri(seed, size),
     source: 'generated',
   };
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/resolveUserAvatar.js` around lines 61 - 89, The seed derivation for
generated avatars is duplicated in resolveUserAvatar, making the function harder
to maintain. Extract the repeated `(email ?? 'bayan-flow').trim() ||
'bayan-flow'` logic into a small shared helper or local variable inside
resolveUserAvatar, and use it in both the avatarPreference === 'generated'
branch and the fallback generated-avatar branch to keep behavior identical.
src/contexts/AuthProvider.jsx (1)

142-145: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add direct test coverage for refreshProfileForUser.

Codecov flags Line 143 as uncovered. This is the entry point ProfileSettingsPage will call after a successful save to refresh the displayed avatar/name, so it's worth a direct assertion that context.refreshProfile() re-fetches the profile for the current user.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/contexts/AuthProvider.jsx` around lines 142 - 145, Add direct test
coverage for the AuthProvider refreshProfileForUser callback, which is currently
uncovered. Update the AuthProvider tests to assert that calling
context.refreshProfile() invokes refreshProfile with the current user from user,
so the ProfileSettingsPage post-save refresh path is exercised explicitly. Use
the refreshProfileForUser and refreshProfile symbols to locate the behavior and
verify the current-user re-fetch is wired correctly.

Source: Linters/SAST tools

src/components/RequireAuth.jsx (1)

1-43: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No test coverage for RequireAuth.

Codecov flags the entire file as uncovered, and no RequireAuth.test.jsx appears in this cohort. Given it gates a protected route, a couple of focused tests (redirect-when-unauthenticated, render-children-when-authenticated) would materially reduce regression risk.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/RequireAuth.jsx` around lines 1 - 43, Add focused test
coverage for RequireAuth because the whole component is currently uncovered.
Create tests for the RequireAuth component that mock useAuth and useNavigate to
verify it redirects to “/” when isConfigured is true, isLoading is false, and
isAuthenticated is false, and that it renders children when isAuthenticated is
true. Also cover the loading/unconfigured state by asserting the placeholder is
shown before auth is resolved.
src/i18n/locales/en/translation.json (1)

33-34: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unused "bio" translation keys — no corresponding field in profile schema/service.

profileService.js (getProfile/updateProfile) and the ProfileSettingsPage.jsx snippets only handle display_name and avatar_preference; there's no description/bio field anywhere in this PR. These keys (also duplicated in fr and ar) appear to be dead strings added ahead of the feature. Consider removing them until the bio field ships, to avoid confusing translators and future readers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/locales/en/translation.json` around lines 33 - 34, Remove the unused
bio-related translation entries from the locale files, since `profileService.js`
(`getProfile`/`updateProfile`) and `ProfileSettingsPage.jsx` only use
`display_name` and `avatar_preference`. Delete the `description` and
`descriptionPlaceholder` keys from the `translation.json` entries in `en` and
the matching duplicated keys in `fr` and `ar`, keeping only strings that
correspond to actual profile schema/service fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@AGENTS.md`:
- Line 9: The route inventory update belongs in docs/AGENTS_REFERENCE.md, not
AGENTS.md. Remove the added /settings/profile entry from the Product line in
AGENTS.md, and apply the route-list change in docs/AGENTS_REFERENCE.md instead,
keeping AGENTS.md limited to non-negotiable rules/contracts.

In `@src/components/RequireAuth.jsx`:
- Around line 18-33: RequireAuth is treating the unconfigured auth state as
loading, which leaves the app stuck on the skeleton when auth is disabled.
Update the RequireAuth component’s useEffect and early return so the
!isConfigured path is handled explicitly in addition to !isAuthenticated, using
navigate and/or a clear fallback instead of returning the spinner. Keep the fix
localized to RequireAuth and its isConfigured/isLoading guard logic.

In `@src/pages/ProfileSettingsPage.jsx`:
- Around line 79-93: The optimistic avatar toggle in autoSaveAvatar does not
revert when updateProfile fails, so the UI can մն leave AvatarPreference out of
sync with persisted state. Update autoSaveAvatar in ProfileSettingsPage to
capture the previous avatar preference and roll back the local state when the
save throws, or move the revert logic to the caller around
setAvatarPreference(next) so the switch returns to the prior value on failure.
Make sure the existing showToast error path remains intact and avoid duplicating
the rollback in both places.

In `@src/pages/ProfileSettingsPage.test.jsx`:
- Around line 142-156: The ProfileSettingsPage test is asserting only the final
submitted payload even though the profile picture switch triggers an earlier
autosave via updateProfileMock. Update the test around the ProfileSettingsPage
flow to account for both actions by asserting the switch-driven avatarPreference
write separately and then verifying the Save changes submission, or by checking
the updateProfileMock call count/order instead of a single toHaveBeenCalledWith
on the combined state.

---

Nitpick comments:
In `@src/components/RequireAuth.jsx`:
- Around line 1-43: Add focused test coverage for RequireAuth because the whole
component is currently uncovered. Create tests for the RequireAuth component
that mock useAuth and useNavigate to verify it redirects to “/” when
isConfigured is true, isLoading is false, and isAuthenticated is false, and that
it renders children when isAuthenticated is true. Also cover the
loading/unconfigured state by asserting the placeholder is shown before auth is
resolved.

In `@src/contexts/AuthProvider.jsx`:
- Around line 142-145: Add direct test coverage for the AuthProvider
refreshProfileForUser callback, which is currently uncovered. Update the
AuthProvider tests to assert that calling context.refreshProfile() invokes
refreshProfile with the current user from user, so the ProfileSettingsPage
post-save refresh path is exercised explicitly. Use the refreshProfileForUser
and refreshProfile symbols to locate the behavior and verify the current-user
re-fetch is wired correctly.

In `@src/i18n/locales/en/translation.json`:
- Around line 33-34: Remove the unused bio-related translation entries from the
locale files, since `profileService.js` (`getProfile`/`updateProfile`) and
`ProfileSettingsPage.jsx` only use `display_name` and `avatar_preference`.
Delete the `description` and `descriptionPlaceholder` keys from the
`translation.json` entries in `en` and the matching duplicated keys in `fr` and
`ar`, keeping only strings that correspond to actual profile schema/service
fields.

In `@src/utils/resolveUserAvatar.js`:
- Around line 61-89: The seed derivation for generated avatars is duplicated in
resolveUserAvatar, making the function harder to maintain. Extract the repeated
`(email ?? 'bayan-flow').trim() || 'bayan-flow'` logic into a small shared
helper or local variable inside resolveUserAvatar, and use it in both the
avatarPreference === 'generated' branch and the fallback generated-avatar branch
to keep behavior identical.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7e823629-5d95-4610-960c-eb3a2ce24937

📥 Commits

Reviewing files that changed from the base of the PR and between 318ab1f and 82c7efa.

📒 Files selected for processing (22)
  • AGENTS.md
  • docs/AGENTS_REFERENCE.md
  • src/components/DocumentTitle.jsx
  • src/components/RequireAuth.jsx
  • src/components/UserMenu.jsx
  • src/components/UserMenu.test.jsx
  • src/contexts/AuthContextDefinition.js
  • src/contexts/AuthProvider.jsx
  • src/contexts/AuthProvider.test.jsx
  • src/i18n/locales/ar/translation.json
  • src/i18n/locales/en/translation.json
  • src/i18n/locales/fr/translation.json
  • src/index.css
  • src/main.jsx
  • src/pages/ProfileSettingsPage.jsx
  • src/pages/ProfileSettingsPage.test.jsx
  • src/services/profileService.js
  • src/services/profileService.test.js
  • src/test/supabaseMock.js
  • src/utils/resolveUserAvatar.js
  • src/utils/resolveUserAvatar.test.js
  • supabase/migrations/20260630120000_profiles_profile_settings.sql

Comment thread AGENTS.md Outdated
Comment thread src/components/RequireAuth.jsx
Comment thread src/pages/ProfileSettingsPage.jsx
Comment thread src/pages/ProfileSettingsPage.test.jsx
- Refactor resolveUserAvatar to extract shared resolveAvatarSeed helper
- Fix RequireAuth to handle !isConfigured path without infinite spinner
- Add RequireAuth.test.jsx with 4 focused tests
- Fix ProfileSettingsPage optimistic avatar toggle to revert on failure
- Update ProfileSettingsPage.test.jsx to verify both avatar autosave and form submit calls
- Add AuthProvider.test.jsx coverage for refreshProfileForUser callback
- Remove unused bio/description translation keys from en/fr/ar locales
- Update AGENTS.md with comprehensive project analysis snapshot

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/pages/ProfileSettingsPage.jsx (3)

65-77: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Toast timeout isn't cleared on unmount.

toastTimeoutRef is set via setTimeout in showToast but there's no cleanup effect to clear it if the component unmounts before the 3s delay elapses (e.g., user navigates away right after a save). This calls setToast on an unmounted component.

🔧 Proposed fix
   const showToast = useCallback((message, type = 'success') => {
     if (toastTimeoutRef.current) {
       clearTimeout(toastTimeoutRef.current);
     }
     setToastType(type);
     setToast(message);
     toastTimeoutRef.current = setTimeout(() => setToast(null), 3000);
   }, []);
+
+  useEffect(() => {
+    return () => {
+      if (toastTimeoutRef.current) {
+        clearTimeout(toastTimeoutRef.current);
+      }
+    };
+  }, []);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/ProfileSettingsPage.jsx` around lines 65 - 77, The toast timer in
showToast can still fire after ProfileSettingsPage unmounts, causing setToast on
an unmounted component. Add a cleanup effect in ProfileSettingsPage that clears
toastTimeoutRef.current on unmount, and keep the existing timeout reset logic
inside showToast so only one timer remains active at a time.

165-185: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

displayName isn't trimmed before saving.

The loaded value is trimmed (row?.display_name?.trim() at line 115), but the value submitted here is used as-is, so leading/trailing whitespace can be persisted, creating inconsistency with the load path.

🔧 Proposed fix
       await updateProfile(user.id, {
-        displayName,
+        displayName: displayName.trim(),
         avatarPreference,
       });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/ProfileSettingsPage.jsx` around lines 165 - 185, The submitted
displayName in handleSubmit is saved without trimming, which can persist
leading/trailing whitespace even though the load path normalizes it. Update the
handleSubmit flow in ProfileSettingsPage so the displayName passed to
updateProfile is trimmed before saving, keeping it consistent with the value
loaded from the profile data.

423-441: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add a polite live region to the toast

The toast message needs role="status" and aria-live="polite" so save success/error feedback is announced to screen readers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/ProfileSettingsPage.jsx` around lines 423 - 441, The toast in
ProfileSettingsPage is missing an accessible live region, so screen readers may
not announce save feedback. Update the toast container in the
AnimatePresence/motion.div block to include role="status" and
aria-live="polite", keeping the existing success/error styling and toastType
logic unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/pages/ProfileSettingsPage.jsx`:
- Around line 65-77: The toast timer in showToast can still fire after
ProfileSettingsPage unmounts, causing setToast on an unmounted component. Add a
cleanup effect in ProfileSettingsPage that clears toastTimeoutRef.current on
unmount, and keep the existing timeout reset logic inside showToast so only one
timer remains active at a time.
- Around line 165-185: The submitted displayName in handleSubmit is saved
without trimming, which can persist leading/trailing whitespace even though the
load path normalizes it. Update the handleSubmit flow in ProfileSettingsPage so
the displayName passed to updateProfile is trimmed before saving, keeping it
consistent with the value loaded from the profile data.
- Around line 423-441: The toast in ProfileSettingsPage is missing an accessible
live region, so screen readers may not announce save feedback. Update the toast
container in the AnimatePresence/motion.div block to include role="status" and
aria-live="polite", keeping the existing success/error styling and toastType
logic unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6df292a9-588b-45d0-987a-8693fe5e9a47

📥 Commits

Reviewing files that changed from the base of the PR and between 82c7efa and 3fbc9b1.

📒 Files selected for processing (10)
  • AGENTS.md
  • src/components/RequireAuth.jsx
  • src/components/RequireAuth.test.jsx
  • src/contexts/AuthProvider.test.jsx
  • src/i18n/locales/ar/translation.json
  • src/i18n/locales/en/translation.json
  • src/i18n/locales/fr/translation.json
  • src/pages/ProfileSettingsPage.jsx
  • src/pages/ProfileSettingsPage.test.jsx
  • src/utils/resolveUserAvatar.js
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/i18n/locales/en/translation.json
  • src/i18n/locales/ar/translation.json
  • src/utils/resolveUserAvatar.js
  • AGENTS.md
  • src/i18n/locales/fr/translation.json
  • src/pages/ProfileSettingsPage.test.jsx

@ayoub3bidi
ayoub3bidi merged commit 866bead into develop Jul 2, 2026
16 checks passed
@ayoub3bidi
ayoub3bidi deleted the feature/profile-settings branch July 2, 2026 17:40
@ayoub3bidi ayoub3bidi mentioned this pull request Jul 16, 2026
35 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation style Improve styling, design, and animation tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant