Open In App

Daily Activity Planner App using MERN Stack

Last Updated : 22 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

This project is a web-based Daily Planner application built using React for the frontend and Node.js with Express for the backend. It allows users to schedule and manage their daily tasks, providing features such as adding, deleting, and marking tasks as completed.

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

Screenshot-2024-03-07-102025

Daily Planner App final output image

Prerequisites

Approach

1. Frontend (React):

  • Calendar component to select dates.
  • Display tasks for the selected date.
  • Add, delete, and mark tasks as completed.

2. Backend (Express):

  • CRUD operations for tasks (Create, Read, Update, Delete).
  • MongoDB as the database to store tasks.

3. Communication (Axios):

  • Communication between frontend and backend through Axios for API requests.

Steps to Create the Project

1. Setting up server side

Project structure for server:

Screenshot-2024-03-07-104525

server project structure



Step 1: Initialize a Node.js Project

  • Open your terminal.
  • Create a new project directory,Navigate to your project directory.
mkdir <<name of project>>
cd <<name of project>>

Run the following command to initialize a new Node.js project and create a package.json file:

npm init -y

Step 2: Install Dependencies

  • Run the following command to install the required dependencies (Express.js,cors):
npm install express cors

Step 3: The server code uses MongoDB as the database. Make sure you have MongoDB installed and running.

npm install mongoose

Step 4: Create index.js File

Javascript
// server/index.js

const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const mongoose = require("mongoose");

const app = express();
const PORT = 5000;

app.use(cors());
app.use(bodyParser.json());

// Connect to MongoDB
mongoose.connect(
"mongodb+srv://Ashish:Ashish@cluster0.7ulei1j.mongodb.net/plan?retryWrites=true&w=majority&appName=Cluster0",
    { useNewUrlParser: true, useUnifiedTopology: true }
);

// Define Task schema;
const taskSchema = new mongoose.Schema({
    date: String,
    todo: String,
    startTime: String,
    endTime: String,
    completed: { type: Boolean, default: false },
});

// Create Task model
const Task = mongoose.model("Task", taskSchema);

app.get("/plan", async (req, res) => {
    console.log("Received GET request at /plan");
    try {
        const tasks = await Task.find();
        res.json(tasks);
    } catch (error) {
        res.status(500).send(error.message);
    }
});

app.post("/plan", async (req, res) => {
    const { date, todo, startTime, endTime } = req.body;
    const newTask = new Task({
        date,
        todo,
        startTime,
        endTime,
        completed: false,
    });

    try {
        await newTask.save();
        res.sendStatus(201);
    } catch (error) {
        res.status(500).send(error.message);
    }
});

app.delete("/plan/:taskId", async (req, res) => {
    const taskId = req.params.taskId;

    try {
        const result = await Task.deleteOne({ _id: taskId });

        if (result.deletedCount === 0) {
            return res.status(404).json({ error: "Task not found" });
        }

        res.sendStatus(204);
    } catch (error) {
        console.error("Error deleting task:", error);
        res.status(500).send(error.message);
    }
});

app.patch("/plan/:taskId", async (req, res) => {
    const taskId = req.params.taskId;

    try {
        const updatedTask = await Task.findByIdAndUpdate(
            taskId,
            { completed: req.body.completed },
            { new: true }
        );

        res.json(updatedTask);
    } catch (error) {
        res.status(500).send(error.message);
    }
});

app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

Step 5: Start the Server

In the terminal, run the following command to start the server:

node index.js

This will run your server on http://localhost:5000/plan. You should see the message “Server is running on port 5000” in the terminal.

2. Setting up FRONTEND

Project Structure for Frontend (client)

Screenshot-2024-03-07-104503

Client project structure

Step 1:

  • Open your terminal.
  • Choose or create a directory for your React app.
npx create-react-app <<Name_of_project>>
cd <<Name_of_project>>
  • Install Axios (for making HTTP requests):
npm install axios
  • Also install other required packages
npm install react-calendar

Step 2:

  • Replace the contents of src/App.js and App.css with the following:
  • Replace the contents of src/index.js with the following content:
CSS
/* App.css */

body {
    font-family: 'Arial', sans-serif;
    margin: 0;
    padding: 0;
    background-color: #f2f2f2; 
  }
  
  .App {
    text-align: center;
  }
  
  nav {
    padding: 1rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: #3498db; 
    color: #fff;
  }
  
  .logo {
    font-size: 1.5rem;
  }
  
  .button {
    border: 1px solid #3498db;
    padding: 0.5rem 1rem;
    font-size: 1rem;
    cursor: pointer;
  }
  
  .content {
    display: flex;
    justify-content: center;
    align-items: center;
    /* margin-top: 1rem; */
  }
  
  .hero-section {
    display: flex;
    align-items: flex-start;
    padding: 7rem;
    background-color: #fff;
  }
  
  .left-part {
    flex: 1;
    text-align: left;
    width: 100%;
    max-width: none;
    padding-right: 2rem;
  }
  
  .calendar-container {
    width: 100%;
    max-width: none;
    border-right: 1px solid #ccc; 
    box-sizing: border-box; 
  }
  
  .right-part {
    flex: 1;
    text-align: left;
    padding-left: 2rem;
  }
  
  .tasks {
    margin-left: 2rem;
  }
  
  h2 {
    font-size: 1.5rem;
  }
  
  ul {
    list-style: none;
    padding: 0;
  }
  
  li {
    margin: 0.5rem 0;
  }
  
  .add-task {
    margin-top: 1rem;
  }
  
  input {
    padding: 0.5rem;
    font-size: 1rem;
  }
  
  button {
    margin-left: 0.5rem;
    border: 1px solid #3498db;
    padding: 0.5rem 1rem;
    font-size: 1rem;
    cursor: pointer;
  }
  
  
  
  .react-calendar__tile--active {
    background-color: #3498db;
    color: #fff;
  }
  

.task-details {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  
  .time-range {
    font-size: 0.8rem;
    opacity: 0.7; 
  }
  .task-details {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  
  .delete-button {
    background: none;
    border: none;
    font-size: 1rem;
    cursor: pointer;
    color: red;
  }
  
Javascript
//client/src/App.js

import React, { useState, useEffect } from "react";
import axios from "axios";
import Calendar from "react-calendar";
import "react-calendar/dist/Calendar.css";
import "./App.css";

function App() {
    const [tasks, setTasks] = useState([]);
    const [selectedDate, setSelectedDate] = useState(new Date());
    const [newTask, setNewTask] = useState("");
    const [newTaskStartTime, setNewTaskStartTime] = useState("00:00");
    const [newTaskEndTime, setNewTaskEndTime] = useState("00:00");

    const handleDateClick = (date) => {
        setSelectedDate(date);
    };

    const fetchTasks = async () => {
        try {
            const response = await axios.get(
                `http://localhost:5000/plan?date=${
                    selectedDate.toISOString().split("T")[0]
                }`
            );
            const tasksData = response.data;
            setTasks(tasksData);

            // Store tasks in local storage
            localStorage.setItem("tasks", JSON.stringify(tasksData));
        } catch (error) {
            console.error("Error fetching tasks:", error);
        }
    };

    const handleAddTask = async () => {
        if (newTask) {
            const formattedDate = selectedDate.toISOString()
                                              .split("T")[0];
            const startTime = newTaskStartTime;
            const endTime = newTaskEndTime;

            try {
                // Add the new task
                await axios.post("http://localhost:5000/plan", {
                    date: formattedDate,
                    todo: newTask,
                    startTime,
                    endTime,
                });

                // Fetch tasks after adding the new task
                await fetchTasks();

                // Clear the input fields
                setNewTask("");
                setNewTaskStartTime("00:00");
                setNewTaskEndTime("00:00");
            } catch (error) {
                console.error("Error adding task:", error);
            }
        }
    };

    useEffect(() => {
        fetchTasks();
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [selectedDate]);

    const handleDeleteTask = async (taskId) => {
        try {
            await axios.delete(`http://localhost:5000/plan/${taskId}`);

            // Update state by removing the deleted task
            setTasks((prevTasks) =>
                prevTasks.filter((task) => task._id !== taskId)
            );
        } catch (error) {
            console.error("Error deleting task:", error);
        }
    };

    const handleCompleteTask = async (taskId, taskIndex) => {
        try {
            // Send a request to mark the task as completed on the server
            await axios.patch(`http://localhost:5000/plan/${taskId}`, {
                completed: true,
            });

            // Fetch the updated tasks from the server after completion
            await fetchTasks();

            setTasks((prevTasks) => {
                const updatedTasks = [...prevTasks];
                updatedTasks[taskIndex].completed = true;
                return updatedTasks;
            });
        } catch (error) {
            console.error("Error marking task as completed:", error);
        }
    };

    useEffect(() => {
        // Retrieve tasks from local storage on component mount
        const storedTasks = localStorage.getItem("tasks");
        if (storedTasks) {
            setTasks(JSON.parse(storedTasks));
        } else {
            fetchTasks();
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    useEffect(() => {
        localStorage.setItem("tasks", JSON.stringify(tasks));
    }, [tasks]);

    return (
        <div className="App">
            <nav>
                <div className="logo">Daily Planner App</div>
            </nav>
            <div className="content">
                <div className="hero-section">
                    <div className="left-part">
                        <div className="calendar-container">
                            <Calendar
                                onChange={handleDateClick}
                                value={selectedDate}
                                onClickDay={() => {}}
                            />
                        </div>
                    </div>
                    <div className="right-part">
                        <div className="tasks">
                            <h2>Tasks for {selectedDate.toDateString()}</h2>
                            <ul>
                                {tasks
                                    .filter(
                                        (task) =>
                                            task.date ===
                                            selectedDate
                                                .toISOString()
                                                .split("T")[0]
                                    )
                                    .map((task, index) => (
                                        <li
                                            key={index}
                                            style={{
                                                backgroundColor: task.completed
                                                    ? "lightgreen"
                                                    : "inherit",
                                            }}
                                        >
                                            <div className="task-details">
                                                <span className="task-text">
                                                    {task.todo}
                                                </span>
                                                {task.startTime &&
                                                    task.endTime && (
                                                        <span className="time-range">
                                                            {task.startTime} -{" "}
                                                            {task.endTime}
                                                        </span>
                                                    )}
                                                <button
                                                    className="delete-button"
                                                    onClick={() =>
                                                        handleDeleteTask(
                                                            task._id
                                                        )
                                                    }
                                                >
                                                    X
                                                </button>
                                                {!task.completed && (
                                                    <button
                                                        className="complete-button"
                                                        onClick={() =>
                                                            handleCompleteTask(
                                                                task._id,
                                                                index
                                                            )
                                                        }
                                                    >
                                                        &#10004;
                                                    </button>
                                                )}
                                            </div>
                                        </li>
                                    ))}
                            </ul>
                            <div className="add-task">
                                <input
                                    type="text"
                                    placeholder="Add a new task"
                                    value={newTask}
                                    onChange={(e) => setNewTask(e.target.value)}
                                />
                                <div className="time-inputs">
                                    <input
                                        type="time"
                                        value={newTaskStartTime}
                                        onChange={(e) =>
                                            setNewTaskStartTime(e.target.value)
                                        }
                                    />
                                    <span>-</span>
                                    <input
                                        type="time"
                                        value={newTaskEndTime}
                                        onChange={(e) =>
                                            setNewTaskEndTime(e.target.value)
                                        }
                                    />
                                </div>
                                <button onClick={handleAddTask}>
                                    Add Task
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    );
}

export default App;
Javascript
//client/src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Step 3: Start the React app:

cd client
npm start

Ouput:

plan

Daily Planner using Node js and express js



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads