In my next.js component that handles the change of sku of product it first shows the change to new sku but then goes back to initial state

import React, { useState, useEffect } from "react";
import axios from "axios";
import Cookies from "js-cookie";
import Accordion from "./Accordion";
import { FaMinus, FaPlus } from "react-icons/fa";
import { useAuth } from "@/context/AuthContext";
import { useRouter } from "next/navigation";
import styles from "./Productpricing.module.scss";

function ProductPricing({ productData }) {
  const [selectedAttributes, setSelectedAttributes] = useState({});
  const [matchingPrices, setMatchingPrices] = useState([]);
  const [matchingSkuIds, setMatchingSkuIds] = useState([]);
  const [matchingName, setMatchingName] = useState([]);
  const [noMatchingSku, setNoMatchingSku] = useState(false);
  const storedMobileNumber = Cookies.get("mobileNumber");
  const [amount, setAmount] = useState(1);
  const { user } = useAuth();
  const navigate = useRouter();
  const [lastValidSkuName, setLastValidSkuName] = useState("");

  const setDecrease = () => {
    amount > 1 ? setAmount(amount - 1) : setAmount(1);
  };

  const setIncrease = () => {
    setAmount(amount + 1);
  };

  const handleInputChange = (e) => {
    // Ensure the input value is a positive integer
    const newValue = parseInt(e.target.value, 10);

    if (!isNaN(newValue) && newValue >= 1) {
      setAmount(newValue);
    }
  };

  useEffect(() => {
    if (
      productData.responseProductSkus &&
      productData.responseProductSkus.length > 0
    ) {
      // Set the default selected attributes based on the first SKU
      const firstSku = productData.responseProductSkus[0];
      const defaultAttributes = {};
      firstSku.responseSkuParams.forEach((param) => {
        defaultAttributes[param.key] = param.value;
      });
      setSelectedAttributes(defaultAttributes);
    }
  }, [productData]);

  useEffect(() => {
    calculateMatchingPrices();
  }, [productData.responseProductSkus, selectedAttributes]);

  useEffect(() => {
    if (!noMatchingSku) {
      const urlFriendlyProductName = getMatchingSkuName();
      if (urlFriendlyProductName) {
        setLastValidSkuName(urlFriendlyProductName); // Update last valid SKU name
        const url = `/product/${urlFriendlyProductName}/${productData.externalProductId}`;
        navigate.replace(url);
      } else if (lastValidSkuName) {
        const url = `/product/${lastValidSkuName}/${productData.externalProductId}`;
        navigate.replace(url);
      }
    }
  }, [selectedAttributes, noMatchingSku, navigate]);

  const calculateMatchingPrices = () => {
    const matchingProducts = productData.responseProductSkus.filter((sku) => {
      const skuParams = {};
      sku.responseSkuParams.forEach((param) => {
        skuParams[param.key] = param.value;
      });
      return Object.entries(selectedAttributes).every(
        ([key, value]) =>
          value === "" || value === undefined || skuParams[key] === value
      );
    });

    if (matchingProducts.length === 0) {
      setNoMatchingSku(true);
    } else {
      setNoMatchingSku(false);
    }

    const prices = matchingProducts.flatMap((sku) => [
      sku.prices.find((price) => price.pricingType === "UNIT")?.price,
      sku.prices.find((price) => price.pricingType === "FINAL")?.price,
    ]);

    const skuIds = matchingProducts.map((sku) => sku.externalProductSkuId);
    const names = matchingProducts.map((sku) => sku.name);

    setMatchingPrices(prices);
    setMatchingSkuIds(skuIds);
    setMatchingName(names);
  };

  const getMatchingSkuName = () => {
    // Implement this function to find the SKU name based on selected attributes
    // This is just a placeholder implementation
    const matchingSku = productData.responseProductSkus.find((sku) => {
      const skuParams = {};
      sku.responseSkuParams.forEach((param) => {
        skuParams[param.key] = param.value;
      });
      return Object.entries(selectedAttributes).every(
        ([key, value]) =>
          value === "" || value === undefined || skuParams[key] === value
      );
    });

    if (!matchingSku) return lastValidSkuName;

    return matchingSku.name
      .trim() // Remove leading/trailing spaces
      .replace(/s+/g, "-") // Replace spaces with hyphens
      .replace(/--+/g, "-") // Replace multiple hyphens with a single hyphen
      .replace(/[^a-zA-Z0-9.-*]/g, "") // Remove all special characters except periods, hyphens, and alphanumeric characters
      .replace(/([*])/g, "$1"); // Preserve periods
  };

  const handleAttributeChange = (key, value) => {
    setSelectedAttributes((prevSelected) => ({
      ...prevSelected,
      [key]: value,
    }));
  };

  const renderAttributeLists = () => {
    const uniqueAttributes = {};

    productData.responseProductSkus &&
      productData.responseProductSkus.forEach((sku) => {
        sku.responseSkuParams.forEach((param) => {
          if (!uniqueAttributes[param.key]) {
            uniqueAttributes[param.key] = [];
          }
          if (!uniqueAttributes[param.key].includes(param.value)) {
            uniqueAttributes[param.key].push(param.value);
          }
        });
      });

    return Object.entries(uniqueAttributes).map(([key, values]) => (
      <div key={key} className={styles.attribute_list}>
        <h3>{key}:</h3>
        <ul className={styles.attribute_row}>
          {values.map((value) => (
            <li
              key={value}
              className={`${styles.attribute_item} ${
                selectedAttributes[key] === value ? styles.selected : ""
              }`}
              onClick={() => handleAttributeChange(key, value)}
            >
              {value}
            </li>
          ))}
        </ul>
      </div>
    ));
  };

  let minPrice = Infinity;
  let minPriceSku = null;
  let minPriceTex = null;
  let minPriceTex1 = null;

  // SKU iteration and minimum price calculation
  if (productData?.responseProductSkus) {
    for (const sku of productData.responseProductSkus) {
      for (const price of sku.prices) {
        if (price.pricingType === "UNIT" && price.price < minPrice) {
          minPrice = price.price;
          minPriceSku = sku;
        }
      }
    }
    if (minPriceSku) {
      const unitPrice = minPriceSku.prices.find(
        (price) => price.pricingType === "UNIT"
      );
      const finalPrice = minPriceSku.prices.find(
        (price) => price.pricingType === "FINAL"
      );
      if (unitPrice && finalPrice) {
        minPriceTex = unitPrice.priceText;
        minPriceTex1 = finalPrice.priceText;
      }
    }
  }

  const addtocart = async () => {
    try {
      const authToken = localStorage.getItem("authToken");
      const headers = {
        accept: "*/*",
        authToken: authToken,
      };
      // eslint-disable-next-line no-unused-vars
      const response = await axios.post(
        `${process.env.NEXT_PUBLIC_API_URL}/cart/add`,
        {
          authToken: "NULL",
          customerMobile: storedMobileNumber,
          skuExternalId: matchingSkuIds[0],
          quantity: amount,
        },
        { headers: headers }
      );
      window.location.href = "/cart"; // Handle the response as needed
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <div className={styles.product_data}>
      {noMatchingSku && (
        <p className={styles.notavbl}>This variant isn&apos;t available</p>
      )}
      <h2>{matchingName}</h2>
      {user && user.authToken ? (
        <>
          <strong className={styles.price_heading}>Rate Inclusive GST</strong>
          <div className={styles.price}>
            <div className={styles.price_data}>
              <p>Per {minPriceTex}</p>
              <p className={styles.product_data_price}>₹ {matchingPrices[0]}</p>
            </div>
            <div className={styles.price_data}>
              <p>Per {minPriceTex1}</p>
              <p className={styles.product_data_price}>₹ {matchingPrices[1]}</p>
            </div>
          </div>
        </>
      ) : (
        <p>To See Prices Please Sign Up.</p>
      )}
      {renderAttributeLists()}
      <div>
        <h3 className={styles.qty}>Quantity:</h3>
        <div className={styles.cart_button}>
          <div className={styles.amount_toggle}>
            <button onClick={() => setDecrease()}>
              <FaMinus />
            </button>
            <div className={styles.amount_style}>
              <input
                type="text"
                name="amount"
                value={amount}
                onChange={handleInputChange}
              />
            </div>
            <button onClick={() => setIncrease()}>
              <FaPlus />
            </button>
          </div>
        </div>
      </div>
      <div>
        <div className={styles.accordion}>
          <Accordion
            title="Product Details"
            productInfo={productData.productInfo}
            description={productData.description}
          />
        </div>
      </div>
      <button className={styles.btn} onClick={addtocart}>
        Add to Cart
      </button>
    </div>
  );
}

export default ProductPricing;

I tried changing the dependencies of useEffects and also console logging to check if the skus change or not,but everything worked fine .This same component worked fine in react.js,but in next.js it first renders the new sku but then changes back to the default sku.
I cannot figure out where i am going wrong or what is the issue if it is regarding to state or useeffects,or something that is different in nextjs than react

Top dynamic bar in wordpress site

I have a dynamic top bar on my WordPress website with 3 messages that appear in constant loop one after the other. The issue is that there is like 5 seconds of delay between the 3rd item(message) and the first item that appears again where there is no message shown in the top bar, it’s supposed to be a continuous flow.

This is the code that I use:

var topBarItems = document.querySelectorAll('.top-bar-item');
var currentItemIndex = 0;

function showNextItem() {
  // Oculta el item actual
  topBarItems[currentItemIndex].style.display = 'none';

  // Mueve al siguiente item
  currentItemIndex++;

  // Si el índice supera el número de items, vuelve al primero
  if (currentItemIndex >= topBarItems.length) {
    currentItemIndex = 0;
  }

  // Muestra el siguiente item
  topBarItems[currentItemIndex].style.display = 'flex';

  // Configura el próximo ciclo
  setTimeout(showNextItem, 2000);
}

// Inicializa el ciclo
showNextItem();
.top-bar {
  background-color: #000;
  height: 35px;
  display: flex;
  justify-content: center;
  color: white;
}

.top-bar-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

.top-bar-item {
  display: none;
  align-items: center;
  margin-right: 20px;
  font-size: 12px;
  font-weight: 500;
  margin-bottom: 5px;
  margin-top: 5px
}

.top-bar-item:first-child {
  display: flex;
}

.top-bar-item img {
  width: auto;
  height: 25px;
  margin-right: 15px;
}

.top-bar-item span {
  margin-left: 10px;
  font-size: 12px;
}

.top-bar-wrap .top-bar-item:not(:first-child) {
  position: absolute;
  left: -100%;
  animation-name: move-left;
  animation-duration: 10s;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
}

.top-bar-wrap .top-bar-item:nth-child(2) {
  animation-delay: 6s;
}

.top-bar-wrap .top-bar-item:nth-child(3) {
  animation-delay: 12s;
}

@keyframes move-left {
  from {
    transform: translateX(0);
    opacity: 1;
  }
  to {
    transform: translateX(-100%);
    opacity: 0;
  }
}

@media only screen and (max-width: 768px) {
  .top-bar {
    height: 35px;
    overflow: hidden;
  }
  .top-bar-content {
    flex-wrap: wrap;
    align-items: center;
  }
  .top-bar-item {
    width: 100%;
    display: flex;
    align-items: center;
    margin-right: 0;
    margin-bottom: 5px;
    margin-top: 8px;
    font-size: 12px;
    font-weight: 500;
    line-height: 0px;
    /* Añadido para alinear verticalmente el texto */
    text-align: center;
  }
  .top-bar-item img {
    width: auto;
    height: 20px;
    margin-right: 10px;
  }
}
<div class="top-bar">
  <div class="top-bar-content">
    <div class="top-bar-item"><img src="https://picsum.photos/seed/78909812-1/200/300" alt="Envío gratis" /> Envío gratis por compras mayores a $200</div>
    <div class="top-bar-item"><img src="https://picsum.photos/seed/78909812-2/200/300" alt="Entregas" /> Entregas de 5 - 7 días</div>
    <div class="top-bar-item"><img src="https://picsum.photos/seed/78909812-3/200/300" alt="Devoluciones" /> Devoluciones gratis</div>
  </div>
</div>

Kadence Blocks and blank Gutenberg (WordPress)

For some reason WordPress won’t load page editor correctly. It loads it blank only for this one particular page (other pages load correctly). I was editing it and clicked to toggle tablet view for further styling. Editor crashed and I can’t load it since then.

Page works correctly at front, only editor fails to load.

Console gives me this error:
Uncaught SyntaxError: Unexpected token ‘<‘ (at post.php?post=7&action=edit:453:1)

I’ve tried to:

  • duplicate this page
  • migrate entire site to different hosting
  • purge cache
  • switch themes
  • use different browsers (incognito and not)
  • turn various plugins on and off

None of above worked.
Any idea how can I fix it?

How to forward cookies set by an API to the browser in SSR with Next.js?

I’m working on a Next.js application, and I have a method that calls an API from the server. This API sets a cookie, and I need to forward this cookie to the browser.

However, I’m facing a challenge:

  1. Server Actions: I can set cookies from server actions, but this requires triggering the method from the client side.
  2. Route Handlers: Alternatively, I can create a route handler, but this also needs to be called from the client side.

This approach doesn’t seem to leverage SSR effectively. Where is the SSR in this method? Is there a better way to achieve this in Next.js that fits within the SSR paradigm? Any guidance would be appreciated.

for example

export async function getData(): Promise<ServerState> {
  const res = await fetch(`${getApiUrl()}/user`, {
    method: 'GET',
    headers: {
      Cookie: cookies().toString(),
    },
  });

  if (!res.ok) {
    return {
      status: ServerStateStatus.ERROR,
      message: JSON.stringify(res),
    };
  }

  // Revalidate user requests to pull in new payload
  revalidateTag('user');

//here i am setting the response cookie so when i am doing this then i can't call it from server as in prod it throws error setting cookie is not allowed in server but when i am calling it from client it behaves like server action so works fine. 
setServerCookies(response.headers.getSetCookie());

  return {
    status: ServerStateStatus.SUCCESS,
    message: 'got the data',
  };
}

//for ref


'use server';

import { ServerState, ServerStateStatus } from '@common-utils';
import { ResponseCookie } from 'next/dist/compiled/@edge-runtime/cookies';
import { cookies } from 'next/headers';

export interface Cookie {
  name: string;
  value: string;
  [attr: string]: unknown;
}

export const setServerCookies = async (cookieArray: string[]) => {
  cookieArray.forEach((cookieString) => {
    const cookie: Cookie = { name: '', value: '' };

    const parts = cookieString.split(';');

    // Process the first part to extract name and value
    const firstPart = parts.shift() || '';
    const [name, value] = firstPart.trim().split('=');
    cookie.name = name.trim();
    cookie.value = value.trim();

    parts.forEach((part) => {
      const keyValue = part.trim().split('=');

      // If there's no '=', it means it's a boolean attribute (e.g., httpOnly, secure)
      if (keyValue.length === 1) {
        const key = keyValue[0].trim();
        cookie[key.charAt(0).toLowerCase() + key.slice(1)] = true;
      } else {
        const key = keyValue[0].trim();
        const value = keyValue.slice(1).join('=').trim();

        // Convert 'expires' field to Date if key is 'expires'
        if (key === 'expires') {
          cookie.expires = new Date(value);
        } else {
          cookie[key] = value;
        }
      }
    });

    // Set the cookie using Next.js cookies API
    cookies().set(cookie as ResponseCookie);
  });
};

I have done a bit of research on this found this discussion https://github.com/vercel/next.js/discussions/49843 but it didn’t gave me a way.

Understanding Promise Chaining Internal Mechanics

I am learning promise chaining and I stumbled upon a doubt. Consider the below promise chain –

const myPromise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("foo");
    }, 10000);
});

myPromise
    .then(handleFulfilledA, handleRejectedA)  // first then
    .then(handleFulfilledB, handleRejectedB)  // second then
    .then(handleFulfilledC, handleRejectedC); // third then

The promise constructor returns a promise object myPromise. The handleFulfilledA and handleRejectedA are attached to the [[PromiseFulfillReactions]] and [[PromiseRejectReactions]] of myPromise object. The second and the third then method will be called before myPromise is resolved as myPromise takes 10 seconds.

What happens internally when the second and the third .then method is encountered?

I tried to find an answer and came to know that each then method returns a new Promise object. Let’s call them promiseB and promiseC. The handleFulfilledB and handleRejectedB are attached to the [[PromiseFulfillReactions]] and [[PromiseRejectReactions]] of promiseB. Similarly, handleFulfilledC and handleRejectedC are attached to promiseC.

But if this is the case, when myPromise is fulfilled and its [[PromiseFulfillReactions]] are executed, how will its reactionhandlers(handleFulfilledA, handleRejectedA) know that it has to resolve or reject promiseB? How will the handler come to know that the then to which it was passed to has created a promise which is promiseB? In other words, how is the connection between the handlers and the new promises established?”

Get/Output Dynamic Prices of the Variations on Shopify Product Page

I am adding a custom code to add the discounted price of the products on my shopify product page.
Here is the code :

{% assign discount_percentage = 20 %} {% assign discounted_price = product.price | times: discount_percentage | divided_by: 100 %} {% assign final_price = product.price | minus: discounted_price %} {% assign rounded_final_price = final_price | floor %} 
<div class="best-price">
    <span>Best Price:</span>
    <span class="discounted-price">{{ rounded_final_price | money_without_trailing_zeros }}</span>
</div>

It is working fine, but when different variation with different pricing is selected, it suppose to change the discounted price.

So I need help to make it ajax.

I tried script from this answer but it didn’t work : https://community.shopify.com/c/shopify-design/need-help-with-dynamic-liquid-code-update-for-variant-switching/m-p/2258140

Implementing a Group Feature Similar to Facebook Groups

I’m working on a project where I want to implement a group feature similar to Facebook Groups. Users should be able to:

  • Create groups
  • Join existing groups either by invitation or through a public join option

I’m unsure how to start with the backend and frontend development for this feature. Specifically, I’m looking for guidance on:

  1. The best database structure to store group information and user memberships.
  2. How to handle group creation and invitations.
  3. Any libraries or frameworks that could help streamline this process.

I haven’t tried anything yet since I’m still in the planning phase, but I’m eager to get started.

Any advice or resources would be greatly appreciated!

Thanks in advance!

QuerySelector returns null even though page has completely rendered

I am querying a complex page that is using non standard html elements with standard html elements. The page has completely loaded and I can see the HTML within “elements” when inspecting the page.

HTML (simplified)

<dl class="slds-form">
 <slot class="slds-grid slds-size_1-of-1">
  ...
 </slot>
</dl>

Ran below JS in console

document.querySelector('.slds-form');

Result

null

Is it not possible to query non-standard HTML element?

Methods that don’t work because they don’t recognize it

My intention was to make a page for modifying a map, where I take the positions of each element (they are images of tables) and make a real-time editor.

However, when trying to move a table from one point to another, despite calling the functions correctly, I get errors that I am not making calls.

I have looked at possible errors such as that the methods should not be static, but they are not.

@page "/mapa-edicion/{id:int}"
@inject NavigationManager Navigation
@inject ILogger<SalonModify> Logger
@inject IJSRuntime JSRuntime

@using System.Text.Json
@using System.Net.Http
@using RMSuit_v2.Models

<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js"></script>


<style>
    .map-container {
        position: relative;
        width: 100%;
        height: 700px;
        border: 1px solid #ccc;
        overflow: hidden;
        background-color: #b8b8b8;
    }

    .zoom-container {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        transform-origin: top left;
        transition: transform 0.3s;
    }

    .drawing-item {
        position: absolute;
        width: 100px;
        height: 100px;
        cursor: pointer;
        user-select: none;
    }

        .drawing-item img {
            max-width: 100%;
            max-height: 100%;
            width: auto;
            height: auto;
        }
</style>

<h3>Mapa del Salón</h3>

@if (salonResponse == null)
{
    <p>Cargando detalles del salón...</p>
}
else
{
    <div class="map-container" @onclick="OnMapClick">
        <div class="zoom-container" style="transform: scale(1);">
            @if (salonResponse.dibujos != null && salonResponse.dibujos.Any())
            {
                var orderedDrawings = salonResponse.dibujos
                .OrderBy(d => d.estado == "D")
                .ThenBy(d => d.estado)
                .ToList();

                var occupiedPositions = new HashSet<(int, int)>();

                @foreach (var dibujo in orderedDrawings)
                {
                    var salonDetails = salonResponse.mesas
                    .Where(m => m.dibujos == dibujo.dibujos)
                    .ToList();

                    foreach (var salonDetail in salonDetails)
                    {
                        int adjustedLeft = (int)(salonDetail.posicionX);
                        int adjustedTop = (int)(salonDetail.posicionY);

                        // Aplicar el ratio de pantalla
                        int ratioAdjustedTop = (int)(adjustedTop * ratioPantalla);
                        int ratioAdjustedLeft = (int)(adjustedLeft * ratioPantalla);

                        var adjustedPosition = (ratioAdjustedTop, ratioAdjustedLeft);

                        Logger.LogInformation($"ID Dibujo: {dibujo.dibujos}, Estado: {dibujo.estado}, Posición Ajustada: (top: {adjustedTop}, left: {adjustedLeft}), Ratio: {ratioPantalla}");

                        if (dibujo.estado == "D" || !occupiedPositions.Contains(adjustedPosition))
                        {
                            Logger.LogInformation($"Procesando dibujo con ID: {dibujo.dibujos}, Posición: (top: {adjustedPosition.Item1}, left: {adjustedPosition.Item2})");
                            occupiedPositions.Add(adjustedPosition);

                            <div class="drawing-item"
                                 style="top:@(adjustedPosition.Item1 + "px"); left:@(adjustedPosition.Item2 + "px");"
                                 @onclick="() => OnImageClick(dibujo.dibujos)"
                                 id="[email protected]">
                                @if (!string.IsNullOrEmpty(dibujo.grafico))
                                {
                                    <img src="data:image/jpeg;base64,@dibujo.grafico" alt="@dibujo.estado" />
                                }
                                else
                                {
                                    <p>No hay imagen disponible.</p>
                                }
                            </div>
                        }
                    }
                }
            }
            else
            {
                <p>No se encontraron dibujos para este salón.</p>
            }
        </div>
    </div>
}

<button @onclick="GuardarCambios">Guardar Cambios</button>
<button @onclick="Cancelar">Cancelar</button>

@code {
    [Parameter] public int id { get; set; }
    private SalonResponse? salonResponse;
    private double ratioPantalla = 1.0;
    private int? hiddenDibujoId = null;
    private int maxX;
    private int maxY;

    private bool isDragging = false;

    private void CalculateMaxDimensions()
    {
        maxX = 0;
        maxY = 0;


        if (salonResponse?.dibujos != null && salonResponse.mesas != null)
        {
            foreach (var dibujo in salonResponse.dibujos)
            {

                var salonDetails = salonResponse.mesas
                    .Where(m => m.dibujos == dibujo.dibujos)
                    .ToList();

                foreach (var salonDetail in salonDetails)
                {

                    var adjustedLeft = (int)(salonDetail.posicionX);
                    var adjustedTop = (int)(salonDetail.posicionY);

                    maxX = Math.Max(maxX, adjustedLeft);
                    maxY = Math.Max(maxY, adjustedTop);
                }
            }
        }
        else
        {
            Logger.LogWarning("No se pudo calcular las dimensiones máximas: 'salonResponse', 'dibujos' o 'mesas' es nulo.");
        }
    }

    protected override async Task OnInitializedAsync()
    {
        await LoadSalonDetail();
        CalculateMaxDimensions();

    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await Task.Delay(500); // Esperar milisegundos
            ratioPantalla = await CalculateScreenRatio();

            await JSRuntime.InvokeVoidAsync("initializeSortable");
        }
    }
    private async Task LoadSalonDetail()
    {
        try
        {
            using var client = new HttpClient(new HttpClientHandler
                {
                    ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true
                });

            var url = $"https://37.59.32.58:1380/Master/Salons/GetSalonDetail/{id}?includeDrawings=true&initialCatalog=ELSIFON";
            var response = await client.GetStringAsync(url);

            var options = new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                    PropertyNameCaseInsensitive = true
                };

            salonResponse = JsonSerializer.Deserialize<SalonResponse>(response, options);

            if (salonResponse == null)
            {
                Logger.LogWarning("No se pudieron cargar los detalles del salón. salonResponse es null.");
            }
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, "Error al cargar los detalles del salón.");
        }
    }

    private async Task<double> CalculateScreenRatio()
    {
        return await JSRuntime.InvokeAsync<double>("calculateScreenRatio");
    }

    private void Cancelar()
    {
        Navigation.NavigateTo($"/salonmapa/{id}");
    }

    private void OnImageClick(int dibujoId)
    {

        Logger.LogWarning($"Image clicked: {dibujoId}");

        hiddenDibujoId = dibujoId;
        StateHasChanged();
    }

    private async Task AddDraggingClass(string elementId)
    {
        await JSRuntime.InvokeVoidAsync("addDraggingClass", elementId);
    }






    private async Task OnMapClick(MouseEventArgs e)
    {

        Logger.LogWarning($"Map clicked: {e.ClientX}, {e.ClientY}");

        if (hiddenDibujoId.HasValue && isDragging)
        {
            var position = await JSRuntime.InvokeAsync<(int x, int y)>("getMousePosition", e.ClientX, e.ClientY);

            // Actualizar la posición en la lista de mesas
            var dibujoId = hiddenDibujoId.Value;
            hiddenDibujoId = null;

            await JSRuntime.InvokeVoidAsync("updateElementPosition", $"dibujo-{dibujoId}", position.x, position.y);

            Logger.LogInformation($"Dibujo {dibujoId} movido a nueva posición: (x: {position.x}, y: {position.y})");

            // Actualizar la posición en el modelo
            await UpdateElementPositionAsync(dibujoId, position.x, position.y);

            isDragging = false;
        }
        else
        {
            Logger.LogWarning("No se encontró un dibujo seleccionado para mover o no se está arrastrando.");
        }
    }

    private async Task GuardarCambios()
    {
        try
        {

            await JSRuntime.InvokeVoidAsync("saveNewPositions");

            using var client = new HttpClient();


            if (salonResponse?.dibujos != null)
            {
                foreach (var dibujo in salonResponse.dibujos)
                {

                    var detalle = salonResponse.mesas?.FirstOrDefault(m => m.dibujos == dibujo.dibujos);
                    if (detalle != null)
                    {
                        var url = $"https://37.59.32.58:1380/Master/SalonTables/UpdateTablePosition/{id}/{detalle.dibujos}/{detalle.dibujos}?initialCatalog=ELSIFON";
                        var response = await client.PostAsJsonAsync(url, detalle);

                        if (response.IsSuccessStatusCode)
                        {
                            Logger.LogInformation($"Posición actualizada para dibujo ID: {detalle.dibujos}");
                        }
                        else
                        {
                            Logger.LogError($"Error al actualizar la posición para dibujo ID: {detalle.dibujos}");
                        }
                    }
                    else
                    {
                        Logger.LogWarning($"No se encontró un detalle para el dibujo con ID: {dibujo.dibujos}");
                    }
                }
            }
            else
            {
                Logger.LogWarning("No se encontraron dibujos en el salón o la respuesta del salón es nula.");
            }


            Navigation.NavigateTo($"/salonmapa/{id}");
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, "Error al guardar los cambios en las posiciones.");
        }
    }

    public event Action<int, int, int> OnPositionUpdated = delegate { };


    // Arrastre

    [JSInvokable]
    public Task SetDraggingState(bool dragging)
    {
        // Lógica para actualizar el estado de arrastre
        isDragging = dragging;
        return Task.CompletedTask;
    }

    [JSInvokable]
    public async Task UpdateElementPositionAsync(int dibujoId, int newX, int newY)
    {
        if (salonResponse?.mesas != null)
        {
            var detalle = salonResponse.mesas.FirstOrDefault(m => m.dibujos == dibujoId);
            if (detalle != null)
            {
                Logger.LogInformation($"Actualizando posición para dibujo ID {dibujoId}: (X: {newX}, Y: {newY})");

                // Validar y actualizar posición
                if (newX >= 0 && newY >= 0 && newX <= maxX && newY <= maxY)
                {
                    detalle.posicionX = (int)(newX / ratioPantalla);
                    detalle.posicionY = (int)(newY / ratioPantalla);

                    // Actualizar en la interfaz de usuario
                    await JSRuntime.InvokeVoidAsync("updateElementPosition", $"dibujo-{dibujoId}", newX, newY);

                    OnPositionUpdated?.Invoke(dibujoId, newX, newY);
                }
                else
                {
                    Logger.LogWarning($"Coordenadas fuera de rango para dibujo ID {dibujoId}: (X: {newX}, Y: {newY})");
                }
            }
            else
            {
                Logger.LogWarning($"No se encontró un detalle para el dibujo con ID: {dibujoId}");
            }
        }
    }


    // Para mostrar mensajes de js en logger

    [JSInvokable]
    public static Task LogMessage(string message)
    {
        var logger = LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger("JSLogger");
        logger.LogInformation($"Mensaje desde JS: {message}");
        return Task.CompletedTask;
    }




}

<script>


    window.addEventListener('load', () => {
        initializeSortable();
    });

    function logMessage(message) {
        DotNet.invokeMethodAsync('RMSuit_v2', 'LogMessage', message)
            .then(result => {
                console.log('Mensaje registrado:', message);
            })
            .catch(error => {
                console.error('Error al registrar el mensaje:', error);
            });
    }

    window.calculateScreenRatio = () => {
        let width = window.innerWidth;
        let height = window.innerHeight;
        let ratio = 1.0;
        let baseWidth = 1920;
        let baseHeight = 1080;

        ratio = Math.min(width / baseWidth, height / baseHeight);

        logMessage(`Screen Ratio Calculated: ${ratio}`);

        return ratio;
    };

    window.saveNewPositions = () => {
        Object.keys(newPositionData).forEach(dibujoId => {
            let position = newPositionData[dibujoId];
            DotNet.invokeMethodAsync('RMSuit_v2', 'UpdateElementPositionAsync', parseInt(dibujoId), position.x, position.y)
                .then(() => {
                    logMessage(`Posición guardada para Dibujo ID: ${dibujoId}, X: ${position.x}, Y: ${position.y}`);
                })
                .catch(error => {
                    logMessage('Error al guardar la posición:', error);
                });
        });
        newPositionData = {};
    };

    window.addDraggingClass = (elementId) => {

        DotNet.invokeMethodAsync('RMSuit_v2', 'SetDraggingState', true)
            .catch(error => console.error('Error al actualizar estado de arrastre:', error));

        const element = document.getElementById(elementId);
        if (element) {
            element.classList.add("dragging");
        }
    };

    window.initializeSortable = () => {
        const tryInitialize = () => {
            const container = document.querySelector('.zoom-container');
            if (container) {
                logMessage('Contenedor encontrado:', container);

                Sortable.create(container, {
                    animation: 150,
                    onStart: () => {
                        DotNet.invokeMethodAsync('RMSuit_v2', 'SetDraggingState', true)
                            .catch(error => logMessage(`Error al actualizar estado de arrastre: ${error}`));
                    },
                    onEnd: (evt) => {
                        const elementId = evt.item.id.replace('dibujo-', '');
                        const newX = evt.item.offsetLeft;
                        const newY = evt.item.offsetTop;

                        logMessage(`Elemento ${elementId} movido a X: ${newX}, Y: ${newY}`);

                        DotNet.invokeMethodAsync('RMSuit_v2', 'UpdateElementPositionAsync', parseInt(elementId), newX, newY)
                            .catch(error => logMessage(`Error al actualizar la posición: ${error}`));

                        DotNet.invokeMethodAsync('RMSuit_v2', 'SetDraggingState', false)
                            .catch(error => logMessage(`Error al actualizar estado de arrastre: ${error}`));
                    }
                });
            } else {
                logMessage('Sortable: el contenedor no se encontró, reintentando...');
                setTimeout(tryInitialize, 100); // Reintento después de 100ms
            }
        };

        tryInitialize();
    };

    window.updateElementPosition = (elementId, newX, newY) => {
        DotNet.invokeMethodAsync('RMSuit_v2', 'UpdateElementPositionAsync', parseInt(elementId), newX, newY)
            .catch(error => logMessage(`Error al actualizar la posición: ${error}`));
    };




</script>

The error:

Mensaje registrado: Error al actualizar estado de arrastre: Error: System.ArgumentException: The assembly ‘RMSuit_v2’ does not contain a public invokable method with [JSInvokableAttribute(“SetDraggingState”)].
at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.GetCachedMethodInfo(AssemblyKey assemblyKey, String methodIdentifier)
at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.InvokeSynchronously(JSRuntime jsRuntime, DotNetInvocationInfo& callInfo, IDotNetObjectReference objectReference, String argsJson)
at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.BeginInvokeDotNet(JSRuntime jsRuntime, DotNetInvocationInfo invocationInfo, String argsJson)
VM15:11 Mensaje registrado: Elemento 101 movido a X: 303, Y: 164
VM15:11 Mensaje registrado: Error al actualizar la posición: Error: System.ArgumentException: The assembly ‘RMSuit_v2’ does not contain a public invokable method with [JSInvokableAttribute(“UpdateElementPositionAsync”)].
at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.GetCachedMethodInfo(AssemblyKey assemblyKey, String methodIdentifier)
at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.InvokeSynchronously(JSRuntime jsRuntime, DotNetInvocationInfo& callInfo, IDotNetObjectReference objectReference, String argsJson)
at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.BeginInvokeDotNet(JSRuntime jsRuntime, DotNetInvocationInfo invocationInfo, String argsJson)
VM15:11 Mensaje registrado: Error al actualizar estado de arrastre: Error: System.ArgumentException: The assembly ‘RMSuit_v2’ does not contain a public invokable method with [JSInvokableAttribute(“SetDraggingState”)].
at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.GetCachedMethodInfo(AssemblyKey assemblyKey, String methodIdentifier)
at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.InvokeSynchronously(JSRuntime jsRuntime, DotNetInvocationInfo& callInfo, IDotNetObjectReference objectReference, String argsJson)
at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.BeginInvokeDotNet(JSRuntime jsRuntime, DotNetInvocationInfo invocationInfo, String argsJson)

I am trying to get these methods to work so that it works with the objective of being able to drag the elements of the images that I am recreating, to create a real-time editor of the map.

Get multiple response in a Promise Array when sending message with chrome.tabs.sendMessage

When all_frames: true is set in manifest.json, the content script runs on all frames of the target page, but when a message is sent to the content script from another script, I would like to know how to get the response of all frames as Promise array like [Promise(Response of frame1), Promise(Response of frame2)...].

The extension and test page I created for this question can be found on my Github.

If anyone knows of a better way to do this, I would be grateful if anyone could let me know.

Thanks.

React Native Expo Library [TypeError: Network request failed] error only on Android

I am using

"expo": "~51.0.28",
"react-native": "0.74.5",

and when I try to fetch method in the giving code I am getting an error network request error.IOS working fine but when it comes to the android I am getting error. What can it be the reason if you help I m glad that I m stuck on this about a week.

I’m using SQL server and my api is public certificated SSL.

I am running on development build.

android:usesCleartextTraffic=”true” this didnt help what else can be solve the problem.

export const login = createAsyncThunk("user/login", async ({email, password}, { rejectWithValue }) => {
    try {
      console.log(email);
      console.log(password);
      const response = await fetch(
        "https://trendpiyasaapi.pazaryericonverter.com/v1/api/Auth/login/",
        {
          method: "POST",
          headers: {
            'Accept': 'application/json',
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            email,
            password,
          }),
        }
      );
  
      console.log("58. line login: ", response);
  
      const json = await response.json();
  
      if (!response.ok) {
        return rejectWithValue(json); 
      }
      const accessToken = json.data.accessToken;
      console.log(accessToken, "Access token from login");

      await AsyncStorage.setItem("UserData", accessToken);
  
      console.log("70. line login function:",json);
      return json;
    } catch (err) {
      console.log("line 72 userSlice:", err);
      return rejectWithValue({ message: "Network Error" }); // Handle network errors
    }
  });

Safari cannot open the page because the address is invalid for Apple Maps link on iPhone

Based on the Map links documentation “https://developer.apple.com/library/archive/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html”

I am trying to open map links from my app. When I tried on Safari with iPhone 15 pro iOS 17 and iPhone 12 iOS 17, I get a “Safari cannot open the page because the address is invalid”. This is not working when clicking on the link within my app but also when entering the link directly in the browser bar.

http://maps.apple.com/ works
but
http://maps.apple.com/?q=Mexican+Restaurant does not work (this the first link example of the Apple doc)

The links work well on Safari with my iPad pro and my Mac Boo pro.

I tried with https:// and maps://maps.apple.com … same result.

Has the doc changed? This one seems to be an archive.

How to do that?

Thanks

Displaying the expiry date in my input whenever I open the modal

When I open my modal for updating my ingredients it automatically sets the values in my input. The problem is that it doesn’t set the value for my expiry date

This is my button when I am passing the values, when I click this button a modal will shows up

This is where I set the default values of my inputs, the others are working fine and shows up inside my value except for the expiry date

**This is my date input**

Sorry my poor English, I just need help to set the values in my date input!

I am still searching for different solutions right now, I didn’t encountered for a possible solutions yet, hopefully I can soon since this is for my capstone project

Refused to display site in Iframe because X-Frame-Options set to sameorigin

I am having a wordpress site hosted App service and trying to load in and iframe. But i am getting X-Frame options issue. I added headers plugin in wordpress and added X-frame-options heaer with value as *. But still getting the same error and some how App service is blocking us to load. Need to add this header in app service. So i want to know how to add this header in app service

Expecting wordpress site to load in iframe