Summary
Transform the Profile page from a basic wallet card + withdraw button into a full producer earnings dashboard with sales analytics, revenue charts, beat performance metrics, and withdrawal history. Producers should be able to see exactly how their beats are performing at a glance.
Why
- The current Profile page shows only: wallet address, pending XLM balance, and a withdraw button. A producer has zero visibility into which beats are selling, when sales happened, or how much they've earned over time.
- Without analytics, producers can't optimize pricing, identify trending genres, or understand their audience.
- The contract already exposes
get_earnings and get_stats — we need to surface this data in a useful way.
What to build
1. Earnings overview cards (top row)
Four stat cards in a horizontal grid:
- Total Earned (lifetime) — pulled from contract
get_earnings + local tx history
- This Month — filtered from local transaction history
- Pending Withdrawal — current
get_earnings value (existing)
- Total Sales — count of all purchases across producer's beats
Each card: large number, label, percentage change vs last month (↑12% / ↓3%), sparkline mini-chart.
2. Revenue chart (src/components/RevenueChart.tsx)
- Area chart showing earnings over time (last 30 days, 90 days, 1 year toggle)
- X-axis: dates. Y-axis: XLM earned
- Hover tooltip: exact date + amount
- Data source: local transaction history aggregated by day
- Library: lightweight — use a simple SVG chart (no heavy charting lib). ~200 lines.
- Fallback: if no data, show "No sales data yet" with a CTA to upload beats
3. Beat performance table
- Table listing all beats the producer has uploaded
- Columns: Beat Title, Genre, Total Sales, Revenue, Avg Price, Last Sold, Status (Active/Delisted)
- Sortable columns (click header to sort)
- Click row → navigate to sample detail page
- Row highlight for top-performing beat (gold left border)
4. Recent sales feed
- Chronological list of the last 20 sales
- Each entry: beat title, buyer address (truncated), tier purchased, amount, timestamp
- Real-time: poll contract or backend every 30 seconds for new sales
- New sale notification: toast + subtle animation on the new row
- "View on Explorer" link for each tx hash
5. Withdrawal history (src/components/WithdrawalHistory.tsx)
- Table below the withdraw button
- Columns: Date, Amount, Tx Hash, Status (Confirmed/Pending)
- Data from local storage (record each withdrawal)
- Tx hash links to Stellar block explorer
- Total withdrawn all-time at the bottom
6. Data hooks
src/hooks/useProducerStats.ts — aggregates contract data + local history
totalEarned, monthlyEarnings, totalSales, topBeat, salesByDay
src/hooks/useSalesFeed.ts — polls for new sales, maintains a reactive list
- Polls every 30s when tab is visible, pauses when hidden
- Returns
{ sales, newSaleCount, loading }
src/services/analytics.ts — local analytics aggregation
aggregateSalesByDay(history) — groups sales into daily buckets for chart
calculateGrowth(current, previous) — percentage change
7. Local storage schema
interface SaleRecord {
txHash: string;
sampleId: number;
sampleTitle: string;
buyer: string;
tier: "lease" | "premium" | "exclusive";
amount: string; // in XLM
token: string;
timestamp: number;
}
interface WithdrawalRecord {
txHash: string;
amount: string;
timestamp: number;
status: "confirmed" | "pending";
}
- Key:
crate_sales_{producerAddress} and crate_withdrawals_{producerAddress}
- Max 500 records per key (oldest auto-pruned)
UI layout
┌─────────────────────────────────────────────────────────┐
│ Profile │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Total │ │This │ │Pending │ │Total │ │
│ │Earned │ │Month │ │Balance │ │Sales │ │
│ │1,240 XLM│ │320 XLM │ │45.50 XLM│ │28 │ │
│ │↑12% ↑ │ │↑8% ↑ │ │ │ │↑3 this wk│ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Revenue (30d) │ │
│ │ ╭──╮ ╭──╮ │ │
│ │ ╭╯ ╰──╮╯ ╰──╮ │ │
│ │╯ ╰ ╰── │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────┐ ┌──────────────────────────┐ │
│ │ Beat Performance │ │ Recent Sales │ │
│ │ Title | Sales | Rev │ │ Beat - Buyer - Tier - $ │ │
│ │ ──────┼───────┼────── │ │ ────────────────────── │ │
│ │ Mid.. │ 12 │ 340 │ │ Midnight.. GBB.. Lease 25 │ │
│ │ Lag.. │ 8 │ 210 │ │ Lagos Su.. GCY.. Prem 200 │ │
│ └───────────────────────┘ └──────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Withdrawal History │ │
│ │ Date | Amount | Tx Hash | Status │ │
│ │ 2026-08-10 | 45.50 | abc123... | Confirmed │ │
│ └────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Files to create/modify
src/pages/Profile.tsx — full rewrite with dashboard layout
src/components/RevenueChart.tsx — new (SVG area chart)
src/components/StatsCard.tsx — new (reusable stat card with sparkline)
src/components/BeatPerformanceTable.tsx — new
src/components/SalesFeed.tsx — new
src/components/WithdrawalHistory.tsx — new
src/hooks/useProducerStats.ts — new
src/hooks/useSalesFeed.ts — new
src/services/analytics.ts — new
src/index.css — dashboard grid, table, chart styles
Acceptance criteria
Labels
enhancement Maybe Rewarded GrantFox OSS Official Campaign | FWC26
Summary
Transform the Profile page from a basic wallet card + withdraw button into a full producer earnings dashboard with sales analytics, revenue charts, beat performance metrics, and withdrawal history. Producers should be able to see exactly how their beats are performing at a glance.
Why
get_earningsandget_stats— we need to surface this data in a useful way.What to build
1. Earnings overview cards (top row)
Four stat cards in a horizontal grid:
get_earnings+ local tx historyget_earningsvalue (existing)Each card: large number, label, percentage change vs last month (↑12% / ↓3%), sparkline mini-chart.
2. Revenue chart (
src/components/RevenueChart.tsx)3. Beat performance table
4. Recent sales feed
5. Withdrawal history (
src/components/WithdrawalHistory.tsx)6. Data hooks
src/hooks/useProducerStats.ts— aggregates contract data + local historytotalEarned,monthlyEarnings,totalSales,topBeat,salesByDaysrc/hooks/useSalesFeed.ts— polls for new sales, maintains a reactive list{ sales, newSaleCount, loading }src/services/analytics.ts— local analytics aggregationaggregateSalesByDay(history)— groups sales into daily buckets for chartcalculateGrowth(current, previous)— percentage change7. Local storage schema
crate_sales_{producerAddress}andcrate_withdrawals_{producerAddress}UI layout
Files to create/modify
src/pages/Profile.tsx— full rewrite with dashboard layoutsrc/components/RevenueChart.tsx— new (SVG area chart)src/components/StatsCard.tsx— new (reusable stat card with sparkline)src/components/BeatPerformanceTable.tsx— newsrc/components/SalesFeed.tsx— newsrc/components/WithdrawalHistory.tsx— newsrc/hooks/useProducerStats.ts— newsrc/hooks/useSalesFeed.ts— newsrc/services/analytics.ts— newsrc/index.css— dashboard grid, table, chart stylesAcceptance criteria
Labels
enhancementMaybe RewardedGrantFox OSSOfficial Campaign | FWC26