How to turn a MERN app into a desktop app?

I am very new in front-end application development. I made a MERN application in react, divided into two parts, a frontend and a backend. Now they all work fine, but I want to turn them into a desktop application that can be executed by itself, so that I don’t have to enter commands like npm start or npx nodemon in VScode. I successfully packaged the front-end with electron, but I don’t know how to handle the part of connecting to the server in the backend and how to pack it with frontend together.

Can anyone give me some advice? Thanks a lot.

Large XLSX file in Nodejs returning empty data

I have built a web crawler that goes to a page and downloads a large inventory xlsx file. I am attempting to read the file, create a id out of specific cell values in the file and then save it to a csv.

Usually I have no issue doing this, but with the particular file, it is very large. When attempting to use node-xlsx, excellJs, and XLSX npm packages all do the same thing. They just return empty for the data, even though the file definately exists.

I’ve tested the same code on smaller xlsx files and it works, but the large file just returns an empty array for the sheets variable.

           const inventoryFile = readFileSync('./tmp/inventory.xlsx');
const inventoryWorkbook = xlsx.parse(inventoryFile)
console.log({inventoryWorkbook})  //returns [];

I also tried using a stream and still when parsed it returns an empty array even though I can see the data buffers logging.

let sheet:string = '';
const stream = createReadStream(`./tmp/${timeInSecs}/nb-inventory-${fileDate}.xlsx`)
const buffers: Buffer[] = [];
stream.on('data',(data: Buffer)=>{ 
   console.log({data})
   buffers.push(data); 
});
stream.on('end',()=>{
   const buffer = Buffer.concat(buffers);
   console.log({buffer})
   const sheets = xlsx.parse(buffer, {})
   console.log({sheets}); //returns []               
})
                                    

Is there anyway to get around this limit?

Thanks.

Is there a way I can apply a function to one specific sheet?

Is there any way to apply this function to a sheet named “Production Log”?

function CopyDatatoLog() {
  var spreadsheet = SpreadsheetApp.getActive().getSheetByName('Production Log');
  spreadsheet.getRange('B8:B11').activate();
  spreadsheet.getActiveSheet().insertRowsBefore(spreadsheet.getActiveRange().getRow(), 4);
  spreadsheet.getActiveRange().offset(0, 0, 4,            spreadsheet.getActiveRange().getNumColumns()).activate();
  spreadsheet.getRange('A8:BL11').activate();
  spreadsheet.getRange('4:7').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
};

I keep getting this error “TypeError: spreadsheet.getActive sheet is not a function”. I’m not sure what I’m missing here. This function runs on a trigger and adds 4 rows above a specific row and then copy’s and pastes 4 rows of data (just the values) into the added rows. This code does work in the sheet as long as i’m active in it but as soon as I added in the getSheetByName, It stopped working. If any one has any advice or can point me in the right direction, I would greatly appreciate it!

NodeJS MVC Framework [closed]

I have been looking for some examples on how to roll your own MVC framework for NodeJS. I want to run this application offline. Every resource I come across says I have to use Express as an MVC, but express is a web framework. Are there any other frameworks available to me or am i stuck with web development? Thanks a bunch.

I built a three.js scene that I would like to stick into the View portion of MVC. I am really concerned about how messy this will become without any sort of framework or design pattern.

How make an animation between change fullscreen-video, where while change 2 videos are visible? (image)

I have 2 or more video one by one, and i want to split into 5 pieces. Next i want to “change slide” and I want to make an animation, where slices one by one goint upper and showing next video.

I’m attaching image to visualize.

example on image

Is it possible using css and js?

I’m trying set video for each slice (5 same videos for one slide) but it’s lagging…

Flexbox container not showing all the content

I have a sidebar in my app that contains collections of projects and 2 other containers, the problem is: when the number of projects is too high, scrolling is only available for a couple of projects and some of them just don’t show.

As you can see in the image, the scroll ends on the FR project but there are more projects above that are not been shown, I really do not know what the issue is, can anyone catch what I have wrong in this code, many thanks in advance

This is the componet:

`const Projects = ({ projects }) => {
    const {showExecutionsView, setShowExectutionsView} = useContext(executionsContext)
    return (
        <div className='projects-sidebar'>
            <div className="toggle" onClick={()=>setShowExectutionsView(!showExecutionsView)}>
             <BiGridAlt/>
            </div>
            <div className="projects-list">
            {
                projects.map((project, index) => (
                    <ProjectCard key={index} project={project} />
                ))
            }
            </div>
            <div className="version"><span>ALPHA</span></div>
        </div>
    )
}`

This is the CSS code:

@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@900&family=Rubik:wght@800&display=swap');
@import '../../index.scss';
.projects-sidebar {
    background: black;
    display: flex;
    flex-direction: column;
    align-items: left;
    justify-content: center;
    z-index: 10;
    box-sizing: content-box;
    overflow: auto;
    position: relative;
    display: flex;
    flex-direction: column;
    height: auto;
    .toggle{
       top: 0;
       color: green;
       display: flex;
       justify-content: center;
       align-items: center;
       width: 100%;
       margin-top: 10px;
       font-size: 30px;
       cursor: pointer;
       height: 50px;
       &:hover{
        color: greenyellow;
       }
    }

    .projects-list{
        flex-grow: 1;
        padding-top: 20px;
        display: flex;
        flex-direction: column;
        align-items: center;
        align-content: center;
        justify-content:center;
        overflow-y: scroll;
         &::-webkit-scrollbar{
            display: block;
            background-color:transparent;
            width: 6px;
        }
        &::-webkit-scrollbar-track{
            color: green;
        }
        &::-webkit-scrollbar-thumb {
            background-color:rgb(187, 187, 187);    
            border-radius: 8px;       
            border: none; 
            
          }
        .project-short-name {
            font-family: 'Roboto', sans-serif;
            padding: 4px;
            margin: 4px 4px 4px 8px;
            width: 30px;
            max-width: 80px;
            border-radius: 6px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            cursor: pointer;
        }
    }
   .version{
    margin: auto;
    height: 50px;
    display: flex;
    justify-content: center;
    align-items: center;
    span{
        font-size: 0.6em;
        font-family: 'Roboto', sans-serif;
        border-radius: 6px;
        background-color: purple;
        padding: 3px;
        width: 40px;
        height: auto;
        color: white;
        height: 12px;
        text-align: center;
    }
   }
}

I have played araund with the height and max-height properties among several other properties but I really do not catch what is the cause of this error.

How to use jsPDF in generate page numbers in footer and saving to google drive

I would like to use jsPDF to create PDF
(a) where in the page numbers in the footer should display like ‘Page 1 of 15’
(b) PDF should be saved to Google drive (its sub folders)
(c) Whole PDF creation should be invoked using Google App Script
Please let me know if this can be achieved using jsPDF

I tried to check whether there are any sample scripts to achieve the same, but could not manage.
Thanks

Javascript – Sort nested objects within an object [duplicate]

In my application, I have an object called chats with the following structure:

  let chats = {id1: {value: "Hello", updatedAt: 2024-02-21T00:24:57.157Z},  id2: {value: "Goodbye", updatedAt: 2024-02-21T00:18:00.937Z}}

I would like to sort this object by the updatedAt property, so that the id with the highest date value is at the beginning of the object, and the id with the smallest/oldest date value is at the bottom of the object. I would also like to keep the exact same structure of the object so that the ids are still keys, and the nested objects are still included. How could this be accomplished? Thanks.

R shiny update column value to check-box controls value on child rows on nested table

I would like to set check-box values to the corresponding values in column ‘YN’ when a child rows loads and after the user clicks/unclicks a checkbox I would like ‘YN’ column to update. I don’t need check-boxes on parent rows. I’ve tried to modify an example I’ve found, but it’s not working on child rows. Please suggest how to implement this correctly. Here is an example of code that works but doesn’t update the ‘YN’ column. Thank you very much. Here is the code:

data

library(DT)

dat <- data.frame(
  Sr = c(1.5, 2.3),
  Description = c("A - B", "X - Y")
)
## details of row 1
subdat1 <- data.frame(
  Chromosome = c("chr18","chr4"),
  SNP = c("rs2","rs3"),
  YN = c(TRUE, FALSE),
  stringsAsFactors = FALSE
)
subdat1$check <- shinyCheckbox("check", subdat1$YN)
## details of row 2
subdat2 <- data.frame(
  Chromosome = c("chr19","chr20"), 
  SNP = c("rs3","rs4"),
  YN = c(TRUE, FALSE),
  stringsAsFactors = FALSE
)
subdat2$check <- shinyCheckbox("check", subdat2$YN)
## merge the row details
subdats <- lapply(list(subdat1, subdat2), purrr::transpose)
## dataframe for the datatable
Dat <- cbind(" " = "&oplus;", dat, details = I(subdats))

## the callback
callback = JS(
  "$('[id^=check]').on('click', function(){",
  "  var id = this.getAttribute('id');",
  "  var i = parseInt(/check(\d+)/.exec(id)[1]);",
  "  var value = $(this).prop('checked');",
  "  var cell = table.cell(i-1, 2).data(value).draw();",
  "})",
  "table.column(1).nodes().to$().css({cursor: 'pointer'});",
  "// Format the nested table into another table",
  "var childId = function(d){",
  "  var tail = d.slice(2, d.length - 1);",
  "  return 'child_' + tail.join('_').replace(/[\s|\.|'|,|\(|\)]/g, '_');",
  "};",
  "var format = function (d) {",
  "  if (d != null) {",
  "    var id = childId(d);",
  "    var html = ", 
  "          '<table class="display compact" id="' + id + '"><thead><tr>';",
  "    for (var key in d[d.length-1][0]) {",
  "      html += '<th>' + key + '</th>';",
  "    }",
  "    html += '</tr></thead></table>'",
  "    return html;",
  "  } else {",
  "    return '';",
  "  }",
  "};",
  "var rowCallback = function(row, dat, displayNum, index){",
  "  if($(row).hasClass('odd')){",
  "    for(var j=0; j<dat.length; j++){",
  "      $('td:eq('+j+')', row).css('background-color', 'papayawhip');",
  "    }",
  "  } else {",
  "    for(var j=0; j<dat.length; j++){",
  "      $('td:eq('+j+')', row).css('background-color', 'lemonchiffon');",
  "    }",
  "  }",
  "};",
  "var headerCallback = function(thead, data, start, end, display){",
  "  $('th', thead).css({",
  "    'border-top': '3px solid indigo',", 
  "    'color': 'indigo',",
  "    'background-color': '#fadadd'",
  "  });",
  "};",
  "var format_datatable = function (d) {",
  "  var dataset = [];",
  "  var n = d.length - 1;",
  "  for (var i = 0; i < d[n].length; i++) {",
  "    var datarow = $.map(d[n][i], function (value, index) {",
  "      return [value];",
  "    });",
  "    dataset.push(datarow);",
  "  }",
  "  var id = 'table#' + childId(d);",
  "  var subtable = $(id).DataTable({",
  "                     'data': dataset,",
  "                     'autoWidth': true,",
  "                     'deferRender': true,",
  "                     'info': false,",
  "                     'lengthChange': false,",
  "                     'ordering': d[n].length > 1,",
  "                     'order': [],",
  "                     'paging': false,",
  "                     'scrollX': false,",
  "                     'scrollY': false,",
  "                     'searching': false,",
  "                     'sortClasses': false,",
  "                     'rowCallback': rowCallback,",
  "                     'headerCallback': headerCallback,",
  "                     'columnDefs': [{targets: '_all', className: 'dt-center'}]",
  "                   });",
  "};",
  "table.on('click', 'td.details-control', function () {",
  "  var td = $(this),",
  "      row = table.row(td.closest('tr'));",
  "  if (row.child.isShown()) {",
  "    row.child.hide();",
  "    td.html('&oplus;');",
  "  } else {",
  "    row.child(format(row.data())).show();",
  "    td.html('&CircleMinus;');",
  "    format_datatable(row.data());",
  "  }",
  "});")

## datatable

datatable(Dat, callback = callback, escape = FALSE,
          options = list(
            columnDefs = list(
              list(visible = FALSE, targets = ncol(Dat)),
              list(orderable = FALSE, className = 'details-control', targets = 1),
              list(className = "dt-center", targets = "_all")
            )
            #preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
            #drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')
          ),
          
          )

Svelte change bind:value in keydown event

I want to add spaces in a card ID input field automatically as the user is typing it. Here is my setup:

    <input placeholder="e.g. 5200 1234 5678 9012 3456" bind:value={inputAC}
           on:keydown={inputACKeydown}>
  let inputAC = ""

  function inputACKeydown(e: KeyboardEvent) {
    // Add spaces to the input
    if (e.key !== "Backspace" && e.key !== "Delete" && inputAC.length % 5 === 4) {
      inputAC += " "
    }
  }

However, the on:keydown event seems to be called before reactivity happens, which means that the inputAC value when the event calls are still the old value, not the new value. So spaces will only be added when the user enters the 5th character, not when the user finishes entering the 4th character.

Vue.js3 render() function not letting me render multiple components in the same parent

I’m trying to make a Google Calendar app clone using Vue.js 3

The issue I’m facing is that whenever I try to render a new Event component using Vue.js render() and h() functions inside its parent element, only the previous Event component gets updated (because I change its props).

Calendar.vue (parent)

<script setup lang="ts">
import { ref, onMounted, computed, watch, h, render, reactive } from "vue";
import Event from "@components/Event.vue";

export interface IEvent {
  id: number;
  title: string;
  description?: string;
  startDate: Date | null;
  endDate: Date | null;
  color?: string;
}

const CELL_HEIGHT = 40;

const eventElementStyles = ref({
  position: "absolute",
  width: "",
  height: CELL_HEIGHT + "px",
  backgroundColor: "rgb(141, 224, 141)",
  zIndex: "100",
  top: "",
  left: "",
});

const columnElementRefs = ref<HTMLDivElement[] | null>(null);
const isClicked = ref<boolean>(false);
const indexOfClickedColumn = ref<number>(-1);

const newEvent = ref<IEvent>({
  id: 1,
  title: "New Event Title",
  description: "New Event Description",
  startDate: null,
  endDate: null,
  color: "rgb(141, 224, 141)",
});

function resetStyles() {
  eventElementStyles.value = {
    position: "absolute",
    width: "",
    height: CELL_HEIGHT + "px",
    backgroundColor: "rgb(141, 224, 141)",
    zIndex: "100",
    top: "",
    left: "",
  };
}

function resetNewEvent() {
  newEvent.value = {
    id: 1,
    title: "New Event Title",
    description: "New Event Description",
    startDate: null,
    endDate: null,
    color: "rgb(141, 224, 141)",
  };
}

function renderComponent(component, parent, props) {
  console.log(props);
  const vueComponent = h(component, props);
  render(vueComponent, parent);
}

function handleMousedown(
  startDate: Date,
  index: number,
  rowIndex: number
): void {
  indexOfClickedColumn.value = index;
  isClicked.value = true;
  resetNewEvent();
  resetStyles();
  newEvent.value.startDate = startDate;
  newEvent.value.endDate = new Date(startDate.getTime() + 60 * 60_000);

  eventElementStyles.value.width = `180.58px`;

  eventElementStyles.value.top = `${rowIndex * CELL_HEIGHT}px`;

  renderComponent(Event, columnElementRefs.value![index], {
    styles: eventElementStyles.value,
    event: newEvent.value,
  });
}

function isPartiallyResizable(colIndex: number): boolean {
  return isClicked.value && colIndex === indexOfClickedColumn.value;
}

function canExtendEventTime(colIndex: number, cellDate: Date): boolean {
  return (
    isPartiallyResizable(colIndex) &&
    cellDate.getTime() >= newEvent.value.endDate!.getTime()
  );
}

function canShrinkEventTime(colIndex: number, cellDate: Date): boolean {
  return (
    isPartiallyResizable(colIndex) &&
    cellDate.getTime() < newEvent.value.endDate!.getTime()
  );
}

function getIncreasedEventHeight(
  oldHeight: number,
  increaseBy: number
): number {
  return oldHeight + increaseBy;
}

function getDecreasedEventHeight(
  oldHeight: number,
  decreaseBy: number
): number {
  return oldHeight - decreaseBy;
}

function handleMouseover(colIndex: number, cellDate: Date): void {
  // increase event element height
  if (canExtendEventTime(colIndex, cellDate)) {
    newEvent.value.endDate = new Date(
      newEvent.value.endDate!.getTime() + 60 * 60_000
    );

    eventElementStyles.value.height =
      getIncreasedEventHeight(
        Number(eventElementStyles.value.height.split("px")[0]),
        CELL_HEIGHT
      ) + "px";
    return;
  }

  // decrease event time
  if (canShrinkEventTime(colIndex, cellDate)) {
    newEvent.value.endDate = new Date(
      newEvent.value.endDate!.getTime() - 60 * 60_000
    );

    eventElementStyles.value.height =
      getDecreasedEventHeight(
        Number(eventElementStyles.value.height.split("px")[0]),
        CELL_HEIGHT
      ) + "px";

    return;
  }
}

function handleMouseup(endDate: Date): void {
  isClicked.value = false;
}
</script>

Event.vue (Child)

<template>
  <div :style="styles" class="eventContainer">
    <span class="title">(No title) </span>
    <span class="times">{{ time }}</span>
  </div>
</template>

<script setup lang="ts">
import { IEvent } from "@/pages/Calendar.vue";
import { computed } from "vue";

const { styles, event } = defineProps<{
  styles: any;
  event: IEvent;
}>();

const time = computed(() => {
  return `${extractTimeFromDate(event.startDate!)} - ${extractTimeFromDate(
    event.endDate!
  )}`;
});

function extractTimeFromDate(date: Date): string {
  return `${date.getHours().toString().padStart(2, "0")}:${date
    .getMinutes()
    .toString()
    .padStart(2, "0")}`;
}
</script>

I think the issue is that I’m always passing the same props (eventElementStyles and event). But why it only works when I render the component in different parent elements and when I try to render multiple Event components in the same parent, only the old one gets updated.

enter image description here

How to temporarily remove eventListener in JavaScript?

I want to render an error whenever someone chooses a date that is off day (like Saturday or Sunday, it may be any one of the day from an array of closing days).

I have HTML:

<div>
  <input type="date" id="date-input">
</div>

<br>

<div id="error-container">
</div>

CSS:

.d-error{
  background: orangered;
  color: white;
  padding: 4px 8px;
}

Here is the JavaScript:

'use strict';

const dateInput = document.getElementById('date-input');
const errorContainer = document.getElementById('error-container');
const closingDays = [0, 6];
const weekDays = ['Sunday', 'Monday', 'Tuesday', 'Thursday','Friday', 'Saturday'];

const displayError = function ({ parentEl, message, position = 'prepend', durationSec = 0 }) {
  const errorElement = document.createElement('p');
  errorElement.classList.add('d-error');
  errorElement.textContent = message;
  parentEl[position](errorElement);

  if (durationSec) {
    setTimeout(() => {
      errorElement.remove();
    }, durationSec * 1000);
  }
};

const handleDateChange = function (event) {
  const selectedDay = new Date(event.currentTarget.value).getDay();

  if (closingDays.includes(selectedDay)) {
    displayError({
      parentEl: errorContainer,
      message: `We are closed on ${weekDays[selectedDay]}. Please select another day.`,
      durationSec: 5
    });

    event.currentTarget.value = '';
  }
};

dateInput.addEventListener('change', handleDateChange);

This works, but the error is rendered twice. Once due to user change and once due to programmatically changing the value of the input event.currentTarget.value = '';. So, how to temporarily remove the change event listener and reattach to it? Or any other way to solve this issue?

I tried:

const handleDateChange = function(event) {
  ...

  event.currentTarget.removeEventListener('change', handleDateChange);
  event.currentTarget.value = '';  
  event.currentTarget.addEventListener('change', handleDateChange);

  ...
}

But this did not fix the issue.

'use strict';

const dateInput = document.getElementById('date-input');
const errorContainer = document.getElementById('error-container');
const closingDays = [0, 6];
const weekDays = ['Sunday', 'Monday', 'Tuesday', 'Thursday', 'Friday', 'Saturday'];

const displayError = function({
  parentEl,
  message,
  position = 'prepend',
  durationSec = 0
}) {
  const errorElement = document.createElement('p');
  errorElement.classList.add('d-error');
  errorElement.textContent = message;
  parentEl[position](errorElement);

  if (durationSec) {
    setTimeout(() => {
      errorElement.remove();
    }, durationSec * 1000);
  }
};

const handleDateChange = function(event) {
  const selectedDay = new Date(event.currentTarget.value).getDay();

  if (closingDays.includes(selectedDay)) {
    displayError({
      parentEl: errorContainer,
      message: `We are closed on ${weekDays[selectedDay]}. Please select another day.`,
      durationSec: 5
    });

    event.currentTarget.value = '';
  }
};

dateInput.addEventListener('change', handleDateChange);
.d-error {
  background: orangered;
  color: white;
  padding: 4px 8px;
}
<div>
  <input type="date" id="date-input">
</div>

<br>

<div id="error-container">
</div>