feat: User management, SMTP email activation and password resets
Build and Deploy / build-and-push (push) Successful in 1m0s

This commit is contained in:
AI Bot
2026-09-17 08:49:11 +05:30
parent 603aee646c
commit cbf44587aa
9 changed files with 571 additions and 51 deletions
+33 -18
View File
@@ -26,10 +26,13 @@ export function AuthModal() {
setSuccess('');
try {
if (isRegister) {
if (authMode === 'forgot-password') {
await api.forgotPassword(email);
setSuccess('If an account exists, a reset link has been sent to your email.');
} else if (isRegister) {
const res = await api.register(email, password);
if (res.status === 'pending') {
setSuccess(res.message || 'Account created successfully! Please contact an admin to activate your account.');
setSuccess(res.message || 'Account created successfully! Please check your email for the activation link.');
setEmail('');
setPassword('');
} else {
@@ -84,10 +87,10 @@ export function AuthModal() {
</div>
<h2 className="text-2xl font-bold text-white text-center mb-2 relative z-10">
{isRegister ? 'Create an Account' : 'Welcome Back'}
{authMode === 'forgot-password' ? 'Reset Password' : isRegister ? 'Create an Account' : 'Welcome Back'}
</h2>
<p className="text-zinc-400 text-sm text-center mb-8 relative z-10">
{isRegister ? 'Sign up to start building 3D scenes.' : 'Sign in to access your projects.'}
{authMode === 'forgot-password' ? 'Enter your email to receive a reset link.' : isRegister ? 'Sign up to start building 3D scenes.' : 'Sign in to access your projects.'}
</p>
{error && (
@@ -116,18 +119,28 @@ export function AuthModal() {
/>
</div>
<div className="relative">
<Lock className="absolute left-3 top-1/2 -translate-y-1/2 text-zinc-400" size={18} />
<input
type="password"
placeholder="Password"
required
autoComplete={isRegister ? "new-password" : "current-password"}
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full bg-zinc-950/50 border border-zinc-700/50 rounded-xl py-3 pl-10 pr-4 text-white placeholder-zinc-500 focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all"
/>
</div>
{authMode !== 'forgot-password' && (
<div className="relative">
<Lock className="absolute left-3 top-1/2 -translate-y-1/2 text-zinc-400" size={18} />
<input
type="password"
placeholder="Password"
required
autoComplete={isRegister ? "new-password" : "current-password"}
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full bg-zinc-950/50 border border-zinc-700/50 rounded-xl py-3 pl-10 pr-4 text-white placeholder-zinc-500 focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all"
/>
</div>
)}
{authMode === 'login' && (
<div className="flex justify-end">
<button type="button" onClick={() => openAuthModal('forgot-password')} className="text-xs text-primary hover:underline">
Forgot Password?
</button>
</div>
)}
<button
type="submit"
@@ -135,12 +148,14 @@ export function AuthModal() {
className="w-full bg-primary hover:bg-primary/90 text-white font-bold py-3 rounded-xl mt-2 transition-all flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed shadow-[0_0_20px_rgba(var(--primary-rgb),0.3)] hover:shadow-[0_0_30px_rgba(var(--primary-rgb),0.5)]"
>
{loading && <Loader2 size={18} className="animate-spin" />}
{isRegister ? 'Sign Up' : 'Sign In'}
{authMode === 'forgot-password' ? 'Send Reset Link' : isRegister ? 'Sign Up' : 'Sign In'}
</button>
</form>
<div className="mt-8 text-center text-sm text-zinc-400 relative z-10">
{isRegister ? (
{authMode === 'forgot-password' ? (
<p>Remember your password? <button onClick={() => openAuthModal('login')} className="text-primary hover:underline font-medium">Sign in</button></p>
) : isRegister ? (
<p>Already have an account? <button onClick={() => openAuthModal('login')} className="text-primary hover:underline font-medium">Sign in</button></p>
) : (
<p>Don't have an account? <button onClick={() => openAuthModal('register')} className="text-primary hover:underline font-medium">Sign up</button></p>