How to implement dragula drag and drop with dynamic add row and column

I created a HTML Page which we can dynamically add rows and columns using JS. I would like to implement dragula jQuery for dragging both row and column draggable, like other column can draggable to different rows or blank rows. Looking for solution

HTML

<div class="wrapper">
      <div class="main-content">

          <div class="header">
            <button class="add-row" onclick="addRow()">Add Row +</button>
            <button class="add-column" onclick="addCol()">Add Column +</button>
          </div>
                 
          <div class="container-box" id="contentBox">
            
          </div>
        
      </div>
    </div>

here the id contentBox is the container div which appending rows and columns

JS

var i=0;
var j=0;

let newColNode = null;

function addRow() {    
    const row = document.createElement('div');
    row.className = 'block';
    row.id = "b" + ++i;
    document.getElementById('contentBox').append(row);

    row.addEventListener('click', function (event) {
        console.log(newColNode)
        console.log(row)
        if(newColNode != null ) 
        row.appendChild(newColNode);        
        newColNode = null
    });
}
  
// Column Addition

function addCol() {
    const col = document.createElement('div');
    col.className = 'block-inner';
    col.id = "c" + ++j;
    col.textContent = `Column ${j}`;
    newColNode = col;
}

in this code, added both add row and add column button function. There is requirement reference url and jsfiddle url which is adding below

Thanks in advance.

Dragula documentation: https://github.com/bevacqua/dragula

requirement reference URL: https://codepen.io/gabouh/pen/ZXrMzW

jsfiddle: https://jsfiddle.net/unni2003pj/2b68u0ka/5/

Shopify Checkout Ui Extension Unable To Get address From ShippingAddress (API) Method Using Javascript

Need a function built that block checkout if it’s an International Order with a PO Box.

For international orders shopify populates DHL Express as a shipping name.

IF DHL Express and Address = PO Box in this condition we need to Block Progress of checkout.

How to get the ShippingAddress using api in javascript code, First i need to get the address after that am going to validate if address have PO Box .

Am not using react, am using the javascript. It seems there is no proper example for using the Ui Extension Api with javascript.

Here is my code, Am new to using the app with extension, Am not sure my code is correct.


import {
extension,
} from "@shopify/ui-extensions/checkout";
// Set the entry point for the extension
export default extension("purchase.checkout.delivery-address.render-before", renderApp);

function renderApp(root, api, { extension, buyerJourney }) {

const address = api.shippingAddress();

// Use the `buyerJourney` intercept to conditionally block checkout progress
buyerJourney.intercept(({ canBlockProgress }) => {

if (canBlockProgress && address?.address1 && address.address1.length > 30 ) {
console.log(address);
console.log(address.city);
return {
behavior: "block",
reason: `Invalid shipping country`,
errors: [
{
// Show a validation error on the page
message: "Please keep your input under 30 characters.",
target: '$.cart.deliveryGroups[0].deliveryAddress.address1',
},
],
};
}
return {
behavior: "allow",      
};
});
}

Am not getting any answer, It may be error.

I want to display from date and to date on the frontend container from the json data

I have 4-5 containers in my html. Refer the sample code below.

<div class="mainContainer"> <div class="subContainer"> <%--<button id="testdata" CssClass="btn btn-primary" runat="server">Refresh</button>--%> <div class="divContainer"> <div class="appContainer" > Application 1 </div> <div class="hiddenContainer" id="app1" data-jsonData="0" hidden> <div class="lblContainer">Application 1</div> <div class="dateContainer"> <div class="fromDateContainer"> <label for="fromDate">From date</label> <span class="fromDate">From Date Val</span> </div> <div class="toDateContainer"> <label for="toDate">To date</label> <span class="toDate">To date val</span> </div> </div> <div class="timeContainer"> <label for="timeLeft">Time remaining</label> <span>Time remaining value</span> </div> </div> <div class="appContainer" data-jsonData="1"> Application 2 </div> <div class="hiddenContainer" id="app2" data-jsonData="1" hidden> <div class="lblContainer">Application 2</div> <div class="dateContainer"> <div class="fromDateContainer"> <label for="fromDate">From date</label> <span class="fromDate">From Date Val</span> </div> <div class="toDateContainer"> <label for="toDate">To date</label> <span class="toDate">To date val</span> </div> </div> <div class="timeContainer"> <label for="timeLeft">Time remaining</label> <span>Time remaining value</span> </div> </div> </div> </div>

I using the below javascript code. First I use the json data which is an array of objects.

Json data sample:

0: {app_Name: 'Application 1', to_Date: '2023-11-07T16:48:00', from_Date: '2023-11-09T14:47:00'} 1: {app_Name: 'Application 2', to_Date: '2023-11-23T15:57:00', from_Date: '2023-11-24T15:57:00'}

In the below javascript code I am trying to add ids dynamically to the containers in html.

<script type="text/javascript"> let jsonData; let fromDate = []; let toDate = []; function loadData(data) { jsonData = data; console.log(jsonData) } document.addEventListener("DOMContentLoaded", function () { let appCon = document.getElementsByClassName("appContainer"); let hiddenCon = document.getElementsByClassName("hiddenContainer"); // Assuming you want the first element with the class 'hiddenContainer' for (let i = 0; i < appCon.length; i++) { fromDate.push({ id: `fromDateId${i}` }); toDate.push({ id: `toDateId${i}` }); appCon[i].addEventListener("mouseover", function () { let appDetails = this.dataset.jsonData; hiddenCon[i].removeAttribute("hidden"); /*console.log(appDetails)*/ displayData(i) }); appCon[i].addEventListener("mouseout", function () { hiddenCon[i].setAttribute("hidden", "true"); // hideDetails(i); }); } }) function displayData(index) { if (fromDate.length > index && toDate.length > index) { let appData = jsonData[index]; if (appData) { console.log(appData); let fromDateId = fromDate[index].id; let toDateId = toDate[index].id; console.log("Generated Ids:" + fromDateId, toDateId) let fromDateElem = document.querySelector(`#${fromDateId}`); let toDateElem = document.querySelector(`#${toDateId}`); console.log(fromDateElem, toDateElem); if (fromDateElem && toDateElem) { let fromDateElemValue = fromDateElem.querySelector('.fromDate'); let toDateElemValue = toDateElem.querySelector('.toDate'); console.log(fromDateElemValue, toDateElemValue); if (fromDateElemValue && toDateElemValue) { fromDateElemValue.textContent = appData.from_Date; toDateElemValue.textContent = appData.to_Date; } else { console.log("One or more value elements not found."); } } else { console.log("One or more elements not found."); } } else { console.log("App data is null."); } } } </script>

I get stuck here because fromDateElemValue and toDateElemValue returns null in the console.

Nginx sending .js as text/html

first time working with nginx.

I have an Angular application I’m trying to serve inside a Docker container, but when I navigate to where my page should be hosted, I get these errors:

Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
polyfills.2d196681208a24b4.js:1 Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
main.091492de223f47fc.js:1 Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.

Here is my nginx.conf file:

server {
  include /etc/nginx/mime.types;
  listen 4200;
  sendfile on;
  default_type text/javascript;

  gzip on;
  gzip_http_version 1.1;
  gzip_disable      "MSIE [1-6].";
  gzip_min_length   256;
  gzip_vary         on;
  gzip_proxied      expired no-cache no-store private auth;
  gzip_types        text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
  gzip_comp_level   9;

  root /usr/share/nginx/html;

  location / {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        alias /usr/share/nginx/html/demo;
        try_files $uri $uri/ /index.html =404;
  }
}

I have tried a few different things, but no luck so far.

I can confirm that in chrome dev tools, the .js files have the Content-Type header text/html. My styles.*.css also has Content-Type set to text/html. The .js files are getting 200 OK, so it’s not being converted to text/html because it failed to retrieve the files or anything.

Matching permission ids between Node.js server and MySQL database

I have a database that is structured as follows (I’m not set on the structure, it’s just what I’ve come up with. it’s also not inclusive of all columns):

Table Columns
permission_project (id, name)
user (id)
project (id)
project_user_permission (project_id, permission_id, user_id)

(ID columns with prefixes are FKs)
In my application code, I will want to reference the permission values to authorize user/api actions, and as such I want to ensure the JS values are in sync with the database values. However, I’m unsure of the best methodology for this.

I’ve come up with three potential solutions (with varying feelings about them):

  1. Define and populate the permissions table within the application code, ensuring the application’s values are authoritative (I don’t know if this is practical. Also concerns me regarding potentially invalidating data and mixing up permissions).
  2. Populate a JS object with the contents of the permissions table, and refer to this object when querying permissions (I don’t like that this requires updating the permission names everywhere they’re used in the application if the database content changes)
  3. Map database permission names to application permission names, then populate a JS object with the application permission names. This at least narrows the maintenance of solution 2 down to a single point, but I’m not jumping for joy at having to change permission names in two separate locations.

Are any of these solutions practical? Is there a better solution that I’m not aware of?
As mentioned earlier, I’m not married to the structure. I’m happy to modify the database if it can be improved.

How to prevent overlapping between dots on scatter plot via D3 and ensure that dots remain within chart?

Problem Description:
I am building a scatter plot using D3.js within a React component. My objective is to display a set of data points (nodes) without them overlapping each other or overflowing outside the chart boundaries. I am using D3’s force simulation to achieve this. However, I am encountering two issues:

  1. The nodes are overlapping each other.
  2. Some nodes are overflowing outside the chart boundaries.

I am basing my work off this observable: https://observablehq.com/@keckelt/collision-free-scatter-plot.

Attempted Solution:
I used D3’s forceSimulation with forceX, forceY, and forceCollide to position the nodes and prevent overlap. However, the nodes still overlap and some even overflow the chart area.

Setting Up Scales:
Here’s the useEffect hook where I set up the scales:

useEffect(() => {
  const [widthAdjusted, heightAdjusted] = getAdjustedWidth(width, height);

  const scaleX = scaleLinear()
    .domain([Math.min(...data.map(d => d.x)), Math.max(...data.map(d => d.x))])
    .nice()
    .range([0, widthAdjusted]);

  const scaleY = scaleLinear()
    .domain([Math.min(...data.map(d => d.y)), Math.max(...data.map(d => d.y))])
    .nice()
    .range([heightAdjusted, 0]);

  setScales({ scaleX, scaleY });
}, [data, width, height]);

Force Simulation:
The D3 force simulation setup in another useEffect hook:

useEffect(() => {
  if (!scales) return;

  const transformedData = data.map(d => ({
    ...d,
    x: scales.scaleX(d.x),
    y: scales.scaleY(d.y),
  }));

  const forceSimulation = d3.forceSimulation(transformedData)
    .force('x', d3.forceX(d => d.x).strength(0.1))
    .force('y', d3.forceY(d => d.y).strength(0.1))
    .force('collide', d3.forceCollide().radius(20).strength(1))
    .stop();

  for (let i = 0; i < 4; i++) {
    forceSimulation.tick();
  }

  const updatedData = forceSimulation.nodes().map(d => ({
    ...d,
    x: scales.scaleX.invert(d.x),
    y: scales.scaleY.invert(d.y),
  }));

  setNodes(updatedData);
}, [data, scales]);

How can I adjust my force simulation and scaling to ensure nodes don’t overlap and stay within the chart boundaries?

Definition of `integer index` in JavaScript (ECMAScript 2015)

I’m trying to understand how a JavaSript object sorts its properties. As far as I understood, from ECMA262, the first properties are always an integer index properties. For example, if print these objects using Node.js, Deno, or Bun:

console.log({ a: 0, [-1]: 1 })
console.log({ a: 0, [0]: 1 })
console.log({ a: 0, [2 ** 32 - 2]: 1 })
console.log({ a: 0, [2 ** 32 - 1]: 1 })
console.log({ a: 0, [2 ** 32]: 1 })

we will have

{ a: 0, '-1': 1 }
{ '0': 1, a: 0 }
{ '4294967294': 1, a: 0 }
{ a: 0, '4294967295': 1 }
{ a: 0, '4294967296': 1 }

It looks like an integer index is defined in the range [0, 2^32-2]. It matches the definition of an array index:

An array index is an integer index whose numeric value i is in the range +0 ≤ i < 2^32 – 1.

However, it’s different from the definition of an integer index:

An integer index is a String-valued property key that is a canonical numeric String (see 7.1.16) and whose numeric value is either +0 or a positive integer ≤ 2^53−1.

So, my question is, should JavaScript engines use [0, 2^53-1] or ECMAScript 2015 should use [0, 2^32-2] for the definition of an integer index? Did I miss something?

Geoserver: LWGEOM_dwithin: Operation on mixed SRID geometries (MultiPolygon, 4326) != (Point, 0)

I got this response executing a cql filter over a parametric SQL View in Geoserver.

<ows:ExceptionReport version="1.0.0" xsi:schemaLocation="http://www.opengis.net/ows http://localhost:8080/geoserver/schemas/ows/1.0.0/owsExceptionReport.xsd">
 <ows:Exception exceptionCode="NoApplicableCode">
  <ows:ExceptionText>
    java.lang.RuntimeException: java.io.IOException java.io.IOExceptionERROR: LWGEOM_dwithin: Operation on mixed SRID geometries (MultiPolygon, 4326) != (Point, 0)
  </ows:ExceptionText>
 </ows:Exception>
</ows:ExceptionReport>

The paramas of the request are correct:

 var wfsParams = {
    service: "WFS",
    version: "1.1.0",
    request: "GetFeature",
    typeName: `${workspace}:${layer}`,
    outputFormat: "application/json",
    srs: "EPSG:4326",
    cql_filter: `DWITHIN(geom, POINT(${latitud} ${longitud}), ${radio}, meters)`
  };

 axios.get(wfsUrl, { params: wfsParams }).then((res)=>{...})

SVG drag and drop – declarative, functional programming

Can someone review this code and offer suggestions? I dislike the imperative block of code and want suggestions how it can be in a more declarative style. The SVG element contains draggable images that are created in another component.

export class TestComponent implements AfterViewInit {

  @ViewChild("svg") svg: ElementRef<SVGSVGElement>;
  selectedElement: HTMLElement;
  offsetX: number;
  offsetY: number;

  constructor() { }

  ngAfterViewInit(): void {

    const moveMode$ = merge(
      fromEvent(this.svg.nativeElement, "pointerdown").pipe(
        map((event: Event) => {
          if ((event.target as HTMLElement).classList.contains("draggable")) {
            this.selectedElement = event.target as HTMLElement;
            let targetPositionX = (this.selectedElement.getAttributeNS(null, 'x') as number | null)!;
            let targetPositionY = (this.selectedElement.getAttributeNS(null, 'y') as number | null)!;
            let mousePositionX = (event as MouseEvent).clientX;
            let mousePositionY = (event as MouseEvent).clientY;
            let ctm = this.svg.nativeElement.getScreenCTM()!;
            mousePositionX -= ctm.e;
            mousePositionY -= ctm.f;
            this.offsetX = mousePositionX - targetPositionX;
            this.offsetY = mousePositionY - targetPositionY;
          }
        })
      ),
      fromEvent(this.svg.nativeElement, "pointermove").pipe(
        map((event: Event) => {
          if (this.selectedElement) {
            let mousePositionX = event.clientX;
            let mousePositionY = event.clientY;
            let ctm = this.svg.getScreenCTM();
            mousePositionX -= ctm!.e;
            mousePositionY -= ctm!.f;
            mousePositionX -= this.offsetX;
            mousePositionY -= this.offsetY;
            this.selectedElement.setAttributeNS(null, 'x', mousePositionX);
            this.selectedElement.setAttributeNS(null, 'y', mousePositionY);
          }
          event.preventDefault();
        }
      ),
      fromEvent(this.svg.nativeElement, "pointerup").pipe()
    );

    const linkMode$ = merge(
      fromEvent(this.svg.nativeElement, "pointerdown").pipe(),
      fromEvent(this.svg.nativeElement, "pointermove").pipe(),
      fromEvent(this.svg.nativeElement, "pointerup").pipe()
    );

    moveMode$.subscribe();
  }
}

How to implement a jump link for a JavaScript-driven single-page app?

A jump link is a path that ends with a hash, e.g. /mypage#heading. After navigating to the path portion (e.g. /mypage), the browser will:

  1. Look for an element with an ID that matches the hash (e.g. #heading would be matched by <h1 id="heading">) and if one is found will scroll (or “jump”) that element into view
  2. Make the matching element have the CSS :target pseudoselector state

The first item is easy to implement with $element.scrollIntoView.

It’s also easy to change the appearance of the target element by using JS to toggle CSS classes and HTML attributes.

But I can’t figure out how to use JavaScript to make an element have the :target pseudoselector state. For accessibility reasons (and for my own curiosity) I want to reproduce the browser’s native jump link behavior, not something that just looks like it.

Manually dispatching HashChangeEvent('hashchange') doesn’t appear to have the desired effect.

Note when you run the demo code below: if you click a jump link for an element on the current “page” then that element is correctly highlighted, but if you click a jump link for an element on a different page then it is not highlighted, indicating :target is not set.

How can JavaScript make an element have the CSS :target pseudoselector state?

for (const $anchor of document.querySelectorAll(`a`)) {
  $anchor.innerHTML = $anchor.getAttribute(`href`);
  $anchor.addEventListener(`click`, onClick);
}

render(`/js`); // This is the path StackOverflow uses to run demo code snippets

function onClick(event) {
  const [path, hash] = event.target.getAttribute(`href`).split(`#`);

  if (path === location.pathname) {
    return;
  }
  
  event.preventDefault();
  window.history.pushState({}, ``, path);
  
  render(path);

  if (hash) {
    const $target = document.getElementById(hash);
    if ($target) {
      $target.scrollIntoView();
    }
    window.dispatchEvent(new HashChangeEvent(`hashchange`));
  }
}

function render(pageName) {
  const page = document.getElementById(pageName).innerHTML;
  document.getElementById(`output`).innerHTML = page;
}
#output {
  height: 200px;
  outline: 1px solid #00000060;
  width: 300px;
}

*:target {
  background: gold;
}
<template id="/js">
  <h1 id="target1">Target 1</h1>
  <h1 id="target2">Target 2</h1>
</template>

<template id="/other">
  <h1 id="target3">Target 3</h1>
  <h1 id="target4">Target 4</h1>
</template>


<ul>
  <li><a href="/js#target1" target="_self"></a></li>
  <li><a href="/js#target2" target="_self"></a></li>
  <li><a href="/other#target3" target="_self"></a></li>
  <li><a href="/other#target4" target="_self"></a></li>
</ul>

<p>Current "page":</p>

<div id="output"></div>

Having trouble getting bubbles to cluster together in center of doughnut chart

visual_look

Inspiration_of_what_I_want_it_to_look_like

Visual Issue:

I have been trying to create a doughnut chart with clustered bubbles. The goal is to have all the bubbles grouped closely together in the center of the doughnut chart. However, the current implementation does not produce the expected result.

What I’ve Tried:

I have attempted to cluster the bubbles by calculating their positions relative to the center of the chart. I’ve used polar coordinates to determine their locations, but the bubbles still do not cluster as desired.

Desired Outcome:

I want all the bubbles to be tightly clustered together at the center of the doughnut chart, creating a visually appealing and coherent representation of the data.

Request for Assistance:

I’m seeking guidance on how to modify my code to achieve the desired clustering effect. Are there any adjustments or approaches that I should consider to make the bubbles cluster together effectively in the center of the doughnut chart?

Thank you for your help!





class BubbleChart {
    constructor(canvasId, data) {
        this.canvasId = canvasId;
        this.data = data;
        this.initVis();
    }

    initVis() {
        let vis = this; // Define 'vis' as a reference to the class instance

        // Initialize chart dimensions and other settings using 'vis'
        vis.margin = { top: 100, right: 50, bottom: 50, left: 110 };
        vis.width = 400 - vis.margin.left - vis.margin.right;  // Width of the bubble chart canvas
        vis.height = 400 - vis.margin.top - vis.margin.bottom; // Height of the bubble chart canvas

        vis.createChart();
    }

    createChart() {
        let vis = this; // Reference to the class instance

        const canvas = document.getElementById(vis.canvasId);
        const ctx = canvas.getContext('2d');

        // Define the number of bubbles
        const numBubbles = vis.data.length;
        const clusterRadius = Math.min(vis.width, vis.height) * 0.3; // Radius of the cluster

        // Calculate the positions of bubbles closely together in the center
        const clusterX = vis.width / 2; // Cluster center X
        const clusterY = vis.height / 2; // Cluster center Y
        const angleIncrement = (2 * Math.PI) / numBubbles; // Angle increment for placing bubbles

        const bubbleData = {
            datasets: [{
                label: vis.data.map(d => d.Topic),
                backgroundColor: vis.data.map((_, i) => vis.getColor(i)),
                data: vis.data.map((item, i) => {
                    // Calculate positions closely together in the center
                    const bubbleAngle = i * angleIncrement; // Angle for the current bubble within the cluster
                    const bubbleX = clusterX + clusterRadius * Math.cos(bubbleAngle); // Adjusted X within cluster
                    const bubbleY = clusterY + clusterRadius * Math.sin(bubbleAngle); // Adjusted Y within cluster
                    const r = 10; // Use a fixed radius for all bubbles within the cluster
                    return {
                        x: bubbleX,
                        y: bubbleY,
                        r: r
                    };
                })
            }]
        };

        new Chart(ctx, {
            type: 'bubble',
            data: bubbleData,
            options: {
                plugins: {
                    legend: {
                        display: false // This will hide the legend
                    }
                },
                scales: {
                    x: { display: false },
                    y: { display: false }
                },
                tooltips: { // Ensure tooltips are enabled for hover information
                    enabled: true
                },
                maintainAspectRatio: false
            }
        });
    }

    getColor(index) {
        const colors = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40'];
        return colors[index % colors.length];
    }
}


[[enter image description here](https://i.stack.imgur.com/oVWjW.jpg)](https://i.stack.imgur.com/HYTw7.jpg)

jwt token undefined when open website on mobile browser

On the computer, everything works fine, but when I access the website on a cellphone, req.token is undefined. I used console.log to check the token when it is generated – in this case, during the login process. The log confirms that the token is generated successfully at login. However, certain parts of the website check if the token is valid. In these instances, I encounter issues: I receive a denial, and the token is undefined. Can someone help?”

enter image description hereenter image description here

I expect the token not to be undefined when I use the mobile browser.

Enquiry about frontend and backend web dev

I am a beginner frontend developer who is very much passionate about AI/ML and want to delve into AI to learn it full time, but I am confused as to whether just frontend can get me a job or that I should do backend and then move into AI after backend.

Any advisory help for me will be appreciated.

I actually have done html, css, js, react, Python, and still in the learning phase.

How to set envs into process.env with nginx and vuejs app

I’m trying to add envs to the process.env for my .JS files in NGINX, it’s the first time I’m using it.

However, I’ve tried everything I found on the internet and nothing works.

My nginx.config

# env VUE_APP_API_URL3;
location / {
    try_files $uri /index.html;
    fastcgi_param VUE_APP_API_URL 'teste';
    # set VUE_APP_API_URL1 'teste';
    sub_filter 'VUE_APP_API_URL2' 'teste';
    # set_by_lua VUE_APP_API_URL3 'teste'
}

What is commented is what I tried and it didn’t work (it broke the build).

My auth.js

console.log(process.env)

Does someone know what I need to do ?

I need to do this because I need to get the ENV VALUE from the build tool (eg. docker)

One specific how-to-do

Updating table from js file Electron

Hello Im trying to update a table with data that is read from a textile. The textfile is correctly read and inserted into the constructor. The Table however in the HTMl does not update. Why is this and how can I fix it. Not the html file that contains the table is not the root view that is rendered when I run the electron app. There is a home page and from the home page I navigate to this recipe page. Im not sure if this is the cause But that’s why I added a timeout function to give me time to navigate to the correct view before running the func.

const { app, BrowserWindow, ipcMain } = require('electron');
const fs = require('fs');

// Mark ALL Constructors
class Recipe {
  constructor() {
    this.instructions = [];
    this.image = 'path';
    this.ingredients = [];
    this.description = '';
    this.nutrition_facts = [];
    this.cuisine = '';
    this.favorite = false;
    this.restrictions = [];
    this.difficulty = 0;
    this.review = '';
  }
}

var recipeArray = []; // store all recipes

function read_file(filePath) {
  fs.readFile(filePath, 'utf8', (err, data) => {
    if (err) {
      console.error(err);
      return;
    }

    const lines = data.split('n');
    const recipe = new Recipe();
    // I trim all of them to get rid of whitespaces around
    recipe.description = lines[0].trim();
    recipe.ingredients = lines[1].split(',').map(item => item.trim());
    recipe.image = lines[2].trim();
    recipe.nutrition_facts = lines[3].trim().split(',').map(item => item.trim());
    recipe.cuisine = lines[4].trim();
    recipe.favorite = lines[5].trim() === 'true'; // check to make sure type right and equal to true if not its auto gonna be false
    recipe.restrictions = lines[6].split(',').map(item => item.trim());
    recipe.difficulty = parseInt(lines[7].trim(), 10);
    recipe.review = lines[8].trim(); // should this be int like 8/10 or string?

    // instructions can be any length starting from the 9th line
    for (let i = 9; i < lines.length; i++) {
      recipe.instructions.push(lines[i].trim());
    }
    recipeArray.push(recipe);

    // Send the parsed recipe to the renderer process
    mainWindow.webContents.send('recipeData', recipe);
  });
}

function populateRecipies(fileName) {
  const filePath = __dirname + '/' + fileName;
  read_file(filePath);
}

let mainWindow;

const createWindow = () => {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
  });

  mainWindow.loadFile('index.html');

  mainWindow.webContents.once('dom-ready', () => {
    // Access the document object after the DOM is ready
    setTimeout(() => {
      populateRecipies('testRecipe.txt');
    }, 10000);
  });
};

app.whenReady().then(() => {
  createWindow();
});

// Quit the app when all windows are closed (except on macOS)
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

// Create a new window when the app is activated (on macOS)
app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow();
  }
});

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>ALL Recipes</title>
  </head>
  <body>
    <header>
        ALL Recipes
    </header>
    <main>
      <div>
        <table id="table">           
          <thead>
            <tr>
              <th>NAME:</th>
              <th>Ingrediants:</th>
              <th>ImageURL:</th>
              <th>facts:</th>
              <th>Cuisine:</th>
              <th>Is favorite:</th>
              <th>restrictions</th>
              <th>difficulty</th>
              <th>review</th>
              <th>instructions:</th>
            </tr>
          </thead>
          <tbody>
          </tbody>
        </table>
      </div>
    </main>
    <footer>
      &copy; SOFTWARE 1 GROUP
    </footer>
    <script>
        const tableBody = document.querySelector('#table tbody');
      
        // Listen for the recipe data from the main process
        ipcRenderer.on('recipeData', (event, recipe) => {
          // Update the table with the recipe data
          console.log('Recipe data received:', recipe);
          updateTable(recipe);
        });
      
        // Function to update the HTML table with recipe data
        function updateTable(recipe) {
          const row = tableBody.insertRow();
          row.innerHTML = `
            <td>${recipe.description}</td>
            <td>${recipe.ingredients.join(', ')}</td>
            <td>${recipe.image}</td>
            <td>${recipe.nutrition_facts.join(', ')}</td>
            <td>${recipe.cuisine}</td>
            <td>${recipe.favorite}</td>
            <td>${recipe.restrictions.join(', ')}</td>
            <td>${recipe.difficulty}</td>
            <td>${recipe.review}</td>
            <td>${recipe.instructions.join('<br>')}</td>
          `;
        }
      </script>
  </body>
</html>