Skip to content

Commit

Permalink
Merge pull request #15 from alfiyafatima09/issue-10
Browse files Browse the repository at this point in the history
Added Login and Signup page
  • Loading branch information
SkySingh04 authored Aug 14, 2024
2 parents b29ed51 + c9f9ddf commit f7d3e91
Show file tree
Hide file tree
Showing 7 changed files with 357 additions and 2 deletions.
5 changes: 3 additions & 2 deletions Firebase.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getAuth, GoogleAuthProvider } from "firebase/auth";
import { getFirestore } from 'firebase/firestore';
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
Expand All @@ -21,5 +21,6 @@ const firebaseConfig = {
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
const googleProvider = new GoogleAuthProvider();

export {auth , db};
export { auth, googleProvider, db };
14 changes: 14 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,17 @@ body {
text-wrap: balance;
}
}

input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
-webkit-box-shadow: 0 0 0 1000px #151919 inset !important;
box-shadow: 0 0 0 1000px #151519 inset !important;
-webkit-text-fill-color: white !important;
background-color: #151519 !important;
padding-top: 10px;
font-size: 14px;
}


29 changes: 29 additions & 0 deletions app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"use client";
import React, { useState } from 'react';
import Login from '../../components/Login';
import Signup from '../../components/Signup';

export default function Home() {
const [isLogin, setIsLogin] = useState(true);

return (
<div className="flex flex-col items-center justify-center min-h-screen">
<div className="flex space-x-4 mb-6">
<button
onClick={() => setIsLogin(true)}
className={`p-3 rounded-md font-semibold ${isLogin ? 'bg-green-500 text-white' : 'bg-gray-200 text-gray-800'}`}
>
Login
</button>
<button
onClick={() => setIsLogin(false)}
className={`p-3 rounded-md font-semibold ${!isLogin ? 'bg-green-500 text-white' : 'bg-gray-200 text-gray-800'}`}
>
Signup
</button>
</div>
{isLogin ? <Login /> : <Signup />}
</div>
);
}

123 changes: 123 additions & 0 deletions components/Login.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
"use client";

import React, { useState } from "react";
import { useRouter } from "next/navigation";
import { signInWithEmailAndPassword, signInWithPopup, sendPasswordResetEmail } from "firebase/auth";
import { auth, googleProvider } from "../Firebase"; // Update the path
const Login = () => {
const router = useRouter();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [resetMessage, setResetMessage] = useState(""); // State for reset message

const handleLogin = async (event: React.FormEvent) => {
event.preventDefault();
try {
await signInWithEmailAndPassword(auth, email, password);
router.push("/"); // Redirect to a home-page after successful login
} catch (error) {
setError("Failed to log in");
console.error(error);
}
};

const handleGoogleSignIn = async () => {
try {
await signInWithPopup(auth, googleProvider);
router.push("/"); // Redirect to a home-page after successful login
} catch (error: any) {
setError(error.message || "Failed to sign in with Google");
console.error(error);
}
};

const handlePasswordReset = async () => {
if (!email) {
setResetMessage("Please enter your email address");
return;
}
try {
await sendPasswordResetEmail(auth, email);
setResetMessage("Password reset email sent!");
} catch (error) {
setResetMessage("Failed to send password reset email");
console.error(error);
}
};

return (
<div className="max-w-md bg-[#151916] p-12 rounded-xl shadow-lg shadow-green-500/100">
<div className="text-3xl font-semibold text-center mb-8 text-white">
Login
</div>
<form onSubmit={handleLogin}>
<div className="relative mb-6">
<input
type="text"
id="email"
placeholder=" "
value={email}
onChange={(e) => setEmail(e.target.value)}
className="peer w-full bg-transparent border-0 border-b-2 border-green-500 text-white placeholder-transparent focus:border-green-400 focus:outline-none focus:ring-0 autofill:shadow-[inset_0_0_0px_1000px_rgba(0,0,0,0)] autofill:text-white pt-2 m-1"
required
/>
<label
htmlFor="email"
className="absolute left-0 top-0 text-white text-base transition-all duration-500 transform -translate-y-3 scale-75 origin-left cursor-text peer-placeholder-shown:translate-y-0 peer-placeholder-shown:scale-100 peer-placeholder-shown:text-base peer-focus:-translate-y-3 peer-focus:scale-75 "
>
Email Address
</label>
</div>
<div className="relative mb-6">
<input
type="password"
id="password"
placeholder=" "
value={password}
onChange={(e) => setPassword(e.target.value)}
className="peer w-full bg-transparent border-0 border-b-2 border-green-500 text-white placeholder-transparent focus:border-green-400 focus:outline-none focus:ring-0 autofill:shadow-[inset_0_0_0px_1000px_rgba(0,0,0,0.8)] autofill:text-white pt-2 m-1"
required
/>
<label
htmlFor="password"
className="absolute left-0 top-0 text-white text-base transition-all duration-500 transform -translate-y-3 scale-75 origin-left cursor-text peer-placeholder-shown:translate-y-0 peer-placeholder-shown:scale-100 peer-placeholder-shown:text-base peer-focus:-translate-y-3 peer-focus:scale-75"
>
Password
</label>
</div>
<div className="text-right mb-4">
<a href="#" className="text-green-500 hover:underline" onClick={handlePasswordReset}>
Forgot password?
</a>
</div>
<div className="mb-4">
<button
type="submit"
className="w-full p-3 bg-green-600 text-white rounded-md hover:bg-green-500 "
>
Login
</button>
</div>
<div className="mb-4">
<button
type="button"
onClick={handleGoogleSignIn}
className="w-full p-3 bg-white text-black rounded-md hover:bg-[#aaabad] flex items-center justify-center"
>
<img
src="/images/google_logo.png"
alt="Google Logo"
className="w-8 h-8 mr-2"
/>
Sign in with Google
</button>
</div>
{error && <p className="text-red-500">{error}</p>}
{resetMessage && <p className="text-green-500">{resetMessage}</p>}
</form>
</div>
);
};

export default Login;
181 changes: 181 additions & 0 deletions components/Signup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
"use client";
import React, { useState } from 'react';
import { useRouter } from 'next/navigation';
import { createUserWithEmailAndPassword } from 'firebase/auth';
import { auth, db } from '../Firebase'; // Firestore initialized
import { doc, setDoc } from 'firebase/firestore';
import '../app/globals.css';


const Signup = () => {
const router = useRouter();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [role, setRole] = useState('user');
const [secretCode, setSecretCode] = useState('');
const [signupError, setSignupError] = useState(''); // State for signup error
const [dbError, setDbError] = useState(''); // State for database error
const [success, setSuccess] = useState(''); // State for success message

const handleSignup = async (event: React.FormEvent) => {
event.preventDefault();
setSignupError(''); // Clear previous errors
setDbError(''); // Clear previous database errors

if (password !== confirmPassword) {
setSignupError('Passwords do not match');
return;
}

if (role === 'admin' && secretCode !== process.env.NEXT_PUBLIC_ADMIN_SECRET_CODE) {
setSignupError('Invalid secret code for admin');
return;
}

try {
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
const user = userCredential.user;

if (role === 'admin') {
try {
await setDoc(doc(db, 'admin', user.uid), {
email,
role,
});

setSuccess('Successfully signed up!');
window.location.reload(); // Redirect to login after successful signup
} catch (dbErr) {
setDbError('Failed to save user data to the database');
console.error('Database error:', dbErr);
}
} else {
setSuccess('Successfully signed up!');
window.location.reload(); // Redirect to login page after successful signup
}
} catch (signupErr: any) {
setSignupError(signupErr.message || 'Failed to sign up');
console.error('Signup error:', signupErr);
}
};

return (
<div className="max-w-md bg-[#151916] p-10 rounded-xl shadow-lg shadow-green-600/100 ">
<div className="text-3xl font-semibold text-center mb-8 text-white">
Signup
</div>
<form onSubmit={handleSignup}>
<div className="relative mb-6">
<input
type="text"
id="email"
placeholder=" "
value={email}
onChange={(e) => setEmail(e.target.value)}
className="peer w-full bg-transparent border-0 border-b-2 border-green-500 text-white placeholder-transparent focus:border-green-400 focus:outline-none focus:ring-0 autofill:shadow-[inset_0_0_0px_1000px_rgba(0,0,0,0.8)] autofill:text-white pt-2 m-1"
required
/>
<label
htmlFor="email"
className="absolute left-0 top-0 text-white text-base transition-all duration-500 transform -translate-y-3 scale-75 origin-left cursor-text peer-placeholder-shown:translate-y-0 peer-placeholder-shown:scale-100 peer-placeholder-shown:text-base peer-focus:-translate-y-3 peer-focus:scale-75"
>
Email Address
</label>
</div>
<div className="relative mb-6">
<input
type="password"
id="password"
placeholder=" "
value={password}
onChange={(e) => setPassword(e.target.value)}
className="peer w-full bg-transparent border-0 border-b-2 border-green-500 text-white placeholder-transparent focus:border-green-400 focus:outline-none focus:ring-0 autofill:shadow-[inset_0_0_0px_1000px_rgba(0,0,0,0.8)] autofill:text-white pt-2 m-1"
required
/>
<label
htmlFor="password"
className="absolute left-0 top-0 text-white text-base transition-all duration-500 transform -translate-y-3 scale-75 origin-left cursor-text peer-placeholder-shown:translate-y-0 peer-placeholder-shown:scale-100 peer-placeholder-shown:text-base peer-focus:-translate-y-3 peer-focus:scale-75"
>
Password
</label>
</div>
<div className="relative mb-6">
<input
type="password"
id="confirm-password"
placeholder=" "
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
className="peer w-full bg-transparent border-0 border-b-2 border-green-500 text-white placeholder-transparent focus:border-green-400 focus:outline-none focus:ring-0 autofill:shadow-[inset_0_0_0px_1000px_rgba(0,0,0,0.8)] autofill:text-white pt-2 m-1"
required
/>
<label
htmlFor="confirm-password"
className="absolute left-0 top-0 text-white text-base transition-all duration-500 transform -translate-y-3 scale-75 origin-left cursor-text peer-placeholder-shown:translate-y-0 peer-placeholder-shown:scale-100 peer-placeholder-shown:text-base peer-focus:-translate-y-3 peer-focus:scale-75"
>
Confirm Password
</label>
</div>
<div className="mb-4">
<label className="block mb-2 text-white font-semibold">Sign up as:</label>
<div className="flex items-center">
<input
type="radio"
id="user"
name="role"
value="user"
checked={role === 'user'}
onChange={() => setRole('user')}
className="mr-2"
/>
<label htmlFor="user" className="text-white mr-4">User</label>
<input
type="radio"
id="admin"
name="role"
value="admin"
checked={role === 'admin'}
onChange={() => setRole('admin')}
className="mr-2"
/>
<label htmlFor="admin" className="text-white">Admin</label>
</div>
</div>
{role === 'admin' && (
<div className="relative mb-6">
<input
type="text"
id="secret-code"
placeholder=" "
value={secretCode}
onChange={(e) => setSecretCode(e.target.value)}
className="peer w-full bg-transparent border-0 border-b-2 border-green-500 text-white placeholder-transparent focus:border-green-400 focus:outline-none focus:ring-0 autofill:shadow-[inset_0_0_0px_1000px_rgba(0,0,0,0.8)] autofill:text-white pt-2 m-1"
required
/>
<label
htmlFor="secret-code"
className="absolute left-0 top-0 text-white text-base transition-all duration-500 transform -translate-y-3 scale-75 origin-left cursor-text peer-placeholder-shown:translate-y-0 peer-placeholder-shown:scale-100 peer-placeholder-shown:text-base peer-focus:-translate-y-3 peer-focus:scale-75"
>
Secret Code
</label>
</div>
)}
<div className="mb-4">
<button
type="submit"
className="w-full p-3 bg-green-600 text-white rounded-md hover:bg-green-500"
>
Signup
</button>
</div>
{signupError && <p className="text-red-500">{signupError}</p>}
{dbError && <p className="text-yellow-500">{dbError}</p>} {/* Display database error */}
{success && <p className="text-green-500">{success}</p>} {/* Display success message */}
</form>
</div>
);
};

export default Signup;

7 changes: 7 additions & 0 deletions components/ui/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ export default function Header() {
</p>
</Link>
</li>
<li>
<Link href="/login">
<p className={`btn-sm text-black bg-white mx-3 rounded-xl`}>
<span>Login/Signup</span>
</p>
</Link>
</li>
</ul>
</nav>

Expand Down
Binary file added public/images/google_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit f7d3e91

Please sign in to comment.