Created
March 29, 2025 13:15
-
-
Save xerudro/fe50905a3b40e1ca8495b72a78a79d28 to your computer and use it in GitHub Desktop.
SignIn.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // src/pages/Login.tsx | |
| import React, { useState } from 'react'; | |
| import { useNavigate, Link, useLocation } from 'react-router-dom'; // Added useLocation | |
| import { Mail, Lock, Loader2, AlertTriangle } from 'lucide-react'; | |
| import { useAuth } from '../components/AuthContext'; // Ensure correct path | |
| import { z } from 'zod'; | |
| import { toast } from 'react-hot-toast'; | |
| // Schema Zod pentru validare (similar cu AuthModal) | |
| const loginSchema = z.object({ | |
| email: z.string().email('Invalid email address'), | |
| password: z.string().min(1, 'Password is required'), | |
| }); | |
| type LoginFormData = z.infer<typeof loginSchema>; | |
| const Login: React.FC = () => { | |
| const navigate = useNavigate(); | |
| const location = useLocation(); // Get location state | |
| const { login, isSubmitting } = useAuth(); // Use login and loading state from context | |
| const [formData, setFormData] = useState<LoginFormData>({ email: '', password: '' }); | |
| const [formErrors, setFormErrors] = useState<Partial<Record<keyof LoginFormData, string>>>({}); | |
| const [submitError, setSubmitError] = useState<string | null>(null); | |
| // Obține locația de unde a venit utilizatorul, dacă există (setată de ProtectedRoute) | |
| const from = location.state?.from?.pathname || "/dashboard"; // Default redirect to dashboard | |
| const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { | |
| const { id, value } = e.target; | |
| setFormData(prev => ({ ...prev, [id]: value })); | |
| if (formErrors[id as keyof LoginFormData]) { | |
| setFormErrors(prev => ({ ...prev, [id]: undefined })); | |
| } | |
| setSubmitError(null); | |
| }; | |
| const handleSubmit = async (e: React.FormEvent) => { | |
| e.preventDefault(); | |
| setFormErrors({}); | |
| setSubmitError(null); | |
| const validationResult = loginSchema.safeParse(formData); | |
| if (!validationResult.success) { | |
| const fieldErrors: Partial<Record<keyof LoginFormData, string>> = {}; | |
| validationResult.error.errors.forEach(err => { | |
| if (err.path.length > 0) { | |
| fieldErrors[err.path[0] as keyof LoginFormData] = err.message; | |
| } | |
| }); | |
| setFormErrors(fieldErrors); | |
| toast.error("Please fix the errors in the form."); | |
| return; | |
| } | |
| try { | |
| await login(validationResult.data.email, validationResult.data.password); | |
| // Login successful - AuthContext's login function handles navigation now. | |
| // We can navigate based on the 'from' location state. | |
| console.log(`Login successful, redirecting to: ${from}`); | |
| navigate(from, { replace: true }); // Redirect back to original page or dashboard | |
| } catch (error: any) { | |
| console.error("Login API error:", error); | |
| const message = error.message || 'Login failed. Please check credentials.'; | |
| setSubmitError(message); | |
| // Toast is likely shown by AuthContext's login, but can add one here too if needed | |
| // toast.error(message); | |
| } | |
| }; | |
| return ( | |
| <div className="min-h-screen bg-gradient-to-b from-black via-gray-900 to-black flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8"> | |
| <div className="max-w-md w-full space-y-8 bg-gray-900/50 backdrop-blur-sm p-6 sm:p-8 rounded-xl border border-gray-800/50 shadow-xl"> | |
| <div> | |
| {/* Logo Placeholder/Link */} | |
| <Link to="/" className="flex justify-center mb-6" aria-label="VIP Super Hosting Home"> | |
| <span className="text-orangered font-bold text-xl sm:text-2xl">VIP</span> | |
| <span className="text-white font-bold text-xl sm:text-2xl mx-1 sm:mx-2">SUPER</span> | |
| <span className="text-blue-500 font-bold text-xl sm:text-2xl">HOSTING</span> | |
| </Link> | |
| <h2 className="text-2xl sm:text-3xl font-bold text-white text-center"> | |
| Login to Your Account | |
| </h2> | |
| </div> | |
| {/* Login Form */} | |
| <form className="mt-8 space-y-5" onSubmit={handleSubmit}> | |
| {submitError && ( | |
| <div className="bg-red-600/10 border border-red-600/30 text-red-400 px-4 py-2 rounded-lg text-sm"> | |
| <AlertTriangle className="inline w-4 h-4 mr-2" /> {submitError} | |
| </div> | |
| )} | |
| <div className="space-y-4 rounded-md shadow-sm"> | |
| {/* Email */} | |
| <div> | |
| <label htmlFor="email" className="block text-sm font-medium text-gray-400 mb-1.5">Email Address</label> | |
| <div className="relative"> | |
| <Mail className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-gray-500 pointer-events-none" /> | |
| <input id="email" type="email" value={formData.email} onChange={handleInputChange} required disabled={isSubmitting} | |
| autoComplete="email" | |
| className={`w-full bg-gray-800 border ${formErrors.email ? 'border-red-500' : 'border-gray-700'} rounded-lg pl-10 pr-4 py-2.5 text-white focus:outline-none focus:ring-1 ${formErrors.email ? 'focus:ring-red-500' : 'focu> placeholder="you@example.com" /> | |
| </div> | |
| {formErrors.email && <p className="mt-1 text-xs text-red-400">{formErrors.email}</p>} | |
| </div> | |
| {/* Password */} | |
| <div> | |
| <label htmlFor="password" className="block text-sm font-medium text-gray-400 mb-1.5">Password</label> | |
| <div className="relative"> | |
| <Lock className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-gray-500 pointer-events-none" /> | |
| <input id="password" type="password" value={formData.password} onChange={handleInputChange} required disabled={isSubmitting} | |
| autoComplete="current-password" | |
| className={`w-full bg-gray-800 border ${formErrors.password ? 'border-red-500' : 'border-gray-700'} rounded-lg pl-10 pr-4 py-2.5 text-white focus:outline-none focus:ring-1 ${formErrors.password ? 'focus:ring-red-500' :> placeholder="••••••••" /> | |
| </div> | |
| {formErrors.password && <p className="mt-1 text-xs text-red-400">{formErrors.password}</p>} | |
| </div> | |
| </div> | |
| {/* Remember Me / Forgot Password (Optional) */} | |
| {/* <div className="flex items-center justify-between text-sm"> | |
| <div className="flex items-center">... Remember me ...</div> | |
| <Link to="/forgot-password" className="...">Forgot password?</Link> | |
| </div> */} | |
| {/* Submit Button */} | |
| <button type="submit" disabled={isSubmitting} | |
| className="w-full mt-6 flex justify-center items-center bg-orangered hover:bg-red-600 text-white px-4 py-2.5 rounded-lg transition-colors font-semibold disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visibl> | |
| {isSubmitting ? ( | |
| <Loader2 className="h-5 w-5 animate-spin" /> | |
| ) : ( | |
| 'Log In' | |
| )} | |
| </button> | |
| {/* Link to Signup */} | |
| <p className="text-center text-sm text-gray-400 pt-2"> | |
| Don't have an account?{' '} | |
| <Link to="/signup" className="font-medium text-orangered hover:text-red-600 transition-colors focus:outline-none focus-visible:underline"> | |
| Sign Up | |
| </Link> | |
| </p> | |
| </form> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default Login; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment