learning_ai_invt_trdg/mobile/components/auth/AuthGate.tsx

143 lines
4.1 KiB
TypeScript

import React, { useMemo, useState } from 'react';
import { ActivityIndicator, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
import type { ReactNode } from 'react';
import { LinearGradient } from 'expo-linear-gradient';
import { Colors, Fonts, FontSize, BorderRadius, Spacing } from '@/constants/theme';
import { useMobileAuth } from '@/providers/MobileAuthProvider';
export function AuthGate({ children }: { children: ReactNode }) {
const { user, loading, signIn, error } = useMobileAuth();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [submitting, setSubmitting] = useState(false);
const errorMessage = useMemo(() => error, [error]);
if (loading) {
return (
<View style={styles.centered}>
<ActivityIndicator size="large" color={Colors.accent.green} />
<Text style={styles.loadingText}>Restoring trading session...</Text>
</View>
);
}
if (user) {
return <>{children}</>;
}
return (
<View style={styles.screen}>
<LinearGradient colors={['#14151f', '#0f1017']} style={styles.card}>
<Text style={styles.eyebrow}>BYTElyst TRADING</Text>
<Text style={styles.title}>Sign in to your trading workspace</Text>
<Text style={styles.subtitle}>
Mobile now authenticates against the shared platform-service identity boundary used across the ecosystem.
</Text>
<TextInput
value={email}
onChangeText={setEmail}
style={styles.input}
placeholder="Email"
placeholderTextColor={Colors.text.ultraDim}
autoCapitalize="none"
keyboardType="email-address"
/>
<TextInput
value={password}
onChangeText={setPassword}
style={styles.input}
placeholder="Password"
placeholderTextColor={Colors.text.ultraDim}
autoCapitalize="none"
secureTextEntry
/>
{errorMessage ? <Text style={styles.error}>{errorMessage}</Text> : null}
<Pressable
style={styles.button}
disabled={submitting}
onPress={async () => {
setSubmitting(true);
await signIn(email.trim(), password);
setSubmitting(false);
}}
>
<Text style={styles.buttonText}>{submitting ? 'Signing in...' : 'Sign In'}</Text>
</Pressable>
</LinearGradient>
</View>
);
}
const styles = StyleSheet.create({
screen: {
flex: 1,
backgroundColor: Colors.background.primary,
justifyContent: 'center',
padding: Spacing.screenPadding,
},
centered: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: Colors.background.primary,
gap: 12,
},
loadingText: {
fontFamily: Fonts.inter.medium,
fontSize: FontSize.body,
color: Colors.text.secondary,
},
card: {
borderRadius: BorderRadius.large,
borderWidth: 1,
borderColor: Colors.border.default,
padding: Spacing.cardPaddingLarge,
gap: 14,
},
eyebrow: {
fontFamily: Fonts.inter.black,
fontSize: FontSize.micro,
color: Colors.accent.green,
letterSpacing: 3,
},
title: {
fontFamily: Fonts.inter.black,
fontSize: FontSize.heading,
color: Colors.text.primary,
},
subtitle: {
fontFamily: Fonts.inter.medium,
fontSize: FontSize.body,
color: Colors.text.secondary,
lineHeight: 21,
},
input: {
borderWidth: 1,
borderColor: Colors.border.default,
borderRadius: BorderRadius.medium,
backgroundColor: Colors.background.card,
color: Colors.text.primary,
paddingHorizontal: 14,
paddingVertical: 12,
fontFamily: Fonts.inter.medium,
fontSize: FontSize.body,
},
button: {
marginTop: 6,
borderRadius: BorderRadius.medium,
backgroundColor: Colors.accent.green,
paddingVertical: 14,
alignItems: 'center',
},
buttonText: {
fontFamily: Fonts.inter.black,
fontSize: FontSize.body,
color: '#04120b',
},
error: {
fontFamily: Fonts.inter.medium,
fontSize: FontSize.bodySmall,
color: Colors.accent.red,
},
});