Return the values ​of two scales in a tooltip (echarts barometer)

I tried to create a tooltip (echarts) that returns the values ​​associated with the two series present in a barometer. The first series has values ​​from 0 to 100 and the second from 0 to 60. The problem is that it is only considering the values ​​from 0 to 100, but not from 0 to 60.

This is my code:

const mychartspider1 = echarts.init(document.getElementById('gaugespiderinc1'));

function updateGaugeSpider1(value1, value2) {
  const option = {
    tooltip: {
      trigger: 'item',
      formatter: function(params) {
        if (params.seriesIndex === 0) {
          return params.seriesName + '<br>' + params.value.toFixed(2) + '%';
        } else if (params.seriesIndex === 1) {
          return params.seriesName + '<br>' + value2.toFixed(0);
        }
      }
    },
    series: [{
        type: 'gauge',
        min: 0,
        max: 100,
        splitNumber: 10,
        radius: '80%',
        axisLine: {
          lineStyle: {
            color: [
              [1, '#008cba']
            ],
            width: 3
          }
        },
        splitLine: {
          distance: -18,
          length: 18,
          lineStyle: {
            color: '#008cba'
          }
        },
        axisTick: {
          distance: -12,
          length: 10,
          lineStyle: {
            color: '#008cba'
          }
        },
        axisLabel: {
          distance: -40,
          color: '#008cba',
          fontSize: 20,
          fontFamily: 'Lato' // Adicionado fontFamily
        },
        anchor: {
          show: true,
          size: 20,
          itemStyle: {
            borderColor: '#000',
            borderWidth: 2
          }
        },
        pointer: {
          offsetCenter: [0, '10%'],
          icon: 'path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999 2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929 C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078 C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014 L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423 2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314 2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028 2089.24407,615.30999 2090.36389,615.30999 Z',
          length: '115%'
        },
        detail: {
          valueAnimation: true,
          precision: 1,
          formatter: '{value}%',
          padding: [2, 1, 5, 2],
          borderRadius: 5,
          color: '#333333',
          fontFamily: 'Lato',
          backgroundColor: '#92a192'
        },
        title: {
          offsetCenter: [0, '-50%'],
          fontFamily: 'Lato'
        },
        data: [{
            value: value1,
            name: 'PRESSURE1',
            title: {
              color: 'orange',
              offsetCenter: ['0%', '-50%'],
              fontFamily: 'Lato',
              fontWeight: 'bolder'
            },
            detail: {
              offsetCenter: ['-40%', '110%'],
              fontFamily: 'Lato',
              borderWidth: 3,
              borderColor: 'orange'
            },
            itemStyle: {
              color: 'orange',
              borderWidth: 1,
              borderColor: '#858383'
            }
          },
          {
            value: value2,
            name: 'PRESSURE2',
            title: {
              color: 'green',
              offsetCenter: ['0%', '-30%'],
              fontFamily: 'Lato',
              fontWeight: 'bolder'
            },
            detail: {
              offsetCenter: ['40%', '110%'],
              fontFamily: 'Lato',
              borderWidth: 3,
              borderColor: 'green',
              color: '#333333'
            },
            itemStyle: {
              color: 'green',
              borderWidth: 1,
              borderColor: '#858383'
            }
          }
        ]
      },
      {
        type: 'gauge',
        min: 0,
        max: 60,
        splitNumber: 6,
        axisLine: {
          lineStyle: {
            color: [
              [1, '#858383']
            ],
            width: 3
          }
        },
        splitLine: {
          distance: -2,
          length: 18,
          lineStyle: {
            color: '#858383'
          }
        },
        axisTick: {
          distance: 0,
          length: 10,
          lineStyle: {
            color: '#858383'
          }
        },
        axisLabel: {
          distance: 10,
          fontSize: 25,
          color: '#858383'
        },
        pointer: {
          show: false
        },
        title: {
          show: false
        },
        anchor: {
          show: true,
          size: 14,
          itemStyle: {
            color: 'red'
          }
        }
      }
    ]
  };

  mychartspider1.setOption(option);
}

function updategaugespider1() {
  $('#sliderspidervalue1').text($('#number1').val());
  $('#sliderspidervalue2').text($('#number2').val());
}

updategaugespider1();
updateGaugeSpider1(Number($('#number1').val()), Number($('#number2').val()));

$('#number1').on('input', function() {
  updategaugespider1();
  updateGaugeSpider1(Number($(this).val()), Number($('#number2').val()));
});

$('#number2').on('input', function() {
  updategaugespider1();
  updateGaugeSpider1(Number($('#number1').val()), Number($(this).val()));
});

/// event click
mychartspider1.on('click', {
  dataIndex: 0
}, function(params) {
  alert('clicked')
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.3.0/echarts.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<div id="gaugespiderinc1" style="height: 400px; margin: 0 auto"></div>
<input type="range" id="number1" min="0" max="100" step="1" value="50">
<input type="range" id="number2" min="0" max="100" step="1" value="75">

See that it only returns the values ​​in the series from 0 to 100, but I need both to be returned (0 to 100 and 0 to 60) for each of the pointers.

Google Cloud Storage – Uploading image PUT request, no JSON response – JavaScript

I want to allow users to upload images by storing the images in Google Cloud Storage and saving the uploaded image in my database. I’m generating a presigned URL on my backend and sending a PUT request on my front end with this presigned URL.

The problem is that the successful response doesn’t return a JSON response I was expecting. I was expecting to receive data about the uploaded image, mainly the self_url.

I tried POST request but got Forbidden response. I’ve experimented with different CORS configs, looked at the docs and asked Bard. I can’t work out:

  1. How to get a JSON response from the PUT upload
  2. If using POST instead of PUT, how to not get PermissionDenied.

Upload Response

fetch graphql query from external server

i’m trying to fetch some leetcode stats using leetcode’s graphql schema. when i enter the query in the browser, it gives me a response, but it’s not responding to me when i use axios.

here’s the query i enter in the browser:

https://leetcode.com/graphql?query=query {
 questionSubmissionList(
    offset: 0,
    limit: 20,
    questionSlug: "two-sum"
  ) {
    lastKey
    hasNext
    submissions {
      id
      title
      titleSlug
      status
      statusDisplay
      lang
      langName
      runtime
      timestamp
      url
      isPending
      memory
    }
  }
}

and here’s what i have in my code:

    let url = `https://leetcode.com/graphql`;
    const fetchSubmissionList = async (questionSlug) => {
        let query = `
            query questionSubmissionList(
               offset: 0,
               limit: 20,
               questionSlug: $questionSlug
             ) {
                lastKey
                hasNext
                submissions {
                    id
                    title
                    titleSlug
                    status
                    statusDisplay
                    lang
                    langName
                    runtime
                    timestamp
                    url
                    isPending
                    memory
                }
            }
        }
        `
        const data = await axios.post(url, {
            query: query,
            variables: {
                questionSlug: questionSlug
            }
        }, {
            headers: {
                'Content-Type': 'application/graphql',
                'Access-Control-Allow-Origin':  'http://localhost:5173/',
                'Access-Control-Allow-Methods': 'POST',
                'Access-Control-Allow-Headers': 'Content-Type, Authorization'
            },
        })
        console.log(data)
    }

I’m getting no cors errors whenever i run the query.
i saw online that I’m supposed to implement no cors server side, but since i don’t have access to the server, i obviously can’t change anything over there

one possible reason for this that i can think of is that, on the browser side, I’m logged in using my leetcode account, but i might not be when i use axios. however, when i go incognito, i still get a response (albeit an empty one) from leetcode.

thanks

415 (Unsupported Media Type) error in dot net core web API

I am using dot net core Web API.
I have a controller HomeController.cs

using Microsoft.AspNetCore.Mvc;
using WebAPI.Models;
namespace WebAPI.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class HomeController : Controller
    {
        
        [HttpPost]
        public IActionResult Index(User user)
        {
            return Ok(user);
        }
    }

}

The model user is as follows

namespace WebAPI.Models
{
    public class User
    {
        public string username { get; set; }
        public string password { get; set; }
    }
}

When I run the following jquery code from the front end I get an error 415 (Unsupported Media Type)

$.ajax({
  type: "POST",
  url: "https://localhost:7137/Home",
  data: { username: "username" , password: "password"},
  success: function(data){console.log(data)},
  dataType: "application/json"
});



I am not getting what mistake I am doing.

Nextjs 13.5 server side not working on production deployment vercel but same code working on localhost:3000

I don’t know why server side rendering not working on vercel deployment but same code working in my localhost. After investigate the log I found the api endpoint /user_staff is not calling from nextjs fontend and don’t know why. is it bug on vercel? or doesn’t vercel support server side rendering? or am I doing any mistake? The same code working on localhost:3000

async function getData() {
  const cookieStore = cookies();
  const session_id = cookieStore.get("sessionid");
  const csrftoken = cookieStore.get("csrftoken");
  
  try {
   
    const userisAdmin = await fetch(`${domain_name}/user_staff`, {
      method: 'get',
      headers: {
        'Content-Type': 'application/json',
        'Cookie': `sessionid=${session_id.value}; csrftoken=${csrftoken.value}`,
      },
      
   });

     const result = await userisAdmin.json()   
  
    return {
      userprofile: result ,
    };
  } catch (error) {
    console.error('Error:', error);
    return {
      userprofile: null,
    };
  }
}

export default async function Adminpage() {
  const user = await getData();
  console.log(user)

  return (
    <>
        {user?.userprofile?.extra_data?.name ?(<>
          <Admin UserName={user.userprofile.extra_data.name}  />
        </>):(<>... others code 

here is log

Error: TypeError: Cannot read properties of undefined (reading 'value')
    at getData (/var/task/fontendfb/.next/server/app/admin/page.js:1:21272)
    at Adminpage (/var/task/fontendfb/.next/server/app/admin/page.js:1:21445)
    at /var/task/fontendfb/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:109:21573
    at /var/task/fontendfb/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:109:21702
    at async ev (/var/task/fontendfb/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:109:21396)
    at async /var/task/fontendfb/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:109:20518
    at async Promise.all (index 0)
    at async ev (/var/task/fontendfb/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:109:20287)
    at async /var/task/fontendfb/node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js:109:20518
    at async Promise.all (index 0)

How do I upload a file in in NestJs. Passing an array of DTO and a single file in each of it

I’m working on a Nestjs file upload API and I have the controller method for upload as follows

@Post('file/upload')
      @ApiOperation({ summary: 'Controller API to upload file to S3 bucket' })
      @ApiConsumes('multipart/form-data')
      @CommonHeaders()
      @UseInterceptors(FilesInterceptor('files', 5, {
          fileFilter: (req, file, cb) => {
              if (!file.originalname.match(/^.*.(png|pdf|csv|txt|doc|docx|xls|xlsx|msg|hbs)$/))
                  cb(new HttpException(ERROR_CONSTANTS['E1084'], 400), false)
              else if (parseInt(req.headers["content-length"]) > 1024 * 1024 * 20 /* 20 MB */)
                  cb(new HttpException(ERROR_CONSTANTS['E1090'], 400), false)
              else
                  cb(null, true)
          },
      }), DocHandlerValidationInterceptor)
      async uploadFile(
          @UploadedFiles(new FileValidationPipe) files: Array<Express.Multer.File>,
          @ADUser() user: AzureUser, @Body() request: DocHandlerDTO) {
            try {
              return await this.docHandlerService.uploadFileToS3(files, user, request);
            }
            catch(exception: any) {
              return exception;
            }
          }

The request body DocHandlerDTO is as follows

/** Input arguments for querying the DocHandler Collection */
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
import { IsOptional, MaxLength, ValidateNested } from 'class-validator';
export class DocHandlerDTO {
    @ApiProperty()
    @MaxLength(15)
    applicationName: string;
    @ApiPropertyOptional()
    @IsOptional()
    @MaxLength(100)
    itemId: string;
    @ApiProperty()
    @MaxLength(100)
    category: string;
    @ApiProperty({type: Boolean, default: true, required: false})
    active: boolean;
    @ApiProperty({format: 'binary'})
    files: Array<Express.Multer.File>;
}

Everything is working as expected, But I need a requirement to update my DTO structure as follows

/** Input arguments for querying the DocHandler Collection */
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
import { IsOptional, MaxLength, ValidateNested } from 'class-validator';
class DocDetailDTO {
    @ApiPropertyOptional()
    @IsOptional()
    @MaxLength(100)
    itemId: string;
    @ApiProperty()
    @MaxLength(100)
    category: string;
    @ApiProperty({type: Boolean, default: true, required: false})
    active: boolean;
    @ApiProperty({format: 'binary'})
    file: Express.Multer.File;
}
export class DocHandlerDTO {
    @ApiProperty()
    @MaxLength(15)
    applicationName: string;
    @ApiProperty({type: DocDetailDTO, isArray: true})
    @ValidateNested()
    doc_details: DocDetailDTO[];
}

In new DTO, the files field changed to single file and it moved to the DocDetailDTO. The parent DTO(DocHandlerDTO) is having array of DocDetailDTO.

But I’m unable to figure out the changes that needs to be done in the controller method to accommodate my new DTO structure. What are the changes needs to be done in FilesInterceptor and UploadFiles decorators.

Material ui + react Trying to create a Horizontal list of cards but not cant scroll them

First of all, thanks for helping!!
I am trying to create an scrollable list of cards in my react page using Material ui, but I am not able to make the list scrollable. How could I create a list of scrollable cards.

enter image description here

This is my code:

return (
      <div style={{ display: 'flex',flexWrap: 'wrap',justifyContent: 'space-around',overflow: 'hidden',width: 1200 }}>
        <Grid container spacing={3} style={{flexWrap: 'nowrap'}}>
          {data.map((data, index) => {
            const { Title, Summary } = data;
            return (
              <Grid item>
                <Card sx={{ width:300 }}>
                  <CardMedia
                    sx={{ height: 140 }}
                    image="/static/images/cards/contemplative-reptile.jpg"
                    title="green iguana"
                  />
                  <CardContent>
                    <Typography gutterBottom variant="h5" component="div">
                      {Title}
                    </Typography>
                    <Typography variant="body2" color="text.secondary">
                      {Summary}
                    </Typography>
                  </CardContent>
                </Card>
              </Grid>
            );
          })}
        </Grid>
      </div>
    );

How i can configure my laravel app for make a dinamic layout?

im making a Laravel 10 project to try a make a dinamic layout.
Mi principal layout, is header sticky with a left navbar, the rest of the content is the other blades templates, with @extends(‘layouts.app’) and section(‘content’).
My problem is that i need make “the rest of content” dynamic layout.
-One column class=”col-3″ to show a os a categories.
-Other column class=”col-3″ display none, to show a list of a products with the category selected in the first colunmn, this column is started display none, and we u press a category i want to refresh this column and appear all projects with the category selected.
-3Column class=”col” to fill the rest of content and make some responsive, this section is dedicated to show the info of the product selected in the column 2.


I tried to make a ajax post in my created js file, but i cant get dinamic routes passing info, i dont know how reload only the section that i need, for example, if i press 1 column (categories), refresh only the products, but not all the page.
Using javascript ajax method and passing crsf token i get a “method not allowed” ERROR
I tried too, call products.show method in controller with a $id variable to get a category_id
Im thinking about its possible hide and show sections, and dont use ajax request in javascript.
Anyone have any idea o can send me some guide.
PD: i have all my tables in BBDD with foreigns keys, triying to make a constraints and cascade updating
Thanks for ur time.

If u need some more, say me, i dont need a code, i need a guide to make this proceess, about using js post request or using only laravel blades and routing its possible build this.

Typescript: cartesian product of two generic arrays results to wrong type inferred

I wrote a simple Cartesian product implementation in Typescript, but the type inferred is not what I have expected:

export function cartesianProduct<X, Y> (a: X[], b: Y[]): Array<[X, Y]> {
    return a.flatMap(x => b.map(y => [x, y]));
}

enter image description here

As you can see, the inferred type is (X | Y)[][] instead of [X, Y][]. This seems weird to me because [x, y] should have type [X, Y] (x is of X type and y is of Y type).
Any idea why I am getting this type error and how to fix?

Replace every back slash in a JavaScript string with a different character

How can I replace every character in a JavaScript string with a different character without using template literals?

I have tried using the line: let result = myString.replace(/\/g, "-");
However, this replaces every 2 back slashes with a dash

I have tried using the line: let result = myString.replace(//g, "-");
However, this produces an error

I have tried using the String.raw() function. However, this only works on Template Literal Strings. I am not able to use template literals

CSS Animation Transform a div into another

I’m trying to code an animation that transforms one div into another.

For example, if I want to transform div1 into div2, I’d like div1 to get the size, position, rotation and background color of div2.

Here is my first code (without any animation) :

https://jsfiddle.net/53yr7usq/

<!DOCTYPE html>
<style>
.center {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}
#div1 {
    background-color: red;
    width: 100px;
    height: 100px;
    text-align: center;
}
#div2 {
    position:absolute;
    left:-30px;
    bottom:10px;
    background-color: blue;
    width: 80px;
    height: 120px;
    transform: rotate(-10deg);
}
</style>
<html>
    <body>
        <div class="center">
            <div id="div1">
                <h1>
                    DIV1
                </h1>
            </div>
        </div>
        <div id="div2">
            <h1>
                DIV2
            </h1>
        </div>
    </body>
</html>

So after…

I tried to create an animation with keyframes, but it’s not fluid at all (there’s a jump and the movement isn’t fluid).

https://jsfiddle.net/dnwarojb/2/

<!DOCTYPE html>
<style>
.center {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}
#div1 {
    background-color: red;
    width: 100px;
    height: 100px;
    text-align: center;
    animation: transformation 2s infinite;
}
#div2 {
    position:absolute;
    left:-30px;
    bottom:10px;
    background-color: blue;
    width: 80px;
    height: 120px;
    transform: rotate(-10deg);
}
@keyframes transformation {
    100% {
        position:absolute;
        left:-30px;
        bottom:10px;
        width: 80px;
        height: 120px;
        background-color: blue;
        transform: rotate(-10deg);
    }
}
</style>
<html>
    <body>
        <div class="center">
            <div id="div1">
                <h1>
                    DIV1
                </h1>
            </div>
        </div>
        <div id="div2">
            <h1>
                DIV2
            </h1>
        </div>
    </body>
</html>

Finally, I thought of using a transform translate but I don’t know how to determine the pixels to translate….

https://jsfiddle.net/9egh5unf/3/

<style>
:root {
--x:-10px;
--y:10px;
}
@keyframes transformation {
    100% {
        width: 80px;
        height: 120px;
        background-color: blue;
        transform: rotate(-10deg) translate(var(--x),var(--y));
    }
}
</style>
<script>
function gap() {
    div1 = "div1"
    div2 = "div2"
    w1_rotate = document.getElementById(div1).getBoundingClientRect().width;
    w1_droit = document.getElementById(div1).clientWidth;
    w_cut = (w1_rotate - w1_droit) / 2

    po_x_2 = (window.innerWidth - w1_rotate) / 2
    
    translate_x = w_cut + po_x_2 + 129.5
    
    h1_rotate = document.getElementById(div1).getBoundingClientRect().height;
    h1_droit = document.getElementById(div1).clientHeight;
    h_cut = (h1_rotate - h1_droit) / 2

    po_y_2 = document.getElementById(div2).getBoundingClientRect().bottom;
    po_y_1 = document.getElementById(div1).getBoundingClientRect().bottom;

    translate_y = po_y_1 - po_y_2 + h_cut

    console.log(translate_x)
    console.log(translate_y)
    //Change CSS Variable with the new translate_x and translate_y
}
</script>

But here again I have a problem: the number of pixels I’m calculating isn’t right, so my translation is wrong…

So I’d like to know if there’s a way of transforming div1 into div2, either without jumping in the animation, or with the right number of pixels for translation.

Thanks a lot!

— Summary of what I tried to do —

So, has I said, I tried to create an animation but it wasn’t fluid/smooth… So I decided to use a transform : translate() to make it smoother but I don’t arrive to find the good X_translation and the good Y_translation

Google Tag Manager Parse Error ” ) expected”

I’m trying to create a custom javascript variable in Google Tag Manager to return the subtotal of the order. However it keeps throwing me this error: Error at line 16, character 5: Parse error. ')' expected It works fine when inputted into the browser console, however.

function getSubtotalValue() {
    var subtotalElement = findElementByText('Subtotal');
    if (!subtotalElement) {
        subtotalElement = findElementByText('Total');
    }

    if (subtotalElement) {
        var subtotalText = subtotalElement.nextElementSibling.querySelector('span.woocommerce-Price-amount').textContent;
        var subtotalMatch = subtotalText.match(/d+.d+/);
        return subtotalMatch ? parseFloat(subtotalMatch[0]).toFixed(2) : null;
    }

    return null;
}

function findElementByText(text) {
    var thElements = document.querySelectorAll('th');
    for (var i = 0; i < thElements.length; i++) {
        if (thElements[i].textContent.includes(text)) {
            return thElements[i];
        }
    }
    return null;
}

getSubtotalValue();

Further context: This variable is to be set as the “Order value” for a Checkout event I’m creating which will only trigger when a customer buys something and lands on the “Order Received” page. I’m basically trying to pull the data from the Subtotal row.

<table class="woocommerce-table woocommerce-table--order-details shop_table order_details">
<thead>
<tr>
<th class="woocommerce-table__product-name product-name">Product</th>
<th class="woocommerce-table__product-table product-total">Total</th>
</tr>
</thead>
<tbody>
<tr class="woocommerce-table__line-item order_item">
<td class="woocommerce-table__product-name product-name">
<a href="https://link.com">Product name</a> <strong class="product-quantity">×&nbsp;1</strong><ul class="wc-item-meta"><li><strong class="wc-item-meta-label">Choose an option::</strong> <p>Option 1</p></li></ul> </td>
<td class="woocommerce-table__product-total product-total">
<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">$</span>60.00</bdi></span> </td>
</tr>
<tr class="woocommerce-table__line-item order_item">
<td class="woocommerce-table__product-name product-name">
<a href="https://link.com">Product name</a> <strong class="product-quantity">×&nbsp;1</strong><ul class="wc-item-meta"><li><strong class="wc-item-meta-label">Choose an option::</strong> <p>Option 2</p></li></ul> </td>
<td class="woocommerce-table__product-total product-total">
<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">$</span>25.00</bdi></span> </td>
</tr>
<tr class="woocommerce-table__line-item order_item">
<td class="woocommerce-table__product-name product-name">
<a href="https://link.com">Product name</a> <strong class="product-quantity">×&nbsp;1</strong><ul class="wc-item-meta"><li><strong class="wc-item-meta-label">Choose an option::</strong> <p>Option 1</p></li></ul> </td>
<td class="woocommerce-table__product-total product-total">
<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">$</span>25.00</bdi></span> </td>
</tr>
</tbody>
<tfoot>
<tr>
<th scope="row">Subtotal:</th>
<td><span class="woocommerce-Price-amount amount"><span class="woocommerce-Price-currencySymbol">$</span>110.00</span></td>
</tr>
<tr>
<th scope="row">Shipping:</th>
<td>Flat rate</td>
</tr>
<tr>
<th scope="row">Tax:</th>
<td><span class="woocommerce-Price-amount amount"><span class="woocommerce-Price-currencySymbol">$</span>10.31</span></td>
</tr>
<tr>
<th scope="row">Payment method:</th>
<td>PayPal</td>
</tr>
<tr>
<th scope="row">Total:</th>
<td><span class="woocommerce-Price-amount amount"><span class="woocommerce-Price-currencySymbol">$</span>120.31</span></td>
</tr>
</tfoot>
</table>

How to save data to database when the user request to leave?

What is the proper way to do that? My goal is to save in database the count of minutes of the video the user has watched until he closed the page and set the video’s minutes to where he left off, next time he opens the very same video. I’ve tried to do that with beforeunload event but the page is closing before the function return. I’m using async/await but I don’t know how to make sure the event finish to run properly. I’ve tried something like this in my react component:

const ec = async (e) => await handleBeforeUnload(e);
    window.addEventListener('beforeunload', ec);

    return () => {
        window.removeEventListener('beforeunload', ec);
    }

but doesn’t gurante that the function finish before leaving the page. What is the proper way to do that?

edit: here’s the rest of the code:

    const handleBeforeUnload = async (event) => {
        await save_timestamp();
    }

    const save_timestamp = async () => {

    const v:IResumeVideo = {
        seconds: timeline.current,
        video_id: video_id
    }

    const response = await fetch('/api/save_video', {
        method: 'POST',
        body: JSON.stringify(v)
      });
    const result = await response.json();           
}

Function ‘run’ is not defined

When i am running HTML with script, i got this error
Uncaught ReferenceError: run is not defined
at HTMLParagraphElement.onclick (index.html:11:44)
enter image description here
And what interesting folder ‘js’ does not exists!

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" href="css/style.css">
    </head>
    <body>
            <script src="js/OS.js"></script>
            <input id="getCommand" class="getCommandInput" type="text" maxlength="512"/>
            <button onclick="run()" class="btn">Run</button>
            <p id="output" onclick="run()">p</p>
    </body>
</html>

JS

const debugOBJ = {
  function clog(logText)
  {
    console.log(logText);
  }
  function cerr(errText)
  {
    console.error(errText);
  }
}

function run()
{
  debugOBJ.clog("Pressed")
  let command = document.getElementById("getCommand").value
  if (document.getElementById("getCommand").value != command)
  {
      command = document.getElementById("getCommand").value
      if (command == "exit")
      {
        document.getElementById("output").textContent = "test"
        debugOBJ.clog(command)
          document.close()
      }
      else
      {
          document.getElementById("output").textContent = "Invalid command"
          debugOBJ.cerr("Invalid command")
          debugOBJ.clog(document.getElementById("out").textContent)
      }
  }
    return 0
}

I expected debug log. I tried to enter command and press button. How to fix than. What i am doing wrong?