TaskOrbit is a modern Kanban-style task management application built with React. It features drag-and-drop task movement, real-time search and filtering, activity logging, protected routes, and persistent state using localStorage β enabling users to manage tasks across Todo, Doing, and Done stages without a backend.
- Features
- Tech Stack
- Getting Started
- Application Flow
- Architecture
- Data Model
- Storage
- Reliability & Error Handling
- Testing
- License
| Feature | Description |
|---|---|
| Static Login | Hardcoded credentials with Remember Me support via localStorage/sessionStorage |
| 3-Column Board | Todo Β· Doing Β· Done β each with a unique vibrant color identity |
| Full CRUD | Create, edit, and delete tasks with modal forms and confirmation dialogs |
| Drag & Drop | Move tasks across columns using @dnd-kit with visual feedback |
| Search with Dropdown | Real-time search by title with a dropdown showing matching tasks, status dots, and priority badges |
| Filter by Priority | Filter tasks by Low / Medium / High priority |
| Sort by Due Date | Sort ascending with tasks missing due dates placed last |
| Activity Log | Toggleable sidebar panel tracking every task operation with timestamps |
| Persistence | All data (tasks, logs, session) stored in localStorage β survives page refresh |
| Reset Board | Clear all tasks and activity logs with a confirmation dialog |
| Protected Routes | Users cannot access the board without logging in |
| Responsive Design | Desktop-first layout that adapts to smaller screens |
| Layer | Technology | Purpose |
|---|---|---|
| Framework | React 19 | Functional components + Hooks |
| Build Tool | Vite 7 | Lightning-fast HMR and bundling |
| Routing | react-router-dom v7 | Client-side routing with protected routes |
| Drag & Drop | @dnd-kit/core + @dnd-kit/sortable | Accessible, performant drag-and-drop |
| State | Context API | Centralized state without external libraries |
| Styling | Vanilla CSS | Custom properties, gradients, glow effects |
| IDs | uuid | Unique task and log identifiers |
| Testing | Vitest + React Testing Library | Unit and integration tests |
- No Redux β Context API is sufficient for this app's complexity; avoids unnecessary boilerplate.
- @dnd-kit over react-beautiful-dnd β Actively maintained, modular, better accessibility support, and smaller bundle.
- Vanilla CSS over Tailwind β Full control over the vibrant Gen-Z aesthetic with custom properties, gradients, and glow effects that would be verbose in utility classes.
- Vitest over Jest β Native Vite integration, faster execution, same API.
- Node.js 18 or higher
- npm 9 or higher
- A modern browser (Chrome, Firefox, Edge, Safari)
# Clone the repository
git clone https://github.com/MadtorXD/TaskOrbit.git
# Navigate into the project directory
cd TaskOrbit
# Install dependencies
npm installnpm run devThe development server starts at http://localhost:5173 with hot module replacement (HMR) enabled. Any changes to source files will instantly reflect in the browser.
| Field | Value |
|---|---|
intern@demo.com |
|
| Password | intern123 |
Note: These are hardcoded static credentials. There is no backend authentication β the login is simulated entirely on the client side.
# Run all tests once
npm test
# Run tests in watch mode (re-runs on file changes)
npm run test:watch# Build optimized production bundle
npm run build
# Preview the production build locally
npm run previewThe build output is generated in the dist/ directory, ready for deployment to any static hosting service.
The build output is generated in the dist/ directory, ready for deployment to any static hosting service.
The app starts on the Login Page (/).
- Users enter their email and password
- A "Remember Me" checkbox controls session persistence:
- β
Checked β Session is stored in
localStorageand persists across browser restarts - β Unchecked β Session is stored in
sessionStorageand expires when the tab closes
- β
Checked β Session is stored in
- Invalid credentials display an inline error message
- Empty fields show a validation error prompting the user to fill both
- Successful login redirects to the Task Board (
/board) - A Logout button in the header clears the session and redirects back to login
- Route protection β Navigating to
/boardwithout authentication redirects to/
The main dashboard (/board) displays a 3-column Kanban board:
| Column | Color | Purpose |
|---|---|---|
| π Todo | Hot Pink (#f472b6) |
Tasks not yet started |
| π¨ Doing | Electric Yellow (#facc15) |
Tasks currently in progress |
| β Done | Mint Green (#34d399) |
Completed tasks |
Each column has:
- A color-coded header with task count badge
- An "+ Add Task" button for creating tasks in that column
- A scrollable body containing task cards
- Visual feedback when a card is dragged over the column (glowing border)
- Click "+ Add Task" in any column
- A modal form appears with fields:
- Title (required β validated before submission)
- Description (optional β multi-line textarea)
- Priority (Low / Medium / High β dropdown selector)
- Due Date (optional β date picker)
- Tags (optional β comma-separated text input)
- Tasks are assigned a unique ID (
uuid) and a creation timestamp
- Click the βοΈ pencil icon on any task card
- The same modal opens pre-filled with the task's current data
- All fields can be modified
- Changes are saved to localStorage immediately
- Click the ποΈ trash icon on any task card
- A confirmation dialog appears: "Delete [task name]? This cannot be undone."
- On confirm, the task is removed from state and localStorage
- Drag any task card by clicking and holding
- Drop onto a different column to change the task's status
- The task's
statusfield is automatically updated to match the destination column - A drag overlay shows a preview of the card being moved
- Columns display a glow effect when a card is hovering over them
- All moves are logged in the Activity Log Technical details:
- Uses
@dnd-kit/corefor the DnD context and collision detection @dnd-kit/sortableprovides sortable card behavior within columnsPointerSensorwith a 5px activation distance prevents accidental dragsclosestCornerscollision detection for accurate drop targeting
The toolbar below the header provides three controls:
- Real-time filtering as you type β the board updates instantly
- A dropdown appears below the search box showing matching tasks with:
- Color-coded status dot (pink/yellow/green)
- Task title
- Priority badge
- Click a dropdown result to filter to that specific task
- Clear button (β) resets the search
- Arrow button (β) provides a clickable alternative to pressing Enter
- Dropdown with options: All Priorities, Low, Medium, High
- Filters the entire board β only cards matching the selected priority are shown
- Toggle button that sorts tasks ascending by due date
- Tasks without a due date are automatically placed last
- Active state shows a purple glow indicator
- Toggle the log sidebar using the π Log button in the header
- Slides in from the right with a smooth 300ms transition
- Displays the last 50 actions in reverse chronological order
Events tracked:
| Event | Example Log Entry |
|-------|-------------------|
| Task Created |
Created task "Design Landing Page"| | Task Edited |Edited task "Design Landing Page"| | Task Moved |Moved "Design Landing Page" to Done| | Task Deleted |Deleted task "Design Landing Page"| Each log entry shows the action text and a formatted timestamp (e.g.,Feb 18, 08:30 PM).
TaskOrbit/
βββ public/
β βββ vite.svg # Default favicon
βββ src/
β βββ __tests__/ # Test files
β β βββ Login.test.jsx # Login validation tests (3 tests)
β β βββ TaskCard.test.jsx # Card rendering tests (4 tests)
β β βββ TaskContext.test.jsx # CRUD + state tests (5 tests)
β βββ components/ # Reusable UI components
β β βββ ActivityLog.jsx # Sidebar log panel
β β βββ Column.jsx # Droppable column container
β β βββ ConfirmDialog.jsx # Reusable confirmation modal
β β βββ ProtectedRoute.jsx # Auth route guard
β β βββ SearchFilterBar.jsx # Search/filter/sort toolbar
β β βββ TaskCard.jsx # Draggable task card
β β βββ TaskModal.jsx # Create/edit task form modal
β βββ context/ # State management
β β βββ AuthContext.jsx # Authentication state + login/logout
β β βββ TaskContext.jsx # Task CRUD + filtering + activity log
β βββ pages/ # Route-level components
β β βββ Dashboard.jsx # Main board page (DnD context)
β β βββ Login.jsx # Login form page
β β βββ Login.css # Login-specific styles
β βββ utils/ # Helper utilities
β β βββ storage.js # Safe localStorage/sessionStorage API
β βββ App.jsx # Router + provider setup
β βββ index.css # Global styles (vibrant Gen-Z theme)
β βββ main.jsx # React DOM entry point
β βββ setupTests.js # Vitest setup (jest-dom matchers)
βββ .gitignore
βββ index.html # HTML entry point
βββ package.json # Dependencies + scripts
βββ vite.config.js # Vite + Vitest configuration
βββ README.md # This file
The app uses React Context API with two independent contexts to avoid prop drilling:
App
βββ AuthProvider (AuthContext)
β βββ isAuthenticated, session
β βββ login(email, password, rememberMe)
β βββ logout()
β
βββ TaskProvider (TaskContext)
βββ tasks[], logs[]
βββ searchTerm, priorityFilter, sortByDueDate
βββ addTask(), editTask(), deleteTask(), moveTask()
βββ resetBoard()
βββ getTasksByStatus(status) β filtered task list
βββ filteredTasks (derived via useMemo)
Key design decisions:
- Filtering is centralized β
filteredTasksis a memoized derived value computed fromtasks,searchTerm,priorityFilter, andsortByDueDate. Components never filter locally. - Persistence is automatic β Every state mutation (
addTask,editTask,deleteTask,moveTask) syncs to localStorage immediately. - Activity logging is built-in β Each CRUD operation automatically appends to the activity log.
App (BrowserRouter)
βββ Login Page (/)
β βββ Login form with email, password, remember me
β
βββ Dashboard (/board) [ProtectedRoute]
βββ Header (logo, log toggle, reset, logout)
βββ SearchFilterBar (search box + dropdown, filter, sort)
βββ DndContext
β βββ Column[Todo] β TaskCard[] (draggable)
β βββ Column[Doing] β TaskCard[] (draggable)
β βββ Column[Done] β TaskCard[] (draggable)
β βββ DragOverlay
βββ ActivityLog (sidebar)
βββ TaskModal (create/edit β shared)
βββ ConfirmDialog (delete/reset β shared)
{
id: "550e8400-e29b-41d4-a716-446655440000", // UUID v4
title: "Design Landing Page", // Required, trimmed
description: "Create the new homepage design", // Optional
priority: "High", // "Low" | "Medium" | "High"
dueDate: "2026-03-01", // Optional, ISO date string
tags: "design, frontend", // Optional, comma-separated
createdAt: "2026-02-18T15:08:25.000Z", // Auto-generated ISO timestamp
status: "Todo" // "Todo" | "Doing" | "Done"
}{
id: "7c9e6679-7425-40de-944b-e07fc1f90ae7", // UUID v4
action: "Created task \"Design Landing Page\"", // Human-readable action
timestamp: "2026-02-18T15:08:25.000Z" // ISO timestamp
}{
email: "intern@demo.com",
loggedInAt: "2026-02-18T15:08:25.000Z"
}All data persists in the browser's localStorage under namespaced keys:
| Key | Type | Purpose |
|---|---|---|
taskOrbit_session |
Object | Login session (only if "Remember Me" is checked) |
taskOrbit_tasks |
Array | All task objects |
taskOrbit_logs |
Array | Activity log entries (max 50) |
| Scenario | Behavior |
|---|---|
| Remember Me checked | Session stored in localStorage β persists across browser restarts |
| Remember Me unchecked | Session stored in sessionStorage β expires when tab closes |
| localStorage empty | App initializes with empty arrays [] |
| localStorage corrupted | JSON.parse failures are caught; app falls back to empty defaults |
| Storage full | Write failures are silently caught; app continues working in-memory |
| Reset Board | Clears taskOrbit_tasks and taskOrbit_logs from localStorage |
| Logout | Clears taskOrbit_session from both localStorage and sessionStorage |
getItem(key, fallback) // Safe JSON parse from localStorage
setItem(key, value) // Safe JSON stringify to localStorage
removeItem(key) // Remove key from localStorage
getSessionItem(key, fallback) // Same for sessionStorage
setSessionItem(key, value) // Same for sessionStorage
removeSessionItem(key) // Same for sessionStorageAll functions wrap their operations in try/catch blocks to prevent crashes from storage unavailability or quota errors.
| Scenario | How It's Handled |
|---|---|
| Empty board state | Columns show "No tasks yet" placeholder |
| Missing localStorage | Falls back to empty defaults without crashing |
| Corrupted JSON in storage | JSON.parse wrapped in try/catch, returns fallback |
| Empty task title | Form validates title as required; shows inline error |
| Accidental delete | Confirmation dialog required before any deletion |
| Accidental board reset | Confirmation dialog: "All tasks and logs will be permanently deleted" |
| Accidental drag | 5px activation distance prevents unintentional moves |
Direct URL access to /board |
ProtectedRoute redirects to login if unauthenticated |
| Unknown routes | Catch-all * route redirects to / |
The project includes 12 tests across 3 test files using Vitest and React Testing Library.
| File | Tests | What's Covered |
|---|---|---|
Login.test.jsx |
3 | Invalid credentials error, empty field validation, field rendering |
TaskContext.test.jsx |
5 | Empty state, task creation, deletion, status move, activity logging |
TaskCard.test.jsx |
4 | Title rendering, priority badge, tags display, due date indicator |
# Run all tests once
npm test
# Run in watch mode
npm run test:watchTests run via Vitest with the following setup (vite.config.js):
- Environment:
jsdom(simulates browser DOM) - Globals:
true(no need to importdescribe,it,expect) - Setup file:
src/setupTests.js(loads@testing-library/jest-dommatchers) - CSS:
true(CSS imports are processed during tests)
| Script | Command | Description |
|---|---|---|
dev |
npm run dev |
Start Vite dev server with HMR at port 5173 |
build |
npm run build |
Build optimized production bundle to dist/ |
preview |
npm run preview |
Preview production build locally |
test |
npm test |
Run all tests once via Vitest |
test:watch |
npm run test:watch |
Run tests in watch mode |
| Token | Hex | Usage |
|---|---|---|
| Accent | #a855f7 |
Buttons, links, active states |
| Hot Pink | #f472b6 |
Todo column theme |
| Electric Yellow | #facc15 |
Doing column theme |
| Mint Green | #34d399 |
Done column, Low priority |
| Sunset Orange | #fb923c |
Medium priority |
| Rose Red | #f43f5e |
High priority, danger actions |
| Background | #0a0a0f |
Page background |
| Surface | #12121a |
Cards, panels |
| Priority | Color | Visual |
|---|---|---|
| Low | #34d399 (Mint Green) |
π’ |
| Medium | #fb923c (Sunset Orange) |
π |
| High | #f43f5e (Rose Red) |
π΄ |
Built with β€οΈ by MadtorXD