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,
},
});