Skip to content

new profile feature with modal and updated settings#17

Open
ransuum wants to merge 1 commit intoengly817chat:mainfrom
ransuum:main
Open

new profile feature with modal and updated settings#17
ransuum wants to merge 1 commit intoengly817chat:mainfrom
ransuum:main

Conversation

@ransuum
Copy link
Copy Markdown
Member

@ransuum ransuum commented Dec 26, 2025

Summary by CodeRabbit

  • New Features

    • Added a comprehensive profile page with editable account information and learning profile sections
    • Users can now manage settings including theme, interface language, and notification preferences
    • Added navigation to profile page from the sidebar
  • Chores

    • Updated backend API endpoint configuration
    • Updated chat action translation string

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Copy Markdown

vercel bot commented Dec 26, 2025

@ransuum is attempting to deploy a commit to the Oleksanra's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Dec 26, 2025

📝 Walkthrough

Walkthrough

This PR introduces a user profile management feature with a new profile page component, profile modal, API endpoints for updating profile and settings data, expanded type definitions, navigation updates linking to the profile page, configuration changes including API URL update and i18n namespace defaults, and a single translation update.

Changes

Cohort / File(s) Summary
Profile Page Implementation
src/app/(root)/profile/page.tsx, src/features/profile/ui/profile-modal.tsx
New profile page with editable Account Information and Learning Profile sections; separate ProfileModal component displays read-only profile details; both use react-query for data fetching and mutation with local state management for form changes and pending states.
Authentication API & Types
src/entities/auth/api.ts, src/entities/auth/types.ts
Added UpdateProfileRequest and UpdateSettingsRequest types; expanded UserProfile with imgUrl, updatedAt, lastLogin, and nested userSettings object; added updateProfile() and updateSettings() API methods; corrected getProfile endpoint path with leading slash.
Navigation & Sidebar Updates
src/features/chats/ui/chat-sidebar.tsx
Integrated router navigation to profile page; added conditional click handler logic for nav items with custom onClick behavior; updated profile nav item to trigger navigation.
Configuration & Infrastructure
src/shared/constants/app-consts.ts, src/shared/lib/i18n.ts, src/features/profile/index.ts
Updated API URL to production server; configured i18n with 'common' default namespace; created profile feature barrel export.
Translations
public/locales/en/common.json
Changed chatPage.send label from "Send" to "Go".

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ProfilePage as ProfilePage<br/>(Client)
    participant ReactQuery as React Query<br/>(Cache)
    participant API as Auth API
    participant Server

    User->>ProfilePage: Click profile nav / Page loads
    ProfilePage->>ReactQuery: Check cache for profile
    alt Cache miss
        ReactQuery->>API: getProfile()
        API->>Server: GET /api/profile/check
        Server-->>API: UserProfile response
        API-->>ReactQuery: Profile data
        ReactQuery-->>ProfilePage: Profile + cached state
    else Cache hit
        ReactQuery-->>ProfilePage: Cached profile
    end

    ProfilePage->>ProfilePage: Render editable sections<br/>(Account Info, Learning Profile)
    User->>ProfilePage: Edit fields & apply changes
    ProfilePage->>ProfilePage: Accumulate changes<br/>(profileChanges bag)
    ProfilePage->>API: updateProfile(changes)
    API->>Server: PUT /api/profile
    Server-->>API: Updated UserProfile
    API-->>ReactQuery: Update cache on success
    ReactQuery-->>ProfilePage: Trigger re-render
    ProfilePage->>User: Show success toast
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • PR #7: Both PRs modify the auth entity (src/entities/auth/api.ts and src/entities/auth/types.ts) and extend UserProfile/types to support profile functionality.
  • PR #9: Both PRs edit public/locales/en/common.json and src/features/chats/ui/chat-sidebar.tsx for translation and navigation updates.

Poem

🐰 A profile emerges, editable and bright,
With modals and pages, all gleaming just right!
Forms gather their changes like carrots to store,
React-Query caches what users explore—
Now "Go" says the button, let's hop to the door! 🚀

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: a new profile feature with modal and updated settings management across multiple files.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (7)
src/shared/constants/app-consts.ts (1)

2-2: Consider using environment variables for API URL configuration.

The HTTPS upgrade improves security. However, hardcoding the API URL makes it difficult to switch between environments (development, staging, production). While the change is correct, using environment variables would be a better practice.

The URL is currently used as the axios baseURL and in OAuth redirects. Since no environment variables are currently in use in this project, introducing NEXT_PUBLIC_API_URL would follow Next.js conventions and allow different URLs across build environments.

src/features/chats/ui/chat-sidebar.tsx (1)

142-150: Profile button won't show as active after click.

When clicking the profile item, item.onClick() executes and navigates away, but setActiveItem(item) is never called due to the else branch. This means the profile button won't visually indicate it's active before navigation occurs. This may be intentional since navigation leaves this component, but consider if you want brief visual feedback.

🔎 Optional: Set active state before executing onClick
 onClick={() => {
   if (!item.disabled) {
     if (item.onClick) {
+      setActiveItem(item)
       item.onClick()
     } else {
       setActiveItem(item)
     }
   }
 }}
src/app/(root)/profile/page.tsx (2)

28-29: Consider stronger typing for change tracking state.

Using Record<string, any> loses type safety. Consider using partial types of the request interfaces for better compile-time checks.

🔎 Proposed improvement
-  const [profileChanges, setProfileChanges] = useState<Record<string, any>>({})
-  const [settingsChanges, setSettingsChanges] = useState<Record<string, any>>({})
+  const [profileChanges, setProfileChanges] = useState<Partial<UpdateProfileRequest>>({})
+  const [settingsChanges, setSettingsChanges] = useState<Partial<UpdateSettingsRequest>>({})

Import UpdateProfileRequest and UpdateSettingsRequest from @/entities/auth:

import { authApi, UpdateProfileRequest, UpdateSettingsRequest } from '@/entities/auth'

36-58: Hardcoded user-facing strings should use i18n.

Toast messages like "Profile updated successfully", "Failed to update profile", "Settings updated successfully", and "Failed to update settings" are hardcoded in English. These should use the translation function for consistency with the rest of the app.

🔎 Example fix
   const updateProfileMutation = useMutation({
     mutationFn: authApi.updateProfile,
     onSuccess: (data) => {
       queryClient.setQueryData(['profile'], data)
-      toast.success('Profile updated successfully')
+      toast.success(t('profile.updateSuccess'))
       setProfileChanges({})
     },
     onError: () => {
-      toast.error('Failed to update profile')
+      toast.error(t('profile.updateError'))
     },
   })

Then add corresponding keys to common.json.

src/entities/auth/types.ts (1)

71-76: Consider making userSettings optional if it can be undefined.

The ProfilePage component at line 409 checks {profile.userSettings && ...} suggesting userSettings might not always be present. If the API can return a profile without userSettings, the type should reflect this:

🔎 Proposed fix if userSettings can be absent
-  userSettings: {
+  userSettings?: {
     id: string
     theme: string
     notifications: boolean
     interfaceLanguage: string
-  }
+  } | null
 }

If userSettings is always guaranteed by the API, the null check in ProfilePage is unnecessary and can be removed.

src/features/profile/ui/profile-modal.tsx (2)

14-15: Translation hook is imported but not used.

The t function from useTranslation is imported but all UI strings in the modal are hardcoded in English (e.g., "Account Information", "Learning Profile", "Member since", etc.). Either use t() for these strings or remove the unused import.


68-78: Consider adding keyboard accessibility for the modal.

The modal lacks common accessibility features:

  • No ESC key handler to close the modal
  • No click-outside-to-close behavior
  • No focus trap within the modal

These are nice-to-have improvements for better UX and accessibility.

🔎 Example: Add ESC key handler
import { useEffect } from 'react'

// Inside ProfileModal component:
useEffect(() => {
  const handleEsc = (e: KeyboardEvent) => {
    if (e.key === 'Escape') onClose()
  }
  window.addEventListener('keydown', handleEsc)
  return () => window.removeEventListener('keydown', handleEsc)
}, [onClose])
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b6c8e72 and 1e7ce0d.

📒 Files selected for processing (9)
  • public/locales/en/common.json
  • src/app/(root)/profile/page.tsx
  • src/entities/auth/api.ts
  • src/entities/auth/types.ts
  • src/features/chats/ui/chat-sidebar.tsx
  • src/features/profile/index.ts
  • src/features/profile/ui/profile-modal.tsx
  • src/shared/constants/app-consts.ts
  • src/shared/lib/i18n.ts
🧰 Additional context used
🧬 Code graph analysis (3)
src/entities/auth/types.ts (1)
src/entities/auth/model/auth-context.tsx (2)
  • AuthContextType (9-16)
  • userData (48-50)
src/features/profile/ui/profile-modal.tsx (2)
src/shared/ui/common/avatar.tsx (3)
  • Avatar (50-50)
  • AvatarImage (50-50)
  • AvatarFallback (50-50)
src/shared/ui/message-modal.tsx (2)
  • Props (8-25)
  • Props (1-6)
src/entities/auth/api.ts (2)
src/entities/auth/types.ts (3)
  • UpdateProfileRequest (36-41)
  • UserProfile (53-77)
  • UpdateSettingsRequest (43-47)
src/shared/api/axios.ts (1)
  • axiosWithAuth (42-42)
🔇 Additional comments (9)
public/locales/en/common.json (1)

206-206: Verify the translation change is intentional.

The button label changed from "Send" to "Go" which is less descriptive for a message-sending action. Confirm this is the intended UX decision.

src/features/profile/index.ts (1)

1-1: LGTM!

Clean barrel export following the feature module pattern.

src/shared/lib/i18n.ts (1)

16-19: LGTM!

The namespace configuration is consistent with the hardcoded loadPath for common.json. If additional namespaces are needed in the future, both the ns array and loadPath pattern would need to be updated together.

src/features/chats/ui/chat-sidebar.tsx (1)

83-84: LGTM!

Profile navigation is properly enabled with router push to /profile.

src/app/(root)/profile/page.tsx (1)

175-176: LGTM!

The component properly uses AccessGuard with requireAuth to protect the profile page, and correctly handles loading and error states.

src/entities/auth/api.ts (2)

116-123: LGTM!

New API methods follow the existing patterns in the file and are properly typed. The use of PUT for updates is appropriate.


26-29: Endpoint paths are correctly defined.

Note: Pre-existing inconsistency at line 19 where checkEmail lacks a leading slash ('valid/check-email?email='), unlike other endpoints. Consider fixing for consistency in a follow-up.

src/entities/auth/types.ts (1)

36-47: LGTM!

The request interfaces use optional fields appropriately for partial update semantics.

src/features/profile/ui/profile-modal.tsx (1)

80-216: LGTM!

The conditional rendering for loading, success, and error states is well-structured. The UI layout and styling are clean.

Comment on lines +90 to +148
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
})
}

const formatEnglishLevel = (level: string) => {
const levels: Record<string, string> = {
A1: 'A1 - Beginner',
A2: 'A2 - Elementary',
B1: 'B1 - Intermediate',
B2: 'B2 - Upper Intermediate',
C1: 'C1 - Advanced',
C2: 'C2 - Proficient',
}
return levels[level] || level
}

const formatGoal = (goal: string) => {
const goals: Record<string, string> = {
DEFAULT: 'No specific goal',
IMPROVE_ENGLISH: 'Improve English',
LEARN_NEW_LANGUAGE: 'Learn new language',
MEET_NEW_PEOPLE: 'Meet new people',
}
return goals[goal] || goal.replace(/_/g, ' ').toLowerCase().replace(/^\w/, c => c.toUpperCase())
}

const formatNativeLanguage = (lang: string) => {
const languages: Record<string, string> = {
ENGLISH: 'English',
SPANISH: 'Spanish',
FRENCH: 'French',
GERMAN: 'German',
CHINESE: 'Chinese',
JAPANESE: 'Japanese',
RUSSIAN: 'Russian',
ARABIC: 'Arabic',
PORTUGUESE: 'Portuguese',
HINDI: 'Hindi',
UKRAINIAN: 'Ukrainian',
POLISH: 'Polish',
}
return languages[lang] || lang.charAt(0) + lang.slice(1).toLowerCase()
}

const ENGLISH_LEVELS = ['A1', 'A2', 'B1', 'B2', 'C1', 'C2']
const GOALS = ['DEFAULT', 'IMPROVE_ENGLISH', 'LEARN_NEW_LANGUAGE', 'MEET_NEW_PEOPLE']
const NATIVE_LANGUAGES = [
'ENGLISH', 'SPANISH', 'FRENCH', 'GERMAN', 'CHINESE',
'JAPANESE', 'RUSSIAN', 'ARABIC', 'PORTUGUESE', 'HINDI',
'UKRAINIAN', 'POLISH'
]
const THEMES = ['DARK', 'BRIGHT', 'CYAN']
const INTERFACE_LANGUAGES = ['ENGLISH', 'UKRAINIAN']
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Extract shared formatting utilities to reduce duplication.

The formatDate, formatEnglishLevel, formatGoal, and formatNativeLanguage functions are duplicated between this file and profile-modal.tsx. Additionally, there are inconsistencies:

  • formatDate here includes time (hour/minute), while the modal version shows date only
  • formatGoal uses different keys (DEFAULT, IMPROVE_ENGLISH, LEARN_NEW_LANGUAGE, MEET_NEW_PEOPLE) vs modal (IMPROVE_ENGLISH, LEARN_NEW_LANG, MEET_PEOPLE)
  • formatNativeLanguage here includes POLISH which the modal lacks

Consider extracting these to a shared utility in @/shared/utils or @/entities/auth to ensure consistency.

🤖 Prompt for AI Agents
In src/app/(root)/profile/page.tsx around lines 90 to 148 the formatting helpers
(formatDate, formatEnglishLevel, formatGoal, formatNativeLanguage) are
duplicated and inconsistent with profile-modal.tsx; extract them into a single
shared utility (e.g. src/shared/utils/formatters.ts or
@/entities/auth/formatters) exporting: a configurable formatDate (optionally
includeTime flag), canonical formatEnglishLevel, a single formatGoal with
unified keys (map both variants like LEARN_NEW_LANG → LEARN_NEW_LANGUAGE,
MEET_PEOPLE → MEET_NEW_PEOPLE) and a unified formatNativeLanguage map (including
POLISH), then replace the local functions and constant arrays in both
profile/page.tsx and profile-modal.tsx with imports from that utility and update
the constants (ENGLISH_LEVELS, GOALS, NATIVE_LANGUAGES, THEMES,
INTERFACE_LANGUAGES) to reference the shared definitions to ensure consistency.

Comment on lines +42 to +49
const formatGoal = (goal: string) => {
const goals: Record<string, string> = {
IMPROVE_ENGLISH: 'Improve English',
LEARN_NEW_LANG: 'Learn new language',
MEET_PEOPLE: 'Meet new people',
}
return goals[goal] || goal
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for all goal key variations
rg -n "LEARN_NEW_LANG|MEET_PEOPLE|LEARN_NEW_LANGUAGE|MEET_NEW_PEOPLE" --type=ts --type=tsx

Repository: engly817chat/engly-client

Length of output: 96


🏁 Script executed:

#!/bin/bash
# Find ProfilePage file
fd -type f -name "*profile*" | grep -i page

Repository: engly817chat/engly-client

Length of output: 239


🏁 Script executed:

#!/bin/bash
# Look for API types or constants related to goals
rg -n "goal|Goal" --type=ts --type=tsx | head -50

Repository: engly817chat/engly-client

Length of output: 96


🏁 Script executed:

#!/bin/bash
# Search for all goal key variations without type restriction
rg "LEARN_NEW_LANG|MEET_PEOPLE|LEARN_NEW_LANGUAGE|MEET_NEW_PEOPLE"

Repository: engly817chat/engly-client

Length of output: 735


🏁 Script executed:

#!/bin/bash
# Find ProfilePage file
find . -type f -name "*ProfilePage*" -o -name "*profile-page*"

Repository: engly817chat/engly-client

Length of output: 51


🏁 Script executed:

#!/bin/bash
# Look at the file structure to understand the project
ls -la src/features/profile/

Repository: engly817chat/engly-client

Length of output: 285


🏁 Script executed:

#!/bin/bash
# Examine profile-modal.tsx to see how goals are used
cat -n src/features/profile/ui/profile-modal.tsx | head -60

Repository: engly817chat/engly-client

Length of output: 2191


🏁 Script executed:

#!/bin/bash
# Examine profile/page.tsx to see how they format goals correctly
cat -n src/app/\(root\)/profile/page.tsx | grep -A 10 "formatGoal\|LEARN_NEW_LANGUAGE\|goals"

Repository: engly817chat/engly-client

Length of output: 1761


🏁 Script executed:

#!/bin/bash
# Check auth constants to confirm API values
cat -n src/features/auth/model/constants.ts | grep -A 5 "GOALS\|goal"

Repository: engly817chat/engly-client

Length of output: 692


Update goal key names in formatGoal to match API values.

The formatGoal function uses LEARN_NEW_LANG and MEET_PEOPLE, but the API returns LEARN_NEW_LANGUAGE and MEET_NEW_PEOPLE (as confirmed by auth constants and the GOALS array in profile/page.tsx). This mismatch will cause unformatted goal values to display instead of the intended labels. Update lines 45-46 to:

LEARN_NEW_LANGUAGE: 'Learn new language',
MEET_NEW_PEOPLE: 'Meet new people',
🤖 Prompt for AI Agents
In src/features/profile/ui/profile-modal.tsx around lines 42 to 49, the
formatGoal map uses keys LEARN_NEW_LANG and MEET_PEOPLE which do not match API
values; update the keys to LEARN_NEW_LANGUAGE and MEET_NEW_PEOPLE respectively
so the function returns the intended human-readable labels for those API goal
values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant