import React, { useEffect, useState } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, Alert } from 'react-native'; import axios from 'axios'; import { Link, useRouter } from 'expo-router'; import { useForm, Controller } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { Ionicons } from '@expo/vector-icons'; import * as Google from 'expo-auth-session/providers/google'; import * as WebBrowser from 'expo-web-browser'; import { Screen } from '@presentation/components/layout/Screen'; import { Input } from '@presentation/components/ui/Input'; import { Button } from '@presentation/components/ui/Button'; import { colors, typography, spacing } from '@shared/theme'; import { loginUseCase, googleLoginUseCase } from '@infrastructure/container'; import { useAuthStore } from '@store/authStore'; import { CatIcon } from '@presentation/components/icons/CatIcon'; // Necessário para fechar o browser após redirect OAuth no Android/iOS WebBrowser.maybeCompleteAuthSession(); const schema = z.object({ email: z.string().email('E-mail inválido'), password: z.string().min(1, 'Senha obrigatória'), }); type FormData = z.infer; /** * Tela de Login — G3-0 * E-mail + Senha, "Esqueci minha senha" e OAuth Google. */ export default function LoginScreen(): React.ReactElement { const router = useRouter(); const setSession = useAuthStore((s) => s.setSession); const [isLoading, setIsLoading] = useState(false); const [isGoogleLoading, setIsGoogleLoading] = useState(false); // Hook do expo-auth-session para Google OAuth. // Usa os client IDs de Android e iOS configurados via variáveis de ambiente. const [_request, response, promptAsync] = Google.useAuthRequest({ androidClientId: process.env.EXPO_PUBLIC_GOOGLE_CLIENT_ID_ANDROID, iosClientId: process.env.EXPO_PUBLIC_GOOGLE_CLIENT_ID_IOS, }); // Reage ao resultado do fluxo OAuth assim que o browser fecha useEffect(() => { if (response?.type === 'success') { const idToken = response.authentication?.idToken; if (!idToken) { Alert.alert('Erro', 'Não foi possível obter o token do Google.'); setIsGoogleLoading(false); return; } googleLoginUseCase .execute({ idToken }) .then((session) => setSession(session)) .then(() => router.replace('/(app)/(tabs)/home')) .catch(() => Alert.alert('Erro', 'Não foi possível entrar com o Google.')) .finally(() => setIsGoogleLoading(false)); } else if (response?.type === 'error') { Alert.alert('Erro', 'Autenticação com Google cancelada ou falhou.'); setIsGoogleLoading(false); } else if (response?.type === 'dismiss') { setIsGoogleLoading(false); } }, [response]); const { control, handleSubmit, formState: { errors } } = useForm({ resolver: zodResolver(schema), defaultValues: { email: '', password: '' }, }); async function onSubmit(data: FormData): Promise { setIsLoading(true); try { const session = await loginUseCase.execute(data); await setSession(session); router.replace('/(app)/(tabs)/home'); } catch (err) { if (axios.isAxiosError(err) && err.response?.data?.code === 'EMAIL_NOT_VERIFIED') { Alert.alert( 'E-mail não verificado', 'Confirme seu e-mail antes de entrar. Verifique sua caixa de entrada.', [{ text: 'OK', onPress: () => router.push(`/(auth)/check-email?email=${encodeURIComponent(data.email)}`) }], ); } else { Alert.alert('Erro', 'E-mail ou senha incorretos.'); } } finally { setIsLoading(false); } } function onGoogleLogin(): void { setIsGoogleLoading(true); // promptAsync abre o browser; o resultado chega via useEffect no `response` promptAsync(); } return ( {/* Logo */} MeowSpool Gerencie seus filamentos com precisão. {/* Formulário */} ( } error={errors.email?.message} onChangeText={field.onChange} value={field.value} /> )} /> ( } error={errors.password?.message} onChangeText={field.onChange} value={field.value} /> )} /> router.push('/(auth)/forgot-password')} style={styles.forgotRow}> Esqueci minha senha