Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added google oauth #101

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
1 change: 0 additions & 1 deletion SAMPLE.env.local

This file was deleted.

54 changes: 40 additions & 14 deletions app/(components)/Nav.jsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,47 @@
"use client"
"use client";

import { faHome, faTicket } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import Link from "next/link";
import React, { useState } from 'react';
import React, { useState } 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;

const [tooltip, setTooltip] = useState(null);

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

return (
<nav className="flex justify-between bg-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" : "text-gray-500"}`} />
<Link
href="/"
onMouseEnter={() => showTooltip("Home")}
onMouseLeave={hideTooltip}
>
<FontAwesomeIcon
icon={faHome}
className={`icon ${isActive("/") ? "text-white" : "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" : "text-gray-500"}`} />
<Link
href="/TicketPage/new"
onMouseEnter={() => showTooltip("Create a new ticket")}
onMouseLeave={hideTooltip}
>
<FontAwesomeIcon
icon={faTicket}
className={`icon ${
isActive("/TicketPage/new") ? "text-white" : "text-gray-500"
}`}
/>
</Link>
</div>
{tooltip && (
Expand All @@ -34,9 +50,19 @@ const Nav = () => {
</div>
)}
<div>


<p className=" text-default-text">INFORMATION MANAGEMANT GROUP</p>
{session ? (
<div>
<p className="text-default-text">Welcome, {session.user.name}</p>
<button
onClick={() => signOut()}
className="text-red-500 hover:underline"
>
Sign Out
</button>
</div>
) : (
<p className="text-default-text">INFORMATION MANAGEMENT GROUP</p>
)}
</div>
</nav>
);
Expand Down
51 changes: 42 additions & 9 deletions app/api/Tickets/[id]/route.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,83 @@
import Ticket from "@/app/models/Ticket";
import { NextResponse } from "next/server";
import { getServerSession } from "next-auth/next";
import { authOptions } from "@/app/api/auth/[...nextauth]/route";

export async function GET(request, { params }) {
const { id } = params;
const session = await getServerSession(authOptions);
if (!session) {
return NextResponse.json(
{ message: "Unauthorized access" },
{ status: 401 }
);
}

const foundTicket = await Ticket.findOne({ _id: id });
return NextResponse.json({ foundTicket }, { status: 200 });
const { id } = params;
try {
const foundTicket = await Ticket.findOne({ _id: id });
return NextResponse.json({ foundTicket }, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json({ message: "Error", error }, { status: 500 });
}
}

export async function PUT(req, { params }) {
const session = await getServerSession(authOptions);
if (!session) {
return NextResponse.json(
{ message: "Unauthorized access" },
{ status: 401 }
);
}

try {
const { id } = params;

const body = await req.json();
const ticketData = body.formData;
const existingTicket = await Ticket.findById(id);

const updateTicketData = await Ticket.findByIdAndUpdate(id, {
...ticketData,
});
if (existingTicket.status !== "not started") {
const { title, description, category, priority } = ticketData;

if (title !== existingTicket.title || description !== existingTicket.description || category !== existingTicket.category || priority !== existingTicket.priority) {
if (
title !== existingTicket.title ||
description !== existingTicket.description ||
category !== existingTicket.category ||
priority !== existingTicket.priority
) {
return NextResponse.json(
{ message: "Cannot edit fields once the status is not 'not started'" },
{ status: 400 }
);
}
}

await Ticket.findByIdAndUpdate(id, { ...ticketData });
return NextResponse.json({ message: "Ticket updated" }, { status: 200 });
} catch (error) {
console.log(error);
console.error(error);
return NextResponse.json({ message: "Error", error }, { status: 500 });
}
}

export async function DELETE(req, { params }) {
const session = await getServerSession(authOptions);
if (!session) {
return NextResponse.json(
{ message: "Unauthorized access" },
{ status: 401 }
);
}

try {
const { id } = params;

await Ticket.findByIdAndDelete(id);
return NextResponse.json({ message: "Ticket Deleted" }, { status: 200 });
} catch (error) {
console.log(error);
console.error(error);
return NextResponse.json({ message: "Error", error }, { status: 500 });
}
}
21 changes: 21 additions & 0 deletions app/api/auth/[...nextauth]/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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;
},
},
secret: process.env.NEXTAUTH_SECRET,
};

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;
22 changes: 10 additions & 12 deletions app/layout.jsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
"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">
<body className={inter.className}>
<div className="flex flex-col h-screen max-h-screen">
<Nav />

<div className="flex-grow overflow-y-auto bg-page text-default-text">
{children}
<SessionProvider>
<div className="flex flex-col h-screen max-h-screen">
<Nav />
<div className="flex-grow overflow-y-auto bg-page text-default-text">
{children}
</div>
</div>
</div>
</SessionProvider>
</body>
</html>
);
Expand Down
6 changes: 6 additions & 0 deletions app/metadate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// app/metadata.js
export const metadata = {
title: "Ticket System",
description: "Creating a functional ticketing system.",
};

20 changes: 18 additions & 2 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,21 +26,31 @@ 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");
const [viewBy, setViewBy] = useState("category");
const [groupVisibility, setGroupVisibility] = useState({});

useEffect(() => {
if (status === "unauthenticated") {
router.push("/auth/signin"); // Redirect unauthenticated users to the login page
}
}, [status, router]);

useEffect(() => {
const fetchTickets = async () => {
const data = await getTickets();
setTickets(data?.tickets || []);
setFilteredTickets(data?.tickets || []);
};

fetchTickets();
}, []);
if (session) {
fetchTickets();
}
}, [session]);

useEffect(() => {
if (statusFilter === "all") {
Expand Down Expand Up @@ -75,6 +87,10 @@ const Dashboard = () => {
}));
};

if (status === "loading") {
return <div>Loading...</div>; // Show a loading state while the session is being checked
}

return (
<div className="p-5">
{tickets.length === 0 ? (
Expand Down
Loading