Updated the design step 1 is finsih now I'll check it with mohammed
This commit is contained in:
@@ -0,0 +1,668 @@
|
||||
import { useState } from 'react';
|
||||
// Removed: import { useRouter } from 'next/navigation'; // Next.js specific
|
||||
// Removed: import { motion } from 'framer-motion'; // External library not available
|
||||
|
||||
export default function Login() {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
// Replaced useRouter with a simple object for basic navigation
|
||||
const router = {
|
||||
push: (path: string) => {
|
||||
window.location.href = path; // Simulating navigation for a generic React environment
|
||||
},
|
||||
};
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
// Removed unused state: const [isHovering, setIsHovering] = useState(false);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsLoading(true);
|
||||
setError('');
|
||||
try {
|
||||
const response = await fetch('https://solidpoint-auth.ghaymah.systems/signin/email-password', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ email, password }),
|
||||
});
|
||||
const data = await response.json();
|
||||
if (response.ok) {
|
||||
// استخراج البيانات المهمة من الاستجابة
|
||||
const accessToken = data.session?.accessToken;
|
||||
const refreshToken = data.session?.refreshToken;
|
||||
const userId = data.session?.user?.id;
|
||||
|
||||
// تخزين بيانات المستخدم في localStorage
|
||||
const userData = {
|
||||
email,
|
||||
accessToken,
|
||||
userId,
|
||||
isLoggedIn: true,
|
||||
lastLogin: new Date().toISOString()
|
||||
};
|
||||
|
||||
localStorage.setItem('sp_user', JSON.stringify(userData));
|
||||
localStorage.setItem('user_id', userId); // تخزين user_id بشكل منفصل للمكونات التي تحتاجه
|
||||
window.dispatchEvent(new Event('userChanged'));
|
||||
|
||||
// تخزين الـ tokens في HttpOnly cookies
|
||||
try {
|
||||
const tokenResponse = await fetch('/api/auth/store-tokens', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
access_token: accessToken,
|
||||
refresh_token: refreshToken,
|
||||
expires_in: 3600 // مدة صلاحية الـ token بالثواني (ساعة واحدة)
|
||||
})
|
||||
});
|
||||
|
||||
if (!tokenResponse.ok) {
|
||||
console.error('Failed to store token in HttpOnly cookie');
|
||||
} else {
|
||||
console.log('Token stored successfully in HttpOnly cookie');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error storing token in HttpOnly cookie:', error);
|
||||
}
|
||||
|
||||
// Show success animation before navigating
|
||||
const successElement = document.createElement('div');
|
||||
successElement.className = 'fixed inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-900/80 backdrop-blur-sm z-50';
|
||||
successElement.innerHTML = `
|
||||
<div class="text-center p-8 bg-white dark:bg-gray-800 rounded-lg shadow-lg">
|
||||
<svg class="w-16 h-16 mx-auto text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<h2 class="mt-3 text-xl font-bold text-gray-900 dark:text-white">Welcome back!</h2>
|
||||
<p class="mt-2 text-gray-600 dark:text-gray-300">You have successfully logged in.</p>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(successElement);
|
||||
|
||||
// Add animation with CSS
|
||||
const checkmark = successElement.querySelector('svg');
|
||||
if (checkmark) {
|
||||
checkmark.style.transform = 'scale(0)';
|
||||
checkmark.style.transition = 'transform 0.5s ease-out';
|
||||
setTimeout(() => {
|
||||
checkmark.style.transform = 'scale(1)';
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// Navigate after animation completes
|
||||
setTimeout(() => {
|
||||
// Remove the success element before navigating
|
||||
document.body.removeChild(successElement);
|
||||
router.push('/');
|
||||
}, 1800);
|
||||
} else {
|
||||
setError(data?.message || 'Failed to login. Please check your credentials.');
|
||||
}
|
||||
} catch (err: any) {
|
||||
setError('Failed to login. Please try again.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmitSignUp = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsLoading(true);
|
||||
setError('');
|
||||
|
||||
try {
|
||||
const response = await fetch('https://solidpoint-auth.ghaymah.systems/signup/email-password', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ email, password }), // Add more fields like name if needed
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
console.log(data);
|
||||
|
||||
if (response.ok) {
|
||||
const accessToken = data.session?.accessToken;
|
||||
const refreshToken = data.session?.refreshToken;
|
||||
const userId = data.session?.user?.id;
|
||||
|
||||
const userData = {
|
||||
email,
|
||||
accessToken,
|
||||
userId,
|
||||
isLoggedIn: true,
|
||||
lastLogin: new Date().toISOString()
|
||||
};
|
||||
|
||||
localStorage.setItem('sp_user', JSON.stringify(userData));
|
||||
localStorage.setItem('user_id', userId);
|
||||
window.dispatchEvent(new Event('userChanged'));
|
||||
|
||||
// Store tokens in HttpOnly cookies
|
||||
try {
|
||||
const tokenResponse = await fetch('/api/auth/store-tokens', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
access_token: accessToken,
|
||||
refresh_token: refreshToken,
|
||||
expires_in: 3600
|
||||
})
|
||||
});
|
||||
|
||||
if (!tokenResponse.ok) {
|
||||
console.error('Failed to store token in HttpOnly cookie');
|
||||
} else {
|
||||
console.log('Token stored successfully in HttpOnly cookie');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error storing token in HttpOnly cookie:', error);
|
||||
}
|
||||
|
||||
// Success animation
|
||||
const successElement = document.createElement('div');
|
||||
successElement.className = 'fixed inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-900/80 backdrop-blur-sm z-50';
|
||||
successElement.innerHTML = `
|
||||
<div class="text-center p-8 bg-white dark:bg-gray-800 rounded-lg shadow-lg">
|
||||
<svg class="w-16 h-16 mx-auto text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<h2 class="mt-3 text-xl font-bold text-gray-900 dark:text-white">Account Created!</h2>
|
||||
<p class="mt-2 text-gray-600 dark:text-gray-300">You have successfully signed up.</p>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(successElement);
|
||||
|
||||
const checkmark = successElement.querySelector('svg');
|
||||
if (checkmark) {
|
||||
checkmark.style.transform = 'scale(0)';
|
||||
checkmark.style.transition = 'transform 0.5s ease-out';
|
||||
setTimeout(() => {
|
||||
checkmark.style.transform = 'scale(1)';
|
||||
}, 100);
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(successElement);
|
||||
router.push('/');
|
||||
}, 1800);
|
||||
} else {
|
||||
setError(data?.message || 'Signup failed. Please check your info.');
|
||||
}
|
||||
} catch (err: any) {
|
||||
setError('Signup failed. Please try again.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const [swapAuth, setSwapAuth] = useState(false);
|
||||
|
||||
const swapAuthFunction = () => {
|
||||
setSwapAuth(!swapAuth);
|
||||
setEmail('');
|
||||
setPassword('');
|
||||
setError('');
|
||||
}
|
||||
|
||||
const handleSubmitForgotPassword = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsLoading(true);
|
||||
setError('');
|
||||
// setMessage('');
|
||||
|
||||
try {
|
||||
const res = await fetch('https://solidpoint-auth.ghaymah.systems/user/password/reset', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email }),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
// setMessage('If the email exists, a reset link has been sent.');
|
||||
console.log('If the email exists, a reset link has been sent.');
|
||||
} else {
|
||||
const data = await res.json();
|
||||
setError(data.message || 'Failed to send reset email.');
|
||||
}
|
||||
} catch {
|
||||
setError('Failed to send reset email. Try again later.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const [forgotPassword, setForgotPassword] = useState(false);
|
||||
|
||||
|
||||
if (forgotPassword) {
|
||||
return (
|
||||
<div className="min-h-screen w-full bg-gradient-to-br from-blue-50 via-indigo-50 to-purple-50 dark:from-gray-800 dark:via-indigo-900 dark:to-purple-900 font-inter relative overflow-hidden">
|
||||
<div className="absolute top-0 left-0 w-full h-full overflow-hidden z-0 opacity-20 dark:opacity-10">
|
||||
<div className="absolute top-10 left-10 w-72 h-72 bg-blue-400 dark:bg-blue-600 rounded-full mix-blend-multiply filter blur-2xl"></div>
|
||||
<div className="absolute top-0 right-10 w-72 h-72 bg-purple-400 dark:bg-purple-600 rounded-full mix-blend-multiply filter blur-2xl"></div>
|
||||
<div className="absolute -bottom-8 left-20 w-72 h-72 bg-indigo-400 dark:bg-indigo-600 rounded-full mix-blend-multiply filter blur-2xl"></div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[40%_60%] min-h-screen gap-0 md:gap-4 relative z-10">
|
||||
|
||||
<div className="flex flex-col justify-center px-8 sm:px-12 py-12 bg-white/80 dark:bg-gray-800/90 backdrop-blur-md shadow-lg rounded-xl border border-white/20 dark:border-gray-700/30 transition-all duration-200">
|
||||
{/* Logo */}
|
||||
<div className="flex items-center justify-center mb-6">
|
||||
<div className="relative flex items-center justify-center h-12 w-12">
|
||||
<div className="absolute w-11 h-11 rounded-full border-[1.5px] border-blue-500/40"></div>
|
||||
<div className="absolute w-10 h-10 rounded-full border-2 border-blue-600/70"></div>
|
||||
<div className="absolute w-10 h-10 rounded-full bg-gradient-to-r from-blue-500/20 to-indigo-600/20 blur-md"></div>
|
||||
<div className="absolute w-9 h-9 rounded-full bg-gradient-to-tr from-blue-500/30 to-indigo-600/5 blur-[6px]"></div>
|
||||
<div className="absolute w-8 h-8 rounded-full border-[1px] border-blue-600/60 shadow-[0_0_12px_rgba(59,130,246,0.4)] shadow-[0_0_18px_rgba(79,70,229,0.5)]"></div>
|
||||
</div>
|
||||
<span className="ml-3 text-2xl font-bold bg-gradient-to-r from-blue-500 to-indigo-600 bg-clip-text text-transparent">SolidPoint</span>
|
||||
</div>
|
||||
|
||||
<h1 className="text-3xl font-bold mb-4 bg-gradient-to-r from-blue-600 to-indigo-700 bg-clip-text text-transparent text-center">
|
||||
Welcome Back!
|
||||
</h1>
|
||||
<p className="text-sm mb-6 text-gray-600 dark:text-gray-300 text-center">
|
||||
Please enter your credentials to access your account.
|
||||
</p>
|
||||
|
||||
{error && (
|
||||
<div
|
||||
className="p-3 mb-4 text-red-700 bg-red-100 dark:bg-red-900/30 dark:text-red-300 rounded-lg border border-red-200 dark:border-red-800 flex items-center space-x-2 text-sm"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span>{error}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form onSubmit={handleSubmitForgotPassword} className="space-y-4 mt-4">
|
||||
{/* <form onSubmit={swapAuth ? handleSubmitSignUp : forgotPassword ? handleSubmitForgotPassword : handleSubmit} className="space-y-4 mt-4"> */}
|
||||
<div className="relative">
|
||||
<label htmlFor="email" className="block text-sm font-medium mb-1">Email Address</label>
|
||||
<div className="relative">
|
||||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
required
|
||||
className="w-full pl-10 pr-3 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white/50 dark:bg-gray-800/50 backdrop-blur-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm transition-all duration-300 hover:border-blue-300 dark:hover:border-blue-500 text-white"
|
||||
placeholder="your.email@example.com"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
className="w-full py-3 px-4 bg-gradient-to-r from-blue-600 to-indigo-700 hover:from-blue-700 hover:to-indigo-800 text-white font-medium rounded-lg shadow-md transition-all duration-200 disabled:opacity-70 text-sm flex items-center justify-center space-x-2"
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<svg className="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
|
||||
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
<span>
|
||||
{
|
||||
swapAuth ?
|
||||
"Signing up..."
|
||||
:
|
||||
"Logging in..."
|
||||
}
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span>Get Password</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14 5l7 7m0 0l-7 7m7-7H3" />
|
||||
</svg>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
|
||||
<div className="relative my-6">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="w-full border-t border-gray-300 dark:border-gray-700"></div>
|
||||
</div>
|
||||
<div className="relative flex justify-center text-sm">
|
||||
<span className="px-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm text-gray-500 dark:text-gray-400 rounded-md">
|
||||
remember your password?
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="w-full flex items-center justify-center py-2.5 px-4 border border-gray-300 dark:border-gray-600 rounded-lg shadow-sm bg-white/70 dark:bg-gray-800/70 backdrop-blur-sm hover:bg-gray-50 dark:hover:bg-gray-700 transition-all duration-200"
|
||||
onClick={() => setForgotPassword(false)}
|
||||
>
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
|
||||
</svg>
|
||||
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Back to Login
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<RightSide />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
// Replaced motion.div with standard div and adopted SignUp's overall layout
|
||||
<div className="min-h-screen w-full bg-gradient-to-br from-blue-50 via-indigo-50 to-purple-50 dark:from-gray-800 dark:via-indigo-900 dark:to-purple-900 font-inter relative overflow-hidden">
|
||||
{/* Background decorative elements - optimized for performance */}
|
||||
<div className="absolute top-0 left-0 w-full h-full overflow-hidden z-0 opacity-20 dark:opacity-10">
|
||||
<div className="absolute top-10 left-10 w-72 h-72 bg-blue-400 dark:bg-blue-600 rounded-full mix-blend-multiply filter blur-2xl"></div>
|
||||
<div className="absolute top-0 right-10 w-72 h-72 bg-purple-400 dark:bg-purple-600 rounded-full mix-blend-multiply filter blur-2xl"></div>
|
||||
<div className="absolute -bottom-8 left-20 w-72 h-72 bg-indigo-400 dark:bg-indigo-600 rounded-full mix-blend-multiply filter blur-2xl"></div>
|
||||
</div>
|
||||
|
||||
{/* Page split with 35%/65% ratio and responsiveness */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[40%_60%] min-h-screen gap-0 md:gap-4 relative z-10">
|
||||
{/* Left side - Login Form (aligned with SignUp's form side) */}
|
||||
<div className="flex flex-col justify-center px-8 sm:px-12 py-12 bg-white/80 dark:bg-gray-800/90 backdrop-blur-md shadow-lg rounded-xl border border-white/20 dark:border-gray-700/30 transition-all duration-200">
|
||||
{/* Logo */}
|
||||
<div className="flex items-center justify-center mb-6">
|
||||
<div className="relative flex items-center justify-center h-12 w-12">
|
||||
<div className="absolute w-11 h-11 rounded-full border-[1.5px] border-blue-500/40"></div>
|
||||
<div className="absolute w-10 h-10 rounded-full border-2 border-blue-600/70"></div>
|
||||
<div className="absolute w-10 h-10 rounded-full bg-gradient-to-r from-blue-500/20 to-indigo-600/20 blur-md"></div>
|
||||
<div className="absolute w-9 h-9 rounded-full bg-gradient-to-tr from-blue-500/30 to-indigo-600/5 blur-[6px]"></div>
|
||||
<div className="absolute w-8 h-8 rounded-full border-[1px] border-blue-600/60 shadow-[0_0_12px_rgba(59,130,246,0.4)] shadow-[0_0_18px_rgba(79,70,229,0.5)]"></div>
|
||||
</div>
|
||||
<span className="ml-3 text-2xl font-bold bg-gradient-to-r from-blue-500 to-indigo-600 bg-clip-text text-transparent">SolidPoint</span>
|
||||
</div>
|
||||
|
||||
<h1 className="text-3xl font-bold mb-4 bg-gradient-to-r from-blue-600 to-indigo-700 bg-clip-text text-transparent text-center">
|
||||
Welcome Back!
|
||||
</h1>
|
||||
<p className="text-sm mb-6 text-gray-600 dark:text-gray-300 text-center">
|
||||
Please enter your credentials to access your account.
|
||||
</p>
|
||||
|
||||
{error && (
|
||||
<div
|
||||
className="p-3 mb-4 text-red-700 bg-red-100 dark:bg-red-900/30 dark:text-red-300 rounded-lg border border-red-200 dark:border-red-800 flex items-center space-x-2 text-sm"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span>{error}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form onSubmit={swapAuth ? handleSubmitSignUp : handleSubmit} className="space-y-4 mt-4">
|
||||
<div className="relative">
|
||||
<label htmlFor="email" className="block text-sm font-medium mb-1">Email Address</label>
|
||||
<div className="relative">
|
||||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
required
|
||||
className="w-full pl-10 pr-3 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white/50 dark:bg-gray-800/50 backdrop-blur-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm transition-all duration-300 hover:border-blue-300 dark:hover:border-blue-500 text-white"
|
||||
placeholder="your.email@example.com"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative">
|
||||
<label htmlFor="password" className="block text-sm font-medium mb-1">Password</label>
|
||||
<div className="relative">
|
||||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
required
|
||||
className="w-full pl-10 pr-3 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white/50 dark:bg-gray-800/50 backdrop-blur-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm transition-all duration-300 hover:border-blue-300 dark:hover:border-blue-500 text-white"
|
||||
placeholder="••••••••"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400"
|
||||
onClick={() => {
|
||||
const input = document.getElementById('password') as HTMLInputElement;
|
||||
input.type = input.type === 'password' ? 'text' : 'password';
|
||||
}}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
!forgotPassword && (
|
||||
<div style={{ margin: '10px auto 5px', color: 'blue', cursor: 'pointer', width: '100%', textAlign: 'center' }} onClick={() => setForgotPassword(!forgotPassword)}>
|
||||
Forgot password?
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
className="w-full py-3 px-4 bg-gradient-to-r from-blue-600 to-indigo-700 hover:from-blue-700 hover:to-indigo-800 text-white font-medium rounded-lg shadow-md transition-all duration-200 disabled:opacity-70 text-sm flex items-center justify-center space-x-2"
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<svg className="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
|
||||
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
<span>
|
||||
{
|
||||
swapAuth ?
|
||||
"Signing up..."
|
||||
:
|
||||
"Logging in..."
|
||||
}
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span>{swapAuth ? "Sign Up" : "Login"}</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14 5l7 7m0 0l-7 7m7-7H3" />
|
||||
</svg>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
|
||||
<div className="relative my-6">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="w-full border-t border-gray-300 dark:border-gray-700"></div>
|
||||
</div>
|
||||
<div className="relative flex justify-center text-sm">
|
||||
<span className="px-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm text-gray-500 dark:text-gray-400 rounded-md">
|
||||
{
|
||||
swapAuth ? "Already have an account" : "Don't have an account"
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="w-full flex items-center justify-center py-2.5 px-4 border border-gray-300 dark:border-gray-600 rounded-lg shadow-sm bg-white/70 dark:bg-gray-800/70 backdrop-blur-sm hover:bg-gray-50 dark:hover:bg-gray-700 transition-all duration-200"
|
||||
onClick={swapAuthFunction}
|
||||
>
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
|
||||
</svg>
|
||||
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{
|
||||
swapAuth ?
|
||||
"Login"
|
||||
:
|
||||
"Create an account"
|
||||
}
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<RightSide />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const RightSide = () => {
|
||||
return (
|
||||
<div className="flex flex-col justify-center px-6 sm:px-12 py-8 text-gray-900 dark:text-white bg-white/10 dark:bg-gray-800/20 backdrop-blur-md rounded-xl border border-white/20 dark:border-gray-700/30 shadow-lg transition-all duration-200">
|
||||
<h2 className="text-2xl font-bold mb-6 bg-gradient-to-r from-blue-500 to-indigo-600 bg-clip-text text-transparent text-center">Why Choose SolidPoint?</h2>
|
||||
|
||||
{/* Platform Purpose */}
|
||||
<div className="mb-4 bg-white/20 dark:bg-white/5 p-4 rounded-xl border border-indigo-500/40 dark:border-indigo-500/20 shadow-md hover:shadow-md transition-all duration-200 hover:border-indigo-500/60 dark:hover:border-indigo-500/40 hover:bg-indigo-500/10">
|
||||
<h3 className="text-lg font-bold mb-2 bg-gradient-to-r from-blue-400 to-indigo-500 bg-clip-text text-transparent flex items-center">
|
||||
<div className="shrink-0 bg-gradient-to-br from-blue-500 to-indigo-600 p-1.5 rounded-lg shadow-md mr-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
|
||||
</svg>
|
||||
</div>
|
||||
Platform Purpose
|
||||
</h3>
|
||||
<ul className="space-y-1 text-gray-800 dark:text-gray-300 ml-4 font-medium">
|
||||
<li className="flex items-center">
|
||||
<svg className="w-4 h-4 mr-2 text-indigo-600 dark:text-indigo-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd"></path></svg>
|
||||
SolidPoint is an AI-powered content summarization platform
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<svg className="w-4 h-4 mr-2 text-indigo-600 dark:text-indigo-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd"></path></svg>
|
||||
Helps users save time by extracting key insights from various content types
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Key Features */}
|
||||
<div className="mb-4 bg-white/20 dark:bg-white/5 p-4 rounded-xl border border-purple-500/40 dark:border-purple-500/20 shadow-md hover:shadow-md transition-all duration-200 hover:border-purple-500/60 dark:hover:border-purple-500/40 hover:bg-purple-500/10">
|
||||
<h3 className="text-lg font-bold mb-2 bg-gradient-to-r from-purple-400 to-indigo-500 bg-clip-text text-transparent flex items-center">
|
||||
<div className="shrink-0 bg-gradient-to-br from-purple-500 to-indigo-600 p-1.5 rounded-lg shadow-md mr-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" />
|
||||
</svg>
|
||||
</div>
|
||||
Key Features Highlighted
|
||||
</h3>
|
||||
|
||||
<ul className="space-y-1 text-gray-800 dark:text-gray-300 ml-4">
|
||||
<li className="flex items-center">
|
||||
<svg className="w-4 h-4 mr-2 text-blue-600 dark:text-blue-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd"></path></svg>
|
||||
<span className="font-medium text-blue-700 dark:text-blue-300">Security:</span>
|
||||
<span className="ml-1 text-gray-800 dark:text-gray-300">Data protection and privacy</span>
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<svg className="w-4 h-4 mr-2 text-purple-600 dark:text-purple-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd"></path></svg>
|
||||
<span className="font-medium text-purple-700 dark:text-purple-300">Summarization:</span>
|
||||
<span className="ml-1 text-gray-800 dark:text-gray-300">AI-powered content condensation</span>
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<svg className="w-4 h-4 mr-2 text-pink-600 dark:text-pink-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd"></path></svg>
|
||||
<span className="font-medium text-pink-700 dark:text-pink-300">Performance:</span>
|
||||
<span className="ml-1 text-gray-800 dark:text-gray-300">Fast and reliable service</span>
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<svg className="w-4 h-4 mr-2 text-green-600 dark:text-green-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd"></path></svg>
|
||||
<span className="font-medium text-green-700 dark:text-green-300">Pricing:</span>
|
||||
<span className="ml-1 text-gray-800 dark:text-gray-300">Cost-effective plans for different needs</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Target Use Cases */}
|
||||
<div className="bg-white/10 p-3 rounded-xl border border-teal-500/30 shadow-md hover:shadow-md transition-all duration-200 hover:border-teal-500/40 hover:bg-teal-500/10">
|
||||
<h3 className="text-lg font-bold mb-1 bg-gradient-to-r from-teal-400 to-blue-500 bg-clip-text text-transparent flex items-center">
|
||||
<div className="shrink-0 bg-gradient-to-br from-teal-500 to-blue-600 p-1 rounded-lg shadow-md mr-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
||||
</svg>
|
||||
</div>
|
||||
Target Use Cases
|
||||
</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-1 ml-1 transition-all duration-200">
|
||||
<div className="flex items-center p-1.5 rounded-lg hover:bg-white/20 dark:hover:bg-gray-800/30 transition-all duration-200 hover:shadow-sm">
|
||||
<div className="shrink-0 bg-red-500/30 p-1.5 rounded-full mr-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-red-600 dark:text-red-500" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-gray-900 dark:text-gray-300 text-sm font-medium">YouTube video summarization</span>
|
||||
</div>
|
||||
<div className="flex items-center p-1.5 rounded-lg hover:bg-white/20 dark:hover:bg-gray-800/30 transition-all duration-200 hover:shadow-sm">
|
||||
<div className="shrink-0 bg-orange-500/30 p-1.5 rounded-full mr-2">
|
||||
<img src="/reddit_logo.jpeg" className="h-4 w-4 rounded-full" alt="Reddit logo" />
|
||||
</div>
|
||||
<span className="text-gray-900 dark:text-gray-300 text-sm font-medium">Reddit post summarization</span>
|
||||
</div>
|
||||
<div className="flex items-center p-1.5 rounded-lg hover:bg-white/20 dark:hover:bg-gray-800/30 transition-all duration-200 hover:shadow-sm">
|
||||
<div className="shrink-0 bg-blue-500/30 p-1.5 rounded-full mr-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-blue-600 dark:text-blue-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-gray-900 dark:text-gray-300 text-sm font-medium">arXiv paper summarization</span>
|
||||
</div>
|
||||
<div className="flex items-center p-1.5 rounded-lg hover:bg-white/20 dark:hover:bg-gray-800/30 transition-all duration-200 hover:shadow-sm">
|
||||
<div className="shrink-0 bg-green-500/30 p-1.5 rounded-full mr-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-green-600 dark:text-green-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-gray-900 dark:text-gray-300 text-sm font-medium">Website content summarization</span>
|
||||
</div>
|
||||
<div className="flex items-center p-1.5 rounded-lg hover:bg-white/20 dark:hover:bg-gray-800/30 transition-all duration-200 hover:shadow-sm md:col-span-2">
|
||||
<div className="shrink-0 bg-purple-500/30 p-1.5 rounded-full mr-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-purple-600 dark:text-purple-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-gray-900 dark:text-gray-300 text-sm font-medium">PDF to flashcard conversion</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user