How do I trigger an event on a random second page of a site visit?

I will try my best to articulate this request without getting into specifics since there is sensitive data at play. Language is primarily Javascript with a little JSON, by the way.

I have been tasked with determining how to automatically trigger a popup on a page, but it must be the second page visited after whatever a user’s initial page visit is. So, for example, a user lands on the site’s homepage then navigates to, say, the ‘About’ page—the popup would then trigger on the ‘About’ page.

I have the code written for the popup trigger, which includes manually triggering the popup (which normally seen through a clickable button) and then creating a Local Storage variable to check if the user already viewed and closed it. This is easy to do for the initial page visit, but I have no idea how to code everything to check it for some random second page landing after some random initial page landing.

Is there any way to do this? For what it’s worth, I am also working within a testing platform, Optimizely, that handles some of the page targeting, but I don’t believe the solution is there, which is why I’m asking for help with the code.

Await dispatch does not seem to be working (VueX)

I have functions createSwipe, fetchUserSwipes, and fetchSwipedUserSwipes. I call fetchUserSwipes and fetchSwipedUserSwipes inside createSwipe using these:

await dispatch('fetchSwipedUserSwipes', swipedUserId);
await dispatch('fetchUserSwipes', userId);

They don’t seem to be called because the console logs I included in those functions are not printing in the console. These are the console logs:

//in fetchUserSwipes
console.log('Fetched User swipes:', data.userSwipes);

//in fetchSwipedUserSwipes
console.log('Fetched Swiped User swipes:', data.userSwipes);

Here is the rest of the code:

import { gql } from '@apollo/client/core';
import { apolloProvider } from '@/apollo-config'; 

const GET_TOTAL_SWIPES = gql`
    query {
        totalSwipes
    }
`;

const CREATE_SWIPE = gql`
    mutation($input: CreateSwipeInput!) {
        createSwipe(input: $input) {
            id
            userId
            swipedUserId
            likedBack
            createdAt
            updatedAt
        }
    }
`;

const GET_USER_SWIPES = gql`
  query GetUserSwipes($userId: ID!) {
    userSwipes(userId: $userId) {
      id
      userId
      swipedUserId
      likedBack
    }
  }
`;

const state = {
  totalSwipes: 0,
  userSwipes: {},
  swipedUserSwipes: {},  
  errorMessage: '',
};

const getters = {
  getTotalSwipes: state => state.totalSwipes,
  getUserSwipes: state => state.userSwipes,
  getSwipedUserSwipes: state => state.swipedUserSwipes,
  getSwipesCountErrorMessage: state => state.errorMessage,
  getCreateSwipeErrorMessage: state => state.errorMessage,
};

const actions = {
    async fetchTotalSwipes({ commit }) {
        try {
            const { data } = await apolloProvider.defaultClient.query({
                query: GET_TOTAL_SWIPES,
            });
            commit('SET_TOTAL_SWIPES', data.totalSwipes);
            console.log('Total Swipes:', data.totalSwipes);
        } catch (error) {
            commit('SET_ERROR_MESSAGE', error.message);
        }
    },
    async createSwipe({ commit, dispatch, getters }, { userId, swipedUserId }) {
      try {
        const { data } = await apolloProvider.defaultClient.mutate({
          mutation: CREATE_SWIPE,
          variables: { input: { userId, swipedUserId } },
        });
  
        const swipe = data.createSwipe;
  
        // Fetch swipes for the swiped user
        await dispatch('fetchSwipedUserSwipes', swipedUserId);
        await dispatch('fetchUserSwipes', userId);
  
        // Get the swiped user's swipes from the getter
        const swipedUserSwipes = getters.getSwipedUserSwipes[swipedUserId] || [];
        const matchingSwipe = swipedUserSwipes.find(swipe => swipe.userId === userId);
  
        if (matchingSwipe) {
          // Set likedBack to true for both users
          matchingSwipe.likedBack = true;
          swipe.likedBack = true;
  
          // Create matches for both users
          await dispatch('matches/createMatch', { userId, matchedUserId: swipedUserId }, { root: true });
          await dispatch('matches/createMatch', { userId: swipedUserId, matchedUserId: userId }, { root: true });
        }
      } catch (error) {
        commit('SET_ERROR_MESSAGE', error.message);
      }
    },
    async fetchSwipedUserSwipes({ commit }, userId) {
      try {
        const { data } = await apolloProvider.defaultClient.query({
          query: GET_USER_SWIPES,
          variables: { userId },
        });
        commit('SET_SWIPED_USER_SWIPES', { userId, swipes: data.userSwipes });
        console.log('Fetched Swiped User swipes:', data.userSwipes);
      } catch (error) {
        commit('SET_ERROR_MESSAGE', error.message);
      }
    },       
    async fetchUserSwipes({ commit }, userId) {
      try {
        const { data } = await apolloProvider.defaultClient.query({
          query: GET_USER_SWIPES,
          variables: { userId },
        });
  
        commit('SET_USER_SWIPES', { userId, swipes: data.userSwipes });
        console.log('Fetched User swipes:', data.userSwipes);
      } catch (error) {
        commit('SET_ERROR_MESSAGE', error.message);
      }
    },
};

const mutations = {
  SET_TOTAL_SWIPES(state, totalSwipes) {
      state.totalSwipes = totalSwipes;
  },
  SET_USER_SWIPES(state, { userId, swipes }) {
    state.userSwipes = {
      ...state.userSwipes,
      [userId]: swipes,
    };
  },
  SET_SWIPED_USER_SWIPES(state, { userId, swipes }) {
    state.swipedUserSwipes = {
      ...state.swipedUserSwipes,
      [userId]: swipes,
    };
  },
  SET_ERROR_MESSAGE(state, message) {
      state.errorMessage = message;
  },
};

export default {
    namespaced: true,
    state,
    getters,
    actions,
    mutations,
};

Any help would be greatly appreciated. Thank you so much.

Moving the scroller of a list container based on the position of an item in React

I have a list container and separate items that open as separate pages/routes. I’m trying to dinamically move the scroller of the container to a desired position based on the element’s position. For that I pass a function to the child item that retrieves the position of the item and then in the parent list, after updating the position state I try to set the scroller in useEffect. I have no problem retrieving the item position and setting the current position state in the parent. But the scroller itself never moves. To test with simpler code I checked how the state updates. The parent does re-render and the position does update but scroller position stays the same. I’m a new learner so I must be doing somethiong wrong. I have a separate context for more complex state updates, maybe the way I also update state in the component and not in the provider isn’t consistent and interferes with other async state updates (which involve retrieving the list of items with a request from a mock server)?

I’m copying the relevant part of my code:


    function HotelList() {
  const { hotels, filteredHotels, isLoading } = useHotels();
  const [isItemClicked, setIsItemClicked] = useState(false);

  const currHotel = useRef();

  function handleItemClick() {
    setIsItemClicked((oldStatus) => !oldStatus);
  }

  useEffect(
    function () {
      if (currHotel.current) {
        console.log(`I am refreshed and I'm ${currHotel.current}`);
        // Move the scroller 2 pixels each time there is a click
        currHotel.current.scrollTop += 2;
        console.log(currHotel.current.scrollTop);
      }
    },
    [isItemClicked]
  );`


...

 
   return (
    <ul className={styles.hotelList} ref={currHotel}>
      {filteredHotels.map((hotel) => (
        <HotelItem
          hotel={hotel}
          key={hotel.id}
          handleItemClick={handleItemClick}
        />
      ))}
    </ul>
  );

In the item component I simply pass the clickHandling function as props (again only passing the relevant part):

    <li style={{ cursor: "pointer" }} onClick={handleItemClick}>
      <Link
        className={`${styles.hotelItem} ${
          id === currentHotel.id ? styles["hotelItem--active"] : ""
        }`}
        to={`hotels/${id}?lat=${position.lat}&lng=${position.lng}`}
      >

On the console I get this log

I am refreshed and I'm [object HTMLUListElement]
HotelList.jsx:24 2
HotelList.jsx:21 I am refreshed and I'm [object HTMLUListElement]
HotelList.jsx:24 2

My JavaScript code from one page is inadvertently affecting another page. How can I ensure that scripts are isolated correctly?

I have two HTML pages (page1.html and page2.html) each with their own JavaScript files (home-page.js and add-flashcard.js, respectively). Despite correctly linking the scripts, the JavaScript code from page2.html is somehow being executed or affecting page1.html.

in one JavaScript files my functions use “addEventListeners” and when I run a completely different page not related to the code with the functions, it says cannot read properties of null (reading ‘addEventListeners’) and it says that because the buttons for the event listeners are on a different page and i am sure that the page are not connected.

this is the only Javascript file I linked
Although I did have to import an array from that file that is running on the wrong page

enter image description here

enter image description here

Please can anyone help this is a school project

azure-ai-vision-faceanalyzer not working on React JS

As per azure face liveness detection doc I create a session and got token in server side, but in a client side I’m using React JS.
i followed the link the .npmrc setup and installed the library npm install azure-ai-vision-faceanalyzer

After that I paste the token which is got from session response
when I run the project I got and white page and error like this in my console

GET http://localhost:5173/faceanalyzer-assets/js/AzureAIVisionFace_SIMDBundle.js net::ERR_ABORTED 404 (Not Found)

import React, { useRef } from 'react';

// Step 1: Import the web component.
import "azure-ai-vision-faceanalyzer";

const AzureAIVisionFaceAnalyzerComponent = () => {
    const containerRef = useRef(null);
    // Step 2: Create the faceanalyzer element, set the token and upgrade the element.
    let azureAIVisionFaceAnalyzer = document.createElement("azure-ai-vision-faceanalyzer");
    customElements.upgrade(azureAIVisionFaceAnalyzer);
    azureAIVisionFaceAnalyzer.token = "***TOKEN***";
    azureAIVisionFaceAnalyzer.addEventListener('analyzed', (event) => {
            // The event.result, which is FaceAnalyzedResult interface, contains the result of the analysis. 
            console.log(event);
        });
    if (containerRef.current) {
        containerRef.current.appendChild(azureAIVisionFaceAnalyzer);
    }
    
    return <div ref={containerRef}></div>;
};

function App() {
  return (
    <div className="App">
      <AzureAIVisionFaceAnalyzerComponent />
    </div>
  );
}

export default App;

ODOO V17 JS usage

I’m trying to get record data from a model in my JS. I see that I can use RPC to do this, but when I try, I have a lot of problems loading RPC first, and I don’t know how to execute this correctly.
Here the code i try to execute:
odoo.define('js_worked.record',[] ,function (require) {"use strict";console.log('TEST REUSSI')var rpc = require('web.rpc');rpc.query({model: 'purchase.order',method: '_get_data_records',args: [[]],}).then(function (data){console.log(data);});});
I just want to get odoo record data from model in my js

How to make scrollable game that follows the main character if we use keys or scroll if we use the wheel with Phaser3?

It is my first time using Phaser3 and I am trying to create a game to display in a website. My plan was to make a vertical map that you can navigate either with the keys and scrolling. The thing is that I do not find any examples online, since if the camera follows the character, I do not manage to make the scroll work, and the other way around. Here is a snipet of my code in case it helps

//Creo la configuracion del juego
const config = {
    type: Phaser.AUTO,
    width: window.innerWidth,
    height: 2000,
    scale: {
        mode: Phaser.Scale.NONE,
        parent: 'game',
        autoCenter: Phaser.Scale.CENTER_BOTH
    },
    backgroundColor: '#000000', //fondo
    parent: 'game', //Donde se va a renderizar
    physics:{
        default: 'arcade', // arcade, impact o matery
        arcade: {
            gravity: {y: 300},
            debug: false
        }
    },
    scene: {
        preload: preload, //cargamos imagenes, recursos etc
        create: create, //usamos esas imagenes, recursos
        update: update //se actualiza contantemente
    }
}

//Inicializo el juego con la configuracion
new Phaser.Game(config);

function preload(){ //1
    this.load.image(
        'dessert-background',
        'assets/background/dessert-bg.jpg'
    );

    //Sprite character
    this.load.spritesheet(
        'hero', //id, solo puede haber uno con ese id
        'assets/entities/hero_sprite.png',
        {frameWidth:64, frameHeight: 64} 
    ); 
}

function create(){ //2

    let bg = this.add.image(0, 0, 'dessert-background')
        .setOrigin(0, 0);

    bg.displayWidth = this.sys.game.config.width;
    bg.displayHeight = this.sys.game.config.height;
    bg.alpha = 0.3; //transparencia

    window.addEventListener('resize', () => {
        bg.displayWidth = document.documentElement.clientWidth - scrollbarWidth
    });

    this.hero = this.physics.add.sprite(50,100,'hero')
        .setOrigin(0,1)
        .setCollideWorldBounds(true)
        .setGravityY(300);

    this.physics.world.setBounds(0,0,config.width, 2000);
    this.cameras.main.setBounds(0,0,config.width, 2000);
    this.cameras.main.startFollow(this.hero, true, 0.1, 0.1); // Suavizado de seguimiento

    createAnimations(this);

    this.keys = this.input.keyboard.createCursorKeys();
}

How to create a curve on top of app bar when selected

I am creating one mobile appbar. I am trying to create a curve above when user selects it.i created another curve div. but that is separate div. so it hasn’t worked out. I tried but I don’t how to implement it. Can anyone help me with that. I need a curve above when the user clicked on the item

enter image description here

Here’s the code:

import { AiFillBell } from "react-icons/ai";
import { GoHomeFill } from "react-icons/go";
import { IoMdSettings } from "react-icons/io";
import { FaUser } from "react-icons/fa";
import { useState } from "react";

export default function App() {
  const [selectedItem, setSelectedItem] = useState("home");

  const menuItems = [
    {
      name: "notification",
      icon: <AiFillBell style={{ height: "24px", width: "24px" }} />,
    },
    {
      name: "home",
      icon: <GoHomeFill style={{ height: "24px", width: "24px" }} />,
    },
    {
      name: "settings",
      icon: <IoMdSettings style={{ height: "24px", width: "24px" }} />,
    },
    {
      name: "user",
      icon: <FaUser style={{ height: "24px", width: "24px" }} />,
    },
  ];

  return (
    <div style={{ background: "black", height: "100vh", padding: "50px" }}>
      <div
        style={{
          background: "#0a0e18",
          height: "58px",
          borderRadius: "20px",
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
          padding: "0px 30px",
          border: "1px solid #2e3239",
        }}
      >
        {menuItems.map((item, index) => (
          <div
            key={index}
            onClick={() => setSelectedItem(item.name)}
            style={{
              opacity: selectedItem === item.name ? 1 : 0.2,
              cursor: "pointer",
              color: "#fff",
            }}
          >
            {item.icon}
          </div>
        ))}
      </div>
    </div>
  );
}

How to Merge Cells with Consecutive Duplicate Values in AG Grid and Make Columns Dynamic Based on User Selection?

I am using AG Grid in my HTML, and I need to achieve a functionality that merges cells with the same values in a column. This should make it visually clear when there are repeated values in consecutive rows. if there are consecutive rows with the same value, they should be merged into a single cell spanning multiple rows, with the value centred vertically.

Here is a picture example of what it looks like without the cell merging
What my grid looks like without cell merging

and here is picture of what i am trying to achieve
What my grid should look like after successful implementation of the cell merging

Additionally, I want the columns to be dynamic based on the user’s selection. If a column is removed, the data and summed values should automatically repivot and provide the new value of the pivot.

Additional Information:
I am using AG Grid, and you can find the documentation here.
https://www.ag-grid.com/javascript-data-grid/grid-interface/

Here is a link to my code for review:

https://codesandbox.io/invite/jn5cyy2572zpm2h7

Below is what my python code which can be found i the link above,

@app.route('/get-data-CF')
def get_data_CF():
    try:
        correct_order = ['Cash Flow Main 4', 'Cash Flow Main 3',
                         'Cash Flow Main 2', 'Cash Flow Main 1', 'Cash Flow Category']
        include_currency = request.args.get(
            'include_currency', 'false').lower() == 'true'
        if include_currency:
            correct_order.insert(0, 'transaction_currency_code')

        start_date = request.args.get('start_date')
        end_date = request.args.get('end_date')

        cashforce_df = pd.read_csv('static/excel/Modified_Cash_Pool_Data.csv')
        bank_balance_df = pd.read_csv(
            'static/excel/Modified_Bank_Balances_Data.csv')

        cashforce_df['transaction_dt'] = pd.to_datetime(
            cashforce_df['transaction_dt'])
        if start_date and end_date:
            cashforce_df = cashforce_df[(cashforce_df['transaction_dt'] >= start_date) & (
                cashforce_df['transaction_dt'] <= end_date)]
        else:
            current_month_start = datetime.now().replace(day=1)
            current_month_end = (
                current_month_start + pd.DateOffset(months=1)) - pd.DateOffset(days=1)
            cashforce_df = cashforce_df[(cashforce_df['transaction_dt'] >= current_month_start) & (
                cashforce_df['transaction_dt'] <= current_month_end)]

        grouped_df = cashforce_df.groupby(
            correct_order + ['transaction_dt']).agg({'transaction_amount': 'sum'}).reset_index()
        pivot_df = grouped_df.pivot_table(
            index=correct_order, columns='transaction_dt', values='transaction_amount', aggfunc='sum', fill_value=0)
        pivot_df.columns = [col.strftime(
            '%Y-%m-%d') if isinstance(col, pd.Timestamp) else col for col in pivot_df.columns]
        pivot_df.reset_index(inplace=True)

        combined_rows = []
        for currency in bank_balance_df['transaction_currency_code'].unique() if include_currency else ['GBP']:
            opening_balance_row = {col: '' for col in pivot_df.columns}
            closing_balance_row = {col: '' for col in pivot_df.columns}
            if include_currency:
                opening_balance_row['transaction_currency_code'] = currency
                closing_balance_row['transaction_currency_code'] = currency
            opening_balance_row['Cash Flow Main 4'] = 'Opening Balance'
            closing_balance_row['Cash Flow Main 4'] = 'Closing Balance'
            opening_balance = bank_balance_df.loc[bank_balance_df['transaction_currency_code'] == currency, 'balance'].sum(
            ) if include_currency else 0
            closing_balance = opening_balance
            for date_col in pivot_df.columns:
                if date_col not in correct_order:
                    opening_balance_row[date_col] = f"{opening_balance:.2f}"
                    closing_balance_row[date_col] = f"{closing_balance:.2f}"
            combined_rows.append(pd.DataFrame([opening_balance_row]))
            combined_rows.append(
                pivot_df[pivot_df['transaction_currency_code'] == currency] if include_currency else pivot_df)
            combined_rows.append(pd.DataFrame([closing_balance_row]))

        combined_df = pd.concat(combined_rows, ignore_index=True)

        numeric_columns = combined_df.select_dtypes(include=['number']).columns
        for col in numeric_columns:
            combined_df[col] = combined_df[col].apply(lambda x: f"{x:.2f}")

        json_data_CF = combined_df.to_json(orient='records', date_format='iso')
        print(json_data_CF)

        return jsonify(json_data_CF=json_data_CF)
    except Exception as e:
        return jsonify(error=str(e)), 500

below is my js code which can also be found in the codesandbox

document.addEventListener("DOMContentLoaded", () => {
  const basePinnedColumns = [
    "Cash Flow Main 4",
    "Cash Flow Main 3",
    "Cash Flow Main 2",
    "Cash Flow Main 1",
    "Cash Flow Category",
  ];
  const allPinnedColumns = ["transaction_currency_code"].concat(
    basePinnedColumns,
  );
  let availablePinnedColumns = [];

  function rowSpan(params) {
    if (!params.data || !params.column || !params.api) return 1;
    const column = params.column.colId;
    const rowIndex = params.rowIndex;
    const rowData = params.data;
    let spanCount = 1;

    for (let i = rowIndex + 1; i < params.api.getDisplayedRowCount(); i++) {
      const nextData = params.api.getDisplayedRowAtIndex(i).data;
      if (nextData && nextData[column] === rowData[column]) {
        spanCount++;
      } else {
        break;
      }
    }
    return spanCount;
  }

  const gridOptions = {
    defaultColDef: {
      flex: 1,
      minWidth: 100,
      resizable: true,
      sortable: true,
      filter: true,
      cellClass: (params) => {
        if (
          params.data &&
          (params.data["Cash Flow Main 4"] === "Opening Balance" ||
            params.data["Cash Flow Main 4"] === "Closing Balance")
        ) {
          return params.colDef.field === "Cash Flow Main 4"
            ? "balance-label-cell"
            : "balance-value-cell";
        }
        return null;
      },
      cellStyle: (params) => {
        if (
          params.data &&
          (params.data["Cash Flow Main 4"] === "Opening Balance" ||
            params.data["Cash Flow Main 4"] === "Closing Balance")
        ) {
          return params.colDef.field === "Cash Flow Main 4"
            ? { textAlign: "left" }
            : { textAlign: "right" };
        }
        return null;
      },
    },
    autoGroupColumnDef: {
      headerName: "Account Currency",
      field: "transaction_currency_code",
      cellRenderer: "agGroupCellRenderer",
      cellRendererParams: {
        suppressCount: true,
        innerRenderer: (params) => {
          if (
            params.node.group &&
            params.node.field === "transaction_currency_code"
          ) {
            return `<div class="currency-cell">${params.node.key}</div>`;
          } else {
            return params.value;
          }
        },
      },
    },
    rowGroupPanelShow: "always",
    groupDefaultExpanded: -1,
    columnDefs: [],
    rowData: [],
    suppressRowTransform: true,
  };

  const gridDiv = document.querySelector("#myGrid");
  const gridApi = agGrid.createGrid(gridDiv, gridOptions);

  function updateColumns(columnNames, includeCurrency) {
    const pinnedColumns = includeCurrency
      ? allPinnedColumns
      : basePinnedColumns;
    const orderedColumnNames = pinnedColumns.concat(
      columnNames.filter((name) => !pinnedColumns.includes(name)),
    );

    const columnDefs = orderedColumnNames.map((key) => ({
      headerName:
        key === "transaction_currency_code" ? "Account Currency" : key,
      field: key,
      sortable: true,
      filter: true,
      pinned: pinnedColumns.includes(key) ? "left" : null,
      rowSpan: rowSpan,
      cellClassRules: {
        "cell-span": 'value && value !== ""',
      },
    }));
    gridApi.updateGridOptions({ columnDefs: columnDefs });
    updateColumnControlPanel(
      columnDefs.filter((col) => basePinnedColumns.includes(col.field)),
    );
  }

  function fetchData(startDate, endDate, includeCurrency = false) {
    let url = "/get-data-CF";
    if (startDate && endDate) {
      url += `?start_date=${startDate}&end_date=${endDate}`;
    }
    if (includeCurrency) {
      url += url.includes("?") ? "&" : "?";
      url += "include_currency=true";
    }

    fetch(url)
      .then((response) => {
        if (!response.ok) {
          throw new Error(
            "Network response was not ok: " + response.statusText,
          );
        }
        return response.json();
      })
      .then((response) => {
        const data = JSON.parse(response.json_data_CF);
        if (data && data.length > 0) {
          const columnNames = Object.keys(data[0]);
          updateColumns(columnNames, includeCurrency);
          gridApi.updateGridOptions({ rowData: data });
          availablePinnedColumns = allPinnedColumns.filter(
            (col) => !columnNames.includes(col),
          );
          updateAvailableColumnsDropdown();
        }
      })
      .catch((error) => {
        console.error("Error fetching data:", error);
        fetch(url)
          .then((response) => response.text())
          .then((text) => console.log("Response was:", text));
      });
  }

  const startDatePicker = flatpickr('input[name="start_date"]', {
    dateFormat: "Y-m-d",
  });
  const endDatePicker = flatpickr('input[name="end_date"]', {
    dateFormat: "Y-m-d",
  });

  document.getElementById("dateFilterBtn").addEventListener("click", () => {
    const startDate = startDatePicker.input.value;
    const endDate = endDatePicker.input.value;
    if (startDate && endDate) {
      fetchData(
        startDate,
        endDate,
        document.getElementById("currencyToggle").checked,
      );
    }
  });

  fetchData();

  document.getElementById("currencyToggle").addEventListener("change", () => {
    const startDate = startDatePicker.input.value;
    const endDate = endDatePicker.input.value;
    fetchData(
      startDate,
      endDate,
      document.getElementById("currencyToggle").checked,
    );
  });

  function isColumnOrderValid(currentOrder) {
    let indexMap = currentOrder
      .map((column) => allPinnedColumns.indexOf(column))
      .filter((index) => index !== -1);
    return indexMap.every((val, i, arr) => !i || val > arr[i - 1]);
  }

  function updateColumnControlPanel(columnDefs) {
    const panel = document.getElementById("activeColumns");
    panel.innerHTML = "";
    columnDefs.forEach((col) => {
      const colDiv = document.createElement("div");
      colDiv.textContent = `${col.headerName} `;
      const removeBtn = document.createElement("button");
      removeBtn.textContent = "x";
      removeBtn.onclick = () => removeColumn(col.field);
      colDiv.appendChild(removeBtn);
      panel.appendChild(colDiv);
    });
    updateAvailableColumnsDropdown();
  }

  function removeColumn(field) {
    const allColumns = gridApi.getColumnDefs();
    const newColumnDefs = allColumns.filter((col) => col.field !== field);
    if (!isColumnOrderValid(newColumnDefs.map((def) => def.field))) {
      alert("Removing this column would result in invalid data aggregation.");
      return;
    }
    availablePinnedColumns.push(field);
    gridApi.updateGridOptions({ columnDefs: newColumnDefs });
    updateColumnControlPanel(
      newColumnDefs.filter((col) => basePinnedColumns.includes(col.field)),
    );
    updateAvailableColumnsDropdown();
  }

  function updateAvailableColumnsDropdown() {
    const dropdown = document.getElementById("availableColumns");
    if (!dropdown) {
      console.error("Dropdown element not found");
      return;
    }
    dropdown.innerHTML = "";
    availablePinnedColumns.forEach((field) => {
      const option = new Option(field, field);
      dropdown.add(option);
    });
  }

  window.addColumn = function () {
    const dropdown = document.getElementById("availableColumns");
    const fieldToAdd = dropdown.value;
    if (!fieldToAdd) return;
    const allColumns = gridApi.getColumnDefs();
    const columnToAdd = {
      headerName: fieldToAdd,
      field: fieldToAdd,
      sortable: true,
      filter: true,
      pinned: "left",
    };
    const newColumnDefs = [...allColumns, columnToAdd];
    if (!isColumnOrderValid(newColumnDefs.map((def) => def.field))) {
      alert("Adding this column would result in invalid data aggregation.");
      return;
    }
    gridApi.updateGridOptions({ columnDefs: newColumnDefs });
    availablePinnedColumns = availablePinnedColumns.filter(
      (col) => col !== fieldToAdd,
    );
    updateColumnControlPanel(
      newColumnDefs.filter((col) => basePinnedColumns.includes(col.field)),
    );
    updateAvailableColumnsDropdown();
  };
});

To display the grid, please select a start date from 1st of April and end date of 30th of April and click the filter button, as those are the only data available, and click the filter button to display the grid.

I have looked into AG Grid’s documentation and tried to implement the row spanning functionality, but I am not getting the desired merging effect for consecutive duplicates. I also tried making the columns dynamic but couldn’t achieve the automatic repivoting and summing of values based on user selection.

Creating Framework for using Vanilla Webpack [closed]

Hi I’m jade any suggestion on creating a framework? I am familiar with node but is wepback is the king of framework or just node is best for server…… I’m studying web development for 1.5 years now I’m still a beginner please help me.

node or webpack!? I create my own elements I’m just waiting for

Customize Strapi v4 Left menu items with patch-package

I’m trying to customize the Strapi left menu by using patch-package, but I can’t find how to apply the changes.

I’m using Strapi 4.24.2

First of all, I had the patch-package module and a script “postinstall: patch-package” in the package.json

Then I made some changes inside the “index-hDD1JNph.js” in the node_modules

After that I ran the command :

npx patch-package @strapi/admin

Finally, I ran

docker-compose build

docker-compose up

but I see no changes in the Strapi admin panel

package.json:

{
  "name": "heritage-cms",
  "private": true,
  "version": "0.1.0",
  "description": "A Strapi application",
  "scripts": {
    "develop": "strapi develop",
    "start": "strapi start",
    "build": "strapi build",
    "strapi": "strapi"
  },
  "dependencies": {
    "@_sh/strapi-plugin-ckeditor": "^2.1.1",
    "@strapi/plugin-color-picker": "^4.24.2",
    "@strapi/plugin-documentation": "4.24.2",
    "@strapi/plugin-i18n": "4.24.2",
    "@strapi/plugin-seo": "^1.9.8",
    "@strapi/plugin-users-permissions": "4.24.2",
    "@strapi/provider-upload-cloudinary": "^4.25.0",
    "@strapi/strapi": "4.24.2",
    "cloudinary": "^2.2.0",
    "mysql": "^2.18.1",
    "react": "^18.0.0",
    "react-dom": "^18.0.0",
    "react-is": "^18.3.1",
    "react-router-dom": "5.3.4",
    "strapi-gtm-module": "^0.0.5",
    "strapi-plugin-cookie-manager": "^1.2.4",
    "strapi-plugin-google-analytics": "^0.0.0",
    "strapi-plugin-populate-deep": "^3.0.1",
    "styled-components": "5.3.3"
  },
  "author": {
    "name": "A Strapi developer"
  },
  "strapi": {
    "uuid": "a7af0888-4778-46c2-9a6c-f1d1c2dffdb7"
  },
  "engines": {
    "node": ">=18.0.0 <=20.x.x",
    "npm": ">=6.0.0"
  },
  "license": "MIT"
}

Dockerfile:

FROM node:18-alpine3.18
# Installing libvips-dev for sharp Compatibility
RUN apk update && apk add –no-cache build-base gcc autoconf automake zlib-dev libpng-dev nasm bash vips-dev
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}

WORKDIR /opt/
COPY package.json yarn.lock ./
RUN yarn config set network-timeout 600000 -g && yarn install

WORKDIR /opt/app
COPY . .
ENV PATH /opt/node_modules/.bin:$PATH
RUN chown -R node:node /opt/app
USER node
RUN ["yarn", "build"]
EXPOSE 1337
CMD ["yarn", "develop"]

docker-compose.yml:

services:
  heritage-cms:
    container_name: heritage-cms
    build: .
    env_file: .env
    environment:
      DATABASE_CLIENT: ${DATABASE_CLIENT}
      DATABASE_HOST: ${DATABASE_HOST}
      DATABASE_NAME: ${DATABASE_NAME}
      DATABASE_USERNAME: ${DATABASE_USERNAME}
      DATABASE_PORT: ${DATABASE_PORT}
      JWT_SECRET: ${JWT_SECRET}
      ADMIN_JWT_SECRET: ${ADMIN_JWT_SECRET}
      DATABASE_PASSWORD: ${DATABASE_PASSWORD}
      NODE_ENV: ${NODE_ENV}
    volumes:
      - ./config:/opt/app/config
      - ./src:/opt/app/src
      - ./package.json:/opt/package.json
      - ./yarn.lock:/opt/yarn.lock

      - ./.env:/opt/app/.env
      - ./public/uploads:/opt/app/public/uploads
    ports:
      - "1337:1337"
    networks:
      - heritage-cms
    depends_on:
      - heritage-cmsDB

  heritage-cmsDB:
    container_name: heritage-cmsDB
    platform: linux/amd64 #for platform error on Apple M1 chips
    env_file: .env
    image: mysql:8.3.0
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: ${DATABASE_PASSWORD}
      MYSQL_DATABASE: ${DATABASE_NAME}
    volumes:
      - ./mysql-init-scripts:/docker-entrypoint-initdb.d/heritage_dump
      - heritage-cms-data:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - heritage-cms

  heritage-cmsAdminer:
    container_name: heritage-cmsAdminer
    image: adminer
    ports:
      - "9090:8080"
    environment:
      - ADMINER_DEFAULT_SERVER=heritage-cmsDB
    networks:
      - heritage-cms
    depends_on:
      - heritage-cmsDB

volumes:
  heritage-cms-data:

networks:
  heritage-cms:
    name: Heritage-cms
    driver: bridge

React native ecg charts

For my React Native project, I need to implement an ECG chart. I have already tried several libraries, including svg-charts, react-native-charts-wrapper, react-native-chart-kit, react-native-responsive-linechart, and react-native-gifted-charts.

Could anyone recommend a library specifically designed for plotting ECG data on a chart?

I have already tried several libraries, including svg-charts, react-native-charts-wrapper, react-native-chart-kit, react-native-responsive-linechart, and react-native-gifted-charts.

How to restrict past time selection in jquery-clockpicker.min.js

When I am open the clockpicker at that time past time also show, so i want to disabled the past time based on current time.
If my current time is 4:00 PM so inside the clock picker disabled before 4:00 PM time.

I am try this solution but this is not working
This is my HTML code

@Html.TextBoxFor(x => x.StartTime, new { @class = "form-control clockpicker", autocomplete = "off", @readonly = "readonly", placeholder = "00:00" })

and this is my JS code

var minTime = $("#minTime").val();

    $('.clockpicker').clockpicker({
        donetext: 'Done',
        autoclose: true,
        beforeShow: function () {
            var currentTime = new Date();
            var minHours = currentTime.getHours();
            var minMinutes = currentTime.getMinutes();
            var minTime = (minHours < 10 ? '0' : '') + minHours + ':' + (minMinutes < 10 ? '0' : '') + minMinutes;

            // Disable times earlier than the current time
            $('.clockpicker-span-hours').each(function () {
                debugger;
                var hour = parseInt($(this).text(), 10);
                if (hour < minHours) {
                    $(this).addClass('disabled');
                } else if (hour == minHours) {
                    $('.clockpicker-span-minutes').each(function () {
                        var minute = parseInt($(this).text(), 10);
                        if (minute < minMinutes) {
                            $(this).addClass('disabled');
                        }
                    });
                }
            });
        }
    });

Understanding the work together and howto for <button type="submit" between HTML js and php

I searched around for the last few days, but couldn’t get the entry point of understanding.
How the work together between HTML, Js and PHP for the submit button is.
Especially for my case, I want a submit button that triggers bootstrap toast via id=”” and submit the name=”” value further to PHP (but more later)

So for my comprehension, I thought / knew:

  1. normally a Html <button type="submit" is going via
    form action to PHP and give them the name and value tags that i could grab them.
    (php is not the problem I normally get the data)
  2. and if there is a id="value" it goes to javascript

But in my example code from bootstrap toast, I always get just the name="" and value="" tag back in PHP via var_dump($_POST); or I just
get a pop-up on the JavaScript side from Bootstrap toast. I have seen code who grab the form data to JS and declare own var’s and sends them further to PHP. But this seems for me, not such efficient. Declare twice and also possibility for bugs, security risks (if not declared correct) are higher I think.

So long things short, how is the guideline or standard way to do it ? I am correct on HTML id "" to JS and form to PHP ? What are I been missing to learn about ? I already read the MDN Document: getElementsByClassName() method and also for id and what is an element and so on.

I think I miss something to declare in Js, like the form submit must go imediatly to PHP ?
I have done it also with form.submit() but never receive the post to php $_POST.

Bootstrap example code: //changed button to submit

<button type="submit" class="btn btn-primary" id="liveToastBtn">Show live toast</button>

<div class="toast-container position-fixed bottom-0 end-0 p-3">
  <div id="liveToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
    <div class="toast-header">
      <img src="..." class="rounded me-2" alt="...">
      <strong class="me-auto">Bootstrap</strong>
      <small>11 mins ago</small>
      <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
    </div>
    <div class="toast-body">
      Hello, world! This is a toast message.
    </div>
  </div>
</div>

tied in js:

const toastTrigger = document.getElementById('liveToastBtn')
const toastLiveExample = document.getElementById('liveToast')

if (toastTrigger) {
  const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample)
  toastTrigger.addEventListener('click', () => {
    toastBootstrap.show()
  })
}

changed:

<form id="form>" 
document.getElementById('form')
addEventListener('submit'
// also ofcourse addEventListener('click'

or also included :
preventDefault();

How ever please explain what i missed, to get the submit button working with show bootstrap toast and send the form to php.
I mention 99% i missed something in here :

 toastTrigger.addEventListener('click', () => {
 toastBootstrap.show()
// do submit my form to php
   })