'use client' import { useEffect, useState } from 'react' import { useRouter } from 'next/navigation' import axios from 'axios' import { format, parseISO } from 'date-fns' const API = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001/api/v1' interface DayEarning { session_date: string deliveries_count: number delivery_revenue: number tips_earned: number net_earnings: number daily_fee: number fee_paid: boolean } function BreakEvenBar({ revenue, fee }: { revenue: number; fee: number }) { const pct = Math.min(100, Math.round((revenue / fee) * 100)) const broke = revenue >= fee return (
{broke ? 'Profitable!' : `${Math.ceil((fee - revenue) / 5)} deliveries to break even`} {pct}%
) } export default function DriverEarningsPage() { const router = useRouter() const [days, setDays] = useState(30) const [earnings, setEarnings] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState('') useEffect(() => { const token = localStorage.getItem('token') if (!token) { router.push('/login'); return } fetchEarnings(token) }, [days]) const fetchEarnings = async (token: string) => { setLoading(true) try { const { data } = await axios.get(`${API}/drivers/me/earnings?days=${days}`, { headers: { Authorization: `Bearer ${token}` }, }) setEarnings(data) } catch (err: any) { setError(err.response?.data?.message || 'Failed to load earnings') } finally { setLoading(false) } } // Aggregate stats const totals = earnings.reduce( (acc, d) => ({ deliveries: acc.deliveries + (d.deliveries_count || 0), grossRevenue: acc.grossRevenue + Number(d.delivery_revenue || 0), tips: acc.tips + Number(d.tips_earned || 0), netEarnings: acc.netEarnings + Number(d.net_earnings || 0), fees: acc.fees + Number(d.daily_fee || 0), daysWorked: acc.daysWorked + 1, }), { deliveries: 0, grossRevenue: 0, tips: 0, netEarnings: 0, fees: 0, daysWorked: 0 }, ) const avgPerDay = totals.daysWorked > 0 ? totals.netEarnings / totals.daysWorked : 0 return (
{/* Header */}

Earnings History

Your delivery earnings breakdown

{/* Period selector */}
{[7, 14, 30, 90].map(d => ( ))}
{/* Summary cards */}

Net Earnings

${totals.netEarnings.toFixed(2)}

after $20/day fees

Total Deliveries

{totals.deliveries}

{totals.daysWorked} days worked

Tips Earned

${totals.tips.toFixed(2)}

100% yours

Avg / Day

${avgPerDay.toFixed(2)}

on days worked

{/* Break-even insight */} {totals.daysWorked > 0 && (

Your average: {(totals.deliveries / totals.daysWorked).toFixed(1)} deliveries/day — break-even at 4/day ($20 ÷ $5 = 4 deliveries)

You're earning {Math.round(totals.deliveries / totals.daysWorked) > 4 ? 'above' : 'near'} break-even on average. Every delivery after #4 is pure profit.

)} {/* Day-by-day table */}

Day-by-Day Breakdown

{loading ? (
Loading earnings...
) : error ? (
{error}
) : earnings.length === 0 ? (

No earnings data for this period

Start delivering to see your earnings here

) : (
{earnings.map((day) => { const net = Number(day.net_earnings || 0) const fee = Number(day.daily_fee || 20) const revenue = Number(day.delivery_revenue || 0) const tips = Number(day.tips_earned || 0) const isProfitable = net > 0 return (

{format(parseISO(day.session_date), 'EEE, MMM d')}

{day.deliveries_count} deliveries {tips > 0 && ` · $${tips.toFixed(2)} tips`}

{isProfitable ? '+' : ''}${net.toFixed(2)}

$${revenue.toFixed(2)} earned − $${fee.toFixed(2)} fee {!day.fee_paid && ' (unpaid)'}

) })}
)}
{/* How earnings work */}

How Your Earnings Work

Daily access fee$20.00
Per delivery$5.00 flat
Tips100% yours
Commission taken$0.00
Break-even at4 deliveries
) }