I am trying to get my first Node.js server to work with React Front-end for a site I am building for a client. I have mostly dealt with Django REST when I need a server but I heard Node.js was simpler and maybe more appropriate for this cause, I am also more comfortable with Javascript.
Basic structure of the website:
- - Form for uploading large amounts of PDF documents, images, power point presentations.
- - Search functionality for the database to find certain PDFs by author, country, upload date and other values.
- - I am using React DocViewer to display the PDF documents.
The Problem:
The problem I am having now is that I am able to retrive all the saved data as JSON but not display PDF from a single column based on FileId with DocViewer in ViewPdf.js.
.
This is the page for the DocViewer:
import React, { useState, useEffect } from 'react'; import { useParams } from 'react-router-dom'; import DocViewer, { PDFRenderer, HTMLRenderer } from "react-doc-viewer"; const ViewPdf = () => { const { fileId } = useParams(); const [fileUrl, setFileUrl] = useState('') useEffect(() => { // Construct the URL to fetch the file const url = `/api/uploads/:fileId`; setFileUrl(url); }, [fileUrl, fileId]); const docs = [ { uri: fileUrl } ]; return ( <DocViewer pluginRenderers={[PDFRenderer, HTMLRenderer]} documents={docs} config={{ header: { retainURLParams: true, }, } } /> ); } export default ViewPdf;
The ViewPdf is opened with this Search page:
import React, { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import '@cds/core/select/register.js'; function Search() { const navigate = useNavigate(); const [uploads, setUploads] = useState([]); const [filter, setFilter] = useState({ category: '', uploadDate: '', author: '', country: '' }); useEffect(() => { fetch('http://localhost:8000/api/uploads') .then(response => response.json()) .then(data => setUploads(data)) .catch(error => console.error('Error:', error)); }, []); const handleFilterChange = (event) => { const { name, value } = event.target; setFilter(prevFilter => ({ ...prevFilter, [name]: value })); }; const filteredUploads = uploads.filter(upload => { const { category, uploadDate, author, country } = filter; return ( (category === '' || upload.category === category) && (uploadDate === '' || upload.uploaddate === uploadDate) && (author === '' || upload.author === author) && (country === '' || upload.country === country) ); }); const handleFileClick = (upload) => { const fileId = upload.id; navigate(`/api/uploads/${fileId}`); }; return ( <div style={{ display: "flex", justifyContent: "center" }}> <div style={{ textAlign: "left" }}> <div style={{ marginBottom: "10px" }}> <label style={{ display: "inline-block", width: "100px" }}>Category:</label> <input type="text" name="category" value={filter.category} onChange={handleFilterChange} /> </div> <div style={{ marginBottom: "10px" }}> <label style={{ display: "inline-block", width: "100px" }}>Upload Date:</label> <input type="date" name="uploadDate" value={filter.uploadDate} onChange={handleFilterChange} /> </div> <div style={{ marginBottom: "10px" }}> <label style={{ display: "inline-block", width: "100px" }}>Author:</label> <input type="text" name="author" value={filter.author} onChange={handleFilterChange} /> </div> <div style={{ marginBottom: "10px" }}> <label style={{ display: "inline-block", width: "100px" }}>Country:</label> <select name="country" value={filter.country} onChange={handleFilterChange}> <option value="">All</option> <option value="USA">USA</option> <option value="Canada">Canada</option> <option value="UK">UK</option> <option value="Albania">Albania</option> <option value="Andorra">Andorra</option> <option value="Austria">Austria</option> <option value="Belarus">Belarus</option> <option value="Belgium">Belgium</option> <option value="Bosnia and Herzegovina">Bosnia and Herzegovina</option> <option value="Bulgaria">Bulgaria</option> <option value="Croatia">Croatia</option> <option value="Cyprus">Cyprus</option> <option value="Czech Republic">Czech Republic</option> <option value="Denmark">Denmark</option> <option value="Estonia">Estonia</option> <option value="Finland">Finland</option> <option value="France">France</option> <option value="Germany">Germany</option> <option value="Greece">Greece</option> <option value="Hungary">Hungary</option> <option value="Iceland">Iceland</option> <option value="Ireland">Ireland</option> <option value="Italy">Italy</option> <option value="Kosovo">Kosovo</option> <option value="Latvia">Latvia</option> <option value="Liechtenstein">Liechtenstein</option> <option value="Lithuania">Lithuania</option> <option value="Luxembourg">Luxembourg</option> <option value="Malta">Malta</option> <option value="Moldova">Moldova</option> <option value="Monaco">Monaco</option> <option value="Montenegro">Montenegro</option> <option value="Netherlands">Netherlands</option> <option value="North Macedonia (formerly Macedonia)">North Macedonia (formerly Macedonia)</option> <option value="Norway">Norway</option> <option value="Poland">Poland</option> <option value="Portugal">Portugal</option> <option value="Romania">Romania</option> <option value="Russia">Russia</option> <option value="San Marino">San Marino</option> <option value="Serbia">Serbia</option> <option value="Slovakia">Slovakia</option> <option value="Slovenia">Slovenia</option> <option value="Spain">Spain</option> <option value="Sweden">Sweden</option> <option value="Switzerland">Switzerland</option> <option value="Ukraine">Ukraine</option> <option value="United Kingdom (UK)">United Kingdom (UK)</option> <option value="Vatican City (Holy See)">Vatican City (Holy See)</option> </select> </div> <ol> {filteredUploads.sort((a, b) => new Date(b.uploaddate) - new Date(a.uploaddate)).map((upload, index) => ( <li key={index} onClick={() => handleFileClick(upload)}> <p style={{ display: "inline-block", marginRight: "50px" }}>Upload Date: {upload.uploaddate}</p> <p style={{ display: "inline-block", marginRight: "50px" }}>Category: {upload.category}</p> <p style={{ display: "inline-block", marginRight: "50px" }}>Country: {upload.country}</p> <p style={{ display: "inline-block", marginRight: "50px" }}>Author: {upload.author}</p> <p style={{ display: "inline-block", marginRight: "50px" }}>ID: {upload.id}</p> </li> ))} </ol> </div> </div> ); } export default Search;
The API endpoint for this in Server.js looks like this:
app.get("/api/uploads/:fileId", async (req, res) => { const { fileId } = req.params; try { console.log([fileId]); const queryResult = await pool.query( "SELECT filename FROM uploads WHERE id = $1", [fileId] ); if (queryResult.rows.length > 0) { const { filename } = queryResult.rows[0]; const filePath = path.join(__dirname, "uploads", filename); res.sendFile(filePath); } else { res.status(404).json({ message: "File not found" }); } } catch (err) { console.error(err); res.status(500).json({ message: "Internal server error" }); } });
I have installed DocViewer on the front-end. My guess is that the problem originate from a miss config of the end point and also what the server should diplay, not JSON but PDF. Or that the mounting somehow gets stuck in a loop and closes the connection to early.
I have this error showing when trying to open a PDF file:
ERROR signal is aborted without reason at http://localhost:3000/static/js/bundle.js:23248:18 at safelyCallDestroy (http://localhost:3000/static/js/bundle.js:43291:9) at commitHookEffectListUnmount (http://localhost:3000/static/js/bundle.js:43429:15) at commitPassiveUnmountOnFiber (http://localhost:3000/static/js/bundle.js:45051:15) at commitPassiveUnmountEffects_complete (http://localhost:3000/static/js/bundle.js:45031:11) at commitPassiveUnmountEffects_begin (http://localhost:3000/static/js/bundle.js:45022:11) at commitPassiveUnmountEffects (http://localhost:3000/static/js/bundle.js:44976:7) at flushPassiveEffectsImpl (http://localhost:3000/static/js/bundle.js:46797:7) at flushPassiveEffects (http://localhost:3000/static/js/bundle.js:46751:18) at http://localhost:3000/static/js/bundle.js:46566:13
This is the screen after the error at the ViewPdf.jsx page:
It reads: You need to enable JavaScript to run this app.
As this is my first attempt with Node.js any suggestions are well appreciated. Thanks !
Top comments (1)
Finally solved it today ! Back with a breakdown soon.