Mock multiple capsuled GraphQL requests in JEST

I will test my redux-sagas, and stuck by mocking my api requests.
The scenario is like this:

I have a GraphQL API and each request is capsuled (axios) in a requestApiUtil.

like

/path/api/sampleOneApiRequest.js

import { requestApi } from 'utils';

export const sampleOneApiRequest = ({ arg1 }) => requestApi.query(`
  sampleData {
    id
  }
`)

/path/api/sampleTwoApiRequest.js

import { requestApi } from 'utils';

export const sampleTwoApiRequest = ({ arg1 }) => requestApi.query(`
  otherSampleData {
    id
  }
`)

/path/api/index.js

export * from './sampleOneApiRequest';
export * from './sampleTwoApiRequest';

the saga that i like to test, looks like this

/path/redux/saga/sampleSaga/sampleSaga.js


import { all, put } from 'redux-saga/effects';
import { successAction, failureAction } from 'path/redux/action';
import { sampleOneApiRequest, sampleTwoApiRequest } from 'path/api';

export function* sampleSaga({ payload }) {
  const switch = payload ? payload.switch : false;
  try {
    let response;
    if (switch) {
      response = (yield sampleOneApiRequest());
    } else {
      response = (yield sampleTwoApiRequest());
    }

    if (response.errors) {
      return yield put(failureAction(response.errors));
    }

    yield put(successAction(response.data));
  } catch (error) {
    yield put(failureAction(error));
  }
}

Now to the problem, my test to the saga looks like this:

/path/redux/saga/sampleSaga/sampleSaga.test.js

import { sampleSaga } from './sampleSaga;
import { sampleOneApiRequest, sampleTwoApiRequest } from 'path/api';
import { successAction } from 'path/redux/action';
import { put } from 'redux-saga/effects';

jest.mock('path/api', () => ({
  sampleOneApiRequest: async () => { id: 'sample1' },
  sampleTwoApiRequest: async () => { id: 'sample2' }
}));

descripe('test sampleSaga', () => {
  
  if('test sampleSaga switch false', () => {
    const generator   = sampleSaga({ payload: { switch: false } });
    const apiResponse = { data: { id: 'sample1' } };
    
    expect(generator.next().value).toEqual(sampleOneApiRequest());
    expect(generator.next(apiResponse).value).toEqual(put(successAction(apiResponse)))
  });
  
  if('test sampleSaga switch true', () => {
    const generator   = sampleSaga({ payload: { switch: true } });
    const apiResponse = { data: { id: 'sample2' } };
    
    expect(generator.next().value).toEqual(sampleTwoApiRequest());
    expect(generator.next(apiResponse).value).toEqual(put(successAction(apiResponse)))
  });

});

The problem is, that the second triggert saga, generate a request to the backend, but i aspect the the request to the backend will be mocked. The frist one will mocked perfectly, when i change the order of both tests, always still the second one (in order) will be call to the backend. When i comment out the first test, the second works fine.

I don’t know what its wrong.

Impossible to retrieve an opportunity by name with form with LWC

Creation of a form that allows you to find an opportunity by name and display the necessary information about the opportunity in a table.

So I’m using Lightning Web Component to create a form to retrieve the opportunity when the user search by name.
The result found must return the opportunity fields (StageName, Amount…) with a tab or a datatable (I use a tab)

Important: LWC will be displayed on all accounts in the related section or at home.
The result is not correct, it returns the condition to false” No results “

<template>
    <lightning-card title="Liste d'opportunités du compte" icon-name="standard:opportunity">

        <div class="slds-p-horizontal_small">
            <!--BOUTON SEARCH-->
            <lightning-input type="search" label="Rechercher" value={searchOppo} onchange={handleKeyChange}
                placeholder="Search..."></lightning-input>
            <lightning-button label="Search" onclick={handleSearch} variant="brand"></lightning-button>
        </div>
        <div if:true={messageResult} class="slds-p-horizontal_small">
            <p class="slds-p-horizontal_small">No result found</p>
        </div>
        <!--CONDITIONNEMENT TO DISPLAY RESULTS-->
        <template if:true={showSearchValues}>
            <div class="slds-p-horizontal_small">
                <ul class="slds-list_vertical-space">
                    <template for:each={opportunityList} for:item="actObj">
                        <li key={actObj.Id} onclick={handleParentSelection} data-value={actObj.Id}
                            data-label={actObj.Name} class="slds-p-around_small slds-text-link" style="cursor:pointer;">
                            {actObj.Name} </li>
                    </template>
                </ul>
            </div>
          
            <div class="slds-table">
                <table class="slds-table slds-table_bordered slds-table_cell-buffer">
                    <thead>
                        <tr class="slds-line-height_reset">
                            <th class="slds-text-title_caps" scope="col"> Name </th>
                            <th class="slds-text-title_caps" scope="col"> Stage </th>
                            <th class="slds-text-title_caps" scope="col"> Close Date </th>
                            <th class="slds-text-title_caps" scope="col"> Amount </th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr class="slds-hint-parent">
                            <td data-label="Name">{selectedOpportunity.Name}</td>
                            <td data-label="Stage">{selectedOpportunity.StageName}</td>
                            <td data-label="Close Date">{selectedOpportunity.CloseDate}</td>
                            <td data-label="Amount">{selectedOpportunity.Amount}</td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </template>
    </lightning-card>
</template>
import { LightningElement, wire, track, api } from 'lwc';

import findOpportunityByAccount from '@salesforce/apex/OpportunitySearchControllerLWC.findOpportunityByAccount';

export default class displayOpportunityList extends LightningElement {

    @track opportunityName ='';

    @track opportunityList;

    @track opportunityId;

    @track messageResult = false;

    @track showSearchValues =false;

    @track selectedOpportunity;

    @api accountId;

    accountId;

    opportunities = [];

    error;

    @wire(findOpportunityByAccount, { accountId: '$accountId' }) opportunities;

    wiredOpportunities({ error, data }) {

        if (data) {

            this.opportunityList = data;

            this.showSearchValues = data.length > 0;

            this.messageResult = data.length === 0 && this.opportunityName !== '';

        } else if (error) {

            console.log(error);

        }

    }

    // METHOD //

 handleKeyChange(event) {

    this.opportunityName = event.target.dataset.label;

}
handleSearch() {
    // Perform some validation if needed
    findOpportunityByAccount({ 
        accountId: this.accountId,
        opportunityName: this.opportunityName 
    })
    .then(result => {
        this.opportunityList = result;
        this.showSearchValues = result.length > 0;
        this.messageResult = result.length === 0 && this.opportunityName !== '';
        this.error = undefined;
    })
    .catch(error => {
        this.error = error;
        this.opportunityList = [];
        this.showSearchValues = false;
        this.messageResult = true; // Show message in case of error
    });
}


}
public with sharing class OpportunitySearchControllerLWC {
    @AuraEnabled(cacheable=true)
    public static List<Opportunity>  findOpportunityByAccount(String opportunityName) {
        // Filter opportunities based on the opportunityName
        return [SELECT Id, Name, StageName, Amount FROM Opportunity WHERE Name LIKE :('%' + opportunityName + '%')];
    }
}

npm ERR! enoent ENOENT: no such file or directory, lstat ‘C:UsersAdminAppDataRoamingnpm

npm ERR! code ENOENT
npm ERR! syscall lstat
npm ERR! path C:\Users\Admin\AppData\Roaming\npm
npm ERR! errno -4058
npm ERR! enoent ENOENT: no such file or directory, lstat 'C:\Users\Admin\AppData\Roaming\npm'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent

npm ERR! A complete log of this run can be found in: C:\Users\Admin\AppData\Local\npm-cache_logs\2024-03-06T18_29_49_436Z-debug-0.log 

Send recorder data in chunks to an API

I want to have a recorder running on a website where every few seconds a post request is send to an api call to transcribe it.

However, the first time it works, but after that it will give this error:

“Error code: 400 – {‘error’: {‘message’: ‘The audio file could not be decoded or its format is not supported.’, ‘type’: ‘invalid_request_error’, ‘param’: None, ‘code’: None}}”

I tried to give it every time an temporary file name, but that did not work. I tried making the interval longer or shorter.

let mediaRecorder;
let audioChunks = [];
let sendInterval;

document.getElementById('recordBtn').addEventListener('click', async () => {
    if (mediaRecorder && mediaRecorder.state === "recording") {
        mediaRecorder.stop();
        clearInterval(sendInterval); // Clear the interval when stopping
        document.getElementById('recordBtn').textContent = 'Start Recording';
    } else {
        try {
            const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
            mediaRecorder = new MediaRecorder(stream);
            mediaRecorder.ondataavailable = event => {
                if (event.data.size > 0) {
                    audioChunks.push(event.data);
                    console.log('Chunk received:', event.data.size);
                }
            };

            // Start recording with timeslice to ensure chunks are generated at regular intervals
            mediaRecorder.start(3000);
            document.getElementById('recordBtn').textContent = 'Stop Recording';
            var x = 1;

            const sendAudioChunks = async () => {
                if (audioChunks.length > 0) {
                    console.log('Sending chunks:', audioChunks.length);
                    const audioBlob = new Blob(audioChunks, { 'type': 'audio/wav' });
                    audioChunks = []; // Clear chunks after sending
                    const formData = new FormData();
                    formData.append('audio_file', audioBlob, 'audio.wav');

                    try {
                        // Inside your try block within sendAudioChunks
                        const response = await fetch('/transcribe', {
                            method: 'POST',
                            body: formData,
                        });
                        if (!response.ok) {
                            // Log or handle non-200 responses here
                            console.error('Server responded with non-200 status:', response.status);
                        }

                        const data = await response.json();
                        console.log('Server response:', data);
                        document.getElementById('transcriptionContainer').textContent = data.transcription || 'Transcription failed or was empty.';


                    } catch (error) {
                        console.error('Failed to send audio chunks:', error);
                    }
                } else {
                    console.log('No chunks to send');
                }
            };

            clearInterval(sendInterval);
            sendInterval = setInterval(sendAudioChunks, 3000);

            mediaRecorder.onstop = async () => {
                clearInterval(sendInterval); // Clear the interval when stopping
                await sendAudioChunks(); // Send any remaining chunks
            };
        } catch (error) {
            console.error('Error accessing media devices:', error);
        }
    }
});

Why is it that my javascript is not executing well? I used the sweetalert that pops-up but by then it is not triggering when i click the button

// Perform AJAX request
$.ajax({
url: ‘/Account/Register’,
method: ‘POST’,
data: formData,
enctype: ‘multipart/form-data’,
processData: false,
contentType: false,
success: function (response, status, jqXHR) {
console.log(response); // Log the response to see what the server returns

     // Check if the response contains a success property
     if (response.success) {
         // Display success pop-up
         Swal.fire({
             title: 'Registration Successful',
             icon: 'success',
             showConfirmButton: true
         }).then(function () {
             // Redirect to the appropriate page
             window.location.href = '/Home/Index';
         });
     } else {
         // Handle cases where registration failed
         Swal.fire({
             title: 'Registration Failed',
             text: response.message || 'An error occurred during registration.',
             icon: 'error',
             showConfirmButton: true
         });
     }
 },
 error: function (jqXHR, textStatus, errorThrown) {
     // Log the error for debugging
     console.error(textStatus, errorThrown);

     // Display error message using SweetAlert
     Swal.fire({
         title: 'Registration Failed',
         text: 'An error occurred during registration.',
         icon: 'error',
         showConfirmButton: true
     });
 }

});

Access javascript methods [closed]

I have an object with hundreds of functions, variables… From all of these only two are accessible and these start with this ex: this.methodName().

Is there a way to access the other methods using prototype? I see all the methods in Scopes[1] 0: Global

Here is the code:
https://gist.github.com/zamanuhina/74e636d705e5fe8a010e21550cf5e657

function Playerjs(options) {} creates an object and I want to be able to access other methods in this function.

Uncaught TypeError: Cannot read properties of undefined (reading ‘logopath’)

Can someone please help me with understanding what is wrong with my code here?

I keep getting an uncaught TypeError regarding my logoPath, but it is defined correctly. The page is www.eastvanbaseball.com/standings.

Uncaught TypeError: Cannot read properties of undefined (reading ‘logopath’)

This is a function that takes JSON data and computes standings. There is a bunch of additional logic after what I have shared, I can update with that if helpful, but I assume what i shared is where the issue lays. Thank you!

Below is my code:

<div class="selectGroupWrapper">
    <div class="selectGroupList">
        <select id="selectStandingsYear" onchange="getStandings()">
            <option value="2023" selected>2023</option>
            <option value="2022">2022</option>
            <option value="2021">2021</option>
            <option value="2019">2019</option>
            <option value="2018">2018</option>
            <option value="2017">2017</option>
        </select>
    </div>
</div>

<div id="standings_table"></div>
<div id="ringers_table"></div>

<script>
    $(document).ready(function(){
      $("select").trigger('change');
    });

     var teamDb = [
        { fullName: "Chinatown Cobras", lastName: "Cobras", abbr: "CHN", logoPath: "Cobras.png", participating: [true, true, true, false, true, true, true] },
        { fullName: "Clark Park Brawlers", lastName: "Brawlers", abbr: "CP", logoPath: "Brawlers-2019.png", participating: [true, true, true, false, false, true] },
        { fullName: "East Van Black Sox", lastName: "Black Sox", abbr: "SOX", logoPath: "Black_Sox.png", participating: [true, true, true, false, true, true, true] },
        { fullName: "Blood Alley Butchers", lastName: "Butchers", abbr: "BAB", logoPath: "butchers_2.png", participating: [false, false, false, false, false, false, false] },
        { fullName: "Gastown Gaolers", lastName: "Gaolers", abbr: "GAS", logoPath: "Gaolers.png", participating: [true, true, true, false, true, true, false] },
        { fullName: "Mt Pleasant Murder", lastName: "Murder", abbr: "MT", logoPath: "Murder.png", participating: [true, true, true, false, false, true, true] },
        { fullName: "Railtown Spikers", lastName: "Spikers", abbr: "RT", logoPath: "Spikers_alt.png", participating: [true, true, true, false, true, true, true] },
        { fullName: "Strathcona Stevedores", lastName: "Stevedores", abbr: "STR", logoPath: "Stevedores.png", participating: [true, true, true, false, false, true, true] },
        { fullName: "Sunrise Cosmos", lastName: "Cosmos", abbr: "COS", logoPath: "cosmos.png", participating: [true, true, true, false, true, true, true] },
        { fullName: "Sunset Stilettos", lastName: "Stilettos", abbr: "SET", logoPath: "Stilettos.png", participating: [true, true, true, false, false, true, true] },
        { fullName: "Vancouver Isotopes", lastName: "Isotopes", abbr: "VAN", logoPath: "isotopes.png", participating: [true, true, true, false, false, false, false] },
        { fullName: "Little Mountain Blasters", lastName: "Blasters", abbr: "LM", logoPath: "blasters.png", participating: [false, false, true, false, true, true, true] },
        { fullName: "Brewery Creek Mashers", lastName: "Mashers", abbr: "BC", logoPath: "mashers.png", participating: [false, false, false, false, true, true, true] },
        { fullName: "EVBL Ringers", lastName:"Ringers", abbr:"RNG", logoPath:"ev.png", participating: [false, false, false, false, false, true, false] }];

   var yearToFilePath = {
        "2023": "assets/schedule/evbl_schedule_2023.json",
        "2022": "assets/schedule/evbl_schedule_2022.json",
        "2021": "assets/schedule/evbl_schedule_2021.json",
        "2019": "assets/schedule/evbl_schedule_2019.json",
        "2018": "assets/schedule/evbl_schedule_2018.json",
        "2017": "assets/schedule/evbl_schedule_2017.json"
    };

   var logoRootURL = "/assets/team_logos/";
   var ringerNameData = {fullName:"EVBL Ringers",lastName:"Ringers",abbr:"RNG",logoPath:"ev.png"};
   var tieCheck, numTies, c;
   var useLogos = true;
   var tableContent, ringerTableContent;
   
   function getStandings() {

        var visTeam, visAbbr, visLogo, visScore, homeTeam, homeAbbr, homeLogo, homeScore;
        var teamNameData = [],
            teamRecords = [],
            teamSort = [],
            obj,
            getYear = document.getElementById("selectStandingsYear").value,
            season = getYear - 2017,
            teamSeasonIndex = 0;
      for (let i = 0; i < teamDb.length; i++) {
    console.log("Team Object:", teamDb[i]);
    if (teamDb[i].participating[season]) {
        obj = teamDb[i];
        if (Array.isArray(teamDb[i].logoPath)) { // Check if logoPath is an array
            console.log("Logo Path Array:", teamDb[i].logoPath);
            for (let j = 0; j < teamDb[i].logoPath.length; j++) {
                if (parseInt(teamDb[i].logoPath[j].yearStart) <= getYear) {
                    obj.logoPath = teamDb[i].logoPath[j].useLogo;
                }
            }
        } else { // Handle the case where logoPath is not an array
            obj.logoPath = teamDb[i].logoPath; // Assign logoPath directly
        }
        console.log("Modified Team Object:", obj);
        obj.index = teamSeasonIndex;
        teamNameData[teamDb[i].abbr] = obj;
        teamSeasonIndex++;
        obj = {
            team: teamDb[i].abbr,
            gp: 0,
            w: 0,
            l: 0,
            t: 0,
            rs: 0,
            ra: 0,
            strkW: 0,
            strkL: 0,
            strkUnb: 0,
            strkWnl: 0,
            lastFive: '',
            lastW: 0,
            lastL: 0,
            lastT: 0,
            rng_gp: 0,
            rng_w: 0,
            rng_l: 0,
            rng_t: 0,
            rng_rdiff: 0
        };
        teamRecords.push(obj);
        obj = {
            pct: 0,
            p_pct: 0.5,
            runDiff: 0,
            rngwpct: 0.5,
            totRunDiff: 0,
            w_l: 0
        };
        teamSort.push(obj);
    }
}

How to do this I am not a pro develper [closed]

Hello there I got an query

I didn’t that there are my

Here are many this I trasdsd ;lkjsd and ther

Please do a final review of your question and then post.
Please do a final review of your question and then post.Please do a final review of your question and then post.Please do a final review of your question and then post.Please do a final review of your question and then post.Please do a final review of your question and then post.Please do a final review of your question and then post.Please do a final review of your question and then post.v

Clicking the current audio button doesn’t pause the previous audio that was already being played

import React, { useState, useRef } from 'react';
const PlayAudio = ({ content }) => {
    const [isPlaying, setIsPlaying] = useState(false);
    const [previous, setPrevious] = useState({})
    const audioRef = useRef(null);
    const previousRef = useRef(null);


    const togglePlay = () => {
        previousRef.current = audioRef.current;
        if (!isPlaying) {
            previousRef.current.pause();
            audioRef.current.play();
        } else {
            audioRef.current.pause();
        }
        setIsPlaying(!isPlaying);
    };


    return (
        <div>
            {content.audio && (
                <audio ref={audioRef} src={content.audio}></audio>
            )}
            {content.audio && (
                <img
                    src="play.svg"
                    alt=""
                    onClick={togglePlay}
                    className="cursor-pointer"
                />
            )}
        </div>
    );
};

export default PlayAudio;

Clicking the audioRef doesn’t pause the previous audio that is being played on the website.

I tried doing some tweaks but none of them works! How to achieve that functionality?
Any Idea?

Using Constant while calling a function in a conditional

I am trying to get the end users location and if they are within a service area (poly) let them know. I have managed to get everything functional except the conditional for the output.

I am grabbing geolocation with the following:

if (navigator.geolocation) {
  navigator.geolocation.getCurrentPosition(function(position) {
    const latitude = position.coords.latitude;
    const longitude = position.coords.longitude;
    console.log(`Latitude: ${latitude}, Longitude: ${longitude}`);
  });
} else {
  console.log("Geolocation is not supported by this browser.");
}

My poly detection is:

polygone=   [
    [43.163834,-84.134153],
    [43.163834,-83.420042],
]

function isPointInPoly(point, vs) {
    var x = point[0], y = point[1];
    var inside = false;
    for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
        var xi = vs[i][0], yi = vs[i][1];
        var xj = vs[j][0], yj = vs[j][1];
        var intersect = ((yi > y) != (yj > y))
            && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
        if (intersect) inside = !inside;
    }

    return inside;
};

What I have tried:

if(isPointInPoly([ $latitude, $longitude ], polygone) === true) {
    $("#output").html('Yup');
} else {
    $("#output").html('Nope');
}

I’m not sure if I’m going about this correctly, but I have looked up ‘using const in conditionals’ and a few other term, to no avail.

I set up a fiddle here as well.

In the end I would just like to show a message to users in the area, and another to users outside the area.

unable to get the results on spreadsheet despite running a code and it saying execution completed

Hi guys I am a total noob please if sombody can help

I have a live portfolio in my spread sheet so IN Cell E32 the % change in portfolio gets updated on real time basis, now I want to get the % change every day so I copied a code

I went to my google sheet, clicked on extension and then on add script

Now there I pasted my code and clicked on run, I did this some 10 times but nothing is happening on my google sheet, can somebody please help,

I also dont know how many times I might have run the code so I need help in deleting all these codes executing as well

the code is as follows
enter image description here

also if sombody can explain me, once this code runs how do I run another code because every time I open this add script I can se the old code only, dont know how to add a new one

I have explained everything above

Populating element with thousands of data, freezes the webpage. How do I fix this?

homepage/index.php

var form = document.createElement("form");
form.id = "survey-form";
var elements = [
       {
           type: "select",
           label: "Send to employee",
           id: "empno",
           options: [] // Options will be populated dynamically
       },
];
elements.forEach(function (element) {
       var wrapper;
       var label = document.createElement("label");
       label.className = "form-label";
       label.textContent = element.label;
       if (element.type === "select") {
           input = document.createElement("select");
           input.id = element.id;
           input.className = "user-input";

           form.appendChild(label);
           form.appendChild(input);
           fetchOptionsUsingWorker(input, element.options);

           $(document).ready(function() {
               $('#' + element.id).select2();
           });
       }
});

function fetchOptionsUsingWorker(selectElement) {
    var worker = new Worker('optionsWorker.js');

    worker.addEventListener('message', function(e) {
        if (e.data.type === 'optionsData') {
            var optionsData = e.data.data;
            populateSelectWithOptions(selectElement, optionsData);
        } else if (e.data.type === 'error') {
            console.error('Error fetching options data:', e.data.message);
        }
    });

    worker.postMessage('fetchOptions');
}

function populateSelectWithOptions(selectElement, optionsData) {
    selectElement.innerHTML = '';
    optionsData.forEach(function (option) {
        var optionElement = document.createElement("option");
        optionElement.value = option;
        optionElement.text = option;
        selectElement.appendChild(optionElement);
     });
}

homepage/optionsWorker.js

function fetchOptionsFromServer() {
    return new Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "../backend.php", true);
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xhr.onload = function () {
            if (xhr.status === 200) {
                var data;
                if (xhr.responseText === "No data found") {
                    data = ["No data found"];
                } else {
                    data = JSON.parse(xhr.responseText);
                }
                resolve(data);
            } else {
                reject(xhr.statusText);
            }
        };
        var data = "input=get_options";
        xhr.send(data);
    });
}

self.addEventListener('message', async function(e) {
    if (e.data === 'fetchOptions') {
        try {
            const optionsData = await fetchOptionsFromServer();
            self.postMessage({ type: 'optionsData', data: optionsData });
        } catch (error) {
            self.postMessage({ type: 'error', message: error });
        }
    }
});

As there are thousands of data being fetched from the server, I used webworkers to run the code which fetches the data in the background thread, otherwise the webpage keeps on freezing. But even after using webworkers, it was of no good, as the webpage still freezes. Where am I going wrong? Please guide me.

HTML borders for dynamic data

I have a below data, I’m expecting to generate a border dynamically for each data set,


<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>Subject</th>
      <th>Average Marks</th>
      <th>Name</th>
      <th>Marks Scored</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>Maths</td>
      <td>80</td>
      <td>Student 1</td>
      <td>90</td>
    </tr>
    <tr>
      <th>1</th>
      <td>Maths</td>
      <td>80</td>
      <td>Student 2</td>
      <td>70</td>
    </tr>
    <tr>
      <th>2</th>
      <td>Maths</td>
      <td>80</td>
      <td>Student 3</td>
      <td>80</td>
    </tr>
    <tr>
      <th>3</th>
      <td>English</td>
      <td>80</td>
      <td>Student 1</td>
      <td>90</td>
    </tr>
    <tr>
      <th>4</th>
      <td>English</td>
      <td>80</td>
      <td>Student 2</td>
      <td>70</td>
    </tr>
  </tbody>
</table>

Actual table,

enter image description here

Expectation,

enter image description here

Any suggestion would be appreticiated

Coding a WooCommerce Multi-Step Checkout

I’ve been trying to get some code to work but doesn’t seem to be firing. Think I might be missing something between versions.

I’m using the base checkout from WooCommerce plugin. Text appears at the bottom of checkout instead of buttons, but that might be a theme issue and haven’t added a CSS. Pretty sure I’ve enqueued the script right from everything I can find.

Here’s what I have:

In Function.php

add_action( 'woocommerce_after_checkout_form', 'step_controls');
function step_controls() {
    echo '
        <div class="step_controls_container">
            <a class="btn-primary step_back_to_cart" href="'.site_url("/cart", "https").'">Back to Cart</a>
            <a class="btn-primary step_next">Next</a>
            <a class="btn-primary step_prev">Previous</a>
        </div>
    ';
}
//

function cart_steps() {
    wp_enqueue_script('jquery');
    wp_enqueue_script('cartsteps', get_stylesheet_directory_uri() . '/js/cart-steps.js');

} 
add_action( 'wp_enqueue_scripts', 'cart_steps' ); 

In custom JS file

var steps = [
    {
        name: 'Billing & Shipping Details',
        selector: '#customer_details'
    },
    {
        name: 'Order Review & Payment',
        selector: '#order_review'
    }
]
var activeStep;
// Adjust the array length to match zero-base
var stepsLengthAdjusted = steps.length - 1;

// Utility functions
function initSteps() {
    // Set first checkout step
    sessionStorage.setItem('checkout_step', '0');
}
function getCurrentStep() {
    return sessionStorage.getItem('checkout_step');
}
function showCurrentStep() {
    activeStep = getCurrentStep();
    // Loop through the steps and see which is currently active
    for (let i = 0; i < steps.length; i++){
        let stepSelector = steps[i].selector;
        if ( i != activeStep ) {
            // Hide if not the current step
            $(stepSelector).hide();
        } else {
            // Show the correct step div
            $(stepSelector).fadeIn();
            // Show or hide navigation  buttons as appropriate
            $('.step_next, .step_prev').show();
            if ( getCurrentStep() == stepsLengthAdjusted ) {
                // This is the last step, so remove next button
                $('.step_next').hide();
            }
            if ( getCurrentStep() == 0 ) {
                // This is the first step, so remove previous button
                $('.step_prev').hide();
            }
        }
    }
    // Always go to the top of the steps
    $("body").get(0).scrollIntoView();
}
function nextStep() {
    if ( getCurrentStep() < stepsLengthAdjusted ) {
        var nextStep = parseInt(getCurrentStep()) + 1;
        sessionStorage.setItem('checkout_step', nextStep);
        showCurrentStep();
    }
}
function previousStep() {
    if ( getCurrentStep() > 0 ) {
        var previousStep = parseInt(getCurrentStep()) - 1;
        sessionStorage.setItem('checkout_step', previousStep);
        showCurrentStep();
    }
}

// Initialise
if ( getCurrentStep() == null ) {
    initSteps();
}
// Always show the correct step
showCurrentStep();
// Navigation
$('.step_next').click(function() {
    nextStep();
});
$('.step_prev').click(function() {
    previousStep();
});
// Hide a elements not in parent containers!
$('h3#order_review_heading').hide();

// Flush the current step when navigating away from checkout to prevent customer confusion
if ( !$('body').hasClass('woocommerce-checkout') ) {
    initSteps();
}

$('body').on('checkout_error', function(){
    for (let i = 0; i < steps.length; i++){
        let stepSelector = steps[i].selector;
        let fields = stepSelector + ' p';
        $( fields ).each(function() {
            if ( $(this).hasClass('woocommerce-invalid') ) {
                sessionStorage.setItem('checkout_step', i);
                showCurrentStep();
                return false;
            }
        });
    }
});