diff --git a/README.md b/README.md index 41e5322..5619afd 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,29 @@ # Flowstate -A modern, high-performance To-Do web application designed to help you lock in and enter the productivity flow. +A modern, high-performance Kanban & Workflow web application designed to help you lock in and enter the productivity flow. ![Next.js](https://img.shields.io/badge/Next.js-16-black?style=flat-square&logo=next.js) ![React](https://img.shields.io/badge/React-19-blue?style=flat-square&logo=react) ![TypeScript](https://img.shields.io/badge/TypeScript-5-blue?style=flat-square&logo=typescript) ![Tailwind CSS](https://img.shields.io/badge/Tailwind-v4-38bdf8?style=flat-square&logo=tailwind-css) +![Auth.js](https://img.shields.io/badge/Auth.js-v5-purple?style=flat-square) ![PostgreSQL](https://img.shields.io/badge/PostgreSQL-16-4169E1?style=flat-square&logo=postgresql) -![Redis](https://img.shields.io/badge/Redis-7-DC382D?style=flat-square&logo=redis) ## 🛠️ Tech Stack -- **Framework:** [Next.js 16](https://nextjs.org/) (App Router) +- **Framework:** [Next.js 16](https://nextjs.org/) (App Router, Route Groups) - **UI & Styling:** [React 19](https://react.dev/), [Tailwind CSS v4](https://tailwindcss.com/) -- **Backend:** [Node.js](https://nodejs.org/) -- **Database:** [PostgreSQL 16](https://www.postgresql.org/) -- **Caching & Queue:** [Redis 7](https://redis.io/) +- **Authentication:** [Auth.js v5 (NextAuth)](https://authjs.dev/) with Credentials Provider +- **Database & State:** PostgreSQL / Prisma (in progress) + +## 📂 Architecture & Structure + +The project uses Next.js Route Groups to separate public and protected application areas cleanly: + +- `app/(auth)/` — Public authentication routes (Login, Register) +- `app/(app)/` — Protected workspace & dashboard routes (Sidebar, Header, Kanban Board) +- `app/api/` — Backend API endpoints & Auth handlers ## 🎯 Current Status -_Work in Progress_ — Exploring ideas, setting up the architecture, and defining core features. The journey has just begun! +_In Progress_ — Core layout structure, responsive navigation, and authentication (Auth.js v5) are fully set up. Next up: Kanban board columns and task management features. diff --git a/app/(app)/board/page.tsx b/app/(app)/board/page.tsx new file mode 100644 index 0000000..9d82a68 --- /dev/null +++ b/app/(app)/board/page.tsx @@ -0,0 +1,6 @@ +/** + * Landing page + */ +export default function Home() { + return
Home
; +} diff --git a/app/(app)/layout.tsx b/app/(app)/layout.tsx new file mode 100644 index 0000000..943281c --- /dev/null +++ b/app/(app)/layout.tsx @@ -0,0 +1,34 @@ +import { auth } from "@/auth"; +import { redirect } from "next/navigation"; +import Sidebar from "@/app/components/layout/Sidebar"; +import Header from "@/app/components/layout/Header"; +import Navbar from "@/app/components/layout/Navbar"; + +export default async function AppLayout({ + children, +}: { + children: React.ReactNode; +}) { + const session = typeof auth === "function" ? await auth() : null; + + if (!session) { + redirect("/login"); + } + + return ( + <> +
+ +
+
+
+
+ {children} +
+
+ +
+
+ + ); +} diff --git a/app/(auth)/layout.tsx b/app/(auth)/layout.tsx new file mode 100644 index 0000000..a1363e3 --- /dev/null +++ b/app/(auth)/layout.tsx @@ -0,0 +1,11 @@ +export default function AuthLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+
{children}
+
+ ); +} diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx new file mode 100644 index 0000000..45be1c7 --- /dev/null +++ b/app/(auth)/login/page.tsx @@ -0,0 +1,130 @@ +/** + * @file LoginPage.tsx + * @description Client component providing a user login interface with NextAuth credentials authentication. + */ + +"use client"; + +import { useState } from "react"; +import { signIn } from "next-auth/react"; +import { useRouter } from "next/navigation"; +import Link from "next/link"; + +/** + * Renders the login page containing the authentication form, error handling, + * and navigation links for user sign-in. + * + * @returns {JSX.Element} The rendered login page component. + */ +export default function LoginPage() { + const router = useRouter(); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + /** + * Handles the submission of the login form, validates credentials via NextAuth, + * and manages loading/error states or redirects upon success. + * + * @async + * @param {React.SubmitEvent} e - The form submission event. + * @returns {Promise} + */ + const handleSubmit = async (e: React.SubmitEvent) => { + e.preventDefault(); + setError(null); + setLoading(true); + + const formData = new FormData(e.currentTarget); + const email = formData.get("email") as string; + const password = formData.get("password") as string; + + try { + const res = await signIn("credentials", { + email, + password, + redirect: false, + }); + + if (res?.error) { + if (res.error === "CredentialsSignin") { + setError("Incorrect email address or password."); + } else { + setError("An unexpected error has occurred."); + } + setLoading(false); + } else { + router.push("/"); + router.refresh(); + } + } catch { + setError("Connection error. Please try again later."); + setLoading(false); + } + }; + + return ( +
+ {/* Login Card Container */} +
+ {/* Header Section */} +
+

Flowstate Login

+

Sign in to continue.

+
+ + {/* Error Notification Banner */} + {error && ( +
+ {error} +
+ )} + + {/* Credentials Form */} +
+ + + + + +
+ + {/* Registration Link Footer */} +
+ Don't have an account yet?{" "} + + Register + +
+
+
+ ); +} diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 0000000..7c62e2d --- /dev/null +++ b/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,2 @@ +import { handlers } from "@/auth"; +export const { GET, POST } = handlers; diff --git a/app/components/layout/Brand.tsx b/app/components/layout/BrandLogo.tsx similarity index 95% rename from app/components/layout/Brand.tsx rename to app/components/layout/BrandLogo.tsx index 0beedb2..c0843c6 100644 --- a/app/components/layout/Brand.tsx +++ b/app/components/layout/BrandLogo.tsx @@ -3,7 +3,7 @@ export default function BrandLogo() {
Flowstate Logo diff --git a/app/components/layout/Header.tsx b/app/components/layout/Header.tsx index 0967ac1..1181592 100644 --- a/app/components/layout/Header.tsx +++ b/app/components/layout/Header.tsx @@ -1,4 +1,4 @@ -import Brand from "./Brand"; +import BrandLogo from "./BrandLogo"; import Image from "next/image"; export default function Header() { @@ -6,7 +6,7 @@ export default function Header() {
{/* Brand Element */}
- +
{/* User Profil */}
diff --git a/app/components/layout/Sidebar.tsx b/app/components/layout/Sidebar.tsx index d1232e9..154b81e 100644 --- a/app/components/layout/Sidebar.tsx +++ b/app/components/layout/Sidebar.tsx @@ -1,13 +1,20 @@ -import Brand from "./Brand"; +import BrandLogo from "./BrandLogo"; import Navbar from "./Navbar"; +import SignOutButton from "./buttons/SignOutButton"; export default function Sidebar() { return ( -