import { StyleSheet, Text, View, TouchableOpacity, TextInput, ActivityIndicator, KeyboardAvoidingView, Animated } from 'react-native'
import { useState, useRef } from 'react';
import { AntDesign } from '@expo/vector-icons';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useAppTheme } from '../hooks/colorScheme';
import FeaturesSlideshow from '../components/FeaturesSlideshow'
import Purchases from 'react-native-purchases';
import React from 'react'
import { doc, setDoc } from 'firebase/firestore';
import { FIREBASE_DB } from '../FirebaseConfig';
import { FIREBASE_AUTH } from '../FirebaseConfig'
import { createUserWithEmailAndPassword } from 'firebase/auth'
const Onboarding = ({ navigation }) => {
const colors = useAppTheme();
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
const fadeAnim = useRef(new Animated.Value(0)).current;
const auth = FIREBASE_AUTH
const showError = (message) => {
setError(message);
fadeAnim.setValue(0);
Animated.timing(fadeAnim, {
toValue: 1,
duration: 200,
useNativeDriver: true,
}).start();
};
const handleEmailChange = (text) => {
setEmail(text);
if (error) setError('');
};
const handlePasswordChange = (text) => {
setPassword(text);
if (error) setError('');
};
const getDetailedErrorMessage = (error) => {
const errorCode = error.code?.replace('auth/', '') || 'internal-error';
const errorMessages = {
'invalid-email': 'Please enter a valid email address.',
'email-already-in-use': 'This email is already registered. Please try signing in instead.',
'weak-password': 'Password should be at least 6 characters long.',
'operation-not-allowed': 'Email/password sign up is not enabled. Please contact support.',
'network-request-failed': 'Connection failed. Please check your internet and try again.',
'too-many-requests': 'Too many attempts. Please try again later.',
'internal-error': 'An unexpected error occurred. Please try again.',
'invalid-credential': 'Invalid signup credentials. Please check your information.',
'user-disabled': 'This account has been disabled. Please contact support.',
'missing-email': 'Please enter an email address.',
'missing-password': 'Please enter a password.',
};
return errorMessages[errorCode] ||
'Something went wrong. Please try again or contact support if the problem persists.';
};
const handleFirebaseError = (error) => {
const message = getDetailedErrorMessage(error);
showError(message);
};
const validateForm = () => {
if (!email.trim()) {
showError('Please enter an email address');
return false;
}
if (!password.trim()) {
showError('Please enter a password');
return false;
}
// Basic email format validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
showError('Please enter a valid email address');
return false;
}
// Basic password strength validation
if (password.length < 6) {
showError('Password must be at least 6 characters long');
return false;
}
return true;
};
const signUp = async () => {
if (!validateForm()) return;
setLoading(true);
try {
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
await AsyncStorage.setItem('email', email);
await AsyncStorage.setItem('password', password);
await AsyncStorage.setItem('isLoggedOut', 'false');
await addUserToCollection(email, userCredential.user.uid);
} catch (error) {
handleFirebaseError(error);
console.error('Signup error:', error);
} finally {
setLoading(false);
}
};
const addUserToCollection = async (email, uid) => {
const userDocRef = doc(FIREBASE_DB, "users", uid);
await setDoc(userDocRef, {
email: email,
createdAt: new Date(),
uid: uid,
});
// set default goals if there are none already
if (!(await AsyncStorage.getItem('userGoals'))) {
const defaultGoals = {
protein: '150',
carbs: '150',
fats: '100',
dailyCalories: '2100',
transFat: '2',
saturatedFat: '20',
polyunsaturatedFat: '17',
monounsaturatedFat: '44',
netCarbs: '53',
sugar: '25',
fiber: '28',
cholesterol: '300',
sodium: '2300',
calcium: '1000',
magnesium: '400',
phosphorus: '700',
potassium: '3400',
iron: '18',
copper: '900',
zinc: '11',
manganese: '2.3',
selenium: '55',
vitaminA: '900',
vitaminD: '20',
vitaminE: '15',
vitaminK: '120',
vitaminC: '90',
vitaminB1: '1.2',
vitaminB12: '2.4',
vitaminB2: '1.3',
vitaminB3: '16',
vitaminB5: '5',
vitaminB6: '1.7',
folate: '400',
};
await AsyncStorage.setItem('userGoals', JSON.stringify(defaultGoals));
}
}
return (
<View style={[styles.container, {backgroundColor: colors.background}]}>
<KeyboardAvoidingView behavior='padding' style={styles.mainContainer}>
<View style={styles.intro}>
<Text style={[styles.subtitle, {color:colors.text}]}>You're too intelligent for all the BS</Text>
<Text style={{color: colors.text, fontSize: 16}}>Let's get you started with a free account</Text>
</View>
<View style={styles.inputContainer}>
<View style={styles.inputWrapper}>
<Text style={[styles.inputLabel, {color: colors.text}]}>Email</Text>
<TextInput
style={[styles.input, {
color: colors.text,
backgroundColor: colors.boxes,
borderColor: error ? colors.accent : colors.boxes,
borderWidth: error ? 2 : 1,
}]}
placeholder="Enter your email"
placeholderTextColor={colors.text + '40'}
value={email}
onChangeText={handleEmailChange}
keyboardType='email-address'
autoCapitalize='none'
/>
</View>
<View style={styles.inputWrapper}>
<Text style={[styles.inputLabel, {color: colors.text}]}>Password</Text>
<TextInput
style={[styles.input, {
color: colors.text,
backgroundColor: colors.boxes,
borderColor: error ? colors.accent : colors.boxes,
borderWidth: error ? 2 : 1,
}]}
placeholder="Create a password"
placeholderTextColor={colors.text + '40'}
value={password}
onChangeText={handlePasswordChange}
secureTextEntry
/>
</View>
</View>
<TouchableOpacity
style={[styles.getStartedBtn, { opacity: loading ? 0.7 : 1}]}
onPress={signUp}
disabled={loading}
>
{loading ? (
<ActivityIndicator size="small" color={colors.accent} />
) : (
<View style={{marginHorizontal: 'auto', flexDirection: 'row', alignItems: 'center'}}>
<Text style={[styles.actionText, {color:colors.accent}]}>Sign Up</Text>
<AntDesign name="right" size={24} color={colors.accent} />
</View>
)}
</TouchableOpacity>
<View style={styles.errorOuterContainer}>
<Animated.View style={[styles.errorContainer, {
opacity: fadeAnim,
backgroundColor: error ? colors.accent + '15' : 'transparent',
transform: [{
translateY: fadeAnim.interpolate({
inputRange: [0, 1],
outputRange: [5, 0]
})
}]
}]}>
{error ? (
<View style={styles.errorWrapper}>
<Text style={[styles.errorText, { color: colors.accent }]} numberOfLines={3}>
{error}
</Text>
</View>
) : null}
</Animated.View>
</View>
</KeyboardAvoidingView>
<TouchableOpacity
style={styles.getStartedBtn}
onPress={() => navigation.navigate('Login')}
>
<Text style={[{color:colors.text, fontSize: 16}]}>Already have an account? Sign in</Text>
<AntDesign name="right" size={16} color={colors.text} />
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginHorizontal: 'auto',
justifyContent: 'center'
},
intro: {
gap: 10,
alignItems: 'center',
textAlign: 'center',
width: '100%',
padding: 5,
},
getStartedBtn: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
padding: 16,
borderRadius: 12,
minHeight: 56,
},
actionText: {
fontSize: 24,
fontWeight: 'bold',
},
subtitle: {
fontSize: 20,
fontWeight: 'bold'
},
mainContainer: {
width: '100%',
padding: 30,
alignItems: 'center',
gap: 25,
},
inputContainer: {
width: '100%',
gap: 20,
marginTop: 20,
minHeight: 180,
},
inputWrapper: {
width: '100%',
minHeight: 85,
},
inputLabel: {
fontSize: 16,
fontWeight: '600',
marginBottom: 8,
marginLeft: 4,
},
input: {
width: 300,
padding: 16,
borderRadius: 12,
fontSize: 16,
minHeight: 56,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.05,
shadowRadius: 4,
elevation: 2,
},
errorOuterContainer: {
width: '100%',
minHeight: 70,
maxHeight: 100,
marginVertical: 8,
justifyContent: 'center',
},
errorContainer: {
width: '100%',
borderRadius: 12,
padding: 12,
justifyContent: 'center',
alignItems: 'center',
},
errorWrapper: {
width: '100%',
paddingHorizontal: 16,
},
errorText: {
fontSize: 14,
fontWeight: '500',
textAlign: 'center',
lineHeight: 20,
flexWrap: 'wrap',
},
})
export default Onboarding