Open In App

Build a Task Management App using Next JS

Last Updated : 24 Jul, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

A Task management app is a useful web application that assists in efficiently organizing and managing tasks. It provides various functionalities such as creating tasks, assigning prioritie­s and deadlines, marking complete tasks, and enabling task search based on ke­ywords and priorities.

Preview of final output: Let us have a look at how the final output will look like

Build-a-Task-Management-App-using-Next-Js

Prerequisites :

Approach :

  • The use­State hook is employed to e­ffectively manage compone­nt state, ensuring smooth handling of tasks and input fields re­lated to task management, se­arch, and filtering.
  • To handle task-relate­d information such as name, priority, and deadline, thre­e input handlers are imple­mented to update the­ir respective state­ variables.
  • The addTask function is responsible­ for both validating and adding tasks, while the handleEditTask function facilitate­s task editing and removal.
  • Additionally, the handle­DeleteTask function re­moves tasks when nece­ssary, whereas the markDone­ function marks tasks as completed and moves the­m to the completedTasks se­ction.
  • To further enhance use­r experience­, filteredTasks effe­ctively filters upcoming tasks based on use­r-defined criteria such as se­arching and filtering by priority.

Steps to create the Next JS Application:

Step 1: Create a new Next.js project using the following command

npx create-next-app task-management-app

Step 2: Change to the project directory:

cd task-management-app

Project Structure:

The updated dependencies in package.json file will look like :

"dependencies": {
"next": "^13.0.6",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}

Example: In this example, we will create the Task Management App Using Next Js.

CSS
/* global.css */

.App {
    font-family: 'Arial', sans-serif;
    margin: 30px auto;
    padding: 20px;
    max-width: 800px;
    background-color: white;
    box-shadow: 0 2px 16px rgba(0, 0, 0, 0.1);
    border-radius: 15px;
}

.taskHeader {
    text-align: center;
    background-color: #007bff;
    color: white;
    padding: 10px 0;
    margin-bottom: 20px;
    border-radius: 8px 8px 0 0;
}

.taskForm {
    margin-bottom: 20px;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
}

.taskNameInput,
.taskPrioritySelect,
.taskDeadlineInput,
.addTaskButton {
    margin: 5px;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
    flex-grow: 1;
    font-size: 16px;
}

.taskPrioritySelect {
    cursor: pointer;
    background-color: #f0f0f0;
}

.addTaskButton {
    background-color: #007bff;
    color: white;
    border: none;
    cursor: pointer;
    transition: background-color 0.3s;
}

.addTaskButton:hover {
    background-color: #0056b3;
}

.searchFilter {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.searchInput,
.filterPrioritySelect {
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
    flex-grow: 1;
    font-size: 16px;
}

.taskTable {
    width: 100%;
    border-collapse: collapse;
    background-color: white;
}

.taskTable th,
.taskTable td {
    padding: 10px;
    text-align: left;
}

.taskTable th {
    background-color: #007bff;
    color: white;
}

.taskTable tbody tr:nth-child(even) {
    background-color: #f5f5f5;
}

.completedTable {
    width: 100%;
    border-collapse: collapse;
    background-color: white;
}

.completedTable th,
.completedTable td {
    padding: 10px;
    text-align: left;
}

.completedTable th {
    background-color: #007bff;
    color: white;
}

.completedTable tbody tr:nth-child(even) {
    background-color: #f5f5f5;
}

.deleteTaskButton {
    margin-right: 5px;
    cursor: pointer;
    padding: 12px;
    background: crimson;
    border-radius: 10px;
    border: none;
    color: white;
}

.markDoneButton,
.editTaskButton {
    margin-right: 5px;
    cursor: pointer;
    padding: 12px;
    background: #007bff;
    border-radius: 10px;
    border: none;
    color: white;
}

@media (max-width: 600px) {
    .taskForm {
        flex-direction: column;
    }

    .searchFilter {
        flex-direction: column;
    }
}
JavaScript
//index.js

import { useState } from "react";
import Head from "next/head";
import styles from "../styles/Home.module.css";

export default function TaskScheduler() {
	const [tasks, setTasks] = useState([]);
	const [completedTasks, setCompletedTasks] = useState([]);
	const [taskName, setTaskName] = useState("");
	const [taskPriority, setTaskPriority] = useState("Top");
	const [taskDeadline, setTaskDeadline] = useState("");
	const [searchKeyword, setSearchKeyword] = useState("");
	const [filterPriority, setFilterPriority] = useState("");

	const handleTaskNameChange = (e) => {
		setTaskName(e.target.value);
	};

	const handleTaskPriorityChange = (e) => {
		setTaskPriority(e.target.value);
	};

	const handleTaskDeadlineChange = (e) => {
		setTaskDeadline(e.target.value);
	};

	const addTask = () => {
		if (taskName.trim() === "" || taskDeadline === "") {
			alert("Please enter a task and select a valid deadline.");
			return;
		}

		const selectedDate = new Date(taskDeadline);
		const currentDate = new Date();

		if (selectedDate <= currentDate) {
			alert("Please select a future date for the deadline.");
			return;
		}

		const newTask = {
			id: tasks.length + 1,
			task: taskName,
			priority: taskPriority,
			deadline: taskDeadline,
			done: false,
		};

		setTasks([...tasks, newTask]);

		setTaskName("");
		setTaskPriority("Top");
		setTaskDeadline("");
	};

	const handleEditTask = (id) => {
		const taskToEdit = tasks.find((t) => t.id === id);
		setTaskName(taskToEdit.task);
		setTaskPriority(taskToEdit.priority);
		setTaskDeadline(taskToEdit.deadline);
		const updatedTasks = tasks.filter((t) => t.id !== id);
		setTasks(updatedTasks);
	};

	const handleDeleteTask = (id) => {
		const updatedTasks = tasks.filter((t) => t.id !== id);
		setTasks(updatedTasks);
	};

	const markDone = (id) => {
		const updatedTasks = tasks.map((t) =>
			t.id === id ? { ...t, done: true } : t
		);
		setTasks(updatedTasks);

		const completedTask = tasks.find((t) => t.id === id);
		if (completedTask) {
			setCompletedTasks([...completedTasks, completedTask]);
		}
	};

	const filteredTasks = tasks
		.filter((t) => !t.done)
		.filter((t) =>
			t.task.toLowerCase().includes(searchKeyword.toLowerCase())
		)
		.filter((t) => (filterPriority ? t.priority === filterPriority : true));

	return (
		<div className={styles.App}>
			<Head>
				<title>Task Management - Geeksforgeeks.org</title>
			</Head>
			<header className={styles.taskHeader}>
				<h1>Task Management</h1>
			</header>
			<main>
				<div className={styles.taskForm}>
					<input
						type="text"
						className={styles.taskNameInput}
						placeholder="Enter task..."
						value={taskName}
						onChange={handleTaskNameChange}
					/>
					<select
						className={styles.taskPrioritySelect}
						value={taskPriority}
						onChange={handleTaskPriorityChange}
					>
						<option value="Top">Top Priority</option>
						<option value="Middle">Middle Priority</option>
						<option value="Low">Less Priority</option>
					</select>
					<input
						type="date"
						className={styles.taskDeadlineInput}
						value={taskDeadline}
						onChange={handleTaskDeadlineChange}
					/>
					<button className={styles.addTaskButton} onClick={addTask}>
						Add Task
					</button>
				</div>
				<div className={styles.searchFilter}>
					<input
						type="text"
						className={styles.searchInput}
						placeholder="Search tasks"
						value={searchKeyword}
						onChange={(e) => setSearchKeyword(e.target.value)}
					/>
					<select
						className={styles.filterPrioritySelect}
						value={filterPriority}
						onChange={(e) => setFilterPriority(e.target.value)}
					>
						<option value="">All Priorities</option>
						<option value="Top">Top Priority</option>
						<option value="Middle">Middle Priority</option>
						<option value="Low">Less Priority</option>
					</select>
				</div>
				<h2 className={styles.heading}>Upcoming Tasks</h2>
				<div className={styles.taskList}>
					<table className={styles.taskTable}>
						<thead>
							<tr>
								<th>Task Name</th>
								<th>Priority</th>
								<th>Deadline</th>
								<th>Action</th>
							</tr>
						</thead>
						<tbody>
							{filteredTasks.map((t) => (
								<tr key={t.id}>
									<td>{t.task}</td>
									<td>{t.priority}</td>
									<td>{t.deadline}</td>
									<td>
										{!t.done && (
											<div>
												<button
													className={
														styles.markDoneButton
													}
													onClick={() =>
														markDone(t.id)
													}
												>
													Mark Done
												</button>
												<button
													className={
														styles.editTaskButton
													}
													onClick={() =>
														handleEditTask(t.id)
													}
												>
													Edit
												</button>
												<button
													className={
														styles.deleteTaskButton
													}
													onClick={() =>
														handleDeleteTask(t.id)
													}
												>
													Delete
												</button>
											</div>
										)}
									</td>
								</tr>
							))}
						</tbody>
					</table>
				</div>
				<div className={styles.completedTaskList}>
					<h2 className={styles.completedHeading}>Completed Tasks</h2>
					<table className={styles.completedTable}>
						<thead>
							<tr>
								<th>Task Name</th>
								<th>Priority</th>
								<th>Deadline</th>
							</tr>
						</thead>
						<tbody>
							{completedTasks.map((ct) => (
								<tr key={ct.id}>
									<td>{ct.task}</td>
									<td>{ct.priority}</td>
									<td>{ct.deadline}</td>
								</tr>
							))}
						</tbody>
					</table>
				</div>
			</main>
		</div>
	);
}

Steps to run the application:

Step 1: Run this command to start the application:

npm run dev

Step 2: To run the next.js application use the following command and then go to this URL:

http://localhost:3000

Output:


Next Article

Similar Reads