Open In App

Document Management System using NextJS

The Document Management System is a web application developed using Next.js, that allows users to efficiently manage their documents. The system provides features for uploading, organizing, and retrieving documents. Users can upload documents through the web interface, which are then stored in local storage.

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

gfgd

Prerequisites:

Approach to Create Document Management System:

Steps to Create Document Management System:

Step 1: Create a application of NextJS using the following command.

npx create-next-app doc-management

Step 2: Navigate to project directory

cd doc-management

Step 3: Install the necessary package in your project using the following command.

npm install bootstrap
npm install react-toastify

Step 4: Create the folder structure as shown below and create the files in respective folders.

Project Structure:

Screenshot-(59)

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

"dependencies": {
"bootstrap": "^5.3.3",
"next": "14.1.3",
"react": "^18",
"react-dom": "^18",
"react-toastify": "^10.0.5"
}

Example: Below are the components which describes the implementation Document Management System.

// page.js

import React from 'react'
import Documents from './components/Documents'

const page = () => {
    return (
        <div>
            <Documents />
        </div>
    )
}

export default page;
// Navbar.js
import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Link from 'next/link';
function Navbar() {
    return (
        <nav className="navbar navbar-expand-lg navbar-light 
                        bg-light shadow top-0">
            <div className="container">
                <a className="navbar-brand" href="#">
                    GFG DocManager
                </a>
                <button className="navbar-toggler"
                    type="button" data-toggle="collapse"
                    data-target="#navbarNav" aria-controls="navbarNav"
                    aria-expanded="false" aria-label="Toggle navigation">
                    <span className="navbar-toggler-icon"></span>
                </button>
                <div className="collapse navbar-collapse" id="navbarNav">
                    <ul className="navbar-nav">
                        <li className="nav-item">
                            <Link className="nav-link"
                                href="/">Documents
                            </Link>
                        </li>
                        <li className="nav-item">
                            <Link className="nav-link"
                                href="AddDocument">Add New Document
                            </Link>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    );
}

export default Navbar;
// Documents.js

'use client'
import React, { useState, useEffect } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Navbar from './Navbar';

const Documents = () => {
    const [documents, setDocuments] = useState([]);
    const [selectedDocument, setSelectedDocument] = useState(null);
    const [showModal, setShowModal] = useState(false);
    const [searchQuery, setSearchQuery] = useState('');

    useEffect(() => {
        const storedDocuments = JSON.parse(localStorage.getItem('documents')) || [];
        setDocuments(storedDocuments);
    }, []);

    const handleViewDocument = (id) => {
        const document = documents.find(doc => doc.id === id);
        setSelectedDocument(document);
        setShowModal(true);
    };

    const handleDeleteDocument = (id) => {
        const updatedDocuments = documents.filter((document) => document.id !== id);
        setDocuments(updatedDocuments);
        localStorage.setItem('documents', JSON.stringify(updatedDocuments));
    };

    const filteredDocuments = documents.filter(document =>
        document.name.toLowerCase().includes(searchQuery.toLowerCase())
    );

    return (
        <>
            <Navbar />
            <div className="container mt-5">
                <div className="row">
                    <div className="col-md-1 border-end"></div>
                    <div className="mb-3">
                        <input
                            type="text"
                            className="form-control"
                            placeholder="Search documents..."
                            value={searchQuery}
                            onChange={(e) => setSearchQuery(e.target.value)}
                        />
                    </div>
                    <div className="col">
                        <h2>Document List</h2>

                        <table className="table">
                            <thead>
                                <tr>
                                    <th>ID</th>
                                    <th>Name</th>
                                    <th>Created Date</th>
                                    <th>Action</th>
                                </tr>
                            </thead>
                            <tbody>
                                {filteredDocuments.map((document) => (
                                    <tr key={document.id}>
                                        <td>{document.id}</td>
                                        <td>{document.name}</td>
                                        <td>{document.date}</td>
                                        <td>
                                            <button className="btn btn-primary"
                                                onClick={() =>
                                                    handleViewDocument(document.id)}>
                                                View
                                            </button>
                                            <button className="btn btn-danger ms-2"
                                                onClick={() =>
                                                    handleDeleteDocument(document.id)}>
                                                Delete
                                            </button>
                                        </td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>

            {showModal && (
                <div className="modal" tabIndex="-1" role="dialog" style={{
                    display: 'block', backgroundColor: 'rgba(0, 0, 0, 0.5)'
                }}>
                    <div className="modal-dialog modal-dialog-centered"
                        role="document">
                        <div className="modal-content">
                            <div className="modal-header">
                                <h5 className="modal-title">
                                    {selectedDocument?.name}
                                </h5>
                                <button type="button" className="close"
                                    onClick={() => setShowModal(false)}>
                                    <span aria-hidden="true">&times;</span>
                                </button>
                            </div>
                            <div className="modal-body">
                                {
                                    selectedDocument && selectedDocument.image &&
                                    <img src={selectedDocument.image} alt="Document"
                                        className="img-fluid" />
                                }
                            </div>
                        </div>
                    </div>
                </div>
            )}
        </>
    );
};

export default Documents;
// AddDocument.js

import React, { useState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Navbar from '@/app/components/Navbar';
import { toast, ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

const AddDocument = () => {
    const [documentName, setDocumentName] = useState('');
    const [description, setDescription] = useState('');
    const [image, setImage] = useState('');

    const handleDocumentNameChange = (e) => {
        setDocumentName(e.target.value);
    };

    const handleDescriptionChange = (e) => {
        setDescription(e.target.value);
    };

    const handleImageChange = (e) => {
        const file = e.target.files[0];
        const reader = new FileReader();
        reader.onloadend = () => {
            setImage(reader.result);
        };
        if (file) {
            reader.readAsDataURL(file);
        }
    };

    const handleAddDocument = () => {
        if (!documentName.trim() || !description.trim() || !image) {
            toast.error('Please fill in all fields.');
            return;
        }

        const currentDate = new Date().toLocaleDateString();
        const existingDocuments = JSON.parse(
            localStorage.getItem('documents')) || [];
        const newDocument = {
            id: existingDocuments.length + 1,
            // Use the length of existingDocuments array as the ID
            name: documentName,
            description: description,
            image: image,
            date: currentDate,
        };
        const updatedDocuments = [...existingDocuments, newDocument];
        localStorage.setItem('documents', JSON.stringify(updatedDocuments));
        setDocumentName('');
        setDescription('');
        setImage('');
        toast.success('Document added successfully.');
    };

    return (
        <>
            <Navbar />
            <div className="mb-3 container" style={{ width: '70%' }}>
                <label htmlFor="documentName" className="form-label">
                    Document Name
                </label>
                <input
                    type="text"
                    className="form-control"
                    id="documentName"
                    value={documentName}
                    onChange={handleDocumentNameChange}
                />
                <label htmlFor="description" className="form-label mt-3">
                    Description
                </label>
                <textarea
                    className="form-control"
                    id="description"
                    value={description}
                    onChange={handleDescriptionChange}
                />
                <label htmlFor="image" className="form-label mt-3">
                    Select Image
                </label>
                <input
                    type="file"
                    className="form-control"
                    id="image"
                    onChange={handleImageChange}
                />
                <button className="btn btn-primary mt-3"
                    onClick={handleAddDocument}>
                    Add Document
                </button>
            </div>
            <ToastContainer />
        </>
    );
};

export default AddDocument;

Start your application using the following command:

npm run dev

Output: Naviage to the URL http://localhost:3000:

gfgdoc

Article Tags :