diff --git a/src/screens/AuthScreen.tsx b/src/screens/AuthScreen.tsx index 3c9a0672e..eeb9741aa 100644 --- a/src/screens/AuthScreen.tsx +++ b/src/screens/AuthScreen.tsx @@ -5,7 +5,7 @@ import { LinearGradient } from 'expo-linear-gradient'; import { MaterialIcons } from '@expo/vector-icons'; import { useTheme } from '../contexts/ThemeContext'; import { useAccount } from '../contexts/AccountContext'; -import { useNavigation } from '@react-navigation/native'; +import { useNavigation, useRoute } from '@react-navigation/native'; import * as Haptics from 'expo-haptics'; import ToastOverlay from '../components/common/ToastOverlay'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; @@ -16,11 +16,15 @@ const AuthScreen: React.FC = () => { const { currentTheme } = useTheme(); const { signIn, signUp } = useAccount(); const navigation = useNavigation(); + const route = useRoute(); + const fromOnboarding = !!route?.params?.fromOnboarding; const insets = useSafeAreaInsets(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); const [showPassword, setShowPassword] = useState(false); + const [showConfirm, setShowConfirm] = useState(false); const [mode, setMode] = useState<'signin' | 'signup'>('signin'); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); @@ -131,7 +135,9 @@ const AuthScreen: React.FC = () => { const isEmailValid = useMemo(() => /\S+@\S+\.\S+/.test(email.trim()), [email]); const isPasswordValid = useMemo(() => password.length >= 6, [password]); - const canSubmit = isEmailValid && isPasswordValid; + const isConfirmValid = useMemo(() => (mode === 'signin') || confirmPassword.length >= 6, [confirmPassword, mode]); + const passwordsMatch = useMemo(() => (mode === 'signin') || confirmPassword === password, [confirmPassword, password, mode]); + const canSubmit = isEmailValid && isPasswordValid && (mode === 'signin' || (isConfirmValid && passwordsMatch)); const handleSubmit = async () => { if (loading) return; @@ -149,6 +155,13 @@ const AuthScreen: React.FC = () => { Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error).catch(() => {}); return; } + if (mode === 'signup' && !passwordsMatch) { + const msg = 'Passwords do not match'; + setError(msg); + showToast(msg, 'error'); + Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error).catch(() => {}); + return; + } setLoading(true); setError(null); const err = mode === 'signin' ? await signIn(email.trim(), password) : await signUp(email.trim(), password); @@ -375,6 +388,45 @@ const AuthScreen: React.FC = () => { + {/* Confirm Password (signup only) */} + {mode === 'signup' && ( + + + + + + + setShowConfirm(p => !p)} style={styles.eyeButton}> + + + {Platform.OS !== 'android' && passwordsMatch && isConfirmValid && ( + + )} + + + )} + {/* Error */} {!!error && ( @@ -442,13 +494,26 @@ const AuthScreen: React.FC = () => { - {/* Skip sign in */} + {/* Skip sign in - more prominent when coming from onboarding */} - + Continue without an account diff --git a/src/screens/OnboardingScreen.tsx b/src/screens/OnboardingScreen.tsx index 3409bde66..658de1ad6 100644 --- a/src/screens/OnboardingScreen.tsx +++ b/src/screens/OnboardingScreen.tsx @@ -112,13 +112,13 @@ const OnboardingScreen = () => { await AsyncStorage.setItem('hasCompletedOnboarding', 'true'); // After onboarding, route to login if no user; otherwise go to app if (!user) { - navigation.reset({ index: 0, routes: [{ name: 'Account' }] }); + navigation.reset({ index: 0, routes: [{ name: 'Account', params: { fromOnboarding: true } as any }] }); } else { navigation.reset({ index: 0, routes: [{ name: 'MainTabs' }] }); } } catch (error) { console.error('Error saving onboarding status:', error); - navigation.reset({ index: 0, routes: [{ name: user ? 'MainTabs' : 'Account' }] }); + navigation.reset({ index: 0, routes: [{ name: user ? 'MainTabs' : 'Account', params: !user ? ({ fromOnboarding: true } as any) : undefined }] }); } };