Trying to retrieve an avatar image from an API but receiving an error of avatar not defined

userData is a function that receives user data from an API using getUserByChainAccount. getUserByChainAccount requires a username, which in this case is dynamically retrieved from buyer.

I’m interested in avatar , but I keep getting the following error Unhandled Runtime Error
ReferenceError: avatar is not defined

  return (
    <PageLayout>
      <ul>
        {sales.map((result) => {
          const {
            sale_id,
            buyer,
            seller,
            listing_price,
            listing_symbol,
            created_at_time,
          } = result;
          const userData = async (buyer) => {
            const user = await proton.getUserByChainAccount(buyer);
            const { name, avatar } = user;
          };

          function HandleBuyerClick() {
            window.location = '/user/' + buyer;
          }
          function HandleSellerClick() {
            window.location = '/user/' + seller;
          }

          if (buyer !== null) {
            return (
              <Card>
                <li key={sale_id}>
                  <h3>
                    <Transaction>
                      {avatar}
                      <Button onClick={HandleSellerClick}>{seller}</Button>
                    </Transaction>{' '}
                    just sold item number
                    <Transaction>
                      <Button>{sale_id}</Button>
                    </Transaction>{' '}
                    to{' '}
                    <Transaction>
                      <Button onClick={HandleBuyerClick}>{buyer}</Button>
                    </Transaction>{' '}
                    for <Transaction>{formatNumber(listing_price)}</Transaction>{' '}
                    {listing_symbol} at {parseTimestampJM(created_at_time)}
                  </h3>
                </li>
              </Card>
            );
          }
        })}
      </ul>
    </PageLayout>
  );
}

How is this made? It’s Javascript or some Elementor Plugin?

Hell guys. I have a task with my university class. My task is to do a wordpress site with “my own” customizations.

I already finished the task, on the good way i hope. But i’m trying to make something that my other teammates can’t do, the customization tasks. Recentry i saw a website: cryptonoticias . com and then go some random post, now open the dev console, they have a div which is kinda interesting. if you go on this website and seach on dev console the div: “class=”cri_shortcode” you will see something like a affiliate site. I have experience with elementor and wordpress ( 4/10 score skill to be honest )m but i don’t know how is this made. I want to put on my project website something like this but with recipes, my university project is about cooking website. So in this div they are 4 colums and if you let the mouse hover it show a small popup. Does anybody know how is this possible? it’s not look like a plugin is some js scrip maybe?

Thanks for help guys 🙂

Rock Paper Scissors Javascript not working

I’m learning JS and I’m trying to code a RPS kind of game with a UI, but I’m doing something wrong somewhere and I cannot figure out where.

Whenever I click on one of the options on the UI, the whole thing just freezes. I struggled a bit with the addEventListener logic, but I don’t know if that’s what’s causing it or if it’s something else.

Here’s my HTML and JS.

<!doctype html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="x-ua-compatible" content="ie=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" type="text/css" href="css/styles.css">
        <script src="https://kit.fontawesome.com/77133b1b16.js" crossorigin="anonymous"></script>
        <title>Rock, Paper, Scissors, Lizard, Spock</title>
    </head>
    <body>
        <div class="container">
            <div class="title">
                <h1>CHOOSE YOUR WEAPON</h1>
            </div>
            <div class="weapons">
                <div class="button" id="rock">
                    <div><img src="rock.png" alt="rock"></div>
                    <p>Rock</p>
                </div>
                <div class="button" id="paper">
                    <div><img src="paper.png" alt="paper"></div>
                    <p>Paper</p>
                </div>
                <div class="button" id="scissors">
                    <div><img id="scissors" src="scissors.png" alt="scissors"></div>
                    <p>Scissors</p>
                </div>
                <div class="button" id="lizard">
                    <div><img src="lizard.png" alt="lizard"></div>
                    <p>Lizard</p>
                </div>
                <div class="button" id="spock">
                    <div><img src="spock.png" alt="spock"></div>
                    <p>Spock</p>
                </div>
            </div>
            <h1 class="score-title">Score</h1>
            <div class="score">
                <div class="playerScore">
                    <h2>You</h2>
                    <span id="playerScore"></span>
                </div>
                <div class="computerScore">
                    <h2>Me</h2>
                    <span id="computerScore"></span>
                </div>
            </div>
            <span id="message"></span>
            <div class="rules">
                <h3>Rules:</h3>
                <p>"Scissors cuts Paper, Paper covers Rock, Rock crushes Lizard, Lizard poisons Spock, Spock smashes Scissors, Scissors decapitates Lizard, Lizard eats Paper, Paper disproves Spock, Spock vaporizes Rock, and as it always has, Rock crushes Scissors."</p>
            </div>
        </div>
        <footer class="footer">
            <p>Copyright © CamiCoding 2022</p>
            <a href="https://www.github.com/CamiCoding/" target=”_blank”><i class="fa-brands fa-github fa-beat" style="--fa-beat-scale: 2.0;"></i></a>
        </footer>
        <script src="script.js"></script>
    </body>
    </html>
let weapons = ["rock", "paper", "scissors", "lizard", "spock"];
let playerScore = 0;
let computerScore = 0;
let rounds = 0;
let roundWinner;

const playerScoreNumber = document.getElementById('playerScore');
const computerScoreNumber = document.getElementById('computerScore');
const scoreMessage = document.getElementById('message');
const buttons = document.querySelectorAll('.button');

buttons.forEach(button =>{
    button.addEventListener('click', playRound)
})

function playRound(event) {
    playerSelection = event.target.id;
    let computerSelection = computerPlay();

    if (playerSelection == computerSelection) {
        roundWinner = 'tie';
    } else if (
        (playerSelection == "paper" && computerSelection == "scissors") ||
        (playerSelection == "rock" && computerSelection == "paper") ||
        (playerSelection == "spock" && computerSelection == "lizard") ||
        (playerSelection == "lizard" && computerSelection == "rock") ||
        (playerSelection == "spock" && computerSelection == "lizard") ||
        (playerSelection == "scissors" && computerSelection == "spock") ||
        (playerSelection == "lizard" && computerSelection == "scissors") ||
        (playerSelection == "paper" && computerSelection == "lizard") ||
        (playerSelection == "spock" && computerSelection == "paper") || 
        (playerSelection == "rock" && computerSelection == "spock") ||
        (playerSelection == "scissors" && computerSelection == "rock")) {

        roundWinner = 'computer';
        computerScore++;
        rounds++;
    } else {
        roundWinner = 'player';
        playerScore++;
        rounds++;
    }
    updateScore();
}

function checkVictory() {
    while(rounds < 5) {
        if (playerScore == 3 || computerScore == 3) {
            break;
        }
        
    }

    if (playerScore > computerScore) {
        scoreMessage.textContent = "Fine, you win this time."
    } else {
        scoreMessage.textContent = "Awww, looks like you lost."
    }
}

function computerPlay() {
    const random = Math.floor(Math.random()*weapons.length);
    return weapons[random];
}

function updateScore() {
    if (roundWinner === 'tie') {
        scoreMessage.textContent = "It's a tie!";
    } else if (roundWinner === 'computer') {
        scoreMessage.textContent = "You lose!";
    } else if (roundWinner === 'player') {
        scoreMessage.textContent = "You win!";
    }

    playerScoreNumber.textContent = `${playerScore}`;
    computerScoreNumber.textContent = `${computerScore}`;
    checkVictory();
}

Thanks a lot in advance!

With GoogleMaps API how to create a vertical pole bearing clickable markers for each dwelling at a shared address, geolocation

I am trying to build an interactive GoogleMap in JavaScript via the API for a small town in which some reside in shared buildings. For such locations I would like to show a vertical “pole” on which there is a clickable marker of my choice for each dwelling and the height of the pole varying depending on the number of dwellings.

Or some other useful visualization for such locations.

Would appreciate suggestions and coding tips.

input onChange is wiping all elements from DOM in React. The input form works well with a button, but can’t seem to work onChange on the first load

So I’m creating a grid that you can resize using two input fields on the app. I have the input for cells across, input for cells down and the button to set the grid which works nicely. I want to change so that the input updates the state stored on cellsAcross and cellsDown. When I remove the button and add the onChange attribute to the input elements, it works if I don’t refresh the browser, but as soon as everything renders for the first time, when adding an input everything in the DOM disappears.

Here’s the code with the button:

function App() {
  const [cellsAcross, setCellsAcross] = useState(5);
  const [cellsDown, setCellsDown] = useState(5);

  const getGridSize = () => {
    const inputAcross = document.getElementById("cells-across").value;
    const cellsAcross = parseInt(inputAcross);
    setCellsAcross(cellsAcross);
    const inputDown = document.getElementById("cells-down").value;
    const cellsDown = parseInt(inputDown);
    setCellsDown(cellsDown);
    console.log(`Across: ${cellsAcross} | Down: ${cellsDown}`);
  };

  

  return (
    <div className="app">
      <Header />
      <CellGrid numberOfColumns={cellsAcross} numberOfRows={cellsDown} />
      <label htmlFor="cells-across">Across</label>
      <input 
        type="number" 
        id="cells-across" 
        name="cells-across" 
        min="1"
      />
      <br />
      <label htmlFor="boxes-down">Down (1-20):</label>
      <input 
        type="number" 
        id="cells-down" 
        name="cells-down" 
        min="1"
      />
      <br />
      <button onClick={getGridSize}>Make Grid</button>
      <br />
    </div>
  );
}

export default App;

And this is what I want it to be:

import React, { useState } from "react";
import CellGrid from "./CellGrid";
import "./App.css";
import Header from "./Header";

function App() {
  const [cellsAcross, setCellsAcross] = useState(5);
  const [cellsDown, setCellsDown] = useState(5);

  const getGridSize = () => {
    const inputAcross = document.getElementById("cells-across").value;
    const cellsAcross = parseInt(inputAcross);
    setCellsAcross(cellsAcross);
    const inputDown = document.getElementById("cells-down").value;
    const cellsDown = parseInt(inputDown);
    setCellsDown(cellsDown);
    console.log(`Across: ${cellsAcross} | Down: ${cellsDown}`);
  };

  return (
    <div className="app">
      <Header />
      <CellGrid numberOfColumns={cellsAcross} numberOfRows={cellsDown} />
      <label htmlFor="cells-across">Across</label>
      <input
        type="number"
        id="cells-across"
        name="cells-across"
        min="1"
        onChange={getGridSize}
      />
      <br />
      <label htmlFor="boxes-down">Down (1-20):</label>
      <input
        type="number"
        id="cells-down"
        name="cells-down"
        min="1"
        onChange={getGridSize}
      />
      
    </div>
  );
}

export default App;

Multiple Inputs with Vite

I’m having multiple inputs when building my app with vite. My config looks like this:

export default defineConfig({
  plugins: [
    react(),
    eslintPlugin()
  ],
  build: {
    rollupOptions: {
      input: {
        test1: resolve(__dirname, '/test1.html'),
        test2: resolve(__dirname, '/test2.html')
      }
    }
  }
});

The output looks like this:

dist
|-test1.html
|-test2.html
|-assets

What I actually want is something like this:

dist
|test1
  |-index.html
|test2
  |-index.html
|-assets

Is this possible?

Thanks

Collect values from a spreadsheet, look for those values in a string and replace

The values in my spreadsheet are these:
enter image description here

/2021/
/20212022/
/2022/
/20222023/
/2023/

To try to find these values in a string and then replace with /@@@@/ I tried creating a map:

var sheet = SpreadsheetApp.getActive().getSheetByName('One')
var liga = 'https://int.testestest.com/national/united-states/mls/2022/regular-season/r66725/'
var years = sheet.getRange('One!A10:A14').getValues().flat();
var mapObj = {one: years[0],two: years[1],three: years[2],four: years[3],five: years[4]};

var liga_substitute = liga.replace(/b(?:one|two|three|four|five)b/gi, matched => mapObj[matched]);

var liga_final_subs = liga_substitute.replace('one','/@@@@/').replace('two','/@@@@/').replace('three','/@@@@/').replace('four','/@@@@/').replace('five','/@@@@/')

But the result after substitution remains the same:

https://int.testestest.com/national/united-states/mls/2022/regular-season/r66725/

My final expected result is:

https://int.testestest.com/national/united-states/mls/@@@@/regular-season/r66725/

And in var liga_final_subs = exist the risk of finding these parts of text in the wrong places and replacing what shouldn’t.

How should I go about doing this correctly?

Should I remove “await” keyword to increase response time?

I’ve database of users where they have created their team. and other document for storing racers.

each user can create a team of 6 racers.

but the problem is that I’ve 50k users and using the below code to remove a racer from their team if Admin deleted it from Racers Document.

I’m using express.js and mongoose

team is an array of object which has racers name, it’s shortCode and unique identifier.

async function delete(req, body){
    // code to validate users input
    await Users.updateMany({'tema.shortCode': 'HAM'}, { $pull: {'team.shortCode': 'HAM'}})

}

I’ve seen that response time decreases if i remove await keyword. But is it recommended to do that.

Bulk download of images using JavaScript

I need a piece of JavaScript code that gets an array of image links and downloads them one by one. I know there are tools for this, but due to some access limitations it needs to be JavaScript code that runs on a page in my browser. I get to write the whole page myself, and browse it as a local file on my computer.

As my input I will have a JavaScript array:

var links = ['https://.../img1.jpg','https://.../img2.jpg','https://.../img3.jpg',...]

I will be using a fairly recent build of Firefox. I have figured out that I can get rid of the Save As dialog if I set the browser to always save to a certain location, and I can get rid of the confirmation dialog by checking “Do this for all files of this type”. I can do the foreach myself, I just need the function I can feed the links to.

You’d think there would be many examples how to do this, and there are, but so far I haven’t found a single one that actually works for me. Either they assume you have a static image on your page and want to initiate download by clicking on it, or they run smack into CORS policy error. I even found one complete example that seemed to be working, but once I downloaded and tried it on my machine, it started producing 4.0 KB garbled downloaded files.

How can I do this?

When page reloaded marked(content) disappears when page reloaded || Next Js

import matter from 'gray-matter'
import { marked } from 'marked'
import SearchBar from '../../components/SearchBar'
import fs from 'fs'
import path from 'path'

export default function title({frontmatter: {title, date},slug,content}) {
  return (
    <div className='DISPLAY_Container'>
      <SearchBar />
      <div className="DISPLAY_Sub_Container">
          <h3>{title}</h3>
          <p dangerouslySetInnerHTML={{ __html: marked.parse(content)}}></p>
      </div>

    </div>
  )
}

export async function getStaticPaths() {
  const files = fs.readdirSync(path.join('posts'))

  const paths = files.map((filename) => ({
    params: {
      slug: filename.replace('.md', ''),
    },
  }))

  return {
    paths,
    fallback: false,
  }
}
export async function getStaticProps({ params: { slug } }) {

  const markdownWithMeta = fs.readFileSync(path.join('posts', slug + '.md'), 'utf-8')

  const { data:frontmatter,content } = matter(markdownWithMeta)

  return {
    props: {
      frontmatter,
      content,
      slug
    }
  }
}

the marked(content) function doesn’t work that well, and when the page is reloaded the content disappears

I am using .md files, and a npm package called marked as can be seen in code.
The styling isn’t that good either, i’d wanna use a better parser if possible and want that content not disappear when the page is reloaded

Elegant algorithm to control max value for carousel

I have a slider which at most can show 3 elements. If there are more elements, these are hidden and

can come into view by clicking left right as following image.

enter image description here

This slider will be taking in a position prop. Note that I can’t change this component which is external.

<Slider position={position} />

The position value decide the red position as shown in following image.

enter image description here

I am trying to have an algorithm to set this position with following rules.

If the elements are 3 or less, position should always be 0.

Anything more, it should not slide past the last element.

Meaning let’s say I pass in the value 4 (so index 4, 5th element) for the position value, the component will look like the following.

enter image description here

Above is wrong. It should look like the following where it filled 3 spots while still sliding to the left as much as possible.

Thus it would have worked fine if I passed in the position value as 2.

enter image description here

Also to use position value as is if acceptable without needing to modify it as follows.

enter image description here

Looking for algorithm that will:

Get a position value and decide if it can be used as is or need to amend based on element count and the max visible elements which is 3.
And obtain a modified position value and pass it to the Slider component.

Was thinking something along the line of the following.

Based on testing, believe this work. Looking for validation if this would work.

And advice if there is a way I could make this more elegant and possibly not have

the initial if check for the less than or equals 3 elements.

// elementCount = // dynamic count of elements.
// initialPosition = // initial position being passed in which needs to be validated.
const getPosition = (elementCount, initialPosition) => {
    if (elementCount <= 3) {
        return 0;
    }
    const maxPosition = elementCount - 3;
    return initialPosition <= maxPosition ? initialPosition : maxPosition;
}

Note: This is essentially a React project but didn’t tag it as so considering the query is more algorithm related. Thanks.

Can I compare the answer of a prompt to properties of objects in an array?

I am trying to match the result of a prompt with properties of various objects in an array. (I.e if city entered matches the name of one of the objects listed, return the coinciding temp)

let cities = [
  {
    name: "San Luis Obispo",
    temp: 16,
    uv: 1,
    humidity: 5,
    elevation: 28,
    wind: 2,
  },
  {
    name: "Morro Bay",
    temp: 11,
    uv: 2,
    humidity: 8,
    elevation: 1,
    wind: 8,
  }]

let city = prompt("Enter a city");
if (city === cities.name){
  alert(`It is currently ${temp}°C in ${city}`);
} 

How to correctly return JSX with nested maps

I have a component that shows multiple list names, and if you click to expand the collapsible item displaying the list name, all the ingredient names, ingredient amounts, and ingredient units part of that list are supposed to then display.

The object I am working with is the savedRecipes object, and I want to make lines listing every ingredient name, ingredient amount, and ingredient unit in the drop downs. It seems I need some nesting for this, but I cannot write the code correctly. The dropdowns appear empty.

This is the js file I have:

import * as React from 'react';
import DeleteIcon from '@mui/icons-material/Delete';
import {StyledDiv, StyledDiv2, StyledDiv3} from './GroceryList.styles.js';
import {styled} from '@mui/material/styles';
import ArrowForwardIosSharpIcon from '@mui/icons-material/ArrowForwardIosSharp';
import MuiAccordion from '@mui/material/Accordion';
import MuiAccordionSummary from '@mui/material/AccordionSummary';
import MuiAccordionDetails from '@mui/material/AccordionDetails';
import Typography from '@mui/material/Typography';
import {useState} from 'react';
import {MuiThemeProvider, createTheme} from '@material-ui/core/styles';
import {Card, CardMedia, CardContent, CardActions} from '@mui/material';
import AddIcon from '@mui/icons-material/Add';
import Button from '@mui/material/Button';
import Checkbox from '@mui/material/Checkbox';


const Accordion = styled((props) => (
  <MuiAccordion disableGutters elevation={0} square {...props} />
))(({theme}) => ({
  'border': `1px solid ${theme.palette.divider}`,
  '&:not(:last-child)': {
    borderBottom: 0,
  },
  '&:before': {
    display: 'none',
  },
}));

const AccordionSummary = styled((props) => (
  <MuiAccordionSummary
    expandIcon={<ArrowForwardIosSharpIcon sx={{fontSize: '0.9rem'}} />}
    {...props}
  />
))(({theme}) => ({
  'backgroundColor':
    theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, .05)' : 'rgba(0, 0, 0, .03)',
  'flexDirection': 'row-reverse',
  '& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': {
    transform: 'rotate(90deg)',
  },
  '& .MuiAccordionSummary-content': {
    marginLeft: theme.spacing(1),
  },
}));

const AccordionDetails = styled(MuiAccordionDetails)(({theme}) => ({
  padding: theme.spacing(2),
  borderTop: '1px solid rgba(0, 0, 0, .125)',
}));

export default function GroceryList2() {
  const [expanded, setExpanded] = React.useState(false);
  const [windowWidth, setWindowWidth] = useState(window.innerWidth);
  const textTheme = windowWidth >= 650 ? 'h6' : 'subtitle1';

  const [savedRecipe, setSavedRecipe] = useState(
    {
      list1: [{
        createdAt: "2022-03-05T08:00:00.000Z",
        listName: "list1",
        recipe: {
          id: 642178,
          image: "https://spoonacular.com/recipeImages/642178-556x370.jpg",
          ingredients: [{
            amount: 0.5,
            name: "flour",
            unit: "c"
          }, {
            amount: 0.5,
            name: "whole wheat flour",
            unit: "c"
          }, {
            amount: 1,
            name: "sugar",
            unit: "tbsp"
          }, {
            amount: 1,
            name: "baking powder",
            unit: "tsp"
          }, {
            amount: 0.25,
            name: "baking soda",
            unit: "tsp"
          }, {
            amount: 0.25,
            name: "salt",
            unit: "tsp"
          }, {
            amount: 1,
            name: "ground flaxseed",
            unit: "tbsp"
          }, {
            amount: 1,
            name: "almond milk",
            unit: "c"
          }, {
            amount: 2,
            name: "cooking oil",
            unit: "tbsp"
          }],
          nutrients: [{
            amount: 68.36,
            name: "Calories",
            percentOfDailyNeeds: 3.42,
            unit: "kcal"
          }, {
            amount: 3.12,
            name: "Fat",
            percentOfDailyNeeds: 4.8,
            unit: "g"
          }, {
            amount: 0.23,
            name: "Saturated Fat",
            percentOfDailyNeeds: 1.46,
            unit: "g"
          }, {
            amount: 9.1,
            name: "Carbohydrates",
            percentOfDailyNeeds: 3.03,
            unit: "g"
          }, {
            amount: 1.07,
            name: "Sugar",
            percentOfDailyNeeds: 1.19,
            unit: "g"
          }, {
            amount: 102.6,
            name: "Sodium",
            percentOfDailyNeeds: 4.46,
            unit: "mg"
          }, {
            amount: 1.46,
            name: "Protein",
            percentOfDailyNeeds: 2.92,
            unit: "g"
          }, {
            amount: 0.98,
            name: "Fiber",
            percentOfDailyNeeds: 3.93,
            unit: "g"
          }],
          readyInMinutes: 45,
          servings: 12,
          sourceUrl: "https://www.foodista.com/recipe/DL8G33VY/egg-and-dairy-free-pancakes",
          title: "Egg and Dairy Free Pancakes"
        }
      }],
      list2: [{
        createdAt: "2022-03-05T08:00:00.000Z",
        listName: "list2",
        recipe: {
          id: 638086,
          image: "https://spoonacular.com/recipeImages/638086-556x370.jpg",
          ingredients: [{
            amount: 1,
            name: "cayennepepper",
            unit: "dash"
          }, {
            amount: 1,
            name: "chickenbreasts",
            unit: "pound"
          }, {
            amount: 1.5,
            name: "cornflakes",
            unit: "cup"
          }, {
            amount: 1,
            name: "eggwhite",
            unit: ""
          }, {
            amount: 0.25,
            name: "italianseasoning",
            unit: "teaspoons"
          }, {
            amount: 0.25,
            name: "paprika",
            unit: "teaspoons"
          }, {
            amount: 2,
            name: "parmesancheese",
            unit: "teaspoons"
          }, {
            amount: 1,
            name: "water",
            unit: "Tablespoon"
          }],
          nutrients: [{
            amount: 346.76,
            name: "Calories",
            percentOfDailyNeeds: 17.34,
            unit: "kcal"
          }, {
            amount: 6.29,
            name: "Fat",
            percentOfDailyNeeds: 9.68,
            unit: "g"
          }, {
            amount: 1.49,
            name: "SaturatedFat",
            percentOfDailyNeeds: 9.28,
            unit: "g"
          }, {
            amount: 18.14,
            name: "Carbohydrates",
            percentOfDailyNeeds: 6.05,
            unit: "g"
          }, {
            amount: 2.15,
            name: "Sugar",
            percentOfDailyNeeds: 2.39,
            unit: "g"
          }, {
            amount: 457.72,
            name: "Sodium",
            percentOfDailyNeeds: 19.9,
            unit: "mg"
          }, {
            amount: 51.78,
            name: "Protein",
            percentOfDailyNeeds: 103.56,
            unit: "g"
          }, {
            amount: 0.9,
            name: "Fiber",
            percentOfDailyNeeds: 3.6,
            unit: "g"
          }],
          readyInMinutes: 30,
          servings: 2,
          sourceUrl: "http://www.foodista.com/recipe/6GVTWWJ6/chicken-fingers",
          title: "ChickenFingers"
        }
      }]
    }
  );

  const handleChange = (panel) => (event, newExpanded) => {
    setExpanded(newExpanded ? panel : false);
  };

  return (
    <div>
      {Object.keys(savedRecipe).map(function(key, index) {
        return (
          <Accordion expanded={expanded === key} onChange={handleChange(key)}>
            <StyledDiv>

              <StyledDiv2>
                <AccordionSummary aria-controls="panel1d-content" id="panel1d-header">
                  <Typography>{key}</Typography>
                </AccordionSummary>
              </StyledDiv2>

              <StyledDiv3 variant="contained" style={{backgroundColor: '#F7918C'}}>
                <DeleteIcon style={{color: 'black'}} />
              </StyledDiv3>

            </StyledDiv>
            <AccordionDetails>
              {(savedRecipe[key]).map((obj) => {
                {(obj.recipe.ingredients).map((line) => {

                  return
                  (
                        <Grid item xs="auto">
                          <Card sx={{
                            'maxWidth': 1000, '&:hover': {
                            'boxShadow': '3px 3px 3px #d9d9d9',
                            'cursor': 'pointer',
                            },
                          }}>
                            <CardContent>
                              <Typography variant={textTheme} color='#D24949' >
                                <Checkbox defaultUnchecked color="success" />
                                {line.name} - {line.amount} {line.unit}
                              </Typography>
                            </CardContent>
                          </Card>
                        </Grid>
                    );

                })}
              })}

            </AccordionDetails>
          </Accordion>
        );
      })}
    <Button style={{position: 'fixed', bottom: 0, right: 0, height: '45px', width: '245px', textAlign: 'center'}} variant='contained' endIcon={<AddIcon />}>
          Add new Grocery List
    </Button>
    </div>
  );
}


This is my styles files so that the code works because I used some styled components

import styled from 'styled-components';
import Button from '@mui/material/Button';
import LongMenu from './AddToGroceryListMenu.js';

export const StyledDiv= styled.div`

  display: flex;
  flex-direction: row;
  width: 100%;
`;

export const StyledDiv2 = styled.div`
  position: static;
  width: 95%;
  @media screen and (max-width: 600px) {
  width: 85%;
 }
  &:hover {
    background-color: #D4D4D4;
  }
`;

export const StyledDiv3 = styled(Button)`
  position: static;
  cursor: auto;
  width: 5%;
  background-color: #EA6A6A;
  right: 0;
  &:hover {
    cursor: pointer;
  }
  @media screen and (max-width: 600px) {
  width: 15%;
 }
`;
// roughly: sm, small: 600px. md, medium: 900px. lg, large: 1200px. xl, extra-large: 1536px.

export const StyledLongMenu = styled(LongMenu)`
 position: fixed;
 top: 0;
`;

Reject promise with string in function that has a different return type

I have a function like so:

invoke(token: string): Promise<IUserDto> {
    return new Promise((reject, resolve) => {
        // Tokens are generally passed in the header of the request
        // Due to security reasons.

        let jwtSecretKey = process.env.JWT_SECRET_KEY;
    
        try {       
            const verified = jwt.verify(token, jwtSecretKey!);
            if(verified){
                resolve(verified);
            }else{
                // Access Denied
                reject();
            }
        } catch (error) {
            // Access Denied
            reject();
        }
    });
}

And im trying to test it like so:

it('Validate user token use case', async () => {
    let jwtSecretKey = process.env.JWT_SECRET_KEY;

    let userData: IUserDto = {
        id: 'testid',
        firstName: 'firstName',
        lastName: 'lastName',
        username: 'username',
        email: '[email protected]',
        password: 'testpassword',
        birthDate: new Date('0'),
        reports: [
            new Report('report_id', 'report data', 0)
        ]
    };

    let token = jwt.sign(userData, jwtSecretKey!);

    let validateUserTokenUseCase = new ValidateUserTokenUseCase();

    let validated: IUserDto | String = await validateUserTokenUseCase.invoke(token);

    expect(validated.id).toBe(userData.id);
})

I cannot do this because when rejecting the promise in the function, it doesnt return an object of IUserDto, it returns whatever error string i put in the reject.

I have tried defining the return type like Promise<IUserDto | String>, but my IDE doesnt pick this up well, i cant see for example validated.id when typing it in my IDE, which is annoying.

Is there a way to reject this method without defining the promise type as IUserDto | String?