Problem in rendering ejs template with Express

I am using Node.js together with Express and EJS.

Below is my code:

var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');

var app = express();
var urlencodedParser = bodyParser.urlencoded({ extended: false });
var publicPath = path.resolve(__dirname, 'public');
app.use(express.static(publicPath));
//app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

app.get('/form_get.html', (req, res) => {
    res.sendFile(__dirname + "/" + "form_get.html")
})

app.get('/process_get', (req, res) => {

    console.log(req.query.first_name);
    res.render(path.join(__dirname+'/views/thankyou.ejs'), { name: req.query.first_name});
    
})

var server = app.listen(3000, () => {
    
    var host = server.address().address;
    var port = server.address().port;
    console.log(`Example app listening at ${host}:${port}`);
})

I get the following error message:

Error: Failed to lookup view “…/views/thankyou.ejs” in views directory “…/mysql/views”

What ca be the problem?

facing problem while converting to class to function component

here I have tried to convert code into function component but I am getting to much error pls help me out to convert this code,thank in advance.

import React, { Component, Fragment } from "react";
import {
  TouchableOpacity,
  Text,
  View,
  KeyboardAvoidingView,
  Modal,
  TextInput,
  Platform,
  Keyboard,
  Dimensions,
  ScrollView,
  StatusBar,
  SafeAreaView,
} from "react-native";
import QRCodeScanner from "react-native-qrcode-scanner";
import styles from "./scanStyle";
import AppStore from "../../stores/AppStore";
import { handleScreenNavigation } from "../../utils/NavigationService";
import Theme from "../../utils/Theme";
import LinearGradient from "react-native-linear-gradient";
import CardView from "react-native-cardview";
import Scanstore from "../../stores/Scanstore";
import Toast from 'react-native-simple-toast';
import { Screen } from "../../components/common/Screen";
import { UniversalNavigationHeader } from "../../components/common/NavigationHeader";
import Iconpack from "../../utils/Iconpack";
// import { ScrollView } from "react-native-gesture-handler";

const hRem = AppStore.screenHeight / 812;
const wRem = AppStore.screenWidth / 375;


const STATUSBAR_HEIGHT = StatusBar.currentHeight;

const totp = require("totp-generator");

let b32_regex = /^[a-zA-Z2-7]+=*$/;



class Scan extends Component {
  constructor(props) {
    super(props);
    this.state = {
      scan: false,
      ScanResult: false,
      result: null,
      isShow: false,
      textName: "",
      secretKey: "",
      backupCode: "",
      isBackUpCode: true,
      textInputHighlight: null,
      textInputHighlight2: null,
      textInputHighligh3: null,
      value: "",
      height: 0,
      updateHeightSecretKey: 0,
      platformUri:"",
      styleChange:false,
      keyboardState: 'closed'
    };
  }

  componentDidMount() {
    if(this.props.route.params.edit){
    //   console.log("Appstore.userPin*******************",   this.props.route.params.index,
    //   this.props.route.params.edit,
    //  this.props.route.params.otpFrom,
    //   this.props.route.params.backUpCode,
    //   this.props.route.params.friendlyName)
      this.setState({  secretKey:this.props.route.params.secretKey,
        platformUri :this.props.route.params.otpFrom,
        textName : this.props.route.params.friendlyName ,
        backupCode :  this.props.route.params.backUpCode,
        isBackUpCode: this.props.route.params.backUpCode.length>0?false:true,
        isShow:true
      })
    }
  
    // this.setState({ isShow: true, secretKey: "fsdfsfsf",platformUri:"fdsfsffs" });

    //let data = base32.decode("otpauth://totp/Google%3Arakesh.s%40catalystmedia.io?secret=tqskd2aiylctmid2vzi4lirnuhbshqem&issuer=Googlethe");
    // Keys provided must be base32 strings, ie. only containing characters matching (A-Z, 2-7, =).
    // var hotp = require('hotp')
    // var key = 'tqskd2aiylctmid2vzi4lirnuhbshqem'
    // var counter = 0
    // var tokenhotp = hotp(key, counter, { digits: 6 })
    // // var tokentotp = hotp.totp( key, { digits: 6 })//converting hotp to totp
    // // console.log("totp same---> ", tokentotp)
    // console.log("hotp same ---> ", tokenhotp)
    // console.log("totp diff--->", token);
    // // this.otpList()
    // AppStore.incrementCount()
  }

  componentWillUnmount () {
    this.keyboardDidShowListener.remove();
    this.keyboardDidHideListener.remove();
  }

  componentWillMount () {
    this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);
    this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
  }

  _keyboardDidShow = () => {
    this.setState({
        keyboardState: 'opened'
    });
  }

  _keyboardDidHide = () => {
    this.setState({
        keyboardState: 'closed',
        styleChange:false

    });
    console.log("console,console")
  }

  handleCreate = () => {
    console.log(this.state.secretKey,"---------------->",b32_regex.exec(this.state.secretKey))
    if((this.state.secretKey.length>0) && (b32_regex.test(this.state.secretKey) && (this.state.secretKey.length % 8) === 0) ){
      // console.log("----->",AppStore.secretKeyAdded)
      if (AppStore.secretKeyAdded){

        Scanstore.addNewKeyAuthenticator(
          this.state.secretKey,
          this.state.platformUri !== undefined ?this.state.platformUri:"",
          this.state.textName,
          this.state.backupCode
        );
      } else {
        
        Scanstore.setKeyAuthenticator(
          this.state.secretKey,
          this.state.platformUri !== undefined ?this.state.platformUri:"",
          this.state.textName,
          this.state.backupCode
        );
      }
      Scanstore.fetchSecretKeyArray();
    }
    

    else if(this.state.secretKey.length===0){
      // console.log("enter valid")
      Toast.show("Please enter the Secret Key", Toast.LONG);
    }
    else{
      Toast.show("Please enter valid Secret Key", Toast.LONG);
    }

  };

  updateSize = (height) => {
    this.setState({
      height,
    });
  };

  updateSizeSecretKey = (updateHeightSecretKey) => {
    this.setState({
      updateHeightSecretKey,
    });
  };

  bottomModal = () => {
    return (
      <View style={styles.modalStyle}>
        
        <LinearGradient
          start={{ x: 0, y: 0.3 }}
          end={{ x: 0, y: 1.2 }}
          colors={["#020A13", "#000000"]}
          style={styles.modalContent}
        >
        
          <TouchableOpacity
            onPress={() => this.setState({ isShow: false })}
            style={styles.topBar}
          />

<View style={{height: this.state.styleChange ? 200 :"100%",paddingHorizontal:20 }} >
  <ScrollView>
          <CardView
            cardElevation={8}
            cardMaxElevation={2}
            cornerRadius={15}
            style={[
              {
                shadowColor: this.state.textInputHighlight,
              },
              styles.friendlyNameCard,
            ]}
          >
            <TextInput
              style={[styles.input, styles.mod0]}
              placeholderTextColor={Theme.white_color}
              onFocus={() => {
                this.setState({
                  textInputHighlight: Theme.hightLightColor,
                  textInputHighlight2: null,
                  textInputHighligh3: null,
                  styleChange:true
                });
              }}
              onBlur={()=>{
                this.setState({styleChange:false})
              }}
              onChangeText={(value) => {
                this.setState({ textName: value });
              }}
              onSubmitEditing={Keyboard.dismiss}
              value={this.state.textName}
              placeholder={"Friendly Name"}
            />
          </CardView>

          <CardView
            cardElevation={8}
            cardMaxElevation={2}
            cornerRadius={15}
            style={[
              {
                shadowColor: this.state.textInputHighlight2,
              },
              styles.secretKeyStyle,
            ]}
          >
            <TextInput
              style={[
                styles.input,
                {
                  maxHeight: Platform.OS == "android" ? 76 : 44,
                  height:Platform.OS == "android"?this.state.updateHeightSecretKey :44,
                },
              ]}
              placeholderTextColor={Theme.white_color}
              editable={true}
              multiline={true}
              onFocus={() => {
                this.setState({
                  textInputHighlight2: Theme.hightLightColor,
                  textInputHighlight: null,
                  textInputHighligh3: null,
                  styleChange:true
                });
              }}
              onChangeText={(value) => {
                this.setState({ secretKey: value });
              }}
              onContentSizeChange={(e) =>
                this.updateSizeSecretKey(e.nativeEvent.contentSize.height)
              }
              value={this.state.secretKey}
              onSubmitEditing={Keyboard.dismiss}
              placeholder={"Secret Key"}
            />
          </CardView>

          {this.state.isBackUpCode ? (
            <TouchableOpacity
              style={styles.backUp}
              onPress={() => {
                this.setState({ isBackUpCode: false });
              }}
            >
              <Text style={[styles.backUpText,{marginLeft:10 }]}>Want to add Backup Codes?</Text>
            </TouchableOpacity>
          ) : (
            <View style={styles.backUp}>
              <Text
                style={{ ...Theme.encodeSansReg15, color: Theme.white_color,marginLeft:10 }}
              >
                Enter Backup Codes
              </Text>
              <CardView
                cardElevation={8}
                cardMaxElevation={2}
                cornerRadius={15}
                style={[
                  {
                    shadowColor: this.state.textInputHighligh3,
                  },
                  styles.backUpCodeStyle,
                ]}
              >
                <TextInput
                  style={[
                    styles.input,
                    {
                      maxHeight: Platform.OS == "android" ? 102 : 70,
                      height:Platform.OS == "android"?this.state.height: 70,
                    },
                  ]}
                  placeholderTextColor={Theme.white_color}
                  editable={true}
                  multiline={true}
                  onFocus={() => {
                    this.setState({
                      textInputHighligh3: Theme.hightLightColor,
                      textInputHighlight: null,
                      textInputHighlight2: null,
                      styleChange:true
                    });
                  }}
                  onChangeText={(value) => {
                    this.setState({ backupCode: value });
                  }}
                  onContentSizeChange={(e) =>
                    this.updateSize(e.nativeEvent.contentSize.height)
                  }
                  onSubmitEditing={Keyboard.dismiss}
                  value={this.state.backupCode}
                  placeholder={"Backup Code"}
                />
              </CardView>
            </View>
          )}
<View style={{flexDirection:"row", justifyContent:"space-around",alignItems:"center",marginTop:40,marginBottom:AppStore.isAndroid?20:0}}>
          <TouchableOpacity
            style={styles.createButton}
            onPress={() => {
              if(this.props.route.params.edit){

                Scanstore.editElement( 
                  this.props.route.params.index ,
                  this.state.secretKey,
                  this.state.platformUri ,
                  this.state.textName ,
                  this.state.backupCode 
              )
              this.setState({ isShow: false, styleChange:false });
              Scanstore.fetchSecretKeyArray();
              Toast.show("Updated Successfully.", Toast.LONG);

              }
              else{
                this.handleCreate();
                this.setState({ isShow: false, styleChange:false });
              }
              


            }}
            // onLongPress={() => this.setState({ scan: false })}
          >
            <Text style={[styles.tapText, { fontWeight: "600" }]}>{this.props.route.params.edit?"Update":"Create"}</Text>
          </TouchableOpacity>

          <TouchableOpacity
            // style={{ marginTop: 25 }}
            
            onPress={() => 
              {this.setState({ isShow: false, styleChange:false }) 
          console.log("87887787")
            }
          }
            onLongPress={() => this.setState({ scan: false })}
          >
            <Text style={styles.cancelButton}>Cancel</Text>
          </TouchableOpacity>
         </View>
         </ScrollView>

         </View>
        </LinearGradient>
    
      </View>
    );
  };

  onSuccess = (e) => {
    const check = e.data.substring(0, 7);
    console.log("check", check);
    console.log("scanned data ->    " + e.data + "      the whole bunch of data -> ");
    let fetchedData = e.data;
    let secretKey,platformUri;
    if (fetchedData.includes("totp")) {
      secretKey = fetchedData.split("=");
      platformUri = secretKey[2]
      console.log("------------", secretKey);

      secretKey = secretKey[1].split("&");

      // const totpGen = ;
      // let lengthId = AppStore.rData.length;

      // AppStore.addTotp({
      //   id: lengthId,
      //   title: secretKey[0],
      //   otpFrom:platform,
      // });
    }

    // console.log("what the hell", AppStore.deviceIdInfo);

    this.setState({
      result: e,
      scan: false,
      ScanResult: true,
    });
    if (e.data.includes("totp") ) {
      // handleScreenNavigation("OtpScreen", {})
      this.setState({ isShow: true, secretKey: secretKey[0],platformUri:platformUri });
    }
    else if(e.data.includes("hotp")) {
      Toast.show("Something went wrong", Toast.LONG);

    } else {
      Toast.show("Please scan valid QR", Toast.LONG);
handleScreenNavigation("MainAdd")
    }
  };

  scanAgain = () => {
    this.setState({ scan: true, ScanResult: false });
  };

  render() {
    const { height } = this.state;

    let newStyle = {
      height,
    };
    let newStyleSecretKey = {
      height,
    };
    return (
      <SafeAreaView>
      <KeyboardAvoidingView
        behavior={Platform.OS === "ios" ? "padding" : null}
        style={{ flex: 1 }}
      >
           {/* <Screen
            style={styles.mod1}
            statusBar={"light-content"}
            variant={true}
            showMenu={false}
            onNavigate={this.props.navigation}
          >
                 <UniversalNavigationHeader
                hideBack={false}
                goBack={this.props.navigation.goBack}
              /> */}
        <View style={styles.scrollViewStyle}>
          <Fragment>
            {true && (
              <QRCodeScanner
                reactivate={false}
                showMarker={true}
                ref={(node) => {
                  this.scanner = node;
                }}
                cameraStyle={styles.cameraView}
                onRead={this.onSuccess}
          //       topContent={
          //         <View style={{zIndex:9999,width:AppStore.screenWidth,marginTop:Platform.OS === 'ios'?STATUSBAR_HEIGHT:0 }}>
          // <TouchableOpacity
          //   underlayColor={"none"}
          //   style={{ padding:  20, }}
          //   onPress={() => this.props.navigation.goBack()}
          // >
          //   <Image
          //     style={{ width: wRem * 12, height: hRem * 21, }}
          //     source={Iconpack.GLOBAL_BACK_BUTTON}
          //   />
          // </TouchableOpacity>                  
          // </View>
          //       }
                bottomContent={
                  <View style={styles.bottomContainer}>
                    <TouchableOpacity
                      style={styles.tapStyle}
                      onPress={() => this.setState({ isShow: true })}
                      onLongPress={() => this.setState({ scan: false })}
                    >
                      <Text style={styles.tapText}>Have a Key? Tap Here</Text>
                    </TouchableOpacity>
                  </View>
                }
              />
            )}
          </Fragment>

          <Modal
            animationType="slide"
            transparent={true}
            visible={this.state.isShow}
            onRequestClose={() => {
              this.setState({ isShow: false });
            }}
          >
            <KeyboardAvoidingView
              behavior="position"
              enabled
              // style={{paddingBottom:30}}
            >
              {this.bottomModal(newStyle, newStyleSecretKey)}
            </KeyboardAvoidingView>
          </Modal>
          {/* </View> */}
        </View>
        {/* </Screen> */}
      </KeyboardAvoidingView>
      </SafeAreaView>
    );
  }
}

export default Scan;

somehow i have converted in my branch but its not working as before I have put as my best to convert the code but lots of errors i am getting pls help me out.

HTML5 datalist: Show all options in dropdown when arrow clicked

There are a few solutions out there to display all the options in a datalist dropdown when a value is set and the down arrow is clicked. But none of them dealt with the case when a placeholder was already set initially.

I have therefore adapted a solution so that the initial placeholder is restored.

How it works:

  • Down arrow clicked: Set a placeholder with the input value and clear the input value
  • On mouseenter event: Save the original/initial placeholder value
  • On mouseleave event: Restore the input value and restore the initial
    placeholder, if the input value is blank.

My question is, if you see any flaws or unhandled cases in this code.

https://jsfiddle.net/Smolo/1y9mne2o/

function dlRestoreValue(i) {

    let t = $('#' + i);
    if (t.val() === '') {

        if (t.attr('org-placeholder') !== t.attr('placeholder')) {
            t.val(t.attr('placeholder'));
        }

        t.attr('placeholder', '');
        if (t.val() === '') {
            t.attr('placeholder', t.attr('org-placeholder'));
        }
      
    }

}

function dlShowAllOnArrowClick(i) {

    $('#' + i)
        .on('click', function(e) {

            let t = $(this);
            if ((t.width() - (e.clientX - t.offset().left)) < 14) {
                if (t.val() !== "") {
                    t.attr('placeholder', t.val());
                    t.val('');
                }
            } else {
                dlRestoreValue(i)
            }
        })

    .on('mouseleave', function() {
        dlRestoreValue(this.id);
    })


    .on('mouseenter', function() {
        if (!$(this).is("[org-placeholder]")) $(this).attr('org-placeholder', $(this).attr('placeholder'));
    })

}


dlShowAllOnArrowClick('favcolors');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Favorite color:
  <input type="text" id="favcolors" list="colors" placeholder="Pick a color">
  <datalist id="colors">
   <option value="Blue">
   <option value="Brown">
   <option value="Cyan">
   <option value="Green">
   <option value="Orange">
   <option value="Pink">
   <option value="Purple">
   <option value="Red">
   <option value="Yellow">
  </datalist>

Updating date in Javascript

I’m trying to create a simple “availability schedular” from scratch using Python, Javascript and a bit of Bootstrap (and eventually Django). I know a bit of Python but am new to Javascript.

Project is on fiddle here:
https://jsfiddle.net/surista/a85y7x31/21/

I am trying to show just one week at a time (Sun – Sat), with three header rows: First header is current month and year based on the Sunday of week currently being shown, second row the days of the week, third row is the dates. Below that I have Previous and Next buttons to move forward / backward a week.

When the page is launched, it defaults to the initial week starting from the most recent Sunday, the table and dates are created dynamically. I have this working fine.

today = new Date();

This is used as the basis for initially populating the table with the current week. Right nowe, if you launch the page, today is ‘Mon Dec 27 2021’, and the table shows the current week from the most recent Sunday – ie, Sun Dec 26 2021.

I have three functions that move the week back and forth:

function addDays(dateObj, numDays) {
  dateObj.setDate(today.getDate() + numDays);
  return dateObj;
}

function nextWeek() {
  today = addDays(new Date(), 7);
  showWeek(today);
}

function previousWeek() {
  today = addDays(new Date(), -7);
  showWeek(today);
}

Clicking ‘Previous’ a few times updates fine until Sun Nov 28, and then the month flipping back seems to break it. Ditto going forward with Next. If I go Next, then Previous, I should end up where I started, instead it goes to Sun Jan 2 (as it should) then Sun 21 Nov.

Basically it seems to work perfectly until the month changes. I have a function that I use to pull the days of the month:

function daysMonth(xMonth, xYear) {
  daysInCurrentMonth = 32 - new Date(xYear, xMonth, 32).getDate();
  return daysInCurrentMonth;
}

I’ve tested this and it seems to be working exactly as expected, and I’m always passing in the current base date, so not sure why this wouldn’t be working.

Any thoughts on what I should be looking at?

Error in putting ImageView component within View component

When I’m putting ImageView component within View component, I am getting the error: Error: Text strings must be rendered within a component. I don’t understand what is wrong over here. Below is the code snippet:

import React from 'react';
import { View, Image, ScrollView, TouchableOpacity, Modal, Text } from 'react-native';
import styles from './cameraStyles';
import ImageView from "react-native-image-viewing";

export default ({captures=[], lflagImage=false}) => {
    const [flagImage, setflagImage] = React.useState(lflagImage);
    return (
        <ScrollView horizontal={true} style={[styles.bottomToolbar, styles.galleryContainer]}>
            {captures.map(({ uri }) => (
                <View style={styles.galleryImageContainer} key={uri}>
                    <TouchableOpacity onPress={()=> {setflagImage(prevData => !prevData)}}>
                        <Image source={{ uri }} style={styles.galleryImage}/>                       
                    </TouchableOpacity>
                    <ImageView
                        images={captures}
                        imageIndex={0}
                        visible={flagImage}
                        onRequestClose={() => setflagImage(prevData => !prevData)}
                    />
                </View>
            ))}
        </ScrollView>
    )
}

Phaser 3 game shirt on the top, pants at the back

so I am creating a game using Phaser 3, with a little treat at the end which is to allow people to customize the characters by selecting the outfits that they want. I am able to finish up the customizing, but now I was wondering if it is possible to have the shirt to always be at the top layer, and the pants to be behind the shirt. You are able to select the shirt or pants first, but whatever is selected second would overlap the first like the image below

enter image description here

I would like for it to be the shirt to always be on top, and the pants to always be below, regardless of whether you select the shirt first or the pants first, like the image below

enter image description here

The code below is the code for when the character has any piece of clothing on. Do help me out if possible I would really appreciate it.

tabs.getElement("panel").on(
      "cell.down",
      function (cellContainer, cellIndex, pointer) {
      console.log(playercoin);
        const name = filter.toLowerCase() + "Image" + cellIndex;
        localStorage.setItem("wa", name);
        let itemToRemove;
        for (let i = 0; i < playerContainer.length; i++) {
          const containerItem = playerContainer.list[i];
          if (containerItem.data.get("name") === filter.toLowerCase()) {
            itemToRemove = containerItem;
            itemToRemove.cost = containerItem.data.get("cost");
            break;
          }
        }
        const costUrl = cellContainer.data.get("costUrl");
        const newCost = GetCostFromUrl(costUrl);

React: TextField onchange

I have a list of data that lists on the collapse, I just want to display in my collapse what i put on my Textfield

const onChangeLocation = (locations) =>{
    console.log(locations)
  }

   <TextField
      size="small"
      fullWidth
      onChange={onChangeLocation}
      variant="standard"
      placeholder="Search Locations"
      onFocus={openSearch}
      value={searchParameter}
      }}
    />

  <Collapse in={viewLocationList} sx={{ my: '2px' }}>
    <Box className="rounded-scrollbar widget-result-container">
      {locations.map((location, index) => (
        <LocationWidgetItem
          key={index}
          location={location}
          onClickLocation={setActiveLocation}
        />
      ))}
    </Box>
  </Collapse>

onClick not working from a mapped component

I have a Player component that maps several song names + images to several Song components.
My Player component code looks like this:

      return (
        <div className="App">
          <div className="main-wrapper">
            {props.foundASong && 
            <div className="song_container">{props.songs.map((object, i) => <Song object={object} key={i} />)}</div>
            }
            <div className="background" style={backgroundStyles} />{" "}
          </div>
        </div>
      );

and my Song code looks like this:

import React, { Component } from "react";

import "./Player.css";
import "./Song.css";

class Song extends Component {
  constructor(props) {
    super(props);
    this.state = {
      clicked: false
    };

    this.changeBackground = this.changeBackground.bind(this);
    this.handleClick = this.handleClick.bind(this);

  }

  handleClick() {
    this.setState(prevState => ({
      clicked: !prevState.clicked
    }));
    console.log("clicked");
  }


  render(props){
    return (
      <div>
        <button onClick={() => this.handleClick}>Click me!</button>
        <div className="song_box"> 
            <img src={this.props.object.album.images[0].url} />
          <div>{this.props.object.name}</div> 
        </div>
      </div>
    );
    }
}

export default Song;

But for some reason, nothing happens when I click any of the buttons. Any ideas why?

Fortify Header Manipulation Cookies Using JavaScript?

I have the following code which is throwing an error in the Fortify tool:

const headerCopy = (req, resp, next) => {
    if (req.headers["iv-user"]) {
        resp.setHeader("iv-user", req.headers["iv-user"]);
        resp.setHeader("token", process.env.TOKEN);
    }
    if (req.get("referer")) {
        resp.setHeader("referer", req.get("referer"));
    }
    next();
}


app.use(headerCopy, express.static(path.join(__dirname, './build')));

app.get('*', headerCopy, function (req, res) {
    res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

app.listen(port, () => {
    console.log(`MainApp listening at http://localhost:${port}`)
})

The error in the Fortify tool complains with the following msg:

The method headerCopy() in MainApp.js includes unvalidated data in an
HTTP response header on line 11. This enables attacks such as
cache-poisoning, cross-site scripting, cross-user defacement, page
hijacking, cookie manipulation or open redirect.

Can someone please help me with this error?

Addon or Replace strapi existing rich text editor

There is a CKEditor which is implemented well with Strapi Version3 but not able to setup with Version4 of Strapi . Is it possible to implement in version4 or can addon extra components setup with version4 in existing rich text editor ?

Here is the implementation with strapi version 3
[https://strapi.io/blog/how-to-change-the-wysiwyg-in-strapi][1]

React redux call multiple actions synchronously

enter image description here

In-store I have an array called visited:[]. In a function called changeInfo first I need to clear the array and then add an item to the array.

 const changeInfo = (value) => {
    dispatch(clearVisited());
    console.log("before visited", visited);
    dispatch(addToVisited(value));
    console.log("after visited", visited);
  };

Some can argue that I can have an action type clearAndInsert and reducer like this

 case CLEAR_AND_INSERT:
      return {
        visited: [action.payload],
      };

But this is not wanted I want. I want to dispatch clearVisited and wait until after it clears the array and after that dispatch addToVisited.Want I am getting for the console logs for changeInfo is strange.

enter image description here

HOW CAN I CALL TWO ACTIONS SYNCHRONOUSLY IN REACT?