import React, { useState } from 'react'; import { Alert, View, Text, ScrollView, Switch, StyleSheet } from 'react-native'; import Constants from 'expo-constants'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { LinearGradient } from 'expo-linear-gradient'; import { ChevronRight, Lock, Check } from 'lucide-react-native'; import { Colors, Fonts, FontSize, BorderRadius, Spacing } from '@/constants/theme'; import SegmentedControl from '@/components/SegmentedControl'; import AnimatedCard from '@/components/AnimatedCard'; import PressableScale from '@/components/PressableScale'; import { useTradingData } from '@/providers/TradingDataProvider'; import { useMobileAuth } from '@/providers/MobileAuthProvider'; export default function SettingsScreen() { const insets = useSafeAreaInsets(); const { botState, portfolio, pauseTrading, resumeTrading, connectionState, error, lastUpdatedAt } = useTradingData(); const { profile, signOut } = useMobileAuth(); const executionModeIndex = botState?.settings.executionMode === 'Live' ? 2 : botState?.settings.executionMode === 'Paper' ? 1 : 0; const [maxOpenTrades, setMaxOpenTrades] = useState(botState?.settings.maxOpenTrades || 3); const [notifications, setNotifications] = useState({ priceAlerts: true, tradeExecuted: true, stopLoss: true, dailySummary: false, }); const [oledBlack, setOledBlack] = useState(false); const tradingMode = botState?.health?.tradingControl?.mode ?? 'RUNNING'; const isAdmin = profile?.role === 'admin'; const brokerStatusText = connectionState === 'live' ? 'Connected' : connectionState === 'degraded' ? 'Degraded' : 'Offline'; const brokerHint = error ? error : connectionState === 'live' ? tradingMode === 'PAUSED' ? 'Trading is currently paused.' : 'Broker state is sourced from the live backend.' : lastUpdatedAt ? `Last backend sync ${Math.max(Math.round((Date.now() - lastUpdatedAt) / 60000), 0)}m ago.` : 'Waiting for backend connectivity.'; const modeColors = [Colors.text.secondary, Colors.accent.blue, Colors.accent.orange]; return ( CONFIGURATION Settings ACCOUNT {`${profile?.first_name?.[0] || profile?.email?.[0] || 'T'}${profile?.last_name?.[0] || ''}`.slice(0, 2).toUpperCase()} {[profile?.first_name, profile?.last_name].filter(Boolean).join(' ') || 'Trading User'} {profile?.email || 'No email loaded'} {(profile?.role || 'member').toUpperCase()} EXECUTION MODE undefined} activeColor={modeColors[executionModeIndex]} activeTextColor={executionModeIndex === 2 ? '#fff' : '#000'} /> Execution mode is managed from the web dashboard. {executionModeIndex === 2 && ( Real money trading enabled. Use caution. )} RISK CONFIGURATION {(Number(botState?.settings.riskPerTrade || 0) * 100).toFixed(2)}% setMaxOpenTrades(Math.max(1, maxOpenTrades - 1))} > - {maxOpenTrades} setMaxOpenTrades(Math.min(10, maxOpenTrades + 1))} > + ${portfolio.totalCapital.toLocaleString()} BROKER CONNECTION Alpaca {brokerStatusText} {brokerHint} {isAdmin ? ( TRADING CONTROL Mobile is monitor-first. Only limited safety controls are exposed here. { const result = await pauseTrading('Paused from mobile control surface'); if (result.error) { Alert.alert('Pause failed', result.error); } }} > Pause Trading { const result = await resumeTrading('Resumed from mobile control surface'); if (result.error) { Alert.alert('Resume failed', result.error); } }} > Resume Trading ) : null} NOTIFICATIONS setNotifications(n => ({ ...n, priceAlerts: v }))} /> setNotifications(n => ({ ...n, tradeExecuted: v }))} /> setNotifications(n => ({ ...n, stopLoss: v }))} /> setNotifications(n => ({ ...n, dailySummary: v }))} /> APPEARANCE Dark Mode ABOUT Version v{Constants.expoConfig?.version ?? '1.0.0'} { Alert.alert('Sign Out', 'Are you sure you want to sign out?', [ { text: 'Cancel', style: 'cancel' }, { text: 'Sign Out', style: 'destructive', onPress: () => void signOut() }, ]); }}> Sign Out Terms of Service Support ); } function SettingRow({ label, children }: { label: string; children: React.ReactNode }) { return ( {label} {children} ); } function ToggleRow({ label, value, onChange }: { label: string; value: boolean; onChange: (v: boolean) => void }) { return ( {label} ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: Colors.background.primary, }, headerSection: { padding: Spacing.screenPadding, paddingBottom: 0, }, sectionLabel: { fontFamily: Fonts.inter.black, fontSize: FontSize.micro, color: Colors.accent.green, letterSpacing: 4, marginBottom: 8, }, pageTitle: { fontFamily: Fonts.inter.black, fontSize: FontSize.hero, color: Colors.text.primary, letterSpacing: -0.5, marginBottom: 16, }, scroll: { flex: 1, }, content: { padding: Spacing.screenPadding, gap: 16, paddingBottom: 120, }, section: { backgroundColor: Colors.background.card, borderRadius: BorderRadius.large, padding: Spacing.cardPadding, borderWidth: 1, borderColor: Colors.border.default, gap: 14, }, sectionHeader: { fontFamily: Fonts.inter.black, fontSize: FontSize.micro, color: Colors.text.secondary, letterSpacing: 3, }, accountRow: { flexDirection: 'row', alignItems: 'center', gap: 14, }, avatar: { width: 48, height: 48, borderRadius: 24, alignItems: 'center', justifyContent: 'center', }, avatarText: { fontFamily: Fonts.inter.black, fontSize: FontSize.subheading, color: '#000', }, accountInfo: { flex: 1, }, accountName: { fontFamily: Fonts.inter.extraBold, fontSize: FontSize.subheading, color: Colors.text.primary, }, accountEmail: { fontFamily: Fonts.inter.medium, fontSize: FontSize.body, color: Colors.text.secondary, }, tierBadge: { backgroundColor: 'rgba(0,255,136,0.1)', borderWidth: 1, borderColor: 'rgba(0,255,136,0.2)', paddingHorizontal: 10, paddingVertical: 4, borderRadius: 6, }, tierText: { fontFamily: Fonts.inter.black, fontSize: FontSize.micro, color: Colors.accent.green, letterSpacing: 1, }, readOnlyHint: { fontFamily: Fonts.mono.regular, fontSize: FontSize.micro, color: Colors.text.muted, marginTop: 4, }, warningBanner: { backgroundColor: 'rgba(230,126,34,0.1)', borderWidth: 1, borderColor: 'rgba(230,126,34,0.2)', borderRadius: BorderRadius.xs, padding: 12, marginTop: 4, }, warningText: { fontFamily: Fonts.inter.semiBold, fontSize: FontSize.bodySmall, color: Colors.accent.orange, }, settingRow: { gap: 10, }, settingLabel: { fontFamily: Fonts.inter.semiBold, fontSize: FontSize.body, color: Colors.text.primary, }, sliderRow: { flexDirection: 'row', alignItems: 'center', gap: 12, }, sliderTrack: { flex: 1, height: 6, borderRadius: 3, backgroundColor: Colors.background.elevated, overflow: 'hidden', }, sliderFill: { height: 6, borderRadius: 3, backgroundColor: Colors.accent.green, }, sliderValue: { fontFamily: Fonts.mono.bold, fontSize: FontSize.bodyLarge, color: Colors.accent.green, minWidth: 40, textAlign: 'right', }, stepperRow: { flexDirection: 'row', alignItems: 'center', gap: 16, }, stepperBtn: { width: 36, height: 36, borderRadius: 10, backgroundColor: Colors.background.elevated, alignItems: 'center', justifyContent: 'center', borderWidth: 1, borderColor: Colors.border.subtle, }, stepperBtnText: { fontFamily: Fonts.inter.bold, fontSize: FontSize.heading, color: Colors.text.primary, }, stepperValue: { fontFamily: Fonts.mono.bold, fontSize: FontSize.heading, color: Colors.text.primary, minWidth: 30, textAlign: 'center', }, capitalValue: { fontFamily: Fonts.mono.bold, fontSize: FontSize.subheading, color: Colors.text.primary, }, brokerRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, brokerName: { fontFamily: Fonts.inter.bold, fontSize: FontSize.bodyLarge, color: Colors.text.primary, }, connectedBadge: { flexDirection: 'row', alignItems: 'center', gap: 6, }, connectedText: { fontFamily: Fonts.inter.semiBold, fontSize: FontSize.bodySmall, color: Colors.accent.green, }, degradedText: { color: Colors.accent.amber, }, offlineText: { color: Colors.accent.red, }, apiKeyHint: { fontFamily: Fonts.mono.regular, fontSize: FontSize.bodySmall, color: Colors.text.muted, }, toggleRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, toggleLabel: { flexDirection: 'row', alignItems: 'center', gap: 8, }, toggleText: { fontFamily: Fonts.inter.semiBold, fontSize: FontSize.body, color: Colors.text.primary, }, aboutRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', }, aboutLabel: { fontFamily: Fonts.inter.medium, fontSize: FontSize.body, color: Colors.text.secondary, }, aboutValue: { fontFamily: Fonts.mono.medium, fontSize: FontSize.body, color: Colors.text.primary, }, linkRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 4, }, linkText: { fontFamily: Fonts.inter.semiBold, fontSize: FontSize.body, color: Colors.text.primary, }, actionRow: { flexDirection: 'row', gap: 10, marginTop: 14, }, actionButton: { flex: 1, borderRadius: BorderRadius.medium, backgroundColor: 'rgba(255,149,0,0.16)', borderWidth: 1, borderColor: 'rgba(255,149,0,0.35)', paddingVertical: 12, alignItems: 'center', }, actionButtonSuccess: { backgroundColor: 'rgba(0,255,136,0.14)', borderColor: 'rgba(0,255,136,0.35)', }, actionButtonDisabled: { opacity: 0.45, }, actionButtonText: { fontFamily: Fonts.inter.black, fontSize: FontSize.badge, color: Colors.text.primary, letterSpacing: 0.5, }, });