How add data from API to favourite and save in localStorage

I would like to save the books fetched from the API to favourites and keep a list of favourite books in localStorage so that when the page is refreshed, the favourites list does not disappear.

The books are fetched from the API in the BooksView.js component. The API is constructed in such a way that only 10 books can be fetch and to fetch and display more books I have to send a request for another 10 from the next page in the API. I use the ChangePageButton to send a new request and download more books

In the BookView.js component the list of books fetched from API is saved to a new array of objects and for each book a new key is added with information if the book is in favorites or not. I map the newly created array and if the book has the favourite: true key I display a full heart icon ( <FavouriteBook>) and if it doesn’t have the favourite key I display an empty heart icon.

My problem is that I fetch a list of 10 books from the API and when I fetch a list of more books it overwrites the favorites list with the new list of books.

I don’t know how to solve this problem to save list of favorite books in separate variable which will be saved in localStorage and when opening page list of favorite books will be downloaded from localStorage and selected books will be marked as favorite.

BookView.js

import { styled as materialUIStyled } from "@mui/material/styles";
import Paper from "@mui/material/Paper";
import Button from "@mui/material/Button";
import Link from "@mui/material/Link";
import styled from "styled-components";

import { Grow } from "@mui/material";
import BookCover from "../images/default_book_cover.jpg";
import FavouriteBook from "../favourite-book";
import { useEffect, useState } from "react";

const Img = materialUIStyled("img")({
  margin: "0px",
  display: "block",
  maxWidth: "150px",
  maxHeight: "200px",
});
const MainStyles = styled.div`
  display: flex;
`;
const BooksContainer = styled(MainStyles)`
  //   height: 100vh;
  gap: 20px;
  flex-wrap: wrap;
  justify-content: center;
  margin: 0 50px;
`;

const BookContainer = styled(MainStyles)`
  gap: 5px;
  padding: 15px;
  flex-wrap: wrap;
  justify-content: center;
`;
const BookInfoContainer = styled(MainStyles)`
  gap: 30px;
  width: 100%;
  margin: 10px;
`;

const BookInfoParagraph = styled.span`
  font-size: 16px;
`;
const BookTitleName = styled.h2`
  margin: 2px;
  font-size: 20px;
  font-weight: bold;
`;
const ErrorContainer = styled(BooksContainer)`
  font-size: 50px;
  align-items: center;
  height: 100vh;
  text-align: center;
`;
const ButtonsContainer = styled(MainStyles)`
  gap: 20px;
`;

const BookView = ({ data, setData, error, errorMessage }) => {
  const [favorites, setFavorites] = useState([]);

  useEffect(() => {
    setFavorites(data);
  }, [data]);

  useEffect(() => {
    console.log(favorites);
    console.log(data);
  }, [favorites]);

  if (error) {
    return (
      <ErrorContainer>
        <p>
          Error
          <br></br>
          {errorMessage}
        </p>
      </ErrorContainer>
    );
  }

  function handleFavorite(id) {
    const newFavorites = favorites.map(item => {
      return item.id === id ? { ...item, favorite: !item.favorite } : item;
    });

    setFavorites(newFavorites);
  }
  return (
    <BooksContainer>
      {Array.isArray(data) &&
        data.map(
          book =>
            book.type === "Text" && (
              <Grow key={book.id} in timeout={500}>
                <Paper
                  sx={{
                    p: 2,
                    width: "450px",
                  }}>
                  <BookContainer>
                    <BookInfoContainer>
                      {book.resources.map(
                        item =>
                          item.type === "image/jpeg" &&
                          item.uri.includes("medium") && (
                            <Link
                              target="blank"
                              href={`https://www.gutenberg.org/ebooks/${book.id}`}>
                              <Img
                                key={item.id}
                                alt="book-cover"
                                src={item.uri}
                              />
                            </Link>
                          )
                      )}
                      {book.resources.length < 11 && (
                        <Img alt="book-cover" src={BookCover} />
                      )}
                      <div>
                        <BookInfoParagraph>Book title:</BookInfoParagraph>
                        <BookTitleName>{book.title}</BookTitleName>
                        <BookInfoParagraph>Author:</BookInfoParagraph>

                        {book.agents.map(
                          item =>
                            item.type === "Author" && (
                              <BookTitleName key={item.id}>
                                {item.person}
                              </BookTitleName>
                            )
                        )}
                      </div>
                    </BookInfoContainer>
                    <ButtonsContainer>
                      {book.resources.map(
                        item =>
                          item.type.includes("text/html") &&
                          item.uri.includes(".htm") && (
                            <Button key={item.id} variant="outlined">
                              <Link
                                underline="none"
                                target="blank"
                                href={item.uri}>
                                QUICK READ BOOK
                              </Link>
                            </Button>
                          )
                      )}
                      {favorites.map(
                        (item, i) =>
                          book.id === item.id && (
                            <FavouriteBook
                              key={item.id}
                              add={item.favorite}
                              handleClick={() => {
                                handleFavorite(item.id);
                              }}
                            />
                          )
                      )}
                    </ButtonsContainer>
                  </BookContainer>
                </Paper>
              </Grow>
            )
        )}
    </BooksContainer>
  );
};

export default BookView;

BooksView.js

import { useEffect, useState } from "react";
import axios from "axios";
import PageWrapper from "../../common/page-wrapper";
import ChangePageButton from "./change-page-button";
import BookView from "./book-view";
import ProgressCircle from "./progress-circle";
import styled from "styled-components";

const ChangePageButtonContainer = styled.div`
  position: fixed;
  top: 50%;
  left: ${props => props.theme.left};
  right: ${props => props.theme.right};
`;
const leftPosition = {
  left: "15px",
};
const rightPosition = {
  right: "15px",
};
const BooksView = () => {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [forwardPageLoading, setForwardPageLoading] = useState(false);
  const [backPageLoading, setBackPageLoading] = useState(false);
  const [page, setPage] = useState(1);
  const [error, setError] = useState(false);
  const [errorMessage, setErrorMessage] = useState("");
  useEffect(() => {
    fetchData(page);
  }, [page]);

  const fetchData = page => {
    axios(`https://gnikdroy.pythonanywhere.com/api/book/?page=${page}`)
      .then(res => {
        setData(res.data.results);
        setIsLoading(false);
        setForwardPageLoading(false);
        setBackPageLoading(false);
      })
      .catch(err => {
        setError(true);
        setIsLoading(false);
        setErrorMessage(err.message);
        console.log("Error", err.message);
      });
  };

  let count = page;
  const handleForwardPage = () => {
    setForwardPageLoading(true);
    if (page === 6578) {
      setPage(1);
    } else {
      count += 1;
      setPage(count);
    }
  };
  const handleBackPage = () => {
    setBackPageLoading(true);
    if (count === 1) {
      setPage(6578);
    } else {
      count -= 1;
      setPage(count);
    }
  };
  // console.log("data", data);

  return (
    <>
      {isLoading ? (
        <ProgressCircle height="100vh" />
      ) : (
        <PageWrapper>
          <ChangePageButtonContainer
            theme={leftPosition}
            style={{ display: `${error ? "none" : "inherit"}` }}>
            {backPageLoading ? (
              <ProgressCircle />
            ) : (
              <ChangePageButton handleClick={handleBackPage} type="back" />
            )}
          </ChangePageButtonContainer>

          <section>
            <BookView
              setData={setData}
              data={data}
              error={error}
              errorMessage={errorMessage}
            />
          </section>
          <ChangePageButtonContainer
            style={{ display: `${error ? "none" : "inherit"}` }}
            theme={rightPosition}>
            {forwardPageLoading ? (
              <ProgressCircle />
            ) : (
              <ChangePageButton
                handleClick={handleForwardPage}
                type="forward"
              />
            )}
          </ChangePageButtonContainer>
        </PageWrapper>
      )}
    </>
  );
};

export default BooksView;

FavouriteBook.js

import { Button, Icon } from "@mui/material";

const FavouriteBook = ({ handleClick, add }) => {
  return (
    <Button onClick={handleClick}>
      <Icon sx={{ color: "red" }}>{add ? "favorite" : "favorite_border"}</Icon>
    </Button>
  );
};

export default FavouriteBook;

Why building angular forms with formcontrol.values not setting the validations

I needed to create form in this way. app.ts file ->

courseNameControl = new FormControl(“”,
[Validators.required,Validators.minLength(2)]);

contentControl = new FormControl(“”, Validators.required);

form = { coursename: this.courseNameControl.value, content:
this.contentControl.value, } testForm=this.fb.group(this.form)

This form does not create the validations properly. Does anyone have a clue why?

When NPM says found 0 ‘vulnerabilities’ – what does it mean by ‘Vulnerabilities’?

I understand what a vulnerability is – in essence, a fault in security.

However, is npm simply reporting on all known vulnerabilities?

Or does it somehow automatically scan every package in its registry?

I’m assuming it’s the first & not the latter.

Moreover, I am a beginner in npm & it seems to me that the safest way to use these amazing libraries are by going with the ones which are insanely popular, am I correct?

ssh2 nodejs | upload file to sftp | Error: Permission denied at 101

When trying to upload a file to sftp server permission denied error appears. The same operation works if file is transferred via FilezIlla.

const UploadFiletoFTP = () => {
      let Client = require('ssh2').Client;
      var connSettings = {
        host: 'abc.com',
        port: 22,
        username: 'user',
        password: 'pass',
      };

  var conn = new Client();
  conn
    .on('ready', function () {
      conn.sftp(function (err, sftp) {
        try {
          if (err) {
            console.log(err);
            throw 'error ' + err;
          }
          console.log('connected');
          var fs = require('fs'); // Use node filesystem
          var readStream = fs.createReadStream(
            require('path').join(
              __dirname +
                '/audio/test_data_25_05_2022_09_58_00.zip'
            )
          );

          sftp.readdir(
            'speech/non-english',
            function (err, list) {
              if (err) throw err;
              // List the directory in the console
              console.dir(list);
              // Do not forget to close the connection, otherwise you'll get troubles
              conn.end();
            }
          );

          var writeStream = sftp.createWriteStream('SpeechIQ', {
            flags: 'a', // w - write and a - append
            encoding: null, // use null for binary files
            mode: 0o666, // mode to use for created file (rwx)
          });

          writeStream.on('close', function () {
            console.log('- file transferred succesfully');
          });

          writeStream.on('end', function () {
            console.log('sftp connection closed');
            conn.end();
          });

          readStream.pipe(writeStream);
        } catch (err) {
          console.error(err);
        }
      });
    })
    .connect(connSettings);
};

UploadFiletoFTP();

When the above code is run below error appears:

events.js:377
      throw er; // Unhandled 'error' event
      ^

Error: Permission denied
    at 101
Emitted 'error' event on Client instance at:
.
.
.
.
  code: 3
}

Please advise if I am missing something.

Below snippet lists the files in the directory but the writestream is not working.

sftp.readdir(
            'speech/non-english',
            function (err, list) {
              if (err) throw err;
              // List the directory in the console
              console.dir(list);
              // Do not forget to close the connection, otherwise you'll get troubles
              conn.end();
            }
          );

Why is Reseller Hosting the right choice of business?

Reseller hosting has earned the reputation of one of the profitable business ideas with low investment. It is affordable, highly secure, and offers a stable environment to offer services to website owners. Finding good reseller hosting companies is ideal for your reseller business because of the following reasons:

Design your own packages
Once you buy the best reseller hosting plan from the top reseller hosting companies, you can design your own packages based on the bandwidth, storage capacity, and features you offer. This can help you cater to different customer segments. You can also customize packages based on your target market.

Earn Profits
Best reseller hosting business will help you earn easy recurring profits by acting as a hosting company.

Low set up costs
The costs to set up a reseller web hosting business are very low. It doesn’t require any huge infrastructure costs to be invested. You need to invest only low rental costs to be paid to the server owner, that is the reseller hosting providers.

Flexible
As a reseller host, you have the flexibility to introduce new features at an additional cost. You can upgrade new features and offer multiple packages.

Best reseller hosting plans are the right choice of business if you need independence of operating business and earning profits without heavy investments.

Download image in specified folder not in default browser download folder by javascript

I am capturing image on browser and by clicking the Take Snapshot button image gets download in Browser Default Download Folder. But I want to download it in particular path. (I don’t want to change default download path of browser).

I have attached code below.

Webcam.set({
  width: 320,
  height: 240,
  image_format: 'jpeg',
  jpeg_quality: 90
});
Webcam.attach('#my_camera');

var shutter = new Audio();
shutter.autoplay = false;
shutter.src = navigator.userAgent.match(/Firefox/) ? 'webcamjs/shutter.ogg' : 'webcamjs/shutter.mp3';

takeSnapShot = function () {
  Webcam.snap(function (data_uri) {
    downloadImage('Developer', data_uri);
  });
}

downloadImage = function (name, datauri) {
  var a = document.createElement('a');
  a.setAttribute('download', name + '.png');
  a.setAttribute('href', datauri);
  a.click();
}
#my_camera {
  width: 320px;
  height: 240px;
  border: 1px solid black;
}
<div id="my_camera"></div>
<input type="button" value="Take Snapshot" onClick="takeSnapShot()">
<div id="results"></div>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/webcamjs/1.0.25/webcam.js"></script>

Number.isInteger is not a function in nodejs

module.exports.is_valid_integer_list = async (list, callback) => {
  var s = list.split(',');
  for (var i = 0; i < s.length; i++) {
      if (!this.is_valid_integer(s[i])) {
          return false;
      }
  }
  return true;
}

module.exports.is_valid_integer = async (s, callback) => {
  if (Number.isInteger(s)) {
      return true;
  } else {
      return false;
  }
}

When I run this code it through the error.
“Number.isInteger is not a function”

Pages not linking with HashRouter (react-router-dom) and electron-forge

I’m using electron-forge with react and I’m trying to set up routing using HashRouter in my app using react-router-dom. My app uses links in the sidebar to navigate through the various routes. I tried to set up a HashRouter in the app and no errors pop up when compiling, but nothing shows up when the code is running. All the pages that it links to are blank and the components aren’t displayed.

I suspect this might be because electron-forge is hosting my app on localhost:3000/main_window instead of localhost:3000/ itself. Is there any way I can host the app on localhost:3000/ itself or is there an additional step in setting up HashRouters as compared to BrowserRouters in react-router-dom?

This is how the Routes were set up:

<HashRouter>
  <Routes>
    <Route path="/" exact component={Home} />
    <Route path="/classes/:classId" component={ViewClass} />
    <Route path="/addClass" component={AddClass} />
  </Routes>
</HashRouter>

This is the button with the link to the Home Route:

<button className="nav-icon">
  <FontAwesomeIcon icon={solid('home')} />
  <Link className="nav-icon-text" to="/">Home</Link>
</button>

When the app starts, it automatically hosts to localhost:3000/main_window and nothing is shown. When the sidebar button is pressed, it links to localhost:3000/main_window#/ which doesn’t show anything either.

Does anyone know what the problem is here?

Three.js: How do I get sharper shadows on MeshLambertMaterial?

I’m working on some code to draw 3D images of the moon at various phases, showing libration effects as well. At this point, my image of a first quarter moon looks like this:

enter image description here

Which looks very nice, but the transition from light to shadow is too gradual. As there is no atmosphere on the moon, the transition from light to dark should be more abrupt.

This is the code I have so far:

  private drawMoonWebGL(context: CanvasRenderingContext2D, solarSystem: SolarSystem, time_JDE: number,
           cx: number, cy: number, size: number, pixelsPerArcSec: number, pixelRatio: number,
           parallacticAngle?: Angle, observer?: ISkyObserver, _showEclipses?: boolean): void {
    if (!this.renderer)
      this.setUpRenderer();

    if (size === 0)
      size = MAX_LUNAR_ANGULAR_DIAMETER * pixelsPerArcSec * 60;

    if (this.webGlRendererSize !== size) {
      this.renderer.setSize(size, size);
      this.webGlRendererSize = size;
    }

    const phase = solarSystem.getLunarPhase(time_JDE);
    const libration = solarSystem.getLunarLibration(time_JDE, observer);

    this.camera.position.z = libration.D * KM_PER_AU;
    this.camera.rotation.z = (parallacticAngle ? parallacticAngle.radians : 0);
    this.globeMesh.rotation.y = to_radian(-libration.l);
    this.globeMesh.rotation.x = to_radian(libration.b);
    this.sun.position.x = 93000000 * sin_deg(phase); // Very rough, but adequate for the task!
    this.sun.position.z = -93000000 * cos_deg(phase);
    this.renderer.render(this.scene, this.camera);
    context.drawImage(this.renderer.domElement, cx - size / 2, cy - size / 2);
  }

  private setUpRenderer(): void {
    const globe = new SphereGeometry(MOON_RADIUS, 50, 50);

    globe.rotateY(-PI / 2);
    this.camera = new PerspectiveCamera(MAX_LUNAR_ANGULAR_DIAMETER / 60, 1, 0.1, 500000);
    this.scene = new Scene();
    this.globeMesh = new Mesh(globe, new MeshLambertMaterial({ map: new CanvasTexture(this.moonImageForWebGL) }));
    this.scene.add(this.globeMesh);
    this.renderer = new WebGLRenderer({ alpha: true, antialias: true });
    this.sun = new DirectionalLight('white', 1.5);
    this.sun.position.y = 0;
    this.scene.add(this.sun);
    this.scene.add(new AmbientLight('white', 0.15));
  }

The above code takes an equirectangular moon map (courtesy of NASA) like this:

enter image description here

…and wraps it around a sphere so it can be rotated and illuminated in various ways.

With the searching for answers I’ve done so far I’ve only found information regarding one object casting shadows on a different object. I can’t find anything about adjusting the shadows on a single object with a single main light source.

There’s a little bit of ambient lighting added by my code (representing “earth shine”) to make sure the shadowed part of the moon isn’t pitch black, but removing that ambient lighting doesn’t sharpen the shadow boundary very much at all.

Can anyone tell me what I should to adjust to get the sharper shadow boundaries I’m looking for?

Input value not updating with React state?

Although the state is updated the input tag’s value still shows the last state of the object.
Here is my code:

const OrderForm = ({selectedOrder, setSelectedOrder }) => {
    const [order, setOrder] = useState({});
    useEffect(() => {
        setOrder(selectedOrder);
    }, [selectedOrder]);

    return (
        <section className={styles.formSection}>
            {order.id !== undefined && (
                <div className={styles.formRow}>
                    <button
                        className={styles.clear}
                        onClick={() => {
                            setSelectedOrder({});
                            setOrder({});
                        }}
                    >
                        Clear
                    </button>
                </div>
            )}
            
            <div className={styles.formRow}>
                <div className={styles.formGroup}>
                    <span className={styles.formLabel}>
                        Customer name {order.customer_name}
                    </span>
                    
                    <input
                        type='text'
                        className={styles.formInput}
                        placeholder='Enter Customer name'
                        value={order.customer_name}
                        onChange={(e) =>
                            setOrder({ ...order, customer_name: e.target.value })
                        }
                    />
                </div>
            </div>
        </section>
    )

Here the input values gets updated whenever the selectedOrder gets updated from a sibling component but on clicking the Clear button, although order object updates the input values still shows the last state content.

Selenium alternative for E2E testing of Electron app

I am trying to find a good framework for writing end-to-end tests for my electron app that even contains multiple windows.
Using Selenium for electron e2e tests is giving us a hard time maintaining it.
We thought of using Playwright codegen but it doesn’t support electron yet!!
Any suggestions will be appreciated.

froala editor toolbar position keep moving

I am using froala editor to edit documents in my project.now,the problem is froala toolbar keep on moving.I dont know why its happening.

first of all, i am creating new div by clicking add page button and this button have onclick event where it creates div with froala editor dynamically,If the user enter 2 pages it will create two divs with two toolbar on top of div.when i scroll the page, the toolbar keep on moving its position.please ,kindly help me with this problem.

here my code:

<button id="add_page" onclick="page()">+ Add Page</button>

var id=0;
var div_id=0;

function page(){

var pages= document.getElementById("pages").value;
    
    if(total_pages == ""){
    
        alert("Please enter number of pages");
    }
    else{
        
        for(var start=1;start<=total_pages;start++){
        
            var divRefer = document.querySelector('div.temp');

            var divToCreate = document.createElement('div');
            divToCreate.style.width="595pt";
            divToCreate.style.height="842pt";
            divToCreate.style.pageBreakAfter="always"; 
            div_id++;
            divToCreate.setAttribute("id","display_next"+div_id);
            var div_deleteId="display_next"+div_id;
            divToCreate.setAttribute("Contenteditable","true");
            //divToCreate.innerHTML="Insert Your Text Here";
            delete_btn.setAttribute("onclick","delete_div("+div_deleteId+");");
            var textarea= document.createElement('textarea');
            textarea.setAttribute("Contenteditable","true");
            id++;
            var text_edit="text_edit"+id;
            textarea.setAttribute("id",text_edit);
            //divToCreate.setAttribute("class","ck-editor__editable");
            divReference.parentNode.appendChild(divToCreate);
            divToCreate.appendChild(textarea);
            divToCreate.appendChild(delete_btn);
            var editor = new FroalaEditor("textarea#"+text_edit, {
            height: '542',

             
            });
            
        }
        
        }

}

function CustomizationPlugin( editor ) {

}

NOTE: i attached screenshot,kindly check it.

enter image description here

this is how its moving from div.actually toolbar is created dynamically and appended to div.

shortcut to retrieve array of object property in javascript

I have this array of object

[{
    id: 1,
    checked: true,
    subChild: [{
        id: 11,
        checked: true
    }]
},
{
    id: 2,
    checked: true,
    subChild: [{
        id: 22,
        checked: false
    }]
},
{
    id: 3,
    checked: false,
    subChild: [{
        id: 33,
        checked: true
    }]
}]

is there any lib to get the id base on the checked property? I can use loop through it using filter and find method but it will be a lot of manual work, imagine I have another level of nested array of object.

expected output: [1, 11, 2, 33]