package.json
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
Example: Below is an example of creating frontend for Note-Taking App.
CSS
@import url ( 'https://fonts.googleapis.com/css2?family=Poppins&display=swap' ); * { margin : 0 ; padding : 0 ; box-sizing: border-box; font-family : 'Poppins' , sans-serif ; } .image { background : url ( 'https://media.w3wiki.org/wp-content/uploads/20240222112312/Windows-11-Introduces-a-New-Sticky-Notes-App---Accessible-Exclusively-from-OneNote.webp' ); background-repeat : no-repeat ; background- size : cover; } .submitBTN { width : -webkit-fill-available; } @tailwind base; @tailwind components; @tailwind utilities; |
Javascript
// App.jsx import React from 'react' ; import { BrowserRouter as Router, Route, Routes } from 'react-router-dom' ; import Heading from './components/Heading' ; import AddNotes from './components/AddNotes' ; import DeleteNotes from './components/DeleteNotes' ; import EditNotes from './components/EditNotes' ; const App = () => { return ( <Router> <Routes> <Route path= '/' element={<Heading />} /> <Route path= '/notes/create' element={<AddNotes />} /> <Route path= '/notes/delete/:id' element={<DeleteNotes />} /> <Route path= '/notes/edit/:id' element={<EditNotes />} /> </Routes> </Router> ); }; export default App; |
Javascript
//AddNotes.jsx import React, { useState } from "react" ; import { Link, useNavigate } from "react-router-dom" ; import { IoChevronBackCircle } from "react-icons/io5" ; import Spinner from "../Components/Spinner.jsx" ; import "../index.css" ; import axios from "axios" ; const AddNotes = () => { const [topic, setTopic] = useState( "" ); const [status, setStatus] = useState( "" ); const [notes, setNotes] = useState( "" ); const [isLoading, setIsLoading] = useState( false ); const navigate = useNavigate( "" ); const data = { topic, status, notes }; const handleSubmit = async () => { try { await axios.post( "https://notes-tracker.onrender.com/notes" , data); setIsLoading( false ); navigate( "/" ); } catch (error) { console.log(error.message); console.log(error.response); } }; return ( <div> <div className= "absolute left-8 top-11" > <Link to= "/" > <IoChevronBackCircle className= "-mt-6 text-5xl float-left cursor-pointer hover:shadow-outline" /> </Link> </div> {isLoading ? ( <Spinner /> ) : ( <div className= "flex-wrap flex m-10 min-[500px]" > <div className= "bg-green-100 flex min-w-[460px] items-center justify-center p-10 flex-col w-[450px] m-auto mt-20 mb-20 rounded-md" > <div className= "mt-6" > <label className= "text-3xl font-bold float-left" htmlFor= "Topic" > Topic : </label> <div> <input type= "text" id= "Topic" className= "border-black w-[416px] mt-6 border-2 outline-none p-2 rounded-md focus:ring focus:border-purple-800" placeholder= "Enter topic" value={topic} onChange={(e) => setTopic(e.target.value)} /> </div> </div> <div className= "mt-6" > <label className= "text-3xl font-bold float-left" htmlFor= "Status" > Status :{ " " } </label> <div> <input type= "text" id= "Status" className= "border-black w-[416px] mt-6 border-2 p-2 rounded-md focus:ring focus:border-purple-800 outline-none" placeholder= "Enter status" value={status} onChange={(e) => setStatus(e.target.value)} /> </div> </div> <div className= "mt-6" > <label className= "text-3xl font-bold float-left" htmlFor= "Notes" > Notes : </label> <div> <textarea type= "text" id= "Notes" className= "border-black w-[416px] mt-6 border-2 outline-none p-2 rounded-md h-[105px] focus:ring focus:border-purple-800 " placeholder= "Enter notes" value={notes} onChange={(e) => setNotes(e.target.value)} /> </div> </div> <button className= "p-2 border-2 border-purple-900 text-2xl m-2 rounded-md font-bold text-green-950 transition duration-100 hover:bg-violet-300 hover:text-black delay-75 w-[416px]" onClick={handleSubmit} > Submit </button> </div> </div> )} </div> ); }; export default AddNotes; |
Javascript
//EditNotes.jsx import React, { useState, useEffect } from 'react' ; import { useNavigate, useParams } from 'react-router-dom' ; import axios from 'axios' ; import Spinner from '../Components/Spinner.jsx' ; import { Link } from 'react-router-dom' ; import { IoChevronBackCircle } from 'react-icons/io5' ; const EditNotes = () => { const [topic, setTopic] = useState( '' ); const [status, setStatus] = useState( '' ); const [notes, setNotes] = useState( '' ); const [isLoading, setIsLoading] = useState( false ); const navigate = useNavigate(); const { id } = useParams(); const URL = `https: //notes-tracker.onrender.com/notes/${id}`; const data = { topic, status, notes }; //Get book of specific Id useEffect(() => { const fetchDetails = async () => { try { setIsLoading( true ); const response = await axios.get(URL); // console.log(response.data); setTopic(response.data.topic); setStatus(response.data.status); setNotes(response.data.notes); setIsLoading( false ); } catch (error) { console.log(error.message); setIsLoading( false ); } } fetchDetails(); }, []) /* Handle Edit button after getting book of particular ID */ const handleEdit = async () => { try { setIsLoading( true ); await axios.put(URL, data); setIsLoading( false ); navigate( '/' ); } catch (error) { setIsLoading( false ); console.log(error.message); } } return ( <div> <div className= 'absolute left-8 top-11' > <Link to= '/' > <IoChevronBackCircle className= '-mt-6 text-5xl float-left cursor-pointer hover:shadow-outline' /> </Link> </div> {isLoading ? ( <Spinner /> ) : ( <div className= "bg-green-100 flex min-w-[460px] items-center justify-center p-10 flex-col w-[450px] m-auto mt-20 mb-20 rounded-md" > <div className= "text-left text-2xl bold" > Edit Notes </div> <input type= "text" className= 'border-black w-[416px] mt-6 border-2 outline-none p-2 rounded-md focus:ring focus:border-purple-800 ' value={topic} onChange={(e) => setTopic(e.target.value)} /> <input type= "text" className= 'border-black w-[416px] mt-6 border-2 outline-none p-2 rounded-md focus:ring focus:border-purple-800 ' value={status} onChange={(e) => setStatus(e.target.value)} /> <textarea type= 'text' className= 'border-black w-[416px] mt-6 border-2 outline-none p-2 rounded-md h-[105px] focus:ring focus:border-purple-800 resize-none' value={notes} onChange={(e) => setNotes(e.target.value)} /> <button className= 'p-2 border-2 border-purple-900 text-2xl m-2 rounded-md font-bold text-green-950 transition duration-100 hover:bg-violet-300 hover:text-black delay-75 w-[416px] mt-6' onClick={handleEdit} > Save </button> </div> )} </div> ) } export default EditNotes |
Javascript
//DeleteNotes.jsx import React from 'react' ; import '../index.css' ; import { useNavigate, useParams } from 'react-router-dom' ; import axios from 'axios' ; import Spinner from '../Components/Spinner' ; import { useState } from 'react' ; import { Link } from 'react-router-dom' ; import { IoChevronBackCircle } from 'react-icons/io5' ; const DeleteNotes = () => { const [isLoading, setIsLoading] = useState( false ); const navigate = useNavigate(); const { id } = useParams(); // console.log(id); const handleDelete = async () => { setIsLoading( true ); try { await axios. delete ( `https: //notes-tracker.onrender.com/notes/${id}`); setIsLoading( false ); navigate( '/' ); } catch (error) { setIsLoading( false ); console.log(error.message); } } return ( <div className= 'flex items-center justify-center min-h-screen' > {isLoading ? ( <Spinner /> ) : ( <div className= "flex flex-col items-center justify-center" > <div className= 'absolute left-8 top-11' > <Link to= '/' > <IoChevronBackCircle className= '-mt-6 text-5xl float-left cursor-pointer hover:shadow-outline' /> </Link> </div> <div className= "md:w-[50%] lg:w-[40%] p-8" > <p className= "text-3xl text-center font-bold mb-6" > Do you really want to delete the note you created? Rethink and then click the button below! </p> <button type= "submit" className= 'w-full outline-none border-purple-950 border-2 rounded-md bg-blue-100 text-purple-800 hover:text-cyan-50 hover:bg-slate-950 duration-100 text-3xl submitBTN' onClick={handleDelete} > Delete </button> </div> </div> )} </div> ); }; export default DeleteNotes; |
Javascript
//Heading.jsx import React, { useState } from 'react' ; import NotesCard from '../Components/NotesCard' ; import NotesTable from '../Components/NotesTable' ; import { Link } from 'react-router-dom' ; import { FaSquarePlus } from 'react-icons/fa6' ; const Heading = () => { const [tableNotes, setTableNotes] = useState( false ); const [cardNotes, setCardNotes] = useState( false ); return ( <div> <h2 className= "font-bold text-2xl max-md:ml-28 max-md:w-[300px] text-center pt-4" > Note Taking Application </h2> <div className= "max-md:ml-[385px] flex items-center justify-center max-sm:ml-[100px]" > <div className= "flex items-center justify-center pt-8 gap-4" > <button className= "shadow-lg p-1.5 w-20 text-lg rounded border-2 bg-indigo-200 font-semibold border-purple-600 transition duration-100 hover:bg-violet-800 hover:text-white delay-75" onClick={() => { setTableNotes( true ); setCardNotes( false ); }} > Table </button> <button className= "shadow-lg p-1.5 w-20 text-lg rounded border-2 bg-indigo-200 font-semibold border-purple-600 transition duration-100 hover:bg-violet-800 hover:text-white delay-75" onClick={() => { setCardNotes( true ); setTableNotes( false ); }} > Card </button> </div> </div> <div className= "max-md:float-right pr-12 float-right mt-6" > <Link to= "/notes/create" > <FaSquarePlus className= "text-5xl cursor-pointer hover:shadow-outline" /> </Link> </div> {tableNotes ? <NotesTable /> : <NotesCard />} </div> ); }; export default Heading; |
Javascript
//NotesCard.jsx import React, { useState, useEffect } from 'react' ; import { Link } from 'react-router-dom' ; import axios from 'axios' ; import { FaNoteSticky } from 'react-icons/fa6' ; import { MdEdit } from 'react-icons/md' ; import Spinner from './Spinner' ; import { MdDelete } from 'react-icons/md' ; import { CiCalendarDate } from 'react-icons/ci' ; import NotesModal from '../Modals/NotesModal' ; import DatesModal from '../Modals/DatesModal' ; const NotesCard = () => { const [notes, setNotes] = useState([]); const [isLoading, setIsLoading] = useState( false ); const [selectedIndex, setSelectedIndex] = useState( null ); const [notesModal, setNotesModal] = useState( false ); const [datesModal, setDatesModal] = useState( false ); const API_URL = 'https://notes-tracker.onrender.com/notes' ; const getNotes = async () => { setIsLoading( true ); try { const response = await axios.get(API_URL); setNotes(response.data.data); } catch (error) { console.log(error.message); } finally { setIsLoading( false ); } }; useEffect(() => { getNotes(); }, []); const openNotesModal = (index) => { setSelectedIndex(index); setNotesModal( true ); }; const closeNotesModal = () => { setSelectedIndex( null ); setNotesModal( false ); }; const openDatesModal = (index) => { setSelectedIndex(index); setDatesModal( true ); }; const closeDatesModal = () => { setSelectedIndex( null ); setDatesModal( false ); }; return ( <div> {isLoading ? ( <Spinner /> ) : ( <div className= "flex items-center justify-between mt-[100px]" > <div className= "grid " > <div className= 'grid mt-10 ml-10 mr-4 grid-cols-2 gap-8 min-w-[400px] sm:grid-cols-4 lg:grid-cols-4 xl:grid-cols-4' > {notes.map((note, index) => ( <div key={note.id} className= 'border-cyan-600 hover:shadow-2xl text-[20px] text-pretty text-2xl bg-blue-50 border-4 rounded-md p-6' > <div className= 'text-2xl text-purple-950' > <span className= 'font-bold' >S.No :</span> {index + 1} </div> <div className= 'mt-6' > <span className= 'font-bold ' >Topic :</span> {note.topic} </div> <div className= 'mt-4' > <span className= 'font-bold ' >Status :</span> {note.status} </div> <div className= 'mt-4' > <span className= 'font-bold ' >Date : </span> { new Date(note.createdAt).toDateString()} </div> <div className= 'flex items-center justify-evenly mt-6 mr-2 text-4xl' > <FaNoteSticky className= 'text-purple-950 cursor-pointer' onClick={() => openNotesModal(index)} /> <Link to={`/notes/edit/${note._id}`}> <MdEdit className= 'text-green-800 cursor-pointer' /> </Link> <Link to={`/notes/ delete /${note._id}`}> <MdDelete className= 'text-red-800 cursor-pointer' /> </Link> <CiCalendarDate className= 'text-yellow-500 text-5xl cursor-pointer' onClick={() => openDatesModal(index)} /> </div> {notesModal && selectedIndex === index && ( <NotesModal onClose={closeNotesModal} note={note} /> )} {datesModal && selectedIndex === index && ( <DatesModal onClose={closeDatesModal} note={note} /> )} </div> ))} </div> </div> </div> )} </div> ); }; export default NotesCard; |
Javascript
//NotesTable.jsx import React from 'react' ; import { FaEdit } from "react-icons/fa" ; import { MdDelete } from "react-icons/md" ; import { useState, useEffect } from 'react' ; import axios from 'axios' ; import Spinner from './Spinner.jsx' ; import { Link } from 'react-router-dom' ; const NotesTable = () => { const [notes, setNotes] = useState([]); const [isLoading, setIsLoading] = useState( true ); const URL = `https: //notes-tracker.onrender.com/notes`; const fetchNotes = async () => { try { const notesData = await axios.get(URL); setNotes(notesData.data.data); setIsLoading( false ); } catch (error) { console.log(error.message); } } useEffect(() => { fetchNotes(); }, []) return ( <div> {isLoading ? ( <Spinner /> ) : ( <table className= 'w-full border-separate border-spacing-4 p-4 mt-4' > <thead> <tr> <th className= "border-purple-600 text-xl border-2 rounded-md p-2" > S.No </th> <th className= "border-purple-600 text-xl border-2 rounded-md p-2" > Topic </th> <th className= "border-purple-600 text-xl border-2 rounded-md p-2 max-md:hidden" > Status </th> <th className= "border-purple-600 text-xl border-2 rounded-md p-2 max-md:hidden" > Date </th> <th className= "border-purple-600 text-xl border-2 rounded-md p-2" > Notes </th> </tr> </thead> <tbody> {notes.map((item, index) => <tr key={item.id}> <td className= 'text-center border-purple-600 border-2 rounded-md p-2 ' > {index + 1} </td> <td className= 'border-purple-600 border-2 rounded-md p-2' > {item.topic} </td> <td className= 'max-md:hidden outline-none border-purple-600 border-2 rounded-md p-2' > {item.status} </td> <td className= 'max-md:hidden border-purple-600 border-2 rounded-md p-2' > { new Date(item.createdAt).toString()} </td> <td> <p className= 'border-purple-600 min-h-[116px] border-2 outline-none rounded-md p-2' > {item.notes} </p> </td> <td className= 'flex items-center justify-around p-2' > <Link to={`/notes/edit/${item._id}`}> <FaEdit className= 'cursor-pointer text-3xl ' /> </Link> <Link to={`/notes/ delete /${item._id}`}> <MdDelete className= 'cursor-pointer text-3xl ' /> </Link> </td> </tr> )} </tbody> </table> )} </div> ) } export default NotesTable |
Javascript
//DatesModal.jsx import React from "react" ; import { CiCalendarDate } from "react-icons/ci" ; import { RxCrossCircled } from "react-icons/rx" ; const DatesModal = ({ onClose, note }) => { return ( <div className= "fixed bg-black bg-opacity-60 top-0 left-0 right-0 bottom-0 flex justify-center items-center" > <div onClick={(event) => event.stopPropagation()} className= "w-[600px] max-w-full bg-white h-fit rounded-xl p-4 flex flex-col relative" > <RxCrossCircled className= "absolute right-6 top-6 text-3xl text-red-600 cursor-pointer" onClick={onClose} /> <h4 className= "mt-5 text-2xl font-bold underline" > {note.topic} </h4> <div className= "flex items-center gap-3 my-8" > <CiCalendarDate className= "text-red-500 text-3xl" /> <h2>{ new Date(note.createdAt).toDateString()}</h2> </div> <p> Created at: <span className= "mt-4" > { new Date(note.createdAt).getFullYear()}- { new Date(note.createdAt).getMonth() + 1}- { new Date(note.createdAt).getDate()} { new Date(note.createdAt).toTimeString().split( " " )[0]} </span> </p> <p> Updated at : <span className= "mt-4" > { new Date(note.updatedAt).getFullYear()}- { new Date(note.updatedAt).getMonth() + 1}- { new Date(note.updatedAt).getDate()} { new Date(note.updatedAt).toTimeString().split( " " )[0]} </span> </p> </div> </div> ); }; export default DatesModal; |
Javascript
//NotesModal.jsx import React from 'react' ; import { RxCrossCircled } from "react-icons/rx" ; import { FaBook } from "react-icons/fa" ; const NotesModal = ({ onClose, note }) => { return ( <div className= 'flex bg-black bg-opacity-60 items-center justify-center top-0 left-0 right-0 bottom-0 fixed' > <div onClick={(event) => event.stopPropagation()} className= 'bg-white max-w-full h-fit flex flex-col p-4 w-[500px] rounded-md relative' > <RxCrossCircled onClick={onClose} className= 'text-4xl cursor-pointer text-red-600 absolute right-4' /> <p className= 'text-2xl font-bold' > {note.topic} </p> <p className= 'text-2xl font-bold mt-6' > Status : <span className= 'text-purple-900' > {note.status} </span> </p> <p className= 'flex justify-center' > <FaBook className= 'mr-[11px] -mt-[38px] text-yellow-500 text-[200px]' /> <span className= "text-xl mt-10" > {note.notes} </span> </p> </div> </div> ) } export default NotesModal |
Javascript
//Spinner.jsx (Animation Effect) import React from 'react' const Spinner = () => { return ( <div className= 'animate-ping absolute top-[150px] left-32 h-14 w-14 flex items-center rounded-full bg-purple-800' > </div> ) } export default Spinner |
Javascript
//Main.jsx import React from 'react' ; import ReactDOM from 'react-dom/client' ; import App from './App.jsx' ; import './index.css' ; import {BrowserRouter} from 'react-router-dom' ReactDOM.createRoot(document.getElementById( 'root' )).render( <BrowserRouter> <App /> </BrowserRouter>, ) |
Start your application using the following command.
npm start
Output :
Note-Taking App with Status Tracker using MERN Stack
In this article, we will be creating a simple note-taking application with functionalities to create a note, delete a note, edit a note, and view the note. The project uses NodeJS as a backend server with Postman API to post and get the notes from the HTTP request. It uses ExpressJS as a framework in the backend and MongoDB to create a database and store the notes. The frontend setup can be created using ReactJS.
Contact Us