Skip to content

Add User Profile Page with ENS Subdomain Support#384

Open
tbsoc wants to merge 33 commits into
mainfrom
profile-page-final
Open

Add User Profile Page with ENS Subdomain Support#384
tbsoc wants to merge 33 commits into
mainfrom
profile-page-final

Conversation

@tbsoc

@tbsoc tbsoc commented Jan 2, 2026

Copy link
Copy Markdown
Member

Summary

Implements a comprehensive user profile page at /profile displaying BREAD holdings, yield information, LP positions, voting history, and placeholders for upcoming features.

Closes #380

Features Implemented

Core Profile Components

  • Username/ENS Management: UI for claiming personalized ENS subdomain (username.breadcooperative.eth)
    • Input validation (3-20 chars, alphanumeric + dash + underscore)
    • Coming soon functionality (requires smart contract deployment)
    • Edit mode for updating username
  • BREAD Holdings: Real-time BREAD balance display with empty states
  • Yield Information: APY display with monthly and yearly yield calculations
  • LP Position: Locked BUTTER/BREAD LP tokens with voting power display
  • Voting History: Full-width section reusing existing VotingHistory component
  • Gnosis Pay Card: Placeholder for future Gnosis Pay integration
  • Stacks (Savings Circles): Feature-flagged placeholder for future savings circles app

Technical Implementation

New Files Created:

  • /src/app/profile/page.tsx - Page entry point with metadata
  • /src/app/profile/ProfilePage.tsx - Main client component with user state handling
  • /src/app/profile/components/UsernameCard.tsx - ENS subdomain claiming interface
  • /src/app/profile/components/BreadHoldingsCard.tsx - BREAD balance display
  • /src/app/profile/components/YieldInfoCard.tsx - APY and yield calculations
  • /src/app/profile/components/LPPositionCard.tsx - LP vault position display
  • /src/app/profile/components/VotingHistorySection.tsx - Voting history wrapper
  • /src/app/profile/components/GnosisPayCard.tsx - Gnosis Pay placeholder
  • /src/app/profile/components/StacksCard.tsx - Feature-flagged Stacks card

Files Modified:

  • /src/app/layout.tsx - Added FEATURE_STACKS feature flag
  • .env.example - Added FEATURE_STACKS=false environment variable
  • /src/app/components/nav/account-details.tsx - Added "View Profile" navigation link

Data Integration:

  • useConnectedUser() for wallet state abstraction (supports future wallet provider migration)
  • useTokenBalances() for BREAD balance with auto-refetch on block changes
  • useVaultAPY() for current APY from SDAI adaptor
  • useVaultTokenBalance() for LP position data
  • Proper loading/error/empty states for all data displays

Responsive Design:

  • Mobile-first grid layout: single column on mobile, two-column on desktop
  • Username card spans full width
  • Voting history section full-width on all screen sizes
  • Consistent padding and spacing using WRAPPER_CLASSES

Future Work

Username/ENS Feature

The UsernameCard component is UI-ready but requires smart contract deployment to function:

  • Smart contract functions needed: claimUsername(), getUsernameForAddress(), isUsernameAvailable()
  • Integration with useWriteContract and useReadContract hooks
  • Profanity filter implementation
  • Real-time availability checking with debouncing

Feature Enhancements

  • Gnosis Pay card integration when available
  • Stacks (savings circles) implementation when feature is enabled
  • Avatar/profile picture tied to ENS subdomain
  • Display username in header instead of truncated address

Testing Notes

User States Handled:

  • ✅ Wallet not connected - shows connect prompt with LoginButton
  • ✅ Wallet loading - shows spinner with "Loading your profile..." message
  • ✅ Unsupported chain - shows network switch prompt
  • ✅ Connected with BREAD - shows all data with proper formatting
  • ✅ Connected without BREAD - shows empty states with helpful CTAs

Feature Flags:

  • ✅ Stacks card shows/hides based on FEATURE_STACKS environment variable
  • ✅ Voting history shows/hides based on FEATURE_VOTING_HISTORY
  • ✅ LP vault link shows/hides based on FEATURE_LP_VAULTS

Responsive Layout:

  • ✅ Mobile (375px): Single column, proper spacing
  • ✅ Desktop (1280px+): Two-column grid, full-width voting history

Commits

This PR contains only 3 commits related to the profile page implementation:

  • Add comprehensive user profile page
  • Fix null checks for breadBalance in profile components
  • Shorten profile button text to fit on one line

🤖 Generated with Claude Code

tbsoc and others added 3 commits January 2, 2026 22:35
Implements a full-featured /profile page with the following components:
- User profile overview with wallet information
- Username/ENS subdomain claiming interface (UI ready, requires smart contract)
- BREAD holdings display with real-time balance
- Yield information with APY calculations (monthly and yearly)
- LP position display with voting power
- Voting history section (reuses existing VotingHistory component)
- Gnosis Pay card placeholder for future integration
- Stacks (savings circles) card with feature flag support

Technical changes:
- Created /src/app/profile/ directory with page.tsx and ProfilePage.tsx
- Added 8 new profile components in /src/app/profile/components/
- Added FEATURE_STACKS feature flag to layout.tsx and .env.example
- Added "View Full Profile" navigation link to account details menu
- Integrated with existing hooks: useTokenBalances, useVaultAPY, useVaultTokenBalance
- Implemented proper loading/error/empty states for all data displays
- Responsive design with mobile-first grid layout

Closes #380

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add null checks before accessing breadBalance.status to fix TypeScript
compilation errors. This handles the case where token balances might be
null when the user is not connected.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changed "View Full Profile" to "View Profile" to prevent text wrapping
in the navigation account details button.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@netlify

netlify Bot commented Jan 2, 2026

Copy link
Copy Markdown

Deploy Preview for dapper-sundae-ae0873 ready!

Name Link
🔨 Latest commit b6b3e3e
🔍 Latest deploy log https://app.netlify.com/projects/dapper-sundae-ae0873/deploys/695b93a2acbb0d0008856f09
😎 Deploy Preview https://deploy-preview-384--dapper-sundae-ae0873.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.

tbsoc and others added 26 commits January 2, 2026 23:03
Created new components to show only the user's voting history instead
of overall cycle results:

- New hook useUserVotingHistory: Queries subgraph for BreadHolderVoted
  events filtered by user address
- New component UserVotingHistory: Displays user's vote history with
  project names, percentages, and dates
- Updated VotingHistorySection: Now shows user's personal votes instead
  of overall cycle results

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…bgraph

- Query BreadHolderVoted events directly from blockchain using wagmi
- Filter events by user address using event args
- Fetch block timestamps for each vote event
- Query from block 0 to get complete voting history
- Add Previous/Next navigation buttons to cycle through vote history
- Display all active projects including those not voted for (0%)
- Show unvoted projects in grey color vs voted in orange
- Sort projects by vote percentage descending
- Display 'Vote X of Y' counter
- Remove arrow icon from View Profile button
- Create new useUserVotingHistoryByCycle hook to fetch yield distributions
- Match each vote to its cycle based on timestamp boundaries
- Keep only the most recent vote per cycle (handles vote recasting)
- Display 'Cycle #X' instead of 'Vote X of Y' in navigation
- Fetch cycle end timestamps from yieldDistributed events via subgraph
- Sort cycles descending (most recent first)
…EAD button

- Updated UserVotingHistory to use useDistributions hook to fetch cycle-specific project lists
- Now displays only projects that existed during each cycle (not all currently active projects)
- Added "Bake BREAD" button to BreadHoldingsCard component (links to home page)
- Fixed cycle navigation variable naming for consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Created useUserYieldContributions hook to calculate total yield distributed per project
- Calculates user's proportional contribution to democratic distribution (50% of yield)
- Formula: (user votes for project / total votes) × democratic pool
- New YieldContributionsCard shows total impact and per-project breakdown
- Sorted by contribution amount descending

This gives users visibility into how their voting has directly funded projects
across all cycles.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Fix unit mismatch in yield contribution calculation: vote.points was in wei units while totalVotes was in ether units, causing incorrect calculations
- Convert vote.points from wei to ether (divide by 1e18) to match totalVotes units
- Add "Subscribe to Blog" button to GnosisPayCard linking to https://bread.coop
- Remove unused userTotalPoints calculation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Make Yield Contributions card full width to match its content importance
- Move LP Position and Gnosis Pay cards side by side (half width each)
- Add fixed height to voting history (min 400px, max 600px with scroll)
- Ensures voting history section maintains consistent size across all cycles

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Make Yield Impact half width, spanning 2 rows on desktop
- Position LP Position and Gnosis Pay cards on left, stacked vertically
- Yield Impact card now fills full height with scrollable project list
- Update blog link to correct URL: https://paragraph.com/@breadcoop

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Query projectDistributions and projectAddresses from subgraph
- Calculate each project's democratic pool allocation
- Determine user contribution based on vote percentage of project yield
- Remove incorrect wei conversion and totalVotes division
- Clean up debug logging

This approach calculates yield contributions by determining what portion
of each project's democratic yield the user influenced through their votes.
- Add BREAD logo to holdings section
- Add voting power icon (Scales) to LP position
- Combine BREAD holdings and yield info into single card
- Fix yield impact card to show correct message when user has voted but yield not yet distributed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The previous calculation was fundamentally flawed - it was trying to attribute
a percentage of each project's total democratic yield based on the user's vote
allocation percentage, which doesn't make sense.

The correct formula is:
- User's contribution = (user's vote points / total votes) × (total yield / 2)
- This directly calculates the actual yield the user helped direct to each project

Updated explanation text to be clearer and more accurate.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- View Profile button takes flex-1 (most of the space)
- Sign out button is more compact and sits on the right
- Both buttons now appear on the same row with gap-2 spacing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Make sign out button icon-only to save space in dropdown
- Combine BREAD holdings and LP position into single "BREAD Overview" card
- Add total yield contributed to projects in overview
- Updated layout: BREAD Overview now shows balance, LP tokens, voting power, APY, yields, and total contributions
- Action buttons at bottom: "Bake BREAD" + "Manage/Explore LP"
- Removed separate LPPositionCard component from profile page

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Both buttons now take up 50% of the width (flex-1)
- Sign out button keeps its text and icon
- Buttons are now the same size side by side

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Replace Scales icon with FistIcon for voting power display
- Replace "BREAD" text with Logo icons for monthly/yearly yield
- Remove "BUTTER/BREAD LP" text from locked LP tokens

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Remove "Total Yield Contributed to Projects" section (already shown in Yield Impact card)
- Wrap icons in flex containers for better vertical alignment with text
- Remove unused useUserYieldContributions hook and related code

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Reduce card padding from p-6 to p-4
- Reduce all mb-4 margins to mb-3
- Reduce input padding from py-2 to py-1.5
- Reduce font sizes for better compactness
- Reduce Copy icon size from 20 to 18
- Make all spacing more compact overall

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Change layout from vertical to horizontal (flex items-center)
- Remove all descriptive text and multi-line layouts
- Show "Username (Coming Soon)" inline with input field
- Display username, copy, and edit buttons all on one line
- Reduce input padding from py-1.5 to py-1
- Drastically reduce vertical height by eliminating stacked elements

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Remove lg:col-span-2 so Username card takes only one column
- Reorder cards: Username and Gnosis Pay on first row
- Revert to vertical layout with proper spacing
- Restore heading, descriptions, and standard vertical structure

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Display total distributed yield for each cycle in navigation section
- Calculate and show yield influenced by user per project
- Use BREAD Logo icons for yield amounts
- Calculation formula: (user vote points / total votes) × democratic pool (50% of total yield)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Move useDistributions hook call before early returns
- Add proper type guard for currentVoteCycle
- Fixes ESLint error: react-hooks/rules-of-hooks

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
tbsoc and others added 4 commits January 4, 2026 13:51
- BREAD Overview: Shows actual yield earned from user's collateral (monthly/yearly based on balance * APY)
- Yield Impact: Updated label to "Total Yield Influenced Through Voting" to clarify this is democratic pool allocation based on voting power, not earned yield

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Created useTotalYieldGenerated hook to sum all distributed yield across all cycles
- Added "Total Yield Generated" field to BREAD Overview card
- This shows the total yield from all BREAD holders' collateral since the beginning
- Yield Impact card already shows yield influenced through voting (via useUserYieldContributions)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changed from tracking total protocol yield to user's individual yield earned from their BREAD collateral.

Implementation:
- Created useUserYieldGenerated hook that calculates user yield as: Current Balance - (Total Minted - Total Burned)
- Queries Transfer events from/to address(0) to track mints and burns
- Replaces useTotalYieldGenerated which was tracking protocol-wide yield

The "Total Yield Generated" field in BREAD Overview now shows yield specifically from that user's collateral over time, not the total yield from all users.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixed Yield Impact card showing 0.00 by calculating total yield influenced directly from voting history data.

Implementation:
- Created useUserTotalYieldInfluenced hook that sums yield amounts shown in UserVotingHistory
- Uses same calculation: (user's vote points / total votes) × democratic pool
- Fetches all yield distributions from subgraph and matches with user's voting cycles
- Returns both total yield influenced and per-project breakdown
- Modified YieldContributionsCard to use this new data source

The total now matches the sum of all BREAD amounts shown next to projects in the voting history across all cycles.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
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.

Add User Profile Page

1 participant