Highcharts chart is showing but Highcharts Pattern Fill library is not working

I am trying to use the Highcharts Pattern Fill library in my Vue 3 app. I’ve followed the instructions and the chart shows but the pattern fill does not. What am I doing wrong?

Codepen here: https://codepen.io/epatmalnieksge/pen/YzmOazG

<template>
  <div id="container"></div>
</template>

<script>
import Highcharts from "https://esm.sh/highcharts";
import HighchartsPatternFill from "https://esm.sh/highcharts-pattern-fill";

HighchartsPatternFill(Highcharts);

export default {
  mounted() {
    Highcharts.chart("container", {
      chart: {
        type: "column"
      },
      title: {
        text: "Pattern Fill Example"
      },
      series: [
        {
          data: [1, 3, 2, 4],
          color: {
            pattern: {
              path: {
                d: "M 10 0 L 0 10 M -5 5 L 5 15 M 15 -5 L 25 5",
                strokeWidth: 2
              },
              width: 10,
              height: 10
            }
          }
        }
      ]
    });
  }
};
</script>

add to favorites div function not behaving as expected

I’m creating a dashboard page for a reporting server we have here on site. It’s just a collection of links to reports and a brief description of them. I thought it would be nice to allow users to keep a collection of their favorite reports in a div at the top of the page be checking a box next to the report. I’ve got a js file that is to handle the storing of favorites in localstorage and updating the favorites div on page loads or when a user clicks a checkbox to add it or an X button I fudged to remove it. The first block of code is a snapshot of a portion of the body of the page. The second is the js file. The problem I’m seeing is if there is already a checkbox checked and I check a second box. It seems to be adding the wrong p element although when I deselect some check boxes it sorts itself out. Any help with this weirdness would be appreciated!

<h2>Report Server Dashboard<a href="https://www.freecounterstat.com" title="free website counter"><img src="https://counter6.optistats.ovh/private/freecounterstat.php?c=c4af1t599kzkrhdd7yl7z7qx81nnwrcq" border="0" title="website counter" alt="website counter" style="float:right;"></a></h2>
<div class="ng-binding">
<div class="innerdiv" style="padding-left: 8px; padding-right: 18px; float:left;">
<a style="text-decoration: none" href="/Reports/report/ReportsRun" title="Click here to run a report showing your last 30 days of reports." target="_blank">My last 30 days of reports</a>
</div>
<div class="innerdiv" style="float: inline-start; padding-left: 18px; padding-right: 18px;">
<a style="text-decoration: none" href="mailto:[email protected]?subject=Report%20Server%20report%20or%20customization%20request" title="Click here to start an email to the IT department.">***These are all custom reports displaying information pulled from the live Visual database. If you need a report created or modified please reach out to the IT department***</a>
</div>
<div class="innerdiv" id="expander" style="float: inline-start; padding-left: 18px; padding-right: 18px;">
<span id="spanner" style="text-decoration: none; cursor: pointer;" title="Click to open all sections"></span>
</div>
</div>
<br>
<!--MY FAVORITES-->
<button class="collapsible_nobutton"><strong>MY FAVORITES</strong> - This section contains reports where you've checked the "Add to MY FAVORITES" checkbox.</button>
<div  id="favorites">
    <p><br></p>
</div>

<br>
<!--INFO REPORTS-->
<button class="collapsible"><strong>INFO REPORTS</strong> - General information reports that don't fall under another specific category</button>
<div class="content">
    <p class="paragraph" data-id="1"><input type="checkbox" title="Add to MY FAVORITES section" class="favorite-checkbox" data-id="1"><a href="/Reports/report/INFO%20REPORTS/Customer%20List" target="_blank">CUSTOMER LIST</a>
     - This report provides a listing of customers with address and contact information. It shows customers with a Last Order Date both in the date range you select and customers with no Last Order Date.</p>
    <p class="paragraph" data-id="2"><input type="checkbox" title="Add to MY FAVORITES section" class="favorite-checkbox" data-id="2"><a href="/Reports/report/INFO%20REPORTS/CUSTOMERS" target="_blank">CUSTOMERS</a>
     - This report provides a listing of customers with address and contact information. It has a filterable drop down containing customer names. It also shows the Last Order Date.</p>
</div>

script.js

    // Load favorites from local storage on page load
    var favorites = JSON.parse(localStorage.getItem('newfavorites')) || [];

    // Update the favorites div
    updateFavoritesDiv(favorites);

    // Handle checkbox clicks
    $('.favorite-checkbox').on('change', function() {
        var index = $(this).index('.favorite-checkbox');
        var isChecked = $(this).is(':checked');

        if (isChecked) {
            favorites.push(index);
        } else {
            favorites = favorites.filter(function(i) {
                return i !== index;
            });
        }

        // Update local storage and the favorites div
        localStorage.setItem('newfavorites', JSON.stringify(favorites));
        updateFavoritesDiv(favorites);
    });



function updateFavoritesDiv(favorites) {
        $('#favorites').empty();
        favorites.forEach(function(index) {
            var $p = $('p').eq(index).clone();
            // Remove the checkbox from the cloned paragraph
            $p.find('.favorite-checkbox').remove();
            var $removeBtn = $('<button class="button" title="Remove from MY FAVORITES section">X</button><span style="width:12px; display: inline-block;"></span>');
            $removeBtn.click(function() {
                // Remove the paragraph from favorites and update the display
                favorites = favorites.filter(function(i) {
                    return i !== index;
                });
                localStorage.setItem('newfavorites', JSON.stringify(favorites));
                updateFavoritesDiv(favorites);
            });
            $p.prepend($removeBtn);
            $('#favorites').append($p);
        });
    }
    
});

TinyMCE (basic setup) missing skins and themes in Angular 18.2

I installed the package via npm: npm i tinymce –save version 7 and used the basic setup for tinymce:

in ts component:

tinymce.init({
selector: ‘#scanning’,
plugins: ‘advlist link image lists’,
….
});

and in html:

enter image description here

and I get in console errors:

global:scripts.js:14 Failed to load theme: silver from url themes/silver/theme.js
global:scripts.js:14 Failed to load icons: default from url localhost:4200/icons/default/icons.js
global:scripts.js:14 Failed to load plugin: advlist from url plugins/advlist/plugin.js
global:scripts.js:14 Failed to load model: dom from url models/dom/model.js
global:scripts.js:14 Failed to load plugin: directionality from url plugins/directionality/plugin.js
global:scripts.js:14 Failed to load plugin: lists from url plugins/lists/plugin.js

Checked in node-modules, they exist there, added in angular.json:

“scripts”: [

           "node_modules/tinymce/themes/silver/theme.min.js",
           "node_modules/tinymce/models/dom/model.js",
           "node_modules/tinymce/plugins/lists/plugin.js",
           "node_modules/tinymce/plugins/directionality/plugin.js",
           "node_modules/tinymce/plugins/advlist/plugin.js",

           "node_modules/tinymce/tinymce.min.js"
         
        ]

I get the same errors, had tried with min.js also, doesn’t help.

Creating a custom sidebar google form, and looking for an alternative to passing “this” to allow dynamic fields based on a radio button?

I am working in google app script and JavaScript to create a custom form to input information on to a spreadsheet. I am stuck on creating a dynamic form to update the input fields based on a radio button selection. I found a topic from a while ago to swap the div groups How to change a form using radio buttons?. However, the swapConfig suggestion by CrandellWS uses “this” to base the radio ID to the function. However, I also have an onsubmit passing “this” and I believe they are conflicting with each other. Looking for help on how to do both the swapConfig and onsubmit.

<script>
  function handleFormSubmit(formObject) {
    google.script.run.processForm(formObject);
    document.getElementById("budgetDetails").reset();
  }
  function swapConfig(x) {
    var radioName = document.getElementsByName(x.name);
    for (i = 0; i < radioName.length; i++) {
      document.getElementById(radioName[i].id.concat("Settings")).style.display = "none";
    }
    document.getElementById(x.id.concat("Settings")).style.display = "initial";
  }
</script>

<br>
<form class="form" id="budgetDetails" onsubmit="handleFormSubmit(this)">

  <div class="form-group">
    <label for="entryType" class="form-label">Entry Type</label><br>
    <input type="radio" name="entryType" id="income" value="income" onchange="swapConfig(name)">
    <label for="income" class="btn btn-sm btn-success">Income</label>
    <input type="radio" name="entryType" id="transfer" value="transfer" onchange="swapConfig(name)">
    <label for="transfer" class="btn btn-sm btn-warning">Transfer</label>
    <input type="radio" name="entryType" id="expense" value="expense" onchange="swapConfig(name)" checked>
    <label for="expense" class="btn btn-sm btn-danger">Expense</label>
  </div>

<div id="incomeSettings" class="form-group" style="display:none">
    <label for="incomePayee">Payee</label>
    <input type="text" name="incomePayee" id="incomePayee" class="form-control" placeholder="Payee Name" required>
  </div>

  <div id="transferSettings" class="form-group" style="display:none">
    <label for="paymentTo" class="form-label">Payment To</label>
    <select class="form-select form-select-sm" id="paymentTo" name="paymentTo" required>
        <option>--Select Payment To--</option>
    </select>
  </div>
  
  <div id="expenseSettings"  class="form-group">
    <label for="expensePayee">Payee</label>
    <input type="text" name="expensePayee" id="expensePayee" class="form-control" placeholder="Payee Name" required>
  </div>

  <button type="submit" class="btn btn-primary">Submit</button>
</form>

Tried to figure out an alternative to passing “this” like this.id or this.value in swapConfig() based on one of the suggested posts but it does not seem to work.

Why does my bare-minimum app keeps restarting which was start with pm2?

I have a bare-minium app with only app.js, ecosystem and package.json file and nothing else. The app.js file contains only this:

class App {
    async init() {
        console.log('App started started');
    }
}

const app = new App();

app
    .init()
    .then()
    .catch(err => console.log('Error initializing app: ', err));

And the ecosystem file contains this:

module.exports = {
    apps: [
        {
            name: 'main-app',
            script: './app.js',
            output: "./logs/app-out.log",
            error: "./logs/app-error.log",
            watch: false
        }
    ]
};

After I start the pm2 process with pm2 start, app keeps restarting. What could be the reason? I was facing this restart issue in my other app and so for testing I created this dummy, bare-minimum app and apparently it is happening here as well. Can someone shed some light?

nodemailer not passing user and pass in React app on server – how to replace .env credentials?

TLDR is, I think I know what issue is, but do not know how to fix it:)

I have written my react app with simple contact section. See code for onSubmit:

const ContactForm: React.FC = () => {
{...}

    onSubmit: async (values, { setSubmitting, resetForm }) => {
      try {
        const response = await fetch("https://mywebpage.com/send-contact", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify(values),
        });

        if (!response.ok) {
          throw new Error("Błąd wysyłania wiadomości");
        }
        setSuccessAlert(true);
        resetForm();
      } catch (error: any) {
        alert(`Błąd: ${error.message}`);
      } finally {
        setSubmitting(false);
      }
    },
  });

{...}

Secondly, I have coded nodemailer node.js backend for handling login and form of the e-mail. Credentials for nodemailer were passed through .env and it worked flawlessly in localhost. (Please note both .env and sendtoemail.js are being located in the app folder where index.html is, not in src or public)

import express, { json } from "express";
import { createTransport } from "nodemailer";
import cors from "cors";
import bodyParser from "body-parser";
import "dotenv/config";

const app = express();
const USER = process.env.EMAIL_USER;
const PASS = process.env.EMAIL_PASS;

const corsOrigin = {
  origin: "https://mywebpage.com",
};

app.use(cors(corsOrigin));
app.use(json());
app.use(bodyParser.json());

app.post("/send-contact", async (req, res) => {
  const { name, email, message } = req.body;
  try {
    let transporter = createTransport({
      host: "myhost.com",
      port: 465,
      secure: true,
      auth: {
        user: USER,
        pass: PASS,
      },
    });

    let mailOptions = {
      from: email,
      to: USER,
      subject: `Nowa wiadomość od ${name}`,
      text: message,
      html: `<p><strong>Nadawca:</strong> ${name} </p>
    <p><strong>Email:</strong> ${email}</p>
    <p><strong>Wiadomość:</strong> ${message}</p>`,
    };
    await transporter.sendMail(mailOptions);
    transporter.verify(function (error, success) {
      if (error) {
        console.log(error);
      } else {
        console.log("Server is ready to take our messages");
      }
    });

    res.status(200).json({ message: "Email sent successfully!" });
  } catch (error) {
    console.error("Error sending email:", error);
    res
      .status(500)
      .json({ message: "Error sending email", error: error.toString() });
  }
});

And when I had built my app by npm run build and upladed it on server (I have just domain with server folders such as public-html, nothing like firebase or similar) it does not log in or send my form.

I think I know why it does not work – it probably does not read or even build my node.js script + .env, but I do not not know how to safely fix it. Any help would be highly appreciated 🙂
I want to be sure that I by mistake I do not pass .env credentials to my public folder

Imports in Nuxt with @ or ~, which is better?

In Nuxt 3, imports can reference the project root using either ~ or @, for example:

import SubHeader from "@/components/SubHeader.vue"

vs

import SubHeader from "~/components/SubHeader.vue"

Is there a functional difference between these? Is one preferred over the other?

Problem with useEffect in a Product Listing Page

On my site I have 3 categories. When I click on one of them (for example “sneaker”), I want to display only the products in the selected category. I’m currently doing it this way:

import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import baseURL from "../../utils/baseURL";
import { fecthProductsAction } from "../../redux/slices/products/productsSlice";
import LoadingComponent from "../../components/LoadingComp/LoadingComponent";
import ErrorMsg from "../../components/ErrorMsg/ErrorMsg";
import Products from "../../components/Users/Products/Products";
import { useSearchParams } from "react-router-dom";
import {
  Accordion,
  AccordionDetails,
  AccordionSummary,
  Container,
  Grid,
} from "@mui/material";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import { fetchBrandsAction } from "../../redux/slices/brands/brandsSlice";

export default function PLP() {
  const [color, setColor] = useState("");
  const [price, setPrice] = useState("");
  const [selectedBrands, setSelectedBrands] = useState([]);
  const [page, setPage] = useState(1);
  const [loadingData, setLoadingData] = useState(false);

  const [params] = useSearchParams();
  const category = params.get("category");

  const dispatch = useDispatch();

  // Carrega marcas ao carregar a página
  useEffect(() => {
    dispatch(fetchBrandsAction());
  }, [dispatch]);

  const { products, error } = useSelector((state) => state?.products);
  const { brands } = useSelector((state) => state?.brands);
  const brandsData = brands?.data?.slice(3, 9);

  // Função para buscar produtos
  const fetchProducts = () => {
    setLoadingData(true);
    const brandString = selectedBrands.join(",");
    const productUrl = `${baseURL}/products?category=${category || ""}&brand=${
      brandString || ""
    }&color=${color || ""}&price=${price || ""}&page=${page}&limit=4`;

    try {
      dispatch(fecthProductsAction({ url: productUrl }));
    } catch (error) {
      console.error("Erro na requisição de produtos:", error);
    }
    setLoadingData(false);
  };

  // Carrega produtos ao alterar filtros ou página
  useEffect(() => {
    if (category || selectedBrands.length || color || price) {
      fetchProducts();
    }
  }, [category, selectedBrands, color, price, page, dispatch]);

  // Atualiza a lista de produtos
  const [productData, setProductData] = useState([]);
  useEffect(() => {
    if (products) {
      const uniqueNewProducts =
        products.data?.filter(
          (newProduct) => !productData.some((p) => p.id === newProduct.id)
        ) || [];
      setProductData((prevData) =>
        page === 1 ? uniqueNewProducts : [...prevData, ...uniqueNewProducts]
      );
    }
  }, [products, page]);

  console.log("dados finai", productData);

  // Reinicia a página ao mudar qualquer filtro de busca
  useEffect(() => {
    setPage(1);
    setProductData([]); // Limpa a lista de produtos quando qualquer filtro muda
  }, [category, selectedBrands, color, price]);

  // Função para gerenciar o scroll infinito
  useEffect(() => {
    const handleScroll = () => {
      if (
        window.innerHeight + document.documentElement.scrollTop >=
        document.documentElement.offsetHeight - 100
      ) {
        // Incrementa a página ao atingir o final da página
        if (!loadingData) {
          setPage((prevPage) => prevPage + 1);
        }
      }
    };

    window.addEventListener("scroll", handleScroll);
    return () => window.removeEventListener("scroll", handleScroll);
  }, [loadingData]);

  return (
    <Container fixed>
      <Grid container spacing={2} direction="row" sx={{ marginY: "5rem" }}>
        {/* Filtros de Marca */}
        <Grid item xs={12} sm={12} md={3} lg={3} sx={{ height: "auto" }}>
          <Accordion defaultExpanded>
            <AccordionSummary
              expandIcon={<ExpandMoreIcon />}
              aria-controls="panel1-content"
              id="panel1-header"
            >
              Marca
            </AccordionSummary>
            <AccordionDetails>
              <div className="space-y-2">
                {brandsData?.map((brandItem) => (
                  <div key={brandItem?._id} className="flex items-center">
                    <input
                      type="checkbox"
                      className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
                      checked={selectedBrands.includes(brandItem?.name)}
                      onChange={() =>
                        setSelectedBrands((prevSelected) =>
                          prevSelected.includes(brandItem?.name)
                            ? prevSelected.filter((b) => b !== brandItem?.name)
                            : [...prevSelected, brandItem?.name]
                        )
                      }
                    />
                    <label className="ml-3 min-w-0 flex-1 text-gray-500">
                      {brandItem?.name}
                    </label>
                  </div>
                ))}
              </div>
            </AccordionDetails>
          </Accordion>
        </Grid>

        {/* Produtos */}
        <Grid
          container
          item
          xs={12}
          sm={12}
          md={9}
          lg={9}
          sx={{
            height: products ? "auto" : "100vh",
          }}
        >
          <Products products={productData} />
          {loadingData && <LoadingComponent />}
          {error && <ErrorMsg message={error?.message} />}
        </Grid>
      </Grid>
    </Container>
  );
}

That means, I get the URL param for the category with

  const category = params.get("category");

And loading the data with useEffect based on the URL inside the funcion fecthProducts(). The thing is, when I click on a category, the items are rendered continuously, and in the end I get a list of all the products from the call on page 1, and not just the items in that selected category.

Can anyone help me?

I’m using Redux, and this is the slice:

import {
  createAsyncThunk,
  createSlice,
  rejectWithValue,
} from "@reduxjs/toolkit";
import axios from "axios";
import baseURL from "../../../utils/baseURL";

//initial state
const initialState = {
  loading: false,
  error: null,
  product: {},
  products: [],
  isAdded: false,
  isUpdated: false,
  isDeleted: false,
};

//create product action
export const addProductAction = createAsyncThunk(
  "products/create",
  async (payload, { rejectWithValue, getState, dispatch }) => {
    try {
      const {
        name,
        description,
        category,
        sizes,
        brand,
        colors,
        price,
        totalQty,
        files,
      } = payload;
      //http request

      //token
      const token = getState().users?.userAuth?.userInfo?.token;
      const config = {
        headers: {
          Authorization: `Bearer ${token}`,
        },
      };

      //formData
      const formData = new FormData();
      formData.append("name", name);
      formData.append("brand", brand);
      formData.append("category", category);
      formData.append("description", description);
      formData.append("totalQty", totalQty);
      formData.append("price", price);

      sizes?.forEach((size) => {
        formData.append("sizes", size);
      });
      colors?.forEach((color) => {
        formData.append("color", color);
      });
      files?.forEach((file) => {
        formData.append("files", file);
      });

      const { data } = await axios.post(
        `${baseURL}/products`,
        formData,
        config
      );
      return data;
    } catch (error) {
      return rejectWithValue(error?.response?.data);
    }
  }
);

//create product action
export const updateProductAction = createAsyncThunk(
  "products/update",
  async (payload, { rejectWithValue, getState, dispatch }) => {
    try {
      const {
        id,
        name,
        description,
        category,
        sizes,
        brand,
        colors,
        price,
        totalQty,
        //files,
      } = payload;
      //http request

      //token
      const token = getState().users?.userAuth?.userInfo?.token;
      const config = {
        headers: {
          Authorization: `Bearer ${token}`,
        },
      };

      // //formData
      // const formData = new FormData();
      // formData.append("name", name);
      // formData.append("brand", brand);
      // formData.append("category", category);
      // formData.append("description", description);
      // formData.append("totalQty", totalQty);
      // formData.append("price", price);

      // sizes?.forEach((size) => {
      //   formData.append("sizes", size);
      // });
      // colors?.forEach((color) => {
      //   formData.append("color", color);
      // });
      // files?.forEach((file) => {
      //   formData.append("files", file);
      // });

      const { data } = await axios.put(
        `${baseURL}/products/update/${id}`,
        { name, description, category, sizes, brand, colors, price, totalQty },
        config
      );
      return data;
    } catch (error) {
      return rejectWithValue(error?.response?.data);
    }
  }
);

//fetch all products
export const fecthProductsAction = createAsyncThunk(
  "products/fetch-all",
  async ({ url }, { rejectWithValue }) => {
    try {
      const { data } = await axios.get(`${url}`);
      console.log("Dados retornados da API:", data); // Adicione este log

      return data;
    } catch (error) {
      console.log(error);

      return rejectWithValue(error?.response?.data);
    }
  }
);

//fetch a single product
export const fetchProductAtion = createAsyncThunk(
  "product/details",
  async (id, { rejectWithValue }) => {
    try {
      const { data } = await axios.get(`${baseURL}/products/${id}`);
      return data;
    } catch (error) {
      return rejectWithValue(error?.response?.data);
    }
  }
);

//delete a single product
export const deleteProductAtion = createAsyncThunk(
  "product/delete",
  async (id, { rejectWithValue, getState }) => {
    //token
    const token = getState().users?.userAuth?.userInfo?.token;
    const config = {
      headers: {
        Authorization: `Bearer ${token}`,
      },
    };
    try {
      const { data } = await axios.delete(
        `${baseURL}/products/delete/${id}`,
        config
      );
      return data;
    } catch (error) {
      return rejectWithValue(error?.response?.data);
    }
  }
);

// Action para resetar o estado de isAdded
export const resetProductAdded = createAsyncThunk("products/resetAdded", () => {
  return false;
});

//products slice
const productsSlice = createSlice({
  name: "products",
  initialState,
  extraReducers: (builder) => {
    //create product
    builder.addCase(addProductAction.pending, (state) => {
      state.loading = true;
    });
    builder.addCase(addProductAction.fulfilled, (state, action) => {
      state.loading = false;
      state.isAdded = true;
      state.product = action.payload;
    });
    builder.addCase(addProductAction.rejected, (state, action) => {
      state.error = action.payload;
      state.loading = false;
      state.product = null;
      state.isAdded = false;
    });
    // Reset isAdded
    builder.addCase(resetProductAdded.fulfilled, (state) => {
      state.isAdded = false;
    });
    //update product
    builder.addCase(updateProductAction.pending, (state) => {
      state.loading = true;
    });
    builder.addCase(updateProductAction.fulfilled, (state, action) => {
      state.loading = false;
      state.isUpdated = true;
      state.product = action.payload;
    });
    builder.addCase(updateProductAction.rejected, (state, action) => {
      state.error = action.payload;
      state.loading = false;
      state.product = null;
      state.isUpdated = false;
    });
    //fetch all
    builder.addCase(fecthProductsAction.pending, (state) => {
      state.loading = true;
    });
    builder.addCase(fecthProductsAction.fulfilled, (state, action) => {
      state.loading = false;
      state.products = action.payload;
    });
    builder.addCase(fecthProductsAction.rejected, (state, action) => {
      state.loading = false;
      state.products = null;
      state.error = action.payload;
    });

    //fetch single
    builder.addCase(fetchProductAtion.pending, (state) => {
      state.loading = true;
    });
    builder.addCase(fetchProductAtion.fulfilled, (state, action) => {
      state.loading = false;
      state.product = action.payload;
    });
    builder.addCase(fetchProductAtion.rejected, (state, action) => {
      state.loading = false;
      state.product = action.payload;
      state.product = null;
    });
    //delete single
    builder.addCase(deleteProductAtion.pending, (state) => {
      state.loading = true;
    });
    builder.addCase(deleteProductAtion.fulfilled, (state, action) => {
      state.loading = false;
      state.product = action.payload;
      state.isDeleted = true;
    });
    builder.addCase(deleteProductAtion.rejected, (state, action) => {
      state.loading = false;
      state.error = action.payload;
      state.product = null;
      state.isDeleted = false;
    });
  },
});

//generate reducer
const productsReducer = productsSlice.reducer;

export default productsReducer;

There is no problem with the API. It works fine.

The full code is here, in case you want to point out the adjustment: https://github.com/SoaresAnjos/garimpaae

I expect to recieve just the correspondent items when I click on a category

Next.js scrolling filters together with scrolling products

I am working in next js , and i want to implement endless scrolling and I have a sidebar on the left side of my page, with filters, and I want to make this filters bar scrolling with the products, but when filters bar scrolled to it end/start, i want it to stop (but products should be keep scrolling).

Here is example of what behavior I want:
https://green-dostavka.by/catalog/

Maybe there is a guide for that or smth like that, can’t find solution

Issue with document.requestStorageAccess on Firefox

I just followed this example https://developer.mozilla.org/en-US/docs/Web/API/Document/requestStorageAccess#examples to request localStorage access for a cross domain iframe. This works in Chrome. but in Firefox the handle is undefined. I can confirm that the localStorage access has been granted. Any idea why the handle is undefined in Firefox

document.requestStorageAccess({ localStorage: true }).then(
  (handle) => {
    console.log("localStorage access granted");
    handle.localStorage.setItem("foo", "bar");
  },
  () => {
    console.log("localStorage access denied");
  },
);

stimulus controller not firing on requestSubmit

The following stimulus controller

import { Controller } from "stimulus"
export default class extends Controller {
  connect() {
    let that = this;
    that.element.addEventListener('change', _.debounce(that.handleChange, 500))
  }
  handleChange(event) {
    event.preventDefault()
    event.target.form.requestSubmit()
  }
}

is referenced from the Rails application.js file

import { Application } from "@hotwired/stimulus"
import "controllers"

const application = Application.start()

// Configure Stimulus development experience
application.debug = false
window.Stimulus   = application

export { application }

and is rerefenced with its digest in the header of the page.
<link rel="modulepreload" href="/assets/controllers/buttonless-e2d65585b825be08ee9863e11720e29cf389075ede5ba34fb01abe0d03412d97.js">

However, the form on the page

<%= turbo_frame_tag dom_id(@garment, :intl) do %>
  <%= form_with(model: Measure.new, data: { controller: "buttonless" }) do |form| %>
    <%= form.hidden_field :garment_id, value: @garment.id %>
    <%= form.hidden_field :sequence, value: @next_sequence %>
    <%= form.text_field :value %>
  <% end %> 
<% end %>

and renders as

<form data-controller="buttonless" action="/measures" accept-charset="UTF-8" method="post"><input type="hidden" name="authenticity_token" value="[..]IoV1GW4g" autocomplete="off">
  <input value="1" autocomplete="off" type="hidden" name="measure[garment_id]" id="garment_id">
  <input value="1" autocomplete="off" type="hidden" name="measure[sequence]" id="measure_sequence">
  <input type="text" name="gmeasure[value]" id="measure_value">
</form>

The browser console does not register any errors, whereas a view-source on the page does not reference the data controller
<form action="/measures" accept-charset="UTF-8" method="post"> I am not certain what is at play for this point

clicking in the field, entering data, then tabbing out does not register any submission as expected. What is mistaken here?

Issues with javascript dates /times on server vs local browser (react)

I have a set of code running that checks two dates. If those two dates/times occurred on the same day, one course of action is taken. If they are not, a different set of components are shown. The code initially renders server side and we noticed that there were cases where the server side did not match the client side and this led to a refresh of those components.

We noticed that if one date/time was after 7pm, the date-fns function isSameDay returned false when run on the server despite the two dates being on the same day. This did not happen on the client. Comparing those dates with the .getDate() function on the javascript object also showed different days for the same case.

I output the GMT string, the ISO string, and the date, month and year of a blank date object (current date/time) as well as the two date/time strings referred to as Date 2 and Date 1 using the code below …

    <div>
      <div>{new Date().toGMTString()}</div>
      <Divider />
      <div>{new Date(Date2).toGMTString()}</div>
      <Divider />
      <div>{Date1.toGMTString()}</div>
    </div>
    <div>
      <div>{new Date().toISOString()}</div>
      <Divider />
      <div>{Date2.toISOString()}</div>
      <Divider />
      <div>{Date1.toISOString()}</div>
    </div>
    <div>
      <div>{`${new Date().getDate()}-${new Date().getMonth()}-${new Date().getFullYear()}`}</div>
      <Divider />
      <div>{`${Date2.getDate()}-${Date2.getMonth()}-${Date2.getFullYear()}`}</div>
      <Divider />
      <div>{`${Date1.getDate()}-${Date1.getMonth()}-${Date1.getFullYear()}`}</div>
    </div>

The strings used to create Date 1 and Date 2 are as follows :

Date1 – “2024-07-18T15:05:02.842Z”

Date2 – “2024-07-19T00:10:00Z”

Server Side Results

Item Now Date 2 Date 1
GMT Tue, 05 Nov 2024 16:33:12 GMT Fri, 19 Jul 2024 00:10:00 GMT Thu, 18 Jul 2024 15:05:02 GMT
ISO 2024-11-05T16:33:12.035Z 2024-07-19T00:10:00.000Z 2024-07-18T15:05:02.842Z
Day,month,year 5-10-2024 19-6-2024 18-6-2024

Client Side Results

Item Now Date 2 Date 1
GMT Tue, 05 Nov 2024 16:33:32 GMT Fri, 19 Jul 2024 00:10:00 GMT Thu, 18 Jul 2024 15:05:02 GMT
ISO 2024-11-05T16:33:32.820Z 2024-07-19T00:10:00.000Z 2024-07-18T15:05:02.842Z
Day,month,year 5-10-2024 18-6-2024 18-6-2024

The reason for the two interpretations is likely a timezone issue with my local timezone being 5 hours behind UTC.

The issue is that when Date2 was selected, 7pm on the 18th was selected and i’m not sure why it was stored improperly.

How do I address this? Can I convert “2024-07-19T00:10:00Z” to my local time zone?

load data dependent on language – can’t get dynamic javascript import to work (vanilla JS) [duplicate]

I want to load some javascript data dependent on the user’s language (not translation files). In PHP I would just go if ($lang == 'de') { include 'data-de.php'; } else { include 'data-en.php'; }, or something to that effect.

I understand it doesn’t work like that in JS, and I’ve looked into dynamic imports. This is what I have after determining the language to use (the value of lang):

// in data-{lang}.js
export const points = [{"id":"Q230416", …}, {…}, …];

// in map.js
import('./data-'+lang+'.js')
  .then((data) => {
    const points = data.points;
    console.log(data.points);
  })
  .catch((error) => {
    console.error(error);
  });

This gives me all my points in the log alright. However, how can I use them elsewhere? (The way I went about this is I wrote all the functionality with a fixed data set, and now I am retrofitting different data sets dependent on language – maybe that is not the best way to do it.)

I am pretty sure I’m missing something very basic here, like I haven’t understood all the relevant concepts yet – but I just can’t figure out what exactly I need to dive deeper into. Any pointers are much appreciated!

Firebase auth Problem in Custom API Routes

I used firebase authentication’s method signInWithEmailAndPassword in login api routes and user authenticated with this. Then I want to get user information with get-user api routes. I used auth in get-user api route. When user authenticates with login api routes auth has currentUser but when I want to get currentUser with auth in get-user api route I can’t see currentUser in auth so I want to fetch with get-user api route I always see user as null

/api/auth/login

// import { signInFB } from '@/app/libs/user';
import { NextResponse } from 'next/server';
import { serialize } from 'cookie';
import { SignJWT } from 'jose';
import { auth } from '@/app/libs/firebase';
import { signInWithEmailAndPassword } from 'firebase/auth';

const JWT_TOKEN = new TextEncoder().encode(process.env.JWT_SECRET!);

export const POST = async (req: Request) => {
  if (req.method !== 'POST') return NextResponse.json({ message: 'Invalid method' }, { status: 401 });

  try {
    const { email, password } = await req.json();

    const userCredential = await signInWithEmailAndPassword(auth, email, password);
    const user = userCredential.user;

    if (!user) return NextResponse.json({ message: 'giriş başarılı' }, { status: 401 });

    const payload = {
      id: user.uid,
      email: user.email,
    };

    const token = await new SignJWT(payload)
      .setProtectedHeader({ alg: 'HS256' })
      .setExpirationTime('1h')
      .sign(JWT_TOKEN);

    const response = NextResponse.json({ message: 'giriş başarılı', user }, { status: 200 });

    const cookie = serialize('authToken', token, {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      sameSite: 'strict',
      path: '/',
      maxAge: 60 * 60,
    });

    response.headers.append('Set-Cookie', cookie);

    return response;
  } catch (error) {
    console.log('error:', error);
    return NextResponse.json({ message: 'giriş başarılı' }, { status: 500 });
  }
};

export const runtime = 'nodejs';

/api/auth/get-user

import { auth } from '@/app/libs/firebase';
import { getUserFromFS } from '@/app/libs/user';
import { NextRequest, NextResponse } from 'next/server';

export const GET = async (req: NextRequest) => {
  if (req.method !== 'GET') return NextResponse.json({ message: 'Invalid method' }, { status: 401 });

  const user = auth.currentUser;

  if (user) {
    const fetchedUser = await getUserFromFS(user.uid);

    return NextResponse.json({ fetchedUser }, { status: 200 });
  }

  return NextResponse.json({ message: 'No user!' }, { status: 401 });
};

getUserFromFS function:

export const getUserFromFS = async (uid: string) => {
  try {
    const userDocRef = doc(db, 'users', uid);
    const userRef = await getDoc(userDocRef);

    if (userRef.exists()) {
      return userRef.data() as userProfile;
    } else {
      return null;
    }
  } catch (error) {
    if (error instanceof FirebaseError) {
      // Hata türü FirebaseError ise hatayı olduğu gibi fırlatıyoruz
      throw error;
    } else {
      // FirebaseError değilse genel bir hata olarak fırlatıyoruz
      throw new Error('An unexpected error occurred');
    }
  }
};

I am expecting getting user information