source: src/app/page.tsx@ 50f2fb4

Last change on this file since 50f2fb4 was 50f2fb4, checked in by Stefan-Saveski <stefansaveski19@…>, 8 months ago

Added dual language feature.

  • Property mode set to 100644
File size: 9.4 KB
RevLine 
[6b8332f]1"use client"
2
3import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
4import {
5 faUser,
6 faLock,
7 faEye,
8 faEyeSlash,
9 faSignInAlt,
10 faGraduationCap
11} from '@fortawesome/free-solid-svg-icons';
12import { useState } from 'react';
[b67f274]13import { login } from '@/lib/auth';
[50f2fb4]14import { useTranslation } from 'react-i18next';
15import LanguageSwitcher from '@/components/LanguageSwitcher';
[6b8332f]16
17export default function LoginPage() {
[50f2fb4]18 const { t } = useTranslation();
[6b8332f]19 const [showPassword, setShowPassword] = useState(false);
[b67f274]20 const [isSubmitting, setIsSubmitting] = useState(false);
21 const [errorMessage, setErrorMessage] = useState<string | null>(null);
[6b8332f]22 const [formData, setFormData] = useState({
[b67f274]23 email: '',
[6b8332f]24 password: ''
25 });
26
27 const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
28 const { name, value } = e.target;
29 setFormData(prev => ({
30 ...prev,
31 [name]: value
32 }));
33 };
34
[b67f274]35 const handleSubmit = async (e: React.FormEvent) => {
[6b8332f]36 e.preventDefault();
[b67f274]37 setErrorMessage(null);
38 setIsSubmitting(true);
39 try {
[298f9b3]40 const session = await login({ email: formData.email, password: formData.password });
41 window.location.href = session.role === 'Professor' ? '/professor' : '/students';
[b67f274]42 } catch (err) {
43 setErrorMessage(err instanceof Error ? err.message : 'Login failed.');
44 } finally {
45 setIsSubmitting(false);
46 }
[6b8332f]47 };
[65f7b64]48
49 return (
[6b8332f]50 <div className="container mx-auto px-4">
51 <div className="min-h-screen ">
52 {/* Login Form */}
53 <div className="flex items-center justify-center min-h-[calc(100vh-160px)] p-4">
[90f7842]54 <div className="w-full max-w-5xl">
55 <div className="grid grid-cols-1 gap-6 lg:grid-cols-[24rem_28rem_24rem] lg:items-start lg:justify-center">
56 {/* Sticky Notes */}
57 <div className="w-full flex flex-col gap-4">
58 <div className="bg-yellow-100 border border-yellow-200 rounded-xl shadow-sm p-5">
[50f2fb4]59 <div className="text-sm font-bold text-gray-900 mb-2">{t('login_student_title')}</div>
[90f7842]60 <div className="text-xs text-gray-800 whitespace-pre-wrap font-mono">
[50f2fb4]61 {t('login_student_example')}
[90f7842]62 </div>
63 <div className="mt-3 text-xs text-gray-700">
[50f2fb4]64 {t('login_note_slow')}
[90f7842]65 </div>
66 </div>
67
68 <div className="bg-yellow-100 border border-yellow-200 rounded-xl shadow-sm p-5">
[50f2fb4]69 <div className="text-sm font-bold text-gray-900 mb-2">{t('login_professor_title')}</div>
[90f7842]70 <div className="text-xs text-gray-800 whitespace-pre-wrap font-mono">
[50f2fb4]71 {t('login_professor_example')}
[90f7842]72 </div>
73 </div>
74 </div>
75
76 {/* Login Card Column */}
77 <div className="w-full max-w-md lg:max-w-none lg:w-[28rem] mx-auto">
78 {/* Login Card */}
79 <div className="bg-white rounded-2xl shadow-xl border border-gray-100 overflow-hidden">
80 {/* Header */}
81 <div className="bg-primary text-white px-8 py-6 text-center">
[6b8332f]82 <div className="mb-4">
83 <div className="inline-flex items-center justify-center w-16 h-16 bg-white bg-opacity-20 rounded-full">
84 <FontAwesomeIcon icon={faUser} className="text-2xl text-primary" />
85 </div>
86 </div>
[50f2fb4]87 <h1 className="text-2xl font-bold mb-2">{t('login_welcome')}</h1>
[6b8332f]88 <p className="text-blue-100 text-sm">
[50f2fb4]89 {t('login_subtitle')}
[6b8332f]90 </p>
91 </div>
92
93 {/* Form */}
94 <div className="p-8">
[50f2fb4]95 {/* Language Switcher above email field, centered */}
96 <div className="flex justify-center mb-6">
97 <LanguageSwitcher />
98 </div>
[6b8332f]99 <form onSubmit={handleSubmit} className="space-y-6">
[b67f274]100 {/* Email Field */}
[6b8332f]101 <div>
[b67f274]102 <label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-2">
[50f2fb4]103 {t('login_email_label')}
[6b8332f]104 </label>
105 <div className="relative">
106 <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
107 <FontAwesomeIcon icon={faUser} className="h-4 w-4 text-gray-400" />
108 </div>
109 <input
[b67f274]110 id="email"
111 name="email"
112 type="email"
[6b8332f]113 required
[b67f274]114 value={formData.email}
[6b8332f]115 onChange={handleInputChange}
116 className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary transition-colors"
[50f2fb4]117 placeholder={t('login_email_placeholder')}
[6b8332f]118 />
119 </div>
120 </div>
121
122 {/* Password Field */}
123 <div>
124 <label htmlFor="password" className="block text-sm font-medium text-gray-700 mb-2">
[50f2fb4]125 {t('login_password_label')}
[6b8332f]126 </label>
127 <div className="relative">
128 <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
129 <FontAwesomeIcon icon={faLock} className="h-4 w-4 text-gray-400" />
130 </div>
131 <input
132 id="password"
133 name="password"
134 type={showPassword ? "text" : "password"}
135 required
136 value={formData.password}
137 onChange={handleInputChange}
138 className="w-full pl-10 pr-12 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary transition-colors"
[50f2fb4]139 placeholder={t('login_password_placeholder')}
[6b8332f]140 />
141 <button
142 type="button"
143 onClick={() => setShowPassword(!showPassword)}
144 className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-gray-600 transition-colors"
145 >
146 <FontAwesomeIcon
147 icon={showPassword ? faEyeSlash : faEye}
148 className="h-4 w-4"
149 />
150 </button>
151 </div>
152 </div>
153
154 {/* Remember Me & Forgot Password */}
155 <div className="flex items-center justify-between">
156 <div className="flex items-center">
157 <input
158 id="remember"
159 name="remember"
160 type="checkbox"
161 className="h-4 w-4 text-primary focus:ring-primary border-gray-300 rounded"
162 />
163 <label htmlFor="remember" className="ml-2 block text-sm text-gray-700">
[50f2fb4]164 {t('login_remember_me')}
[6b8332f]165 </label>
166 </div>
167 <button
168 type="button"
169 className="text-sm text-primary hover:text-blue-700 font-medium transition-colors"
170 >
[50f2fb4]171 {t('login_forgot_password')}
[6b8332f]172 </button>
173 </div>
174
[b67f274]175 {errorMessage && (
176 <div className="rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
[50f2fb4]177 {t(errorMessage) || errorMessage}
[b67f274]178 </div>
179 )}
180
[6b8332f]181 {/* Submit Button */}
182 <button
183 type="submit"
[b67f274]184 disabled={isSubmitting}
185 className="w-full bg-primary hover:bg-blue-700 disabled:opacity-60 disabled:hover:bg-primary text-white font-medium py-3 px-4 rounded-lg transition-colors duration-200 flex items-center justify-center gap-2 shadow-lg hover:shadow-xl"
[6b8332f]186 >
187 <FontAwesomeIcon icon={faSignInAlt} className="h-4 w-4" />
[50f2fb4]188 {isSubmitting ? t('login_button_loading') : t('login_button')}
[6b8332f]189 </button>
190 </form>
191 </div>
192
193 {/* Footer */}
194 <div className="bg-gray-50 px-8 py-4 border-t border-gray-100">
195 <p className="text-center text-sm text-gray-600">
[50f2fb4]196 {t('login_no_account')}{' '}
[6b8332f]197 <button className="text-primary hover:text-blue-700 font-medium transition-colors">
[50f2fb4]198 {t('login_contact_admin')}
[6b8332f]199 </button>
200 </p>
201 </div>
[90f7842]202 </div>
[6b8332f]203
[90f7842]204 {/* Additional Info */}
205 <div className="mt-6 text-center">
206 <div className="inline-flex items-center gap-2 px-4 py-2 bg-white bg-opacity-80 rounded-lg shadow-sm">
207 <FontAwesomeIcon icon={faGraduationCap} className="text-primary" />
208 <span className="text-sm text-gray-600">
[50f2fb4]209 {t('login_footer')}
[90f7842]210 </span>
211 </div>
212 </div>
213 </div>
214
215 {/* Right spacer column (keeps login centered) */}
216 <div className="hidden lg:block" />
[6b8332f]217 </div>
218 </div>
219 </div>
220 </div>
221 </div>
[65f7b64]222 );
[6b8332f]223}
Note: See TracBrowser for help on using the repository browser.