Skip to content

Commit

Permalink
add google oauth (#101) close issue#72
Browse files Browse the repository at this point in the history
* added google oauth

* made UI changes

* ticket is editable

* resolved comments

* clean

* corrections
  • Loading branch information
disvid authored Jan 15, 2025
1 parent fa35aa7 commit 5f2d4a2
Show file tree
Hide file tree
Showing 10 changed files with 443 additions and 135 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ npm install

Replace `<no-of-tickets-to-be-shown-per-page-by-default>` with the number of tickets you want to show by default per page.

These variables are needed to configure Google OAuth for authentication:
```env
GOOGLE_CLIENT_ID=<your-google-client-id>
GOOGLE_CLIENT_SECRET=<your-google-client-secret>
```
Replace `<your-google-client-id>` with the Google OAuth client ID and `<your-google-client-secret>` with Google OAuth client secret.
```env
# Redis Configuration
REDIS_HOST=127.0.0.1 # Replace with your Redis server's IP or hostname
Expand Down
4 changes: 3 additions & 1 deletion SAMPLE.env.local
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
MONGODB_URI=mongodb+srv://yourUSER:[email protected]/MondayClone
CLIENT_ID=<google-oauth-clientid>
GOOGLE_CLIENT_SECRET=<google-oauth-clientsecret>
REDIS_HOST=127.0.0.1 # Replace with your Redis server's IP or hostname
REDIS_PORT=6379 # Default Redis port
REDIS_PORT=6379 # Default Redis port
76 changes: 48 additions & 28 deletions app/(components)/Nav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import Link from "next/link";
import React, { useState, useEffect } from 'react';
import { usePathname } from "next/navigation";
import { useSession, signOut } from "next-auth/react";

const Nav = () => {
const currentPath = usePathname()
const currentPath = usePathname();
const { data: session } = useSession();

const isActive = (href) => currentPath === href;

Expand Down Expand Up @@ -39,40 +41,58 @@ const Nav = () => {

const showTooltip = (content) => setTooltip(content);
const hideTooltip = () => setTooltip(null);

return (
<nav className="flex justify-between dark:bg-nav bg-light-nav p-4">
<div className="flex items-center space-x-4">
<Link href="/"
onMouseEnter={() => showTooltip('Home')}
onMouseLeave={hideTooltip}>
<FontAwesomeIcon icon={faHome} className={`icon ${isActive("/") ? "text-white dark:text-white" : "text-gray-500 dark:text-gray-500"}`} />
</Link>
<Link href="/TicketPage/new"
onMouseEnter={() => showTooltip('Create a new ticket')}
onMouseLeave={hideTooltip}>
<FontAwesomeIcon icon={faTicket} className={`icon ${isActive("/TicketPage/new") ? "text-white dark:text-white" : "text-gray-500 dark:text-gray-500"}`} />
</Link>
</div>
{tooltip && (
<div className="absolute bg-black text-white text-xs py-1 px-2 rounded top-12">
{tooltip}
<nav className="flex flex-col dark:bg-nav bg-light-nav p-4">
<div className="flex justify-between items-center mb-4">
<div className="flex items-center space-x-2">
<Link href="http://img.iitr.ac.in/" target="_blank">
<img
src="/img-logo.png"
alt="IMG Logo"
className="w-8 h-8 cursor-pointer"
/>
</Link>
<p className="text-default-text text-lg font-bold">INFORMATION MANAGEMENT GROUP</p>
</div>
)}

<div className="flex items-center space-x-2">
<button onClick={toggleTheme}>
<FontAwesomeIcon icon={theme === "dark" ? faSun : faMoon} className="icon text-white" />
</button>
</div>

<Link href="http://img.iitr.ac.in/" target="_blank">
<img
src="/img-logo.png"
alt="IMG Logo"
className="w-8 h-8 cursor-pointer"
/>
</Link>
<p className="text-default-text">INFORMATION MANAGEMENT GROUP</p>
<div className="flex justify-between items-center">
<div className="flex items-center space-x-4">
<Link href="/"
onMouseEnter={() => showTooltip('Home')}
onMouseLeave={hideTooltip}>
<FontAwesomeIcon icon={faHome} className={`icon ${isActive("/") ? "text-white dark:text-white" : "text-gray-500 dark:text-gray-500"}`} />
</Link>
<Link href="/TicketPage/new"
onMouseEnter={() => showTooltip('Create a new ticket')}
onMouseLeave={hideTooltip}>
<FontAwesomeIcon icon={faTicket} className={`icon ${isActive("/TicketPage/new") ? "text-white dark:text-white" : "text-gray-500 dark:text-gray-500"}`} />
</Link>
</div>

{tooltip && (
<div className="absolute bg-black text-white text-xs py-1 px-2 rounded top-12">
{tooltip}
</div>
)}

<div>
{session ? (
<div className="text-right">
<p className="text-default-text">Welcome, {session.user.name}</p>
<button
onClick={() => signOut()}
className="text-red-500 hover:underline"
>
Sign Out
</button>
</div>
) : null}
</div>
</div>
</nav>
);
Expand Down
20 changes: 20 additions & 0 deletions app/api/auth/[...nextauth]/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";

export const authOptions = {
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
callbacks: {
async session({ session, token }) {
session.user.id = token.sub;
return session;
},
},
};

const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
31 changes: 31 additions & 0 deletions app/auth/signin/page.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"use client";

import React from "react";
import { signIn } from "next-auth/react";

const SignInPage = () => {
const handleGoogleSignIn = () => {
signIn("google", { callbackUrl: "/" });
};

return (
<div className="flex justify-center items-center min-h-screen bg-dark gray-100">
<div className="p-8 border rounded-lg shadow-lg w-96 bg-dark gray">
<h1 className="text-3xl mb-6 text-center font-semibold text-white-700">Sign In</h1>
<button
onClick={handleGoogleSignIn}
className="w-full bg-gradient-to-r from-blue-500 via-blue-600 to-blue-700 text-white p-4 rounded-lg flex items-center justify-center space-x-3 transform transition duration-300 hover:scale-105 shadow-lg"
>
<img
src="/googlelogo.png"
alt="Google"
className="w-6 h-6"
/>
<span className="font-medium">Sign in with Google</span>
</button>
</div>
</div>
);
};

export default SignInPage;
25 changes: 13 additions & 12 deletions app/layout.jsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
"use client";
import Nav from "./(components)/Nav";
import "./globals.css";
import { Inter } from "next/font/google";

import { SessionProvider } from "next-auth/react";
import { config } from "@fortawesome/fontawesome-svg-core";
import "@fortawesome/fontawesome-svg-core/styles.css";

config.autoAddCss = false;

const inter = Inter({ subsets: ["latin"] });

export const metadata = {
title: "Ticket System",
description: "Creating a functional ticketing system.",
};

export default function RootLayout({ children }) {
return (
<html lang="en">
<head>
<title>Ticket System</title>
<meta name="description" content="Creating a functional ticketing system." />
</head>
<body className={inter.className}>
<div className="flex flex-col h-screen max-h-screen">
<Nav />

<div className="flex-grow overflow-y-auto bg-light-page dark:bg-page text-light-default-text dark:text-default-text">
{children}
<SessionProvider>
<div className="flex flex-col h-screen max-h-screen">
<Nav />
<div className="flex-grow overflow-y-auto bg-light-page dark:bg-page text-light-default-text dark:text-default-text">
{children}
</div>
</div>
</div>
</SessionProvider>
</body>
</html>
);
Expand Down
18 changes: 15 additions & 3 deletions app/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronDown, faChevronRight } from "@fortawesome/free-solid-svg-icons";
import TicketCard from "./(components)/TicketCard";
import NoTicketExistsCard from "./(components)/NoTicketExistsCard";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";

const getTickets = async () => {
try {
Expand All @@ -24,6 +26,8 @@ const getTickets = async () => {
};

const Dashboard = () => {
const { data: session, status } = useSession();
const router = useRouter();
const [tickets, setTickets] = useState([]);
const [filteredTickets, setFilteredTickets] = useState([]);
const [statusFilter, setStatusFilter] = useState("all");
Expand All @@ -32,10 +36,18 @@ const Dashboard = () => {
const timeout = 5000;
const [groupVisibility, setGroupVisibility] = useState({});

useEffect(() => {
if (status === "unauthenticated") {
router.push("/auth/signin");
}
}, [status, router]);

useEffect(() => {
let ticketFetchTimeout;

const fetchTicketsWithTimeout = async () => {
if (!session) return;

setIsLoading(true);

try {
Expand All @@ -49,8 +61,8 @@ const Dashboard = () => {
const data = await ticketsPromise;
clearTimeout(ticketFetchTimeout);

setTickets(data.tickets);
setFilteredTickets(data.tickets);
setTickets(data.tickets);
setFilteredTickets(data.tickets);
} catch (error) {
console.error("Error fetching tickets:", error);
setTickets([]);
Expand All @@ -65,7 +77,7 @@ const Dashboard = () => {
return () => {
if (ticketFetchTimeout) clearTimeout(ticketFetchTimeout);
};
}, []);
}, [session, timeout]);

useEffect(() => {
if (statusFilter === "all") {
Expand Down
Loading

0 comments on commit 5f2d4a2

Please sign in to comment.