- Enhance RequestPermitModal with multiple time-off types and validation - Implement CalendarWidget for visualizing time-off requests - Improve API error handling and token management - Add utility functions for consistent date and time formatting - Clean up unused mock data and update types
153 lines
6.9 KiB
TypeScript
153 lines
6.9 KiB
TypeScript
import React, { useState, useContext } from 'react';
|
|
import { Eye, EyeOff, Lock, LogIn, Mail } from 'lucide-react-native';
|
|
import {
|
|
KeyboardAvoidingView,
|
|
Platform,
|
|
ScrollView,
|
|
Text,
|
|
TextInput,
|
|
TouchableOpacity,
|
|
View,
|
|
Image,
|
|
Alert
|
|
} from 'react-native';
|
|
import { AuthContext } from '@/utils/authContext';
|
|
import api from '@/utils/api';
|
|
|
|
export default function LoginScreen() {
|
|
const authContext = useContext(AuthContext);
|
|
const [username, setUsername] = useState('');
|
|
const [password, setPassword] = useState('');
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
const handleLogin = async () => {
|
|
// TODO: Implementa toast o messaggio di errore più user-friendly
|
|
if (!username || !password) {
|
|
Alert.alert("Attenzione", "Inserisci username e password");
|
|
return;
|
|
}
|
|
|
|
setIsLoading(true);
|
|
|
|
try {
|
|
console.log("Tentativo login con:", username);
|
|
|
|
// Chiamata vera al backend
|
|
const response = await api.post("/user/login", {
|
|
username: username,
|
|
password: password
|
|
});
|
|
|
|
const { token, user } = response.data;
|
|
|
|
console.log("Login successo, token ricevuto.");
|
|
console.log("Dati utente:", user);
|
|
|
|
// Passiamo token e dati utente al context che gestirà salvataggio e redirect
|
|
authContext.logIn(token, user);
|
|
|
|
} catch (error: any) {
|
|
console.error("Login Error:", error);
|
|
|
|
let message = "Si è verificato un errore durante l'accesso.";
|
|
|
|
if (error.response) {
|
|
// Errore dal server (es. 401 Credenziali errate)
|
|
if (error.response.status === 401) {
|
|
message = "Credenziali non valide.";
|
|
} else {
|
|
message = `Errore Server: ${error.response.data.message || error.response.status}`;
|
|
}
|
|
} else if (error.request) {
|
|
// Server non raggiungibile
|
|
message = "Impossibile contattare il server. Controlla la connessione.";
|
|
}
|
|
|
|
Alert.alert("Login Fallito", message);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<View className="flex-1 bg-[#099499] h-screen overflow-hidden">
|
|
{/* Header con Logo/Titolo */}
|
|
<View className="h-[35%] flex-column justify-center items-center">
|
|
<Image
|
|
source={require('@/assets/images/mariani-logo.png')}
|
|
className='h-24 w-80'
|
|
resizeMode="contain"
|
|
/>
|
|
</View>
|
|
|
|
{/* Form Container */}
|
|
<View className="flex-1 bg-white rounded-t-[2.5rem] px-8 pt-10 shadow-xl w-full">
|
|
<KeyboardAvoidingView
|
|
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
|
className="flex-1"
|
|
>
|
|
<ScrollView showsVerticalScrollIndicator={false} className="h-full">
|
|
<View className="gap-6 flex flex-col" style={{ gap: '1.5rem' }}>
|
|
{/* Input Username / Email */}
|
|
<View>
|
|
<Text className="text-gray-700 text-lg font-bold mb-3 ml-1">Username o Email</Text>
|
|
<View className="flex-row items-center bg-gray-50 border border-gray-100 rounded-2xl h-16 px-4 flex">
|
|
<Mail size={24} color="#9ca3af" />
|
|
<TextInput
|
|
className="flex-1 ml-4 text-gray-800 text-lg font-medium h-full w-full"
|
|
placeholder="mario.rossi@esempio.com"
|
|
placeholderTextColor="#9ca3af"
|
|
value={username}
|
|
onChangeText={setUsername}
|
|
autoCapitalize="none"
|
|
keyboardType="email-address"
|
|
/>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Input Password */}
|
|
<View>
|
|
<Text className="text-gray-700 text-lg font-bold mb-3 ml-1">Password</Text>
|
|
<View className="flex-row items-center bg-gray-50 border border-gray-100 rounded-2xl h-16 px-4 flex">
|
|
<Lock size={24} color="#9ca3af" />
|
|
<TextInput
|
|
className="flex-1 ml-4 text-gray-800 text-lg font-medium h-full w-full"
|
|
placeholder="••••••••"
|
|
placeholderTextColor="#9ca3af"
|
|
value={password}
|
|
onChangeText={setPassword}
|
|
secureTextEntry={!showPassword}
|
|
/>
|
|
<TouchableOpacity onPress={() => setShowPassword(!showPassword)}>
|
|
{showPassword ? (
|
|
<EyeOff size={24} color="#6b7280" />
|
|
) : (
|
|
<Eye size={24} color="#6b7280" />
|
|
)}
|
|
</TouchableOpacity>
|
|
</View>
|
|
<TouchableOpacity className="mt-3 self-end" style={{ alignSelf: 'flex-end' }}>
|
|
<Text className="text-[#099499] font-bold text-base">Password dimenticata?</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{/* Tasto Login */}
|
|
<TouchableOpacity
|
|
onPress={handleLogin}
|
|
activeOpacity={0.8}
|
|
className={`bg-[#099499] h-16 rounded-2xl flex-row justify-center items-center shadow-md mt-4 flex ${isLoading ? 'opacity-70' : ''}`}
|
|
disabled={isLoading}
|
|
>
|
|
<Text className="text-white text-xl font-bold mr-2">
|
|
{isLoading ? 'Accesso in corso...' : 'Accedi'}
|
|
</Text>
|
|
{!isLoading && <LogIn size={24} color="white" />}
|
|
</TouchableOpacity>
|
|
</View>
|
|
</ScrollView>
|
|
</KeyboardAvoidingView>
|
|
</View>
|
|
</View>
|
|
);
|
|
} |