Conversation
motirebuma
commented
Apr 23, 2026
- Fixed the profile section on the post detail page to correctly redirect to the user profile or avatar editing page.
- Improved the UI of the profile avatar in the navbar.
- Refined the UI for post avatars.
- Updated the avatar UI in the discussion section of posts.
- Designed the Your Profile section, allowing users to edit their avatar and view their personal information.
- Completed the UI for the Settings and Privacy page.
- Implemented the dark mode functionality.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR upgrades profile/avatar handling across the frontend (including deterministic default avatars), introduces/finishes dark mode support with theme preference persistence, and refactors the Settings & Privacy UI into a unified page.
Changes:
- Added
DisplayAvatar+ avatar parsing utilities to support avataaars qualities objects/JSON/URLs and a deterministic default avatar. - Implemented dark mode styling and theme preference support (types, GraphQL mutation selection, theme context integration, CSS variables).
- Refactored profile/follow UI and the Settings page, updating affected components and tests.
Reviewed changes
Copilot reviewed 45 out of 45 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| quotevote-frontend/src/types/store.ts | Updates _followingId to an array type for store user data. |
| quotevote-frontend/src/types/settings.ts | Adds themePreference and updates _followingId typing for settings user data. |
| quotevote-frontend/src/types/profile.ts | Removes profileUserId from UserFollowDisplayProps. |
| quotevote-frontend/src/types/postChat.ts | Broadens avatar typing to support object-based avatar payloads. |
| quotevote-frontend/src/store/useAppStore.ts | Updates updateFollowing to accept string[] and persist it in the store. |
| quotevote-frontend/src/lib/avatar.ts | Adds avatar utilities: deterministic default qualities, URL builder, and parser. |
| quotevote-frontend/src/lib/auth.ts | Changes login to use user from response rather than decoding JWT client-side. |
| quotevote-frontend/src/graphql/mutations.ts | Requests themePreference from updateUser. |
| quotevote-frontend/src/context/ThemeContext.tsx | Applies/removes dark class on <html> when theme mode changes. |
| quotevote-frontend/src/components/UserPosts/PostCard.tsx | Swaps to DisplayAvatar for creator avatar rendering. |
| quotevote-frontend/src/components/Sidebar/Sidebar.tsx | Uses DisplayAvatar and theme-aware text colors. |
| quotevote-frontend/src/components/RequestInviteDialog.tsx | Uses theme tokens (text-foreground, text-muted-foreground) for dark mode. |
| quotevote-frontend/src/components/Profile/UserFollowDisplay.tsx | Replaces legacy avatar component with DisplayAvatar. |
| quotevote-frontend/src/components/Profile/ProfileView.tsx | Adjusts activity filter toggle behavior (select-all/isolate/reset logic). |
| quotevote-frontend/src/components/Profile/ProfileHeader.tsx | Uses DisplayAvatar and adjusts following detection logic. |
| quotevote-frontend/src/components/Profile/ProfileAvatar.tsx | Uses DisplayAvatar and maps named sizes to pixel sizes. |
| quotevote-frontend/src/components/Profile/FollowInfo.tsx | Removes unused profileUserId plumbing. |
| quotevote-frontend/src/components/PostChat/PostChatReactions.tsx | Updates reaction icon colors to theme tokens. |
| quotevote-frontend/src/components/PostChat/PostChatMessage.tsx | Uses DisplayAvatar and theme-aware bubble styling. |
| quotevote-frontend/src/components/PostActions/PostActionCard.tsx | Uses DisplayAvatar and passes avatar through as object/string. |
| quotevote-frontend/src/components/Post/PostCard.tsx | Uses DisplayAvatar for author display in post cards. |
| quotevote-frontend/src/components/Post/Post.tsx | Replaces mixed Avatar/avataaars rendering with DisplayAvatar. |
| quotevote-frontend/src/components/Navbars/NavSearch.tsx | Updates placeholder and colors to support dark mode. |
| quotevote-frontend/src/components/Navbars/MainNavBar.tsx | Uses DisplayAvatar and cleans up avatar/name handling. |
| quotevote-frontend/src/components/DisplayAvatar.tsx | New component: renders avatar URL or deterministic default cartoon as <img>. |
| quotevote-frontend/src/components/CustomButtons/FollowButton.tsx | Updates optimistic follow handling for _followingId as string[]. |
| quotevote-frontend/src/components/BuddyList/BuddyItemList.tsx | Uses theme-aware text colors. |
| quotevote-frontend/src/components/Avatar.tsx | Marks avataaars.io images as unoptimized when using Next <Image>. |
| quotevote-frontend/src/app/layout.tsx | Wraps app with ThemeContextProvider and adds pre-paint theme class script. |
| quotevote-frontend/src/app/globals.css | Reworks CSS variables and adds a dark theme palette; binds Tailwind theme tokens to vars. |
| quotevote-frontend/src/app/dashboard/settings/SettingsPageClient.tsx | Refactors settings into unified form + avatar link + theme toggle + sign out. |
| quotevote-frontend/src/app/dashboard/profile/[username]/avatar/page.tsx | Reuses shared buildAvatarUrl from lib/avatar. |
| quotevote-frontend/src/app/dashboard/layout.tsx | Applies theme tokens across dashboard chrome; uses DisplayAvatar. |
| quotevote-frontend/src/app/dashboard/explore/ExploreContent.tsx | Shows alternate logo rendering for dark mode. |
| quotevote-frontend/src/tests/components/UserPosts/PostCard.test.tsx | Updates avatar assertions to match DisplayAvatar behavior (img + alt text). |
| quotevote-frontend/src/tests/components/Sidebar.test.tsx | Updates avatar alt-text expectations for DisplayAvatar. |
| quotevote-frontend/src/tests/components/Profile/UserFollowDisplay.test.tsx | Updates mocks/assertions for DisplayAvatar. |
| quotevote-frontend/src/tests/components/Profile/ProfileAvatar.test.tsx | Updates mocks/assertions and adds coverage for size mapping + username passing. |
| quotevote-frontend/src/tests/components/Profile/FollowInfo.test.tsx | Updates _followingId test data to array format. |
| quotevote-frontend/src/tests/components/Profile/FollowButton.test.tsx | Updates expectations for updateFollowing array signature. |
| quotevote-frontend/src/tests/components/PostChat/PostChatMessage.test.tsx | Updates mock to DisplayAvatar. |
| quotevote-frontend/src/tests/components/PostActions/PostActionCard.test.tsx | Updates mock to DisplayAvatar. |
| quotevote-frontend/src/tests/components/CustomButtons.test.tsx | Updates _followingId initial state in tests to array format. |
| quotevote-frontend/src/tests/app/dashboard/settings/page.test.tsx | Updates tests for new unified settings page UI + dark mode toggle. |
| quotevote-frontend/next.config.ts | Adds avataaars.io image remote pattern. |
Comments suppressed due to low confidence (1)
quotevote-frontend/src/lib/auth.ts:71
loginUsernow destructures{ token, user }from the/loginresponse and returnsuserwithout any fallback. In this repo the TS backend login handler responds withaccessToken/refreshToken(and optionallyuser) rather thantoken(seequotevote-backend/app/data/utils/authentication.ts), so this will treat successful logins as missing-token and/or setusertoundefined. Update the client to support the backend response shape (and endpoint, if applicable) and ensureuseris populated (e.g., usedata.userwhen present, otherwise derive it from the token or fetchme).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const avatarValue = | ||
| typeof userData?.avatar === 'string' | ||
| ? userData.avatar | ||
| : (userData?.avatar as { url?: string } | undefined)?.url | ||
| setUserData({ |
There was a problem hiding this comment.
After a successful updateUser mutation, the store update derives avatarValue from the previous userData.avatar (and assumes a { url } shape). This can wipe avatar qualities objects (or ignore the avatar returned by the mutation). Prefer using result.data.updateUser.avatar (and/or the full returned user object) when calling setUserData, preserving whatever avatar format the backend returns.
| const handleSignOut = useCallback(() => { | ||
| removeToken() | ||
| router.push('/auths/login') | ||
| }, [router]) |
There was a problem hiding this comment.
handleSignOut removes the token but doesn’t clear the persisted Zustand user state. Because the store is persisted, the app can still render as “logged in” (stale user.data) after redirect. Call the store’s logout()/clearUserData() (and any other relevant resets) alongside removeToken().
| const [localDarkMode, setLocalDarkMode] = useState(isDarkMode) | ||
| const [originalDarkMode, setOriginalDarkMode] = useState(isDarkMode) | ||
|
|
There was a problem hiding this comment.
localDarkMode/originalDarkMode are initialized from isDarkMode only once. If the ThemeContext later updates isDarkMode (e.g., when user.themePreference loads/syncs), the toggle state and dirty calculation can become out of sync with the actual theme. Add an effect to sync these state values when isDarkMode changes (or derive them directly instead of copying into local state).
| const followersCount = _followersId?.length || 0; | ||
| const followingCount = _followingId?.length || 0; |
There was a problem hiding this comment.
followersCount/followingCount are computed from _followersId/_followingId directly. This component already normalizes _followersId into followersArray to handle legacy string formats, but the counts will be wrong if either field is a string (string .length counts characters). Compute counts from the normalized arrays (and normalize _followingId similarly for followingCount).