diff --git a/blotztask-ui/src/app/api/auth/[...nextauth]/options.ts b/blotztask-ui/src/app/api/auth/[...nextauth]/options.ts index efe4bb3..413bfd3 100644 --- a/blotztask-ui/src/app/api/auth/[...nextauth]/options.ts +++ b/blotztask-ui/src/app/api/auth/[...nextauth]/options.ts @@ -1,6 +1,6 @@ -import { NextAuthOptions } from "next-auth"; -import CredentialsProvider from "next-auth/providers/credentials"; -import { cookies } from "next/headers"; +import { NextAuthOptions } from 'next-auth'; +import CredentialsProvider from 'next-auth/providers/credentials'; +import { cookies } from 'next/headers'; interface Credentials { email: string; @@ -15,96 +15,94 @@ interface LoginApiResponse { } export const authOptions: NextAuthOptions = { - // Configure one or more authentication providers - providers: [ - CredentialsProvider({ - // The name to display on the sign in form (e.g. "Sign in with...") - name: "Credentials", - // `credentials` is used to generate a form on the sign in page. - // You can specify which fields should be submitted, by adding keys to the `credentials` object. - // e.g. domain, username, password, 2FA token, etc. - // You can pass any HTML attribute to the tag through the object. - credentials: { - email: { label: "Email", type: "text", placeholder: "your email" }, - password: { label: "Password", type: "password" } - }, - - async authorize(credentials: Credentials) { - const { email, password } = credentials; + // Configure one or more authentication providers + providers: [ + CredentialsProvider({ + // The name to display on the sign in form (e.g. "Sign in with...") + name: 'Credentials', + // `credentials` is used to generate a form on the sign in page. + // You can specify which fields should be submitted, by adding keys to the `credentials` object. + // e.g. domain, username, password, 2FA token, etc. + // You can pass any HTML attribute to the tag through the object. + credentials: { + email: { label: 'Email', type: 'text', placeholder: 'your email' }, + password: { label: 'Password', type: 'password' }, + }, - - try { - //TODO : Remove reject unauthorized set to false - if (process.env.NODE_ENV !== 'production') { - process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; - } - //TODO :Also fix the fetch url for login in prod - const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/login/`, { + async authorize(credentials: Credentials) { + const { email, password } = credentials; + + try { + //TODO : Remove reject unauthorized set to false + if (process.env.NODE_ENV !== 'production') { + process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; + } + //TODO :Also fix the fetch url for login in prod + const response = await fetch( + `${process.env.NEXT_PUBLIC_API_BASE_URL}/login/`, + { method: 'POST', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - body: JSON.stringify({ email, password }) - }); - - if (!response.ok) { - console.error('Failed to authenticate:', response); - return null; + body: JSON.stringify({ email, password }), } - - const data: LoginApiResponse = await response.json(); + ); - cookies().set('authToken', data.accessToken, { - secure: process.env.NODE_ENV === 'production', - sameSite: 'strict' - }); - - if (data.accessToken) { - return { - id: email || 'placeholder-id', - email: email, - accessToken: data.accessToken, // Include the access token here - refreshToken: data.refreshToken, - expiresIn: data.expiresIn, - }; - } else { - console.error('Access token not found in response'); - return null; - } - } catch (error) { - console.error('Unhandled error:', error); + if (!response.ok) { + console.error('Failed to authenticate:', response); return null; } - - } - }) - ], - secret: process.env.NEXTAUTH_SECRET, - callbacks: { - async signIn({ user, account }) { - if (user?.access_token) { - account.access_token = user?.access_token as string + const data: LoginApiResponse = await response.json(); + + cookies().set('authToken', data.accessToken, { + secure: process.env.NODE_ENV === 'production', + sameSite: 'strict', + }); + + if (data.accessToken) { + return { + id: email || 'placeholder-id', + email: email, + accessToken: data.accessToken, // Include the access token here + refreshToken: data.refreshToken, + expiresIn: data.expiresIn, + }; + } else { + console.error('Access token not found in response'); + return null; + } + } catch (error) { + console.error('Unhandled error:', error); + return null; } - if (user?.refresh_token) { - account.refresh_token = user?.refresh_token as string - } - - return true }, - async jwt({ token, session }) { - console.log('jwt callback', token, session); - return token; - }, - async session({ session, token, user }) { - console.log('session callback', session, token, user); - - - return session + }), + ], + secret: process.env.NEXTAUTH_SECRET, + callbacks: { + async signIn({ user, account }) { + if (user?.access_token) { + account.access_token = user?.access_token as string; } + if (user?.refresh_token) { + account.refresh_token = user?.refresh_token as string; + } + + return true; }, - session: { - strategy: "jwt" + async jwt({ token, session }) { + console.log('jwt callback', token, session); + return token; + }, + async session({ session, token, user }) { + console.log('session callback', session, token, user); + + return session; }, - - } \ No newline at end of file + }, + session: { + strategy: 'jwt', + }, +}; diff --git a/blotztask-ui/src/app/api/auth/[...nextauth]/route.ts b/blotztask-ui/src/app/api/auth/[...nextauth]/route.ts index 70b9923..a166338 100644 --- a/blotztask-ui/src/app/api/auth/[...nextauth]/route.ts +++ b/blotztask-ui/src/app/api/auth/[...nextauth]/route.ts @@ -1,6 +1,5 @@ -import NextAuth from "next-auth" -import { authOptions } from "./options" +import NextAuth from 'next-auth'; +import { authOptions } from './options'; - -const handler = NextAuth(authOptions) -export { handler as GET, handler as POST } \ No newline at end of file +const handler = NextAuth(authOptions); +export { handler as GET, handler as POST }; diff --git a/blotztask-ui/src/app/layout.tsx b/blotztask-ui/src/app/layout.tsx index 3b6e983..619747a 100644 --- a/blotztask-ui/src/app/layout.tsx +++ b/blotztask-ui/src/app/layout.tsx @@ -17,7 +17,7 @@ export const metadata: Metadata = { }; export default function RootLayout({ - children + children, }: Readonly<{ children: React.ReactNode; }>) { @@ -38,7 +38,9 @@ export default function RootLayout({ > {/* TODO: Implement navbar to navigate between pages*/} -
{children}
+
+ {children} +
diff --git a/blotztask-ui/src/app/navbar/main-nav.tsx b/blotztask-ui/src/app/navbar/main-nav.tsx index 7886886..5265f1d 100644 --- a/blotztask-ui/src/app/navbar/main-nav.tsx +++ b/blotztask-ui/src/app/navbar/main-nav.tsx @@ -1,13 +1,21 @@ 'use client'; -import { ClientSafeProvider, getProviders, signOut, useSession } from 'next-auth/react'; +import { + ClientSafeProvider, + getProviders, + signOut, + useSession, +} from 'next-auth/react'; import Image from 'next/image'; import Link from 'next/link'; import { useEffect, useState } from 'react'; export function MainNav({}: React.HTMLAttributes) { const { data: session } = useSession(); - const [providers, setProviders] = useState | null>(null); + const [providers, setProviders] = useState | null>(null); // load the registered nextauth providers, in our case is the credential provider useEffect(() => { diff --git a/blotztask-ui/src/app/page.tsx b/blotztask-ui/src/app/page.tsx index ba708bf..39473e3 100644 --- a/blotztask-ui/src/app/page.tsx +++ b/blotztask-ui/src/app/page.tsx @@ -1,14 +1,12 @@ -"use client" +'use client'; import { H1, H3 } from '@/components/ui/heading-with-anchor'; export default function Home() { return ( -
-

Blotz - - Task - +

+ Blotz + Task

diff --git a/blotztask-ui/src/app/provider.tsx b/blotztask-ui/src/app/provider.tsx index 6f6bd45..a2dd450 100644 --- a/blotztask-ui/src/app/provider.tsx +++ b/blotztask-ui/src/app/provider.tsx @@ -1,17 +1,15 @@ -"use client"; +'use client'; -import { Session } from "next-auth"; -import { SessionProvider } from "next-auth/react"; +import { Session } from 'next-auth'; +import { SessionProvider } from 'next-auth/react'; interface ProviderProps { - children: React.ReactNode; - session?: Session | null; - } - - const Provider: React.FC = ({ children, session }) => ( - - {children} - - ); - - export default Provider; \ No newline at end of file + children: React.ReactNode; + session?: Session | null; +} + +const Provider: React.FC = ({ children, session }) => ( + {children} +); + +export default Provider; diff --git a/blotztask-ui/src/app/signin/LoginPage.module.css b/blotztask-ui/src/app/signin/LoginPage.module.css index a3902c8..bbaaeea 100644 --- a/blotztask-ui/src/app/signin/LoginPage.module.css +++ b/blotztask-ui/src/app/signin/LoginPage.module.css @@ -45,7 +45,7 @@ .submitButton { width: 100%; /* Full width for button */ padding: 10px; - background-color: #4CAF50; /* Green background */ + background-color: #4caf50; /* Green background */ color: white; /* White text */ border: none; border-radius: 4px; /* Rounded corners */ diff --git a/blotztask-ui/src/app/signin/page.jsx b/blotztask-ui/src/app/signin/page.jsx index 4107826..86bb177 100644 --- a/blotztask-ui/src/app/signin/page.jsx +++ b/blotztask-ui/src/app/signin/page.jsx @@ -1,4 +1,4 @@ -"use client"; +'use client'; import { signIn } from 'next-auth/react'; import { useRouter, useSearchParams } from 'next/navigation'; @@ -27,14 +27,15 @@ const LoginPage = () => { if (result.error) { setError(result.error); // Set error if login fails } else { - router.push(callbackUrl); + router.push(callbackUrl); } }; return (
-

User Login

{/* Title of the login page */} +

User Login

{' '} + {/* Title of the login page */}
@@ -58,11 +59,21 @@ const LoginPage = () => { placeholder="Enter your password" />
- {error &&

{error}

} {/* Display error message if any */} - + {error &&

{error}

}{' '} + {/* Display error message if any */} +

- Don’t have an account? Register here {/* Registration link */} + Don’t have an account?{' '} + + Register here + {' '} + {/* Registration link */}

diff --git a/blotztask-ui/src/app/signup/SignUpPage.module.css b/blotztask-ui/src/app/signup/SignUpPage.module.css index 9c9dada..a498291 100644 --- a/blotztask-ui/src/app/signup/SignUpPage.module.css +++ b/blotztask-ui/src/app/signup/SignUpPage.module.css @@ -1,54 +1,51 @@ .container { - display: flex; - justify-content: center; - align-items: center; - height: 100vh; - background-color: white; /* Light grey background for contrast */ - padding: 20px; - } - - .form_container { - width: 100%; - max-width: 400px; /* Limit form width */ - padding: 30px; - border: 1px solid #ddd; - border-radius: 10px; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); - background-color: white; /* Form background */ - } - - .title { - text-align: center; - margin-bottom: 30px; - font-size: 24px; - color: #333; /* Darker color for contrast */ - } - - .input_group { - margin-bottom: 20px; /* Space between input groups */ - display: flex; - align-items: center; - } - - .label { - flex: 1; /* Allow label to take up space */ - margin-right: 15px; /* Space between label and input */ - color: #555; /* Softer color for labels */ - font-weight: bold; /* Bold labels */ - } - - .input { - flex: 2; /* Allow input to take up more space */ - padding: 12px; /* More padding for input */ - border: 1px solid #ccc; /* Light border */ - border-radius: 5px; /* Rounded input corners */ - transition: border-color 0.3s; /* Transition effect */ - } - - .input:focus { - border-color: #4CAF50; /* Green border on focus */ - outline: none; /* Remove default outline */ - } + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + background-color: white; /* Light grey background for contrast */ + padding: 20px; +} - - \ No newline at end of file +.form_container { + width: 100%; + max-width: 400px; /* Limit form width */ + padding: 30px; + border: 1px solid #ddd; + border-radius: 10px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); + background-color: white; /* Form background */ +} + +.title { + text-align: center; + margin-bottom: 30px; + font-size: 24px; + color: #333; /* Darker color for contrast */ +} + +.input_group { + margin-bottom: 20px; /* Space between input groups */ + display: flex; + align-items: center; +} + +.label { + flex: 1; /* Allow label to take up space */ + margin-right: 15px; /* Space between label and input */ + color: #555; /* Softer color for labels */ + font-weight: bold; /* Bold labels */ +} + +.input { + flex: 2; /* Allow input to take up more space */ + padding: 12px; /* More padding for input */ + border: 1px solid #ccc; /* Light border */ + border-radius: 5px; /* Rounded input corners */ + transition: border-color 0.3s; /* Transition effect */ +} + +.input:focus { + border-color: #4caf50; /* Green border on focus */ + outline: none; /* Remove default outline */ +} diff --git a/blotztask-ui/src/app/signup/page.jsx b/blotztask-ui/src/app/signup/page.jsx index 2cfd0fe..74b4314 100644 --- a/blotztask-ui/src/app/signup/page.jsx +++ b/blotztask-ui/src/app/signup/page.jsx @@ -1,4 +1,4 @@ -"use client"; +'use client'; import { useRouter } from 'next/navigation'; // Import useRouter for navigation import { useState } from 'react'; @@ -16,25 +16,28 @@ const SignUpPage = () => { event.preventDefault(); if (password !== confirmPassword) { - setError("Passwords do not match"); + setError('Passwords do not match'); return; } // Call the sign-up API - const signUpResponse = await fetch( `${process.env.NEXT_PUBLIC_API_BASE_URL}/register`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ email, password }), - }); + const signUpResponse = await fetch( + `${process.env.NEXT_PUBLIC_API_BASE_URL}/register`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ email, password }), + } + ); if (signUpResponse.ok) { // Redirect to the login page after successful sign-up router.push('/signin'); // Use router to navigate to the login page } else { const errorData = await signUpResponse.json(); - setError(errorData.error || "An error occurred during sign-up."); + setError(errorData.error || 'An error occurred during sign-up.'); } }; @@ -78,7 +81,9 @@ const SignUpPage = () => { {error &&

{error}

} {success &&

{success}

} - + diff --git a/blotztask-ui/src/app/task-list/components/task-table.tsx b/blotztask-ui/src/app/task-list/components/task-table.tsx index 5dd8c71..af719ed 100644 --- a/blotztask-ui/src/app/task-list/components/task-table.tsx +++ b/blotztask-ui/src/app/task-list/components/task-table.tsx @@ -5,40 +5,42 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; +} from '@/components/ui/table'; -import { TaskItemDTO } from "@/model/task-Item-dto"; +import { TaskItemDTO } from '@/model/task-Item-dto'; interface TaskTableProps { tasks: TaskItemDTO[]; // tasks prop is an array of TaskItemDTO objects } - + export function TaskTable({ tasks }: TaskTableProps) { - return ( - - - - Task-id - Title - Isdone + return ( +
+ + + Task-id + Title + Isdone + + + + {tasks.map((task) => ( + + {task.id} + {task.title} + + {' '} + {task.isDone ? 'Yes' : 'No'} + - - - {tasks.map((task) => ( - - {task.id} - {task.title} - {task.isDone ? "Yes" : "No"} - - ))} - - {/* + ))} + + {/* Total $2,500.00 */} -
- ) - } - \ No newline at end of file + + ); +} diff --git a/blotztask-ui/src/app/task-list/mockdata.tsx b/blotztask-ui/src/app/task-list/mockdata.tsx index 6f1ed15..d619050 100644 --- a/blotztask-ui/src/app/task-list/mockdata.tsx +++ b/blotztask-ui/src/app/task-list/mockdata.tsx @@ -1,39 +1,39 @@ -import { TaskItemDTO } from "@/model/task-Item-dto"; - - export const mocktasks : TaskItemDTO[] = [ - { - id: 1, - title: "Complete project report", - isDone: false, - }, - { - id: 2, - title: "Review pull requests", - isDone: true, - }, - { - id: 3, - title: "Team meeting", - isDone: false, - }, - { - id: 4, - title: "Update documentation", - isDone: true, - }, - { - id: 5, - title: "Code review for module A", - isDone: false, - }, - { - id: 6, - title: "Deploy new version", - isDone: true, - }, - { - id: 7, - title: "Refactor authentication service", - isDone: false, - }, -]; \ No newline at end of file +import { TaskItemDTO } from '@/model/task-Item-dto'; + +export const mocktasks: TaskItemDTO[] = [ + { + id: 1, + title: 'Complete project report', + isDone: false, + }, + { + id: 2, + title: 'Review pull requests', + isDone: true, + }, + { + id: 3, + title: 'Team meeting', + isDone: false, + }, + { + id: 4, + title: 'Update documentation', + isDone: true, + }, + { + id: 5, + title: 'Code review for module A', + isDone: false, + }, + { + id: 6, + title: 'Deploy new version', + isDone: true, + }, + { + id: 7, + title: 'Refactor authentication service', + isDone: false, + }, +]; diff --git a/blotztask-ui/src/app/task-list/page.tsx b/blotztask-ui/src/app/task-list/page.tsx index 303a3a9..197706d 100644 --- a/blotztask-ui/src/app/task-list/page.tsx +++ b/blotztask-ui/src/app/task-list/page.tsx @@ -7,16 +7,17 @@ import { mocktasks } from './mockdata'; const page = () => { return (
-
- +
+ +
+
- - ) -} + ); +}; -export default page +export default page; diff --git a/blotztask-ui/src/app/tasks/page.tsx b/blotztask-ui/src/app/tasks/page.tsx index 8911c58..6e17834 100644 --- a/blotztask-ui/src/app/tasks/page.tsx +++ b/blotztask-ui/src/app/tasks/page.tsx @@ -1,4 +1,10 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from '@/components/ui/card'; import { promises as fs } from 'fs'; import { Metadata } from 'next'; import path from 'path'; @@ -48,11 +54,14 @@ export default async function TaskPage() { */} - ℹ️Notice + + ℹ️Notice + - This page is a newer version of the Task List page with more features. Currently still under implementation. + This page is a newer version of the Task List page with more + features. Currently still under implementation. @@ -62,7 +71,7 @@ export default async function TaskPage() {

Task List

- Here's a list of your tasks for this month! + Here's a list of your tasks for this month!

{/* */}
diff --git a/blotztask-ui/src/app/test-connection/page.tsx b/blotztask-ui/src/app/test-connection/page.tsx index 9eaef1a..45baa62 100644 --- a/blotztask-ui/src/app/test-connection/page.tsx +++ b/blotztask-ui/src/app/test-connection/page.tsx @@ -6,7 +6,7 @@ import { TaskItemDTO } from '@/model/task-Item-dto'; import Link from 'next/link'; import { useState } from 'react'; import TaskList from './components/task-list'; -import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'; import { fetchAllTaskItems } from '@/services/taskService'; export default function Home() { @@ -44,24 +44,26 @@ export default function Home() { {error && ( - - - ❌Error fetching todos - - -

{error}

-
-
+ + + ❌Error fetching todos + + +

{error}

+
+
)} {tasks.length > 0 && ( - - - ✅Successfully fetched todos - - - - - + + + + ✅Successfully fetched todos + + + + + + )}

);