Skip to content

Instantly share code, notes, and snippets.

@xerudro
Created March 29, 2025 13:15
Show Gist options
  • Select an option

  • Save xerudro/fe50905a3b40e1ca8495b72a78a79d28 to your computer and use it in GitHub Desktop.

Select an option

Save xerudro/fe50905a3b40e1ca8495b72a78a79d28 to your computer and use it in GitHub Desktop.
SignIn.tsx
// 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