design: redesign login page to professional split-screen layout

This commit is contained in:
2026-06-25 05:35:38 +05:30
parent 025ea01afe
commit 22616a9c1b

View File

@@ -248,206 +248,270 @@ export const LoginPage: React.FC = () => {
const RIT_BLUE_HOVER = 'hover:bg-[#003366]';
return (
<div className="min-h-screen w-full bg-slate-50 flex items-center justify-center font-sans p-6 overflow-x-hidden relative">
<div className="min-h-screen w-full bg-white flex font-sans overflow-x-hidden relative">
{/* Background radial accent */}
<div className="absolute top-0 right-0 w-[500px] h-[500px] bg-brand-glow rounded-full blur-[120px] opacity-40 pointer-events-none -z-10" />
<div className="absolute bottom-0 left-0 w-[500px] h-[500px] bg-indigo-50 rounded-full blur-[120px] opacity-40 pointer-events-none -z-10" />
{/* Left Column: Branding (hidden on mobile, 55% width on desktop) */}
<div className="hidden lg:flex lg:w-[55%] bg-gradient-to-br from-[#003B5C] via-[#004a99] to-[#001D3D] text-white flex-col justify-between p-16 relative overflow-hidden">
{/* Abstract vector backgrounds for a premium institutional feel */}
<div className="absolute inset-0 pointer-events-none opacity-20">
<div className="absolute -top-[20%] -left-[10%] w-[700px] h-[700px] rounded-full border border-white/10" />
<div className="absolute -bottom-[30%] -right-[10%] w-[800px] h-[800px] rounded-full border border-white/10" />
<div className="absolute top-[20%] right-[10%] w-[300px] h-[300px] rounded-full bg-white/5 blur-[50px]" />
</div>
<AnimatePresence mode="wait">
{!isSignUp ? (
// ----------------------------------------------------
// CENTRALIZED SIGN IN
// ----------------------------------------------------
<motion.div
key="login-pane"
initial={{ opacity: 0, scale: 0.95, y: 10 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: -10 }}
transition={{ duration: 0.4 }}
className="w-full max-w-md bg-white rounded-[2.5rem] border border-slate-100 premium-shadow p-10 flex flex-col items-center relative overflow-hidden"
>
<div className="w-full text-center mb-8">
<img src={ritLogo} alt="RIT Logo" className="h-16 w-auto mx-auto mb-6 object-contain" />
<h2 className="text-3xl font-black text-slate-900 tracking-tight flex items-center justify-center gap-1.5 uppercase">
RIT EVENT HUB
</h2>
<p className="text-slate-400 text-xs font-bold uppercase tracking-widest mt-1">Centralized Portal Login</p>
</div>
{/* Top: Brand Header */}
<div className="flex items-center gap-4 z-10">
<img src={ritLogo} alt="RIT Logo" className="h-12 w-auto object-contain bg-white/95 p-2 rounded-xl" />
<div>
<h3 className="text-base font-black tracking-wide leading-none">RAJALAKSHMI</h3>
<span className="text-[9px] font-bold text-slate-300 uppercase tracking-widest leading-none">Institute of Technology</span>
</div>
</div>
{/* Google Sign In Button */}
<button
onClick={handleGoogleSignIn}
onDoubleClick={() => setShowGoogleChooser(true)}
title="Double-click to open mock accounts for local testing"
className="w-full py-4 px-6 bg-white border border-slate-200 hover:border-brand-indigo/30 rounded-2xl flex items-center justify-center text-xs font-black text-slate-700 uppercase tracking-widest hover:bg-slate-50 transition-all hover:scale-[1.02] active:scale-[0.98] premium-shadow-sm mb-6"
>
<GoogleIcon />
Sign in with Google
</button>
{/* Middle: Feature list / value proposition */}
<div className="space-y-8 z-10 my-auto">
<div className="space-y-4">
<span className="px-3 py-1 bg-white/10 rounded-full text-[9px] font-black uppercase tracking-widest text-slate-200">Centralized Portal</span>
<h1 className="text-5xl font-black tracking-tight leading-tight uppercase">
RIT EVENT HUB
</h1>
<p className="text-sm font-medium text-slate-200/80 max-w-lg leading-relaxed">
Schedule, approve, and track academic, placement, and cultural events across Rajalakshmi Institute of Technology with an automated conflict engine.
</p>
</div>
{/* Separator */}
<div className="w-full flex items-center justify-center gap-4 mb-6">
<div className="h-px bg-slate-100 flex-1" />
<span className="text-[9px] font-black text-slate-300 uppercase tracking-widest">or use credentials</span>
<div className="h-px bg-slate-100 flex-1" />
</div>
{/* Email & Password Form */}
<form onSubmit={handleLoginSubmit} className="w-full space-y-4">
<div className="relative">
<Mail className="absolute left-5 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
<input
required
type="email"
placeholder="EMAIL ADDRESS"
value={emailInput}
onChange={(e) => setEmailInput(e.target.value)}
className="w-full bg-slate-50 border border-transparent focus:border-brand-indigo/30 rounded-2xl pl-12 pr-6 py-4.5 text-xs font-bold outline-none transition-all"
/>
</div>
<div className="relative">
<Lock className="absolute left-5 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
<input
required
type={showPassword ? 'text' : 'password'}
placeholder="PASSWORD"
value={passwordInput}
onChange={(e) => setPasswordInput(e.target.value)}
className="w-full bg-slate-50 border border-transparent focus:border-brand-indigo/30 rounded-2xl pl-12 pr-12 py-4.5 text-xs font-bold outline-none transition-all"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-5 top-1/2 -translate-y-1/2 text-slate-300 hover:text-brand-indigo transition-colors"
>
<i className={cn("fas", showPassword ? "fa-eye-slash" : "fa-eye")}></i>
</button>
</div>
{errorMessage && (
<div className="p-4 bg-red-50 text-red-600 rounded-2xl text-xs font-bold flex items-center gap-2 border border-red-100/50">
<AlertCircle className="w-4 h-4 shrink-0" />
<span>{errorMessage}</span>
<div className="space-y-4 pt-6 border-t border-white/10 max-w-md">
{[
{ title: "Smart Scheduling", desc: "Conflict audit for auditoriums, seminar halls, and computer centers in real-time." },
{ title: "Multi-tier Approvals", desc: "Digital verification chain routing proposals through departments, HoDs, and the Principal." },
{ title: "Student Passports", desc: "Secure digital passes, attendance tracking, and automated OD verification." }
].map((f, i) => (
<div key={i} className="flex gap-4 items-start">
<div className="w-6 h-6 rounded-lg bg-white/10 flex items-center justify-center text-xs font-black text-white shrink-0 mt-0.5"></div>
<div>
<h4 className="text-xs font-black uppercase tracking-wider text-white">{f.title}</h4>
<p className="text-[11px] text-slate-300 font-medium mt-1 leading-relaxed">{f.desc}</p>
</div>
)}
</div>
))}
</div>
</div>
<button
type="submit"
disabled={isSubmitting}
className={cn(
"w-full py-5 text-white text-xs font-black rounded-2xl transition-all shadow-lg active:scale-[0.98] disabled:opacity-55 flex items-center justify-center gap-2 mt-4",
RIT_BLUE,
RIT_BLUE_HOVER
)}
{/* Bottom: Institutional footer */}
<div className="z-10 flex items-center justify-between text-[10px] font-bold text-slate-400 uppercase tracking-widest">
<span>RIT Event Hub © {new Date().getFullYear()}</span>
<span>Terms & Conditions</span>
</div>
</div>
{/* Right Column: Form (100% on mobile, 45% on desktop) */}
<div className="w-full lg:w-[45%] flex items-center justify-center p-8 md:p-16 bg-white relative">
{/* Decorative radial accents on the white side to retain look */}
<div className="absolute top-[10%] right-[10%] w-[300px] h-[300px] bg-brand-glow rounded-full blur-[100px] opacity-30 pointer-events-none" />
<div className="absolute bottom-[10%] left-[10%] w-[300px] h-[300px] bg-indigo-50 rounded-full blur-[100px] opacity-30 pointer-events-none" />
<div className="w-full max-w-sm z-10 flex flex-col justify-center min-h-[500px]">
<AnimatePresence mode="wait">
{!isSignUp ? (
// ----------------------------------------------------
// CENTRALIZED SIGN IN (NO CARD)
// ----------------------------------------------------
<motion.div
key="login-pane"
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }}
transition={{ duration: 0.3 }}
className="space-y-8"
>
<LogIn className="w-4 h-4" />
{isSubmitting ? 'Verifying...' : 'Sign in now...'}
</button>
</form>
<div className="mt-8 text-center space-y-3">
<button
type="button"
onClick={() => {
setIsSignUp(true);
setSignUpType('EXTERNAL');
setErrorMessage(null);
}}
className="text-xs font-bold text-slate-400 hover:text-brand-indigo transition-colors block mx-auto"
>
External Student ? Register here..
</button>
</div>
</motion.div>
) : (
// ----------------------------------------------------
// SIGN UP (Only for External Students)
// ----------------------------------------------------
<motion.div
key="signup-pane"
initial={{ opacity: 0, scale: 0.95, y: 10 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: -10 }}
transition={{ duration: 0.4 }}
className="w-full max-w-md bg-white rounded-[2.5rem] border border-slate-100 premium-shadow p-10 flex flex-col relative overflow-hidden"
>
{/* Back Button */}
<button
onClick={() => {
setIsSignUp(false);
setSignUpType(null);
setErrorMessage(null);
}}
className="absolute top-6 left-6 w-10 h-10 bg-slate-50 hover:bg-slate-100 text-slate-500 rounded-full flex items-center justify-center transition-all border border-slate-100"
type="button"
>
<ArrowLeft className="w-4 h-4" />
</button>
<div className="text-center mb-8 pt-4">
<h2 className="text-3xl font-black text-slate-900 uppercase tracking-tighter">
Other College <span className="text-[#004a99]">Sign Up</span>
</h2>
<p className="text-slate-400 text-[10px] font-bold uppercase tracking-widest mt-2">Join the RIT Excellence Hub</p>
</div>
<form onSubmit={handleRegisterSubmit} className="space-y-4 overflow-y-auto max-h-[450px] pr-3 py-1 scrollbar-hide">
<div className="grid grid-cols-2 gap-4">
<input required name="name" placeholder="FULL NAME" className="bg-slate-50 border-transparent focus:border-brand-indigo/30 border rounded-2xl px-5 py-4 text-xs font-bold outline-none transition-all" value={formData.name} onChange={handleInputChange} />
<input required type="email" name="email" placeholder="EMAIL" className="bg-slate-50 border-transparent focus:border-brand-indigo/30 border rounded-2xl px-5 py-4 text-xs font-bold outline-none transition-all" value={formData.email} onChange={handleInputChange} />
</div>
<div className="grid grid-cols-2 gap-4">
<input required name="regNo" placeholder="REG NO" className="bg-slate-50 border-transparent focus:border-brand-indigo/30 border rounded-2xl px-5 py-4 text-xs font-bold outline-none transition-all" value={formData.regNo} onChange={handleInputChange} />
<input required name="phone" placeholder="PHONE NUMBER" className="bg-slate-50 border-transparent focus:border-brand-indigo/30 border rounded-2xl px-5 py-4 text-xs font-bold outline-none transition-all" value={formData.phone} onChange={handleInputChange} />
</div>
<div className="grid grid-cols-2 gap-4">
<input required type="password" name="password" placeholder="PASSWORD" className="bg-slate-50 border-transparent focus:border-brand-indigo/30 border rounded-2xl px-5 py-4 text-xs font-bold outline-none transition-all" value={formData.password} onChange={handleInputChange} />
<input required type="password" name="confirmPassword" placeholder="CONFIRM" className="bg-slate-50 border-transparent focus:border-brand-indigo/30 border rounded-2xl px-5 py-4 text-xs font-bold outline-none transition-all" value={formData.confirmPassword} onChange={handleInputChange} />
</div>
<div className="grid grid-cols-2 gap-4">
<select required name="gender" className="bg-slate-50 border-transparent focus:border-brand-indigo/30 border rounded-2xl px-5 py-4 text-xs font-bold outline-none transition-all cursor-pointer" value={formData.gender} onChange={handleInputChange}>
<option value="">SELECT GENDER</option>
<option value="Male">MALE</option>
<option value="Female">FEMALE</option>
<option value="Other">OTHER</option>
</select>
<input required name="collegeLocation" placeholder="COLLEGE LOCATION" className="bg-slate-50 border-transparent focus:border-brand-indigo/30 border rounded-2xl px-5 py-4 text-xs font-bold outline-none transition-all" value={formData.collegeLocation} onChange={handleInputChange} />
</div>
<input required name="collegeName" placeholder="COLLEGE NAME" className="w-full bg-slate-50 border-transparent focus:border-brand-indigo/30 border rounded-2xl px-5 py-4 text-xs font-bold outline-none transition-all" value={formData.collegeName} onChange={handleInputChange} />
<div className="relative">
<select required name="department" className="w-full bg-slate-50 border-transparent focus:border-brand-indigo/30 border rounded-2xl px-5 py-4 text-xs font-bold outline-none transition-all cursor-pointer appearance-none" value={formData.department} onChange={handleInputChange}>
<option value="">SELECT DEPARTMENT</option>
{EXTERNAL_DEPARTMENTS.map(d => <option key={d} value={d}>{d}</option>)}
</select>
</div>
{errorMessage && (
<div className="p-4 bg-red-50 text-red-600 rounded-2xl text-xs font-bold flex items-center gap-2 border border-red-100/50">
<AlertCircle className="w-4 h-4 shrink-0" />
<span>{errorMessage}</span>
<div className="space-y-3">
{/* Logo only on mobile/tablet */}
<img src={ritLogo} alt="RIT Logo" className="h-10 w-auto object-contain mb-4 lg:hidden" />
<h2 className="text-3xl font-black text-slate-900 tracking-tight uppercase leading-none">
Welcome Back
</h2>
<p className="text-slate-400 text-xs font-bold uppercase tracking-widest">Sign in to your account</p>
</div>
)}
<button
type="submit"
disabled={isSubmitting}
className={cn(
"w-full py-5 text-white text-xs font-black rounded-2xl transition-all shadow-lg active:scale-[0.98] disabled:opacity-55 flex items-center justify-center gap-2",
RIT_BLUE,
RIT_BLUE_HOVER
)}
<div className="space-y-6">
{/* Google Sign In Button */}
<button
onClick={handleGoogleSignIn}
onDoubleClick={() => setShowGoogleChooser(true)}
title="Double-click to open mock accounts for local testing"
className="w-full py-4 px-6 bg-white border border-slate-200 hover:border-slate-300 rounded-2xl flex items-center justify-center text-xs font-black text-slate-700 uppercase tracking-widest hover:bg-slate-50 transition-all hover:scale-[1.01] active:scale-[0.99] shadow-sm"
>
<GoogleIcon />
Sign in with Google
</button>
{/* Separator */}
<div className="flex items-center justify-center gap-4">
<div className="h-px bg-slate-100 flex-1" />
<span className="text-[9px] font-black text-slate-300 uppercase tracking-widest">or use credentials</span>
<div className="h-px bg-slate-100 flex-1" />
</div>
{/* Email & Password Form */}
<form onSubmit={handleLoginSubmit} className="space-y-4">
<div className="relative">
<Mail className="absolute left-5 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
<input
required
type="email"
placeholder="EMAIL ADDRESS"
value={emailInput}
onChange={(e) => setEmailInput(e.target.value)}
className="w-full bg-slate-50 border border-slate-100 focus:bg-white focus:border-brand-indigo/30 rounded-2xl pl-12 pr-6 py-4 text-xs font-bold outline-none transition-all"
/>
</div>
<div className="relative">
<Lock className="absolute left-5 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
<input
required
type={showPassword ? 'text' : 'password'}
placeholder="PASSWORD"
value={passwordInput}
onChange={(e) => setPasswordInput(e.target.value)}
className="w-full bg-slate-50 border border-slate-100 focus:bg-white focus:border-brand-indigo/30 rounded-2xl pl-12 pr-12 py-4 text-xs font-bold outline-none transition-all"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-5 top-1/2 -translate-y-1/2 text-slate-300 hover:text-brand-indigo transition-colors"
>
<i className={cn("fas", showPassword ? "fa-eye-slash" : "fa-eye")}></i>
</button>
</div>
{errorMessage && (
<div className="p-4 bg-red-50 text-red-600 rounded-2xl text-xs font-bold flex items-center gap-2 border border-red-100/50">
<AlertCircle className="w-4 h-4 shrink-0" />
<span>{errorMessage}</span>
</div>
)}
<button
type="submit"
disabled={isSubmitting}
className={cn(
"w-full py-4.5 text-white text-xs font-black rounded-2xl transition-all shadow-md hover:shadow-lg active:scale-[0.99] disabled:opacity-55 flex items-center justify-center gap-2 mt-4",
RIT_BLUE,
RIT_BLUE_HOVER
)}
>
<LogIn className="w-4 h-4" />
{isSubmitting ? 'Verifying...' : 'Sign in now...'}
</button>
</form>
<div className="text-center pt-2">
<button
type="button"
onClick={() => {
setIsSignUp(true);
setSignUpType('EXTERNAL');
setErrorMessage(null);
}}
className="text-xs font-black text-brand-indigo hover:underline transition-colors uppercase tracking-wider"
>
External Student ? Register here..
</button>
</div>
</div>
</motion.div>
) : (
// ----------------------------------------------------
// SIGN UP (Only for External Students - NO CARD)
// ----------------------------------------------------
<motion.div
key="signup-pane"
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }}
transition={{ duration: 0.3 }}
className="space-y-6"
>
{isSubmitting ? 'Registering...' : 'Sign up now...'}
</button>
</form>
</motion.div>
<div className="relative flex items-center justify-between pb-2">
<button
onClick={() => {
setIsSignUp(false);
setSignUpType(null);
setErrorMessage(null);
}}
className="w-8 h-8 bg-slate-50 hover:bg-slate-100 text-slate-500 rounded-full flex items-center justify-center transition-all border border-slate-100"
type="button"
>
<ArrowLeft className="w-3.5 h-3.5" />
</button>
<span className="text-[9px] font-black text-slate-300 uppercase tracking-widest">Other College Sign Up</span>
</div>
<div className="space-y-2">
<h2 className="text-2xl font-black text-slate-900 uppercase tracking-tight leading-none">
Create Account
</h2>
<p className="text-slate-400 text-[10px] font-bold uppercase tracking-widest">Register as external student</p>
</div>
<form onSubmit={handleRegisterSubmit} className="space-y-3.5 max-h-[420px] overflow-y-auto pr-2 py-1 scrollbar-hide">
<div className="grid grid-cols-2 gap-3">
<input required name="name" placeholder="FULL NAME" className="bg-slate-50 border-slate-100 focus:bg-white focus:border-brand-indigo/30 border rounded-xl px-4 py-3 text-xs font-bold outline-none transition-all" value={formData.name} onChange={handleInputChange} />
<input required type="email" name="email" placeholder="EMAIL" className="bg-slate-50 border-slate-100 focus:bg-white focus:border-brand-indigo/30 border rounded-xl px-4 py-3 text-xs font-bold outline-none transition-all" value={formData.email} onChange={handleInputChange} />
</div>
<div className="grid grid-cols-2 gap-3">
<input required name="regNo" placeholder="REG NO" className="bg-slate-50 border-slate-100 focus:bg-white focus:border-brand-indigo/30 border rounded-xl px-4 py-3 text-xs font-bold outline-none transition-all" value={formData.regNo} onChange={handleInputChange} />
<input required name="phone" placeholder="PHONE NUMBER" className="bg-slate-50 border-slate-100 focus:bg-white focus:border-brand-indigo/30 border rounded-xl px-4 py-3 text-xs font-bold outline-none transition-all" value={formData.phone} onChange={handleInputChange} />
</div>
<div className="grid grid-cols-2 gap-3">
<input required type="password" name="password" placeholder="PASSWORD" className="bg-slate-50 border-slate-100 focus:bg-white focus:border-brand-indigo/30 border rounded-xl px-4 py-3 text-xs font-bold outline-none transition-all" value={formData.password} onChange={handleInputChange} />
<input required type="password" name="confirmPassword" placeholder="CONFIRM" className="bg-slate-50 border-slate-100 focus:bg-white focus:border-brand-indigo/30 border rounded-xl px-4 py-3 text-xs font-bold outline-none transition-all" value={formData.confirmPassword} onChange={handleInputChange} />
</div>
<div className="grid grid-cols-2 gap-3">
<select required name="gender" className="bg-slate-50 border-slate-100 focus:bg-white focus:border-brand-indigo/30 border rounded-xl px-4 py-3 text-xs font-bold outline-none transition-all cursor-pointer" value={formData.gender} onChange={handleInputChange}>
<option value="">GENDER</option>
<option value="Male">MALE</option>
<option value="Female">FEMALE</option>
<option value="Other">OTHER</option>
</select>
<input required name="collegeLocation" placeholder="LOCATION" className="bg-slate-50 border-slate-100 focus:bg-white focus:border-brand-indigo/30 border rounded-xl px-4 py-3 text-xs font-bold outline-none transition-all" value={formData.collegeLocation} onChange={handleInputChange} />
</div>
<input required name="collegeName" placeholder="COLLEGE NAME" className="w-full bg-slate-50 border-slate-100 focus:bg-white focus:border-brand-indigo/30 border rounded-xl px-4 py-3 text-xs font-bold outline-none transition-all" value={formData.collegeName} onChange={handleInputChange} />
<select required name="department" className="w-full bg-slate-50 border-slate-100 focus:bg-white focus:border-brand-indigo/30 border rounded-xl px-4 py-3 text-xs font-bold outline-none transition-all cursor-pointer" value={formData.department} onChange={handleInputChange}>
<option value="">SELECT DEPARTMENT</option>
{EXTERNAL_DEPARTMENTS.map(d => <option key={d} value={d}>{d}</option>)}
</select>
{errorMessage && (
<div className="p-4 bg-red-50 text-red-600 rounded-xl text-xs font-bold flex items-center gap-2 border border-red-100/50">
<AlertCircle className="w-4 h-4 shrink-0" />
<span>{errorMessage}</span>
</div>
)}
<button
type="submit"
disabled={isSubmitting}
className={cn(
"w-full py-4.5 text-white text-xs font-black rounded-xl transition-all shadow-md hover:shadow-lg active:scale-[0.99] disabled:opacity-55 flex items-center justify-center gap-2",
RIT_BLUE,
RIT_BLUE_HOVER
)}
>
{isSubmitting ? 'Registering...' : 'Sign up now...'}
</button>
</form>
</motion.div>
)}
</AnimatePresence>
</div>
</div>
)}
</AnimatePresence>