Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="https://github.githubassets.com/favicons/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
<title>GitConnectX</title>
</head>
<body>
<div id="root"></div>
Expand Down
193 changes: 160 additions & 33 deletions frontend/src/components/Header.jsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,168 @@
import React from 'react';
import logo from '../assets/logo.png';
import React, { useState, useEffect, useRef } from "react";
import logo from "../assets/logo.png";
import { useAuth0 } from "@auth0/auth0-react";

const Header = ({ scrollToFeatures, scrollToContact }) => {
const { loginWithRedirect, isAuthenticated, logout, user } = useAuth0();
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [isLoggingOut, setIsLoggingOut] = useState(false);
const [showVerificationAlert, setShowVerificationAlert] = useState(false);
const dropdownRef = useRef(null);

// Check email verification status when user data is available
useEffect(() => {
if (user && !user.email_verified) {
setShowVerificationAlert(true);
// Hide the alert after 5 seconds
const timer = setTimeout(() => {
setShowVerificationAlert(false);
}, 5000);
return () => clearTimeout(timer);
}
}, [user]);

// Get display name from full name or email
const getDisplayName = () => {
if (user?.nickname) return user.nickname;
if (user?.name) {
// Split name and get first part (usually the given name)
return user.name.split(' ')[0];
}
if (user?.email) {
// Get part before @ in email
return user.email.split('@')[0];
}
return 'User';
};

// Close dropdown when clicking outside
useEffect(() => {
const handleClickOutside = (event) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setIsDropdownOpen(false);
}
};

document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);

const handleLogout = () => {
setIsLoggingOut(true);
setTimeout(() => {
logout({ logoutParams: { returnTo: window.location.origin } });
}, 500);
};

return (
<header className="bg-white shadow-md fixed top-0 left-0 w-full z-50">
<div className="container mx-auto flex justify-between items-center p-4">
<div className="flex items-center space-x-2">
<img className="w-10 md:w-10" src={logo} alt="logo" />
<div className="text-xl font-bold text-[#1737A1]">
GitConnectX
<>
{showVerificationAlert && (
<div className="fixed top-0 left-0 right-0 z-50 bg-yellow-100 text-yellow-800 px-4 py-3 shadow-md transition-all duration-300 ease-in-out">
<div className="container mx-auto flex items-center justify-between">
<div className="flex items-center">
<svg className="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd"/>
</svg>
<p>Please verify your email address. Check your inbox for the verification link.</p>
</div>
<button
onClick={() => setShowVerificationAlert(false)}
className="text-yellow-800 hover:text-yellow-900 focus:outline-none"
>
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd"/>
</svg>
</button>
</div>
</div>
)}
<header className={`bg-white shadow-md fixed ${showVerificationAlert ? 'top-12' : 'top-0'} left-0 w-full z-40 transition-all duration-300`}>
<div className="container mx-auto flex justify-between items-center p-4">
<div className="flex items-center space-x-2">
<img className="w-10 md:w-10" src={logo} alt="logo" />
<div className="text-xl font-bold text-[#1737A1]">GitConnectX</div>
</div>
<nav className="space-x-6 flex items-center">
<a href="/" className="text-black hover:text-[#1737A1]">
Home
</a>
<button
onClick={scrollToFeatures}
className="text-black hover:text-[#1737A1] focus:outline-none"
>
Features
</button>
<button
onClick={scrollToContact}
className="text-black hover:text-[#1737A1] focus:outline-none"
>
Contact Us
</button>
{isAuthenticated ? (
<div className="relative" ref={dropdownRef}>
<button
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
className={`flex items-center space-x-2 text-gray-700 hover:text-[#1737A1] focus:outline-none transition-opacity duration-500 ${
isLoggingOut ? 'opacity-0' : 'opacity-100'
}`}
>
{user?.picture ? (
<img
src={user.picture}
alt={getDisplayName()}
className="w-8 h-8 rounded-full object-cover border-2 border-[#1737A1]"
/>
) : (
<div className="w-8 h-8 rounded-full bg-[#1737A1] text-white flex items-center justify-center">
{getDisplayName()[0].toUpperCase()}
</div>
)}
<span className="max-w-[120px] truncate font-medium">{getDisplayName()}</span>
<svg
className={`w-4 h-4 transition-transform duration-300 ${isDropdownOpen ? 'rotate-180' : ''}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7" />
</svg>
</button>

{isDropdownOpen && (
<div className="absolute right-0 mt-2 w-64 bg-white rounded-md shadow-lg py-1 z-50 transform transition-all duration-300 ease-in-out">
<div className="px-4 py-3 border-b border-gray-100">
<p className="text-sm font-medium text-gray-900">{user?.name}</p>
<p className="text-sm text-gray-500 truncate">{user?.email}</p>
{!user?.email_verified && (
<p className="text-xs text-yellow-600 mt-1 flex items-center">
<svg className="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd"/>
</svg>
Email not verified
</p>
)}
</div>
<button
onClick={handleLogout}
className="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-[#b91313] transition-colors duration-200"
>
Logout
</button>
</div>
)}
</div>
) : (
<button
onClick={() => loginWithRedirect()}
className="text-white bg-[#1737A1] px-4 py-2 rounded hover:bg-indigo-700 transition transform hover:-translate-y-1 hover:shadow-md focus:outline-none font-semibold"
>
Login / Signup
</button>
)}
</nav>
</div>
<nav className="space-x-6">
<a href="/" className="text-black hover:text-[#1737A1]">
Home
</a>
<button
onClick={scrollToFeatures}
className="text-black hover:text-[#1737A1] focus:outline-none"
>
Features
</button>
<button
onClick={scrollToContact}
className="text-black hover:text-[#1737A1] focus:outline-none"
>
Contact Us
</button>
<a
href="/login"
className="text-white bg-[#1737A1] px-4 py-2 rounded w-full hover:bg-indigo-700 transition transform hover:-translate-y-1 hover:shadow-md"
>
Login / Signup
</a>
</nav>
</div>
</header>
</header>
</>
);
};

Expand Down
15 changes: 13 additions & 2 deletions frontend/src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,22 @@ import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import { BrowserRouter } from 'react-router-dom'
import { Auth0Provider } from '@auth0/auth0-react';

createRoot(document.getElementById('root')).render(
<StrictMode>
<Auth0Provider
domain="dev-rix5014830kjp6bu.us.auth0.com"
clientId="imHetka8y4HGCtXNEaKK93WtKD9nP76Y"
authorizationParams={{
redirect_uri: window.location.origin,
audience: `https://dev-rix5014830kjp6bu.us.auth0.com/api/v2/`,
scope: "openid profile email"
}}
useRefreshTokens={true}
cacheLocation="localstorage"
>
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>,
</Auth0Provider>
)
69 changes: 27 additions & 42 deletions frontend/src/pages/Login.jsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,40 @@
import React, { useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth0 } from '@auth0/auth0-react';
import Header from '../components/Header';
import Footer from '../components/Footer';

const Login = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const navigate = useNavigate();
const { loginWithRedirect, isAuthenticated } = useAuth0();

const handleLogin = (e) => {
e.preventDefault();
console.log('Logging in with', email, password);
navigate('/');
};
// Redirect to home if already authenticated
React.useEffect(() => {
if (isAuthenticated) {
navigate('/');
}
}, [isAuthenticated, navigate]);

return (
<div className="flex flex-col min-h-screen">
<Header/>
<div className="flex items-center justify-center min-h-screen bg-gradient-to-r from-blue-900 via-purple-800 to-indigo-800">
<div className="bg-white p-8 rounded-lg shadow-lg w-full max-w-md">
<h2 className="text-3xl font-extrabold mb-6 text-center text-gray-800">Login</h2>
<form onSubmit={handleLogin}>
<input
type="email"
placeholder="Email"
className="mb-4 w-full px-4 py-2 border rounded focus:outline-none focus:ring-2 focus:ring-indigo-400"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<input
type="password"
placeholder="Password"
className="mb-4 w-full px-4 py-2 border rounded focus:outline-none focus:ring-2 focus:ring-indigo-400"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button
type="submit"
className="w-full bg-indigo-600 text-white py-2 rounded hover:bg-indigo-700 transition"
>
Login
</button>
</form>
<p className="mt-4 text-center text-sm">
Don’t have an account?{' '}
<Link to="/signup" className="text-indigo-600 font-semibold hover:underline">
Sign up
</Link>
</p>
<div className="flex items-center justify-center min-h-screen bg-gradient-to-r from-blue-900 via-purple-800 to-indigo-800">
<div className="bg-white p-8 rounded-lg shadow-lg w-full max-w-md">
<h2 className="text-3xl font-extrabold mb-6 text-center text-gray-800">Welcome Back!</h2>
<div className="flex flex-col items-center space-y-4">
<button
onClick={() => loginWithRedirect()}
className="w-full bg-[#1737A1] text-white py-3 rounded-lg hover:bg-indigo-700 transition transform hover:-translate-y-1 hover:shadow-md focus:outline-none font-semibold"
>
Continue with Auth0
</button>
<p className="text-sm text-gray-600">
Secure login powered by Auth0
</p>
</div>
</div>
</div>
</div>
<Footer/>
<Footer/>
</div>
);
};
Expand Down