In this tutorial, we will be creating a Full Stack Project Manager App using React, Next.js, MongoDB, and Tailwind CSS. This app will allow users to create projects, add tasks to their projects, and mark tasks as completed.
Before we begin, make sure you have Node.js and npm installed on your computer. You will also need a MongoDB Atlas account to create a free MongoDB database for this project.
Step 1: Setting up the project
First, let’s create a new Next.js project by running the following commands in your terminal:
npx create-next-app project-manager-app
cd project-manager-app
Next, let’s install the required dependencies for this project:
npm install react react-dom next
npm install axios mongoose
npm install tailwindcss postcss autoprefixer
Step 2: Configuring Tailwind CSS
Next, we need to configure Tailwind CSS for our project. Create a postcss.config.js
file in the root of your project with the following content:
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
Create a tailwind.config.js
file in the root of your project with the following content:
module.exports = {
purge: [],
darkMode: false,
theme: {
extend: {},
},
variants: {},
plugins: [],
};
Create a styles
directory in the styles
directory, and create a new tailwind.css
file with the following content:
@tailwind base;
@tailwind components;
@tailwind utilities;
Update your pages/_app.js
file with the following content to include Tailwind CSS:
import "../styles/tailwind.css";
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}
export default MyApp;
Step 3: Setting up MongoDB
Next, we need to set up our MongoDB database. Create a new cluster on MongoDB Atlas and get your connection string.
Create a new db.js
file in the root of your project with the following content:
import mongoose from "mongoose";
const connection_string = "YOUR_CONNECTION_STRING";
const connectDB = async () => {
try {
const conn = await mongoose.connect(connection_string, {
useUnifiedTopology: true,
useNewUrlParser: true,
useCreateIndex: true,
});
console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch (error) {
console.error(`Error: ${error.message}`);
process.exit(1);
}
};
export default connectDB;
Step 4: Creating the models
Next, let’s create our models for the project and tasks. Create a new models
directory in the root of your project.
Create a Project.js
file with the following content:
import mongoose from "mongoose";
const projectSchema = mongoose.Schema({
name: {
type: String,
required: true,
},
tasks: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Task",
},
],
});
const Project = mongoose.model("Project", projectSchema);
export default Project;
Create a Task.js
file with the following content:
import mongoose from "mongoose";
const taskSchema = mongoose.Schema({
name: {
type: String,
required: true,
},
completed: {
type: Boolean,
default: false,
},
});
const Task = mongoose.model("Task", taskSchema);
export default Task;
Step 5: Creating the API routes
Next, let’s create our API routes for handling project and task data. Create a new api
directory in the root of your project.
Create a projects.js
file with the following content:
import connectDB from "../../db";
import Project from "../../models/Project";
connectDB();
export default async (req, res) => {
if (req.method === "POST") {
try {
const project = await Project.create(req.body);
res.status(201).json({ success: true, data: project });
} catch (error) {
res.status(400).json({ success: false });
}
} else if (req.method === "GET") {
try {
const projects = await Project.find().populate("tasks");
res.status(200).json({ success: true, data: projects });
} catch (error) {
res.status(400).json({ success: false });
}
}
};
Create a tasks.js
file with the following content:
import connectDB from "../../db";
import Task from "../../models/Task";
connectDB();
export default async (req, res) => {
if (req.method === "POST") {
try {
const task = await Task.create(req.body);
res.status(201).json({ success: true, data: task });
} catch (error) {
res.status(400).json({ success: false });
}
} else if (req.method === "PUT") {
try {
const task = await Task.findByIdAndUpdate(req.query.id, req.body, {
new: true,
runValidators: true,
});
res.status(200).json({ success: true, data: task });
} catch (error) {
res.status(400).json({ success: false });
}
}
};
Step 6: Creating the components
Next, let’s create our components for displaying projects and tasks. Create a components
directory in the src
directory of your project.
Create a ProjectForm.js
file with the following content:
import { useState } from "react";
import axios from "axios";
const ProjectForm = () => {
const [name, setName] = useState("");
const handleSubmit = async (e) => {
e.preventDefault();
try {
const res = await axios.post("/api/projects", { name });
console.log(res.data);
} catch (error) {
console.error(error.response.data);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Project Name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<button type="submit">Create Project</button>
</form>
);
};
export default ProjectForm;
Create a ProjectsList.js
file with the following content:
import { useState, useEffect } from "react";
import axios from "axios";
const ProjectsList = () => {
const [projects, setProjects] = useState([]);
useEffect(() => {
const fetchProjects = async () => {
const res = await axios.get("/api/projects");
setProjects(res.data.data);
};
fetchProjects();
}, []);
return (
<div>
{projects.map((project) => (
<div key={project._id}>{project.name}</div>
))}
</div>
);
};
export default ProjectsList;
Step 7: Using the components
Finally, let’s use our components in our pages/index.js
file:
import ProjectForm from "../components/ProjectForm";
import ProjectsList from "../components/ProjectsList";
const Home = () => {
return (
<div>
<h1>Project Manager App</h1>
<ProjectForm />
<ProjectsList />
</div>
);
};
export default Home;
And that’s it! You have now created a Full Stack Project Manager App using React, Next.js, MongoDB, and Tailwind CSS. You can now start adding more features to the app such as editing projects, adding due dates to tasks, and filtering projects by status. Happy coding!
Clerk – I'm out 🙁
Davis Paul Rodriguez Brian Anderson Barbara
Loved your work 👏👏 . u've gained a sub
your ideas are so good bro ,can u make a detailed project like typing etc tutorial i guess it may increase your views
Lovely project but could you please have another video where you teach how to deploy the website as that would be really useful
use express js with typescript and not Next js for both front end and back end , not good practice also use jwt auth not 3rd party, i will skop that sorry, thanks for the effort btw
bro you missed some of the parts while recording
It would be better if you could give us a starting template code ( github repository) so that we dont mess up the initial configuration .
Man, please stop using third-party authentication. Whenever a tutorial that use clerk I totally skip it
Not Dark mode ?
Can we deploy this for free somewhere and still ensure it’s fast?
Deployment?