<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Spare</title>
    <description>The latest articles on DEV Community by Spare (@thomasspare).</description>
    <link>https://dev.to/thomasspare</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1268631%2Fffe7862e-154b-43c8-b555-323b988e65af.jpeg</url>
      <title>DEV Community: Spare</title>
      <link>https://dev.to/thomasspare</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thomasspare"/>
    <language>en</language>
    <item>
      <title>Struggling with Node.js</title>
      <dc:creator>Spare</dc:creator>
      <pubDate>Sat, 06 Jul 2024 15:34:59 +0000</pubDate>
      <link>https://dev.to/thomasspare/struggling-with-nodejs-5ch3</link>
      <guid>https://dev.to/thomasspare/struggling-with-nodejs-5ch3</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic structure of the website:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;- Form for uploading large amounts of PDF documents, images, power point presentations.&lt;/li&gt;
&lt;li&gt;- Search functionality for the database to find certain PDFs by author, country, upload date and other values.&lt;/li&gt;
&lt;li&gt;- I am using React DocViewer to display the PDF documents.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;br&gt;
.&lt;br&gt;
This is the page for the DocViewer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import DocViewer, { PDFRenderer, HTMLRenderer } from "react-doc-viewer";


const ViewPdf = () =&amp;gt; {
    const { fileId } = useParams();
    const [fileUrl, setFileUrl] = useState('')

  useEffect(() =&amp;gt; {
    // Construct the URL to fetch the file
    const url = `/api/uploads/:fileId`;

    setFileUrl(url);
  }, [fileUrl, fileId]);

  const docs = [
    { uri: fileUrl }
  ];

  return (

      &amp;lt;DocViewer 
      pluginRenderers={[PDFRenderer, HTMLRenderer]}
      documents={docs}
      config={{
        header: {
            retainURLParams: true,

            },   
       } } /&amp;gt;

    );
}



export default ViewPdf;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The ViewPdf is opened with this Search page:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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(() =&amp;gt; {
    fetch('http://localhost:8000/api/uploads')
      .then(response =&amp;gt; response.json())
      .then(data =&amp;gt; setUploads(data))
      .catch(error =&amp;gt; console.error('Error:', error));
  }, []);

  const handleFilterChange = (event) =&amp;gt; {
    const { name, value } = event.target;
    setFilter(prevFilter =&amp;gt; ({
      ...prevFilter,
      [name]: value
    }));
  };

  const filteredUploads = uploads.filter(upload =&amp;gt; {
    const { category, uploadDate, author, country } = filter;
    return (
      (category === '' || upload.category === category) &amp;amp;&amp;amp;
      (uploadDate === '' || upload.uploaddate === uploadDate) &amp;amp;&amp;amp;
      (author === '' || upload.author === author) &amp;amp;&amp;amp;
      (country === '' || upload.country === country)
    );
  });

  const handleFileClick = (upload) =&amp;gt; {
    const fileId = upload.id;
    navigate(`/api/uploads/${fileId}`);
  };

  return (
    &amp;lt;div style={{ display: "flex", justifyContent: "center" }}&amp;gt;
      &amp;lt;div style={{ textAlign: "left" }}&amp;gt;
        &amp;lt;div style={{ marginBottom: "10px" }}&amp;gt;
          &amp;lt;label style={{ display: "inline-block", width: "100px" }}&amp;gt;Category:&amp;lt;/label&amp;gt;
          &amp;lt;input type="text" name="category" value={filter.category} onChange={handleFilterChange} /&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div style={{ marginBottom: "10px" }}&amp;gt;
          &amp;lt;label style={{ display: "inline-block", width: "100px" }}&amp;gt;Upload Date:&amp;lt;/label&amp;gt;
          &amp;lt;input type="date" name="uploadDate" value={filter.uploadDate} onChange={handleFilterChange} /&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div style={{ marginBottom: "10px" }}&amp;gt;
          &amp;lt;label style={{ display: "inline-block", width: "100px" }}&amp;gt;Author:&amp;lt;/label&amp;gt;
          &amp;lt;input type="text" name="author" value={filter.author} onChange={handleFilterChange} /&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div style={{ marginBottom: "10px" }}&amp;gt;
          &amp;lt;label style={{ display: "inline-block", width: "100px" }}&amp;gt;Country:&amp;lt;/label&amp;gt;
          &amp;lt;select name="country" value={filter.country} onChange={handleFilterChange}&amp;gt;
            &amp;lt;option value=""&amp;gt;All&amp;lt;/option&amp;gt;
            &amp;lt;option value="USA"&amp;gt;USA&amp;lt;/option&amp;gt;
            &amp;lt;option value="Canada"&amp;gt;Canada&amp;lt;/option&amp;gt;
            &amp;lt;option value="UK"&amp;gt;UK&amp;lt;/option&amp;gt;
            &amp;lt;option value="Albania"&amp;gt;Albania&amp;lt;/option&amp;gt;
            &amp;lt;option value="Andorra"&amp;gt;Andorra&amp;lt;/option&amp;gt;
            &amp;lt;option value="Austria"&amp;gt;Austria&amp;lt;/option&amp;gt;
            &amp;lt;option value="Belarus"&amp;gt;Belarus&amp;lt;/option&amp;gt;
            &amp;lt;option value="Belgium"&amp;gt;Belgium&amp;lt;/option&amp;gt;
            &amp;lt;option value="Bosnia and Herzegovina"&amp;gt;Bosnia and Herzegovina&amp;lt;/option&amp;gt;
            &amp;lt;option value="Bulgaria"&amp;gt;Bulgaria&amp;lt;/option&amp;gt;
            &amp;lt;option value="Croatia"&amp;gt;Croatia&amp;lt;/option&amp;gt;
            &amp;lt;option value="Cyprus"&amp;gt;Cyprus&amp;lt;/option&amp;gt;
            &amp;lt;option value="Czech Republic"&amp;gt;Czech Republic&amp;lt;/option&amp;gt;
            &amp;lt;option value="Denmark"&amp;gt;Denmark&amp;lt;/option&amp;gt;
            &amp;lt;option value="Estonia"&amp;gt;Estonia&amp;lt;/option&amp;gt;
            &amp;lt;option value="Finland"&amp;gt;Finland&amp;lt;/option&amp;gt;
            &amp;lt;option value="France"&amp;gt;France&amp;lt;/option&amp;gt;
            &amp;lt;option value="Germany"&amp;gt;Germany&amp;lt;/option&amp;gt;
            &amp;lt;option value="Greece"&amp;gt;Greece&amp;lt;/option&amp;gt;
            &amp;lt;option value="Hungary"&amp;gt;Hungary&amp;lt;/option&amp;gt;
            &amp;lt;option value="Iceland"&amp;gt;Iceland&amp;lt;/option&amp;gt;
            &amp;lt;option value="Ireland"&amp;gt;Ireland&amp;lt;/option&amp;gt;
            &amp;lt;option value="Italy"&amp;gt;Italy&amp;lt;/option&amp;gt;
            &amp;lt;option value="Kosovo"&amp;gt;Kosovo&amp;lt;/option&amp;gt;
            &amp;lt;option value="Latvia"&amp;gt;Latvia&amp;lt;/option&amp;gt;
            &amp;lt;option value="Liechtenstein"&amp;gt;Liechtenstein&amp;lt;/option&amp;gt;
            &amp;lt;option value="Lithuania"&amp;gt;Lithuania&amp;lt;/option&amp;gt;
            &amp;lt;option value="Luxembourg"&amp;gt;Luxembourg&amp;lt;/option&amp;gt;
            &amp;lt;option value="Malta"&amp;gt;Malta&amp;lt;/option&amp;gt;
            &amp;lt;option value="Moldova"&amp;gt;Moldova&amp;lt;/option&amp;gt;
            &amp;lt;option value="Monaco"&amp;gt;Monaco&amp;lt;/option&amp;gt;
            &amp;lt;option value="Montenegro"&amp;gt;Montenegro&amp;lt;/option&amp;gt;
            &amp;lt;option value="Netherlands"&amp;gt;Netherlands&amp;lt;/option&amp;gt;
            &amp;lt;option value="North Macedonia (formerly Macedonia)"&amp;gt;North Macedonia (formerly Macedonia)&amp;lt;/option&amp;gt;
            &amp;lt;option value="Norway"&amp;gt;Norway&amp;lt;/option&amp;gt;
            &amp;lt;option value="Poland"&amp;gt;Poland&amp;lt;/option&amp;gt;
            &amp;lt;option value="Portugal"&amp;gt;Portugal&amp;lt;/option&amp;gt;
            &amp;lt;option value="Romania"&amp;gt;Romania&amp;lt;/option&amp;gt;
            &amp;lt;option value="Russia"&amp;gt;Russia&amp;lt;/option&amp;gt;
            &amp;lt;option value="San Marino"&amp;gt;San Marino&amp;lt;/option&amp;gt;
            &amp;lt;option value="Serbia"&amp;gt;Serbia&amp;lt;/option&amp;gt;
            &amp;lt;option value="Slovakia"&amp;gt;Slovakia&amp;lt;/option&amp;gt;
            &amp;lt;option value="Slovenia"&amp;gt;Slovenia&amp;lt;/option&amp;gt;
            &amp;lt;option value="Spain"&amp;gt;Spain&amp;lt;/option&amp;gt;
            &amp;lt;option value="Sweden"&amp;gt;Sweden&amp;lt;/option&amp;gt;
            &amp;lt;option value="Switzerland"&amp;gt;Switzerland&amp;lt;/option&amp;gt;
            &amp;lt;option value="Ukraine"&amp;gt;Ukraine&amp;lt;/option&amp;gt;
            &amp;lt;option value="United Kingdom (UK)"&amp;gt;United Kingdom (UK)&amp;lt;/option&amp;gt;
            &amp;lt;option value="Vatican City (Holy See)"&amp;gt;Vatican City (Holy See)&amp;lt;/option&amp;gt;
          &amp;lt;/select&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;ol&amp;gt;
          {filteredUploads.sort((a, b) =&amp;gt; new Date(b.uploaddate) - new Date(a.uploaddate)).map((upload, index) =&amp;gt; (
            &amp;lt;li key={index} onClick={() =&amp;gt; handleFileClick(upload)}&amp;gt;
              &amp;lt;p style={{ display: "inline-block", marginRight: "50px" }}&amp;gt;Upload Date: {upload.uploaddate}&amp;lt;/p&amp;gt;
              &amp;lt;p style={{ display: "inline-block", marginRight: "50px" }}&amp;gt;Category: {upload.category}&amp;lt;/p&amp;gt;
              &amp;lt;p style={{ display: "inline-block", marginRight: "50px" }}&amp;gt;Country: {upload.country}&amp;lt;/p&amp;gt;
              &amp;lt;p style={{ display: "inline-block", marginRight: "50px" }}&amp;gt;Author: {upload.author}&amp;lt;/p&amp;gt;
              &amp;lt;p style={{ display: "inline-block", marginRight: "50px" }}&amp;gt;ID: {upload.id}&amp;lt;/p&amp;gt;
            &amp;lt;/li&amp;gt;
          ))}
        &amp;lt;/ol&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default Search;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API endpoint for this in Server.js looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get("/api/uploads/:fileId", async (req, res) =&amp;gt; {
  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 &amp;gt; 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" });
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;I have this error showing when trying to open a PDF file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the screen after the error at the ViewPdf.jsx page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qxh8rxa6dzp9t8g3r6u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qxh8rxa6dzp9t8g3r6u.png" alt=" " width="800" height="253"&gt;&lt;/a&gt;&lt;br&gt;
It reads: You need to enable JavaScript to run this app.&lt;/p&gt;

&lt;p&gt;As this is my first attempt with Node.js any suggestions are well appreciated. Thanks !&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
