UNPKG

leumas-private-shared

Version:

Private React JSX Package For Leumas Shared Components, Headers, Footers, Asides, Login Pages, API Key Manager and much more. Styles and everything reusable to avoid DRY code across all of our subdomains

263 lines (236 loc) 11.3 kB
import { useState, useEffect } from 'react'; import axios from 'axios'; import { Link, useNavigate } from 'react-router-dom'; import { FaCircleCheck } from "react-icons/fa6"; import useSignIn from 'react-auth-kit/hooks/useSignIn'; import { FaCheckCircle } from 'react-icons/fa'; import useAuthUser from 'react-auth-kit/hooks/useAuthUser'; import { Helmet } from 'react-helmet'; import { useTheme } from "../../Theme/ThemeContext"; import InfinityBackgroundComponent from '../../Components/Backgrounds/Infinity'; // Import the new background component import React from 'react'; function Login2({ setMode }) { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [whatsNew, setWhatsNew] = useState([]); const signIn = useSignIn(); const navigate = useNavigate(); const auth = useAuthUser(); const isLoggedIn = auth !== null; const { theme } = useTheme(); useEffect(() => { // Fetch "What's New" content from backend const fetchWhatsNew = async () => { try { const response = await axios.get(`http://localhost:3002/configs/whats-new`); setWhatsNew(response.data); } catch (error) { console.error("Error fetching 'What's New' content:", error); } }; fetchWhatsNew(); }, []); const handleGoogleSuccess = async (response) => { console.log('Google response:', response); const token = response.credential; try { const res = await axios.post(`${import.meta.env.VITE_REACT_APP_LEUMAS_LOGIN_ENDPOINT}/login/google`, { token }); const { token: appToken, expiresIn, authUserState } = res.data; if (signIn({ auth: { token: appToken, type: 'Bearer', expiresIn: expiresIn, authState: res.data.authUserState, }, expiresIn: expiresIn, authState: res.data.authUserState, userState: authUserState })) { navigate('/dashboard'); window.location.href = '/dashboard'; } else { console.error('Sign-in failed'); } navigate("/dashboard"); } catch (error) { console.error('Error during Google Sign In:', error); } }; const handleGoogleFailure = (error) => { if (error.error === 'popup_closed_by_user') { console.log("Popup was closed before completing the sign-in process."); } else { console.error('Google Sign In Failed:', error); } }; const navigateToUserDashboard = () => { navigate("/dashboard"); window.location.href = '/dashboard'; }; const handleLogin = async (e) => { e.preventDefault(); if (!username || !password) { setError('Please enter both username and password.'); return; } setIsLoading(true); setError(null); try { console.log("Fetching from Wordpress "); const wpResponse = await axios.post(`https://leumas.tech/wp-json/jwt-auth/v1/token`, { username: username, password: password, }); const membershipId = wpResponse.data.user_membership_level?.id || 0; const membershipName = wpResponse.data.user_membership_level?.name || "Free"; const { token, user_display_name, user_email, user_nicename } = wpResponse.data; console.log("Fetching From Backend"); const backendResponse = await axios.post(`${import.meta.env.VITE_REACT_APP_LEUMAS_LOGIN_ENDPOINT}/login`, { token, user_display_name, user_email, user_nicename, membershipId, membershipName, }); const appToken = backendResponse.data.token; const expiresIn = backendResponse.data.expiresIn; const authUserState = { ...backendResponse.data.authUserState, membershipId, membershipName }; if (signIn({ auth: { token: appToken, type: 'Bearer', expiresIn: expiresIn, authState: authUserState, }, expiresIn: expiresIn, authState: authUserState, userState: authUserState })) { navigate('/'); window.location.href = '/'; } } catch (error) { console.log("Error ", error); setError(error.response?.data.message || 'An error occurred.'); } finally { setIsLoading(false); } }; return ( <> <Helmet> <title>Login | Bulk Forge - Mass AI Asset Generation</title> <meta name="description" content="Login to Bulk Forge to start mass producing assets with AI. Access your dashboard for code generation, image creation with DALL·E, and more." /> <meta name="keywords" content="Bulk Forge login, AI asset generation, code generation, DALL·E image creation, mass produce AI, AI tools" /> <meta name="robots" content="index, follow" /> <meta name="author" content="Leumas Tech" /> <meta property="og:title" content="Login | Bulk Forge - Mass AI Asset Generation" /> <meta property="og:description" content="Access Bulk Forge to efficiently produce assets with AI, including code and DALL·E generated images." /> <meta property="og:type" content="website" /> <meta property="og:url" content="https://bulkForge.leumas.tech/login" /> <meta property="og:image" content="https://res.cloudinary.com/dx25lltre/image/upload/v1707176122/Leumas/2_t6ap9y.svg" /> <meta property="og:site_name" content="Bulk Forge" /> <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:title" content="Login | Bulk Forge - Mass AI Asset Generation" /> <meta name="twitter:description" content="Access Bulk Forge to start creating assets with AI for code generation and image creation with DALL·E." /> <meta name="twitter:image" content="https://res.cloudinary.com/dx25lltre/image/upload/v1707176122/Leumas/2_t6ap9y.svg" /> <link rel="canonical" href="https://bulkForge.leumas.tech/login" /> <meta httpEquiv="content-language" content="en" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" /> <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" /> <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" /> <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" /> <meta name="msapplication-TileColor" content="#2b5797" /> <meta name="theme-color" content="#ffffff" /> </Helmet> <InfinityBackgroundComponent> {isLoggedIn === false ? ( <div className="flex flex-col md:flex-row items-stretch bg-transparent p-4 md:p-8 border border-green-400 w-full "> <div className={`hidden md:flex w-1/2 flex-col gap-4 mx-auto rounded-lg shadow-3xl p-2 text-blue-400`}> <div className='flex gap-2 items-center justify-start'> <img src={`https://res.cloudinary.com/dx25lltre/image/upload/v1707176122/Leumas/2_t6ap9y.svg`} className='h-12' /> <h1 className='text-2xl md:text-3xl font-bold'>{window.location.href.split("/")[0]}</h1> </div> {/* Slideshow of "What's New" content */} <div className='relative w-full h-full overflow-hidden rounded-lg'> {whatsNew.length > 0 && whatsNew.map((item, index) => ( <div key={index} className='absolute inset-0 transition-opacity duration-1000 ease-in-out'> <img src={item.imageUrl} alt={item.title} className='w-full h-full object-cover rounded-lg' /> <div className='absolute bottom-0 left-0 right-0 bg-black bg-opacity-50 p-4 text-white'> <h2 className='text-xl font-bold'>{item.title}</h2> <p className='text-sm'>{item.description}</p> </div> </div> ))} </div> </div> <div className={`w-full md:w-1/2 p-6 rounded-lg shadow-xl max-h-[500px] mx-auto ${theme === 'dark' ? 'bg-black' : 'bg-white'}`}> <h1 className="text-xl md:text-2xl font-semibold mb-6 text-start">Login</h1> {error && ( <div className="bg-red-100 text-red-700 p-3 mb-6 rounded-lg"> {error} </div> )} <form onSubmit={handleLogin} className="space-y-6"> <div> <label htmlFor="username" className="block text-sm md:text-base font-medium mb-2 text-start"> Username </label> <input type="text" id="username" value={username} onChange={(e) => setUsername(e.target.value)} className="w-full p-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 bg-transparent" /> </div> <div> <label htmlFor="password" className="block text-sm md:text-base font-medium mb-2 text-start"> Password </label> <input type="password" id="password" value={password} onChange={(e) => setPassword(e.target.value)} className="w-full p-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 bg-transparent " /> </div> <button type="submit" className={`w-full p-3 text-base font-semibold text-white rounded-lg ${ isLoading ? 'bg-gray-400 cursor-not-allowed' : 'bg-blue-600 hover:bg-blue-700' }`} disabled={isLoading} > {isLoading ? 'Logging in...' : 'Login'} </button> </form> <div className="mt-4 text-center"> <Link to="https://leumas.tech/signup" className="text-sm md:text-base text-blue-600 hover:text-blue-700"> Don't have an account? Sign up. </Link> </div> </div> </div> ) : ( <div className="flex items-center justify-center min-h-screen"> <div className="text-center"> <FaCheckCircle className="text-green-500 text-6xl mx-auto" /> <p className="text-xl mt-4">You are already logged in {auth?.id}</p> <button onClick={navigateToUserDashboard} className="mt-4 bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded-lg"> Go to Dashboard </button> </div> </div> )} </InfinityBackgroundComponent> </> ); } export default Login2;