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.