FlowWeb / src /pages /AuthPage.jsx
danylokhodus's picture
init
de55c35
Raw
History Blame Contribute Delete
8.48 kB
import React, { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { useAuth } from '../context/AuthContext';
import { GoogleLogin } from '@react-oauth/google';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
const AuthPage = () => {
const { t } = useTranslation();
const [isLogin, setIsLogin] = useState(true);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [displayName, setDisplayName] = useState('');
const [error, setError] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const { user, login, register, googleLogin } = useAuth();
const navigate = useNavigate();
React.useEffect(() => {
if (user) {
navigate('/dashboard');
}
}, [user, navigate]);
const handleSubmit = async (e) => {
e.preventDefault();
setError('');
if (!isLogin && password !== confirmPassword) {
setError(t('auth.passwords_do_not_match', 'Passwords do not match'));
return;
}
setIsSubmitting(true);
let result;
if (isLogin) {
result = await login(email, password);
} else {
result = await register(email, password, displayName);
}
if (result.success) {
navigate('/dashboard');
} else {
setError(result.message);
}
setIsSubmitting(false);
};
const handleGoogleSuccess = async (credentialResponse) => {
setIsSubmitting(true);
const result = await googleLogin(credentialResponse.credential);
if (result.success) {
navigate('/dashboard');
} else {
setError(result.message);
}
setIsSubmitting(false);
};
return (
<div className="min-h-[80vh] flex items-center justify-center py-12 px-4">
<div className="w-full max-w-md relative">
{/* Decorative Scribbles */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 0.1 }}
className="absolute -top-12 -left-12 pointer-events-none"
>
<svg width="150" height="150" viewBox="0 0 100 100">
<path d="M10,10 Q50,0 90,10 T80,90 T10,80 Z" fill="none" stroke="currentColor" strokeWidth="1" />
</svg>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="bg-surface-container-lowest p-8 md:p-10 rough-border rough-shadow relative z-10"
>
<div className="text-center mb-8">
<h1 className="text-5xl font-display-lg text-primary mb-2">
{isLogin ? t('auth.welcome_back', 'Welcome Back!') : t('auth.start_flow', 'Start Your Flow')}
</h1>
<p className="font-accent-note text-2xl text-secondary -rotate-1">
{isLogin ? t('auth.plans_waiting', 'Your plans are waiting for you.') : t('auth.join_revolution', 'Join the visual revolution.')}
</p>
</div>
{error && (
<div className="mb-6 p-4 bg-error-container text-error text-sm font-bold border-2 border-error rounded-lg">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="flex flex-col gap-6">
{!isLogin && (
<div className="flex flex-col gap-2">
<label className="text-sm font-bold uppercase tracking-widest text-on-surface-variant">{t('auth.full_name', 'Full Name')}</label>
<input
type="text"
value={displayName}
onChange={(e) => setDisplayName(e.target.value)}
className="w-full px-4 py-3 bg-surface-container-lowest border-2 border-primary rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary/50 font-body-md"
placeholder={t('auth.enter_name', 'Enter your name')}
required={!isLogin}
/>
</div>
)}
<div className="flex flex-col gap-2">
<label className="text-sm font-bold uppercase tracking-widest text-on-surface-variant">{t('auth.email', 'Email')}</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full px-4 py-3 bg-surface-container-lowest border-2 border-primary rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary/50 font-body-md"
placeholder="your@email.com"
required
/>
</div>
<div className="flex flex-col gap-2">
<div className="flex justify-between items-center">
<label className="text-sm font-bold uppercase tracking-widest text-on-surface-variant">{t('auth.password', 'Password')}</label>
{isLogin && (
<button type="button" className="text-xs font-bold text-secondary hover:underline underline-offset-4">{t('auth.forgot', 'Forgot?')}</button>
)}
</div>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full px-4 py-3 bg-surface-container-lowest border-2 border-primary rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary/50 font-body-md"
placeholder="••••••••"
required
/>
</div>
{!isLogin && (
<div className="flex flex-col gap-2">
<label className="text-sm font-bold uppercase tracking-widest text-on-surface-variant">{t('auth.confirm_password', 'Confirm Password')}</label>
<input
type="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
className="w-full px-4 py-3 bg-surface-container-lowest border-2 border-primary rounded-lg focus:outline-none focus:ring-2 focus:ring-secondary/50 font-body-md"
placeholder="••••••••"
required={!isLogin}
/>
</div>
)}
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
disabled={isSubmitting}
className="mt-4 bg-primary text-on-primary py-4 px-6 text-xl font-bold rough-border rough-shadow-hover transition-all disabled:opacity-50"
>
{isSubmitting ? t('auth.processing', 'Processing...') : (isLogin ? t('auth.enter_workspace', 'Enter Workspace') : t('auth.create_account', 'Create Account'))}
</motion.button>
</form>
<div className="mt-8 flex flex-col gap-4">
<div className="relative flex items-center justify-center">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-dashed border-primary/20"></div>
</div>
<span className="relative px-4 bg-surface-container-lowest text-xs font-bold text-on-surface-variant/40 uppercase tracking-widest">
{t('auth.or_continue', 'Or continue with')}
</span>
</div>
<div className="flex justify-center">
<GoogleLogin
onSuccess={handleGoogleSuccess}
onError={() => setError(t('auth.google_failed', 'Google Login Failed'))}
theme="outline"
size="large"
width="100%"
/>
</div>
</div>
<div className="mt-10 text-center">
<button
onClick={() => {
setIsLogin(!isLogin);
setError('');
setPassword('');
setConfirmPassword('');
}}
className="text-lg font-bold text-primary underline underline-offset-8 decoration-secondary decoration-4 hover:text-secondary transition-all font-accent-note"
>
{isLogin ? t('auth.dont_have_account', "Don't have an account? Sign Up") : t('auth.already_member', 'Already a member? Log In')}
</button>
</div>
</motion.div>
</div>
</div>
);
};
export default AuthPage;