import { useEffect, useState } from 'react' import { View, Text, ScrollView, TouchableOpacity, StyleSheet, ActivityIndicator, RefreshControl, } from 'react-native' import AsyncStorage from '@react-native-async-storage/async-storage' import { api } from '../../app/lib/api' const COLORS = { bg: '#0F172A', card: '#1E293B', teal: '#0D9488', amber: '#F59E0B', green: '#10B981', text: '#F8FAFC', muted: '#94A3B8' } 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, (revenue / fee) * 100) const broke = revenue >= fee return ( ) } export default function EarningsScreen() { const [days, setDays] = useState(7) const [earnings, setEarnings] = useState([]) const [loading, setLoading] = useState(true) const [refreshing, setRefreshing] = useState(false) useEffect(() => { load() }, [days]) const load = async () => { setLoading(true) try { const token = await AsyncStorage.getItem('token') if (!token) return const data = await api.get(`/drivers/me/earnings?days=${days}`, token) setEarnings(data) } catch { /* silent */ } finally { setLoading(false) setRefreshing(false) } } const totals = earnings.reduce( (acc, d) => ({ deliveries: acc.deliveries + (d.deliveries_count || 0), gross: acc.gross + Number(d.delivery_revenue || 0), tips: acc.tips + Number(d.tips_earned || 0), net: acc.net + Number(d.net_earnings || 0), daysWorked: acc.daysWorked + 1, }), { deliveries: 0, gross: 0, tips: 0, net: 0, daysWorked: 0 }, ) const avgPerDay = totals.daysWorked > 0 ? totals.net / totals.daysWorked : 0 const avgDeliveries = totals.daysWorked > 0 ? totals.deliveries / totals.daysWorked : 0 const PERIODS = [ { label: '7d', value: 7 }, { label: '14d', value: 14 }, { label: '30d', value: 30 }, { label: '90d', value: 90 }, ] return ( { setRefreshing(true); load() }} tintColor={COLORS.teal} />} > {/* Period selector */} {PERIODS.map(p => ( setDays(p.value)} style={[styles.periodBtn, days === p.value && styles.periodBtnActive]} > {p.label} ))} {/* Summary cards */} Net Earnings ${totals.net.toFixed(2)} after daily fees Tips ${totals.tips.toFixed(2)} 100% yours Deliveries {totals.deliveries} {totals.daysWorked} days worked Avg / Day ${avgPerDay.toFixed(2)} {avgDeliveries.toFixed(1)} deliveries avg {/* Break-even insight */} {totals.daysWorked > 0 && ( {avgDeliveries >= 4 ? '✅ Breaking even on average!' : '⚠️ Below break-even average'} You average {avgDeliveries.toFixed(1)} deliveries/day. Break-even = 4 deliveries ($5 × 4 = $20 fee). Every delivery past #4 is pure profit. )} {/* Day-by-day */} Daily Breakdown {loading ? ( ) : earnings.length === 0 ? ( No earnings in this period ) : ( earnings.map((day, i) => { const net = Number(day.net_earnings || 0) const revenue = Number(day.delivery_revenue || 0) const fee = Number(day.daily_fee || 20) const tips = Number(day.tips_earned || 0) const date = new Date(day.session_date) const isProfitable = net > 0 return ( 0 && { borderTopColor: '#334155', borderTopWidth: 1 }]}> {date.toLocaleDateString('en-CA', { weekday: 'short', month: 'short', day: 'numeric' })} {day.deliveries_count} deliveries{tips > 0 ? ` · $${tips.toFixed(2)} tips` : ''} {isProfitable ? '+' : ''}${net.toFixed(2)} ${revenue.toFixed(2)} − $20 ) }) )} {/* How it works */} How Your Pay Works {[ ['Daily access fee', '$20.00'], ['Per delivery', '$5.00 flat'], ['Tips', '100% yours'], ['Commission taken', '$0.00'], ['Break-even at', '4 deliveries'], ].map(([label, val]) => ( {label} {val} ))} ) } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: COLORS.bg }, periodRow: { flexDirection: 'row', gap: 8, paddingHorizontal: 16, paddingTop: 16, paddingBottom: 8 }, periodBtn: { flex: 1, paddingVertical: 8, backgroundColor: COLORS.card, borderRadius: 8, alignItems: 'center' }, periodBtnActive: { backgroundColor: COLORS.teal }, periodBtnText: { color: COLORS.muted, fontWeight: '600', fontSize: 13 }, cardRow: { flexDirection: 'row', paddingHorizontal: 16, marginBottom: 10 }, card: { backgroundColor: COLORS.card, borderRadius: 12, padding: 14 }, cardLabel: { color: COLORS.muted, fontSize: 12, marginBottom: 4 }, cardValue: { color: COLORS.text, fontSize: 22, fontWeight: 'bold' }, cardSub: { color: COLORS.muted, fontSize: 11, marginTop: 2 }, sectionTitle: { color: COLORS.text, fontWeight: '700', fontSize: 15, marginBottom: 12 }, dayRow: { paddingVertical: 12, flexDirection: 'row', alignItems: 'center' }, barBg: { height: 4, backgroundColor: '#334155', borderRadius: 2, marginTop: 4 }, barFill: { height: 4, borderRadius: 2 }, infoRow: { flexDirection: 'row', justifyContent: 'space-between', paddingVertical: 6, borderBottomColor: '#334155', borderBottomWidth: 1 }, })