Adding Music to Each HTML page using Javascript [closed]

I am quite new to this and learning from scratch. I am creating a website for my children and I would like to add music to my pages, but not only one, but a different song for each page.

I know this code, plays a song throughout my whole website

var audio = new Audio("C: path");
audio.play()

But what could I do to have a different song added to 4 HTML pages, lets say

I have done this

const pageAudioMap = { //defined an object to map page URLs to audio file

Issue with Predictive Search Add to Cart Button not working for first product result in Shopify Dawn Theme

I’m using Shopify Dawn theme.

In predictive search results, I want to add Quantity selector & Add to cart button beside the product listing.

For the first product result, tag is not showing, due to which I’m not able to add to cart the product. For rest product items, it works perfectly.

Store URL – https://demostore-theme.myshopify.com
Password – 123

Search with keyword – “de”

1st result – https://prnt.sc/vwKRqVRDTYS3
Console error – https://prnt.sc/M_8u_9O7Mm0e

For rest result – https://prnt.sc/DSWORL0h9FEY (works perfectly)

I have edited this code in predictive-search.liquid

{%- for product in predictive_search.resources.products -%}
  <li
    id="predictive-search-option-product-{{ forloop.index }}"
    class="predictive-search__list-item"
    role="option"
    aria-selected="false"
  >
    <a
      href="{{ product.url }}"
      class="predictive-search__item predictive-search__item--link-with-thumbnail link link--text"
      tabindex="-1"
    >
      {%- if product.featured_media != blank -%}
        <img
          class="predictive-search__image"
          src="{{ product.featured_media | image_url: width: 150 }}"
          alt="{{ product.featured_media.alt }}"
          width="50"
          height="{{ 50 | divided_by: product.featured_media.preview_image.aspect_ratio }}"
        >
      {%- endif -%}
      <div class="predictive-search__item-content{% unless settings.predictive_search_show_vendor or settings.predictive_search_show_price %} predictive-search__item-content--centered{% endunless %}">
        {%- if settings.predictive_search_show_vendor -%}
          <span class="visually-hidden">{{ 'accessibility.vendor' | t }}</span>
          <div class="predictive-search__item-vendor caption-with-letter-spacing">
            {{ product.vendor }}
          </div>
        {%- endif -%}
        <p class="predictive-search__item-heading h5">{{ product.title | escape }}</p>
        {%- if settings.predictive_search_show_price -%}
          {% render 'price', product: product, use_variant: true, show_badges: false %}
        {%- endif -%}
      </div>
    </a>

    <!-- Customization for Add to Cart -->
    <div class="quick-add no-js-hidden">
      {%- liquid
        assign section_id = section.id
        assign product_form_id = 'quick-add-' | append: section_id | append: product.id
        assign qty_rules = false
        if product.selected_or_first_available_variant.quantity_rule.min > 1 or product.selected_or_first_available_variant.quantity_rule.max != null or product.selected_or_first_available_variant.quantity_rule.increment > 1
          assign qty_rules = true
        endif
      -%}
      {%- if product.variants.size > 1 or qty_rules -%}
        <modal-opener data-modal="#QuickAdd-{{ product.id }}">
          <button
            id="{{ product_form_id }}-submit"
            type="submit"
            name="add"
            class="quick-add__submit button button--full-width button--secondary{% if horizontal_quick_add %} card--horizontal__quick-add animate-arrow{% endif %}"
            aria-haspopup="dialog"
            aria-labelledby="{{ product_form_id }}-submit title-{{ section_id }}-{{ product.id }}"
            data-product-url="{{ product.url }}"
          >
            {{ 'products.product.choose_options' | t }}
            {%- if horizontal_quick_add -%}
              <span class="icon-wrap">{% render 'icon-arrow' %}</span>
            {%- endif -%}
            {%- render 'loading-spinner' -%}
          </button>
        </modal-opener>
        <quick-add-modal id="QuickAdd-{{ product.id }}" class="quick-add-modal">
          <div
            role="dialog"
            aria-label="{{ 'products.product.choose_product_options' | t: product_name: product.title | escape }}"
            aria-modal="true"
            class="quick-add-modal__content global-settings-popup"
            tabindex="-1"
          >
            <button
              id="ModalClose-{{ product.id }}"
              type="button"
              class="quick-add-modal__toggle"
              aria-label="{{ 'accessibility.close' | t }}"
            >
              {% render 'icon-close' %}
            </button>
            <div id="QuickAddInfo-{{ product.id }}" class="quick-add-modal__content-info"></div>
          </div>
        </quick-add-modal>
      {%- else -%}
        <product-form data-section-id="{{ section.id }}">
          {%- form 'product',
            product,
            id: product_form_id,
            class: 'form',
            novalidate: 'novalidate',
            data-type: 'add-to-cart-form'
          -%}
            <!-- Qty Selection -->
            <div
              id="Quantity-Form-{{ section.id }}"
              class="product-form__input product-form__quantity{% if settings.inputs_shadow_vertical_offset != 0 and settings.inputs_shadow_vertical_offset < 0 %} product-form__quantity-top{% endif %}"
              {{ block.shopify_attributes }}
            >
              {% comment %} TODO: enable theme-check once `item_count_for_variant` is accepted as valid filter {% endcomment %}
              {% # theme-check-disable %}
              {%- assign cart_qty = cart | item_count_for_variant: product.selected_or_first_available_variant.id -%}
              {% # theme-check-enable %}

              <div class="price-per-item__container">
                <quantity-input class="quantity" data-url="{{ product.url }}" data-section="{{ section.id }}">
                  <button class="quantity__button no-js-hidden" name="minus" type="button">
                    <span class="visually-hidden">
                      {{- 'products.product.quantity.decrease' | t: product: product.title | escape -}}
                    </span>
                    {% render 'icon-minus' %}
                  </button>
                  <input
                    class="quantity__input"
                    type="number"
                    name="quantity"
                    id="Quantity-{{ section.id }}"
                    data-cart-quantity="{{ cart_qty }}"
                    data-min="{{ product.selected_or_first_available_variant.quantity_rule.min }}"
                    min="{{ product.selected_or_first_available_variant.quantity_rule.min }}"
                    {% if product.selected_or_first_available_variant.quantity_rule.max != null %}
                      data-max="{{ product.selected_or_first_available_variant.quantity_rule.max }}"
                      max="{{ product.selected_or_first_available_variant.quantity_rule.max }}"
                    {% endif %}
                    step="{{ product.selected_or_first_available_variant.quantity_rule.increment }}"
                    value="{{ product.selected_or_first_available_variant.quantity_rule.min }}"
                    form="{{ product_form_id }}"
                  >
                  <button class="quantity__button no-js-hidden" name="plus" type="button">
                    <span class="visually-hidden">
                      {{- 'products.product.quantity.increase' | t: product: product.title | escape -}}
                    </span>
                    {% render 'icon-plus' %}
                  </button>
                </quantity-input>
                {%- liquid
                  assign volume_pricing_array = product.selected_or_first_available_variant.quantity_price_breaks | sort: 'quantity' | reverse
                  assign current_qty_for_volume_pricing = cart_qty | plus: product.selected_or_first_available_variant.quantity_rule.min
                  if cart_qty > 0
                    assign current_qty_for_volume_pricing = cart_qty | plus: product.selected_or_first_available_variant.quantity_rule.increment
                  endif
                -%}
                {%- if product.quantity_price_breaks_configured? -%}
                  <price-per-item
                    class="no-js-hidden"
                    id="Price-Per-Item-{{ section.id }}"
                    data-section-id="{{ section.id }}"
                    data-variant-id="{{ product.selected_or_first_available_variant.id }}"
                  >
                    {%- if product.selected_or_first_available_variant.quantity_price_breaks.size > 0 -%}
                      {%- assign variant_price_compare = product.selected_or_first_available_variant.compare_at_price -%}
                      <div class="price-per-item">
                        {%- if variant_price_compare -%}
                          <dl class="price-per-item--current">
                            <dt class="visually-hidden">
                              {{ 'products.product.price.regular_price' | t }}
                            </dt>
                            <dd>
                              <s class="variant-item__old-price">
                                {{ variant_price_compare | money_with_currency }}
                              </s>
                            </dd>
                          </dl>
                        {%- endif -%}
                        {%- if current_qty_for_volume_pricing < volume_pricing_array.last.minimum_quantity -%}
                          {%- assign variant_price = product.selected_or_first_available_variant.price
                            | money_with_currency
                          -%}
                          <span class="price-per-item--current">
                            {{- 'products.product.volume_pricing.price_at_each' | t: price: variant_price -}}
                          </span>
                        {%- else -%}
                          {%- for price_break in volume_pricing_array -%}
                            {%- if current_qty_for_volume_pricing >= price_break.minimum_quantity -%}
                              {%- assign price_break_price = price_break.price | money_with_currency -%}
                              <span class="price-per-item--current">
                                {{- 'products.product.volume_pricing.price_at_each' | t: price: price_break_price -}}
                              </span>
                              {%- break -%}
                            {%- endif -%}
                          {%- endfor -%}
                        {%- endif -%}
                      </div>
                    {%- else -%}
                      {%- assign variant_price = product.selected_or_first_available_variant.price
                        | money_with_currency
                      -%}
                      {%- assign variant_price_compare = product.selected_or_first_available_variant.compare_at_price -%}
                      <div class="price-per-item">
                        {%- if variant_price_compare -%}
                          <dl class="price-per-item--current">
                            <dt class="visually-hidden">
                              {{ 'products.product.price.regular_price' | t }}
                            </dt>
                            <dd>
                              <s class="variant-item__old-price">
                                {{ variant_price_compare | money_with_currency }}
                              </s>
                            </dd>
                            <dt class="visually-hidden">
                              {{ 'products.product.price.sale_price' | t }}
                            </dt>
                            <dd>
                              <span class="price-per-item--current">
                                {{- 'products.product.volume_pricing.price_at_each' | t: price: variant_price -}}
                              </span>
                            </dd>
                          </dl>
                        {%- else -%}
                          <span class="price-per-item--current">
                            {{- 'products.product.volume_pricing.price_at_each' | t: price: variant_price -}}
                          </span>
                        {%- endif -%}
                      </div>
                    {%- endif -%}
                  </price-per-item>
                {%- endif -%}
              </div>
              <div class="quantity__rules caption no-js-hidden" id="Quantity-Rules-{{ section.id }}">
                {%- if product.selected_or_first_available_variant.quantity_rule.increment > 1 -%}
                  <span class="divider">
                    {{-
                      'products.product.quantity.multiples_of'
                      | t: quantity: product.selected_or_first_available_variant.quantity_rule.increment
                    -}}
                  </span>
                {%- endif -%}
                {%- if product.selected_or_first_available_variant.quantity_rule.min > 1 -%}
                  <span class="divider">
                    {{-
                      'products.product.quantity.minimum_of'
                      | t: quantity: product.selected_or_first_available_variant.quantity_rule.min
                    -}}
                  </span>
                {%- endif -%}
                {%- if page_titleroduct.selected_or_first_available_variant.quantity_rule.max != null -%}
                  <span class="divider">
                    {{-
                      'products.product.quantity.maximum_of'
                      | t: quantity: product.selected_or_first_available_variant.quantity_rule.max
                    -}}
                  </span>
                {%- endif -%}
              </div>
              {%- if product.quantity_price_breaks_configured? -%}
                <volume-pricing class="parent-display no-js-hidden" id="Volume-{{ section.id }}">
                  {%- if product.selected_or_first_available_variant.quantity_price_breaks.size > 0 -%}
                    <span class="caption-large">{{ 'products.product.volume_pricing.title' | t }}</span>
                    <ul class="list-unstyled no-js-hidden">
                      <li>
                        <span>{{ product.selected_or_first_available_variant.quantity_rule.min }}+</span>
                        {%- assign price = product.selected_or_first_available_variant.price | money_with_currency -%}
                        <span data-text="{{ 'products.product.volume_pricing.price_at_each' | t: price: variant_price }}">
                          {{- 'sections.quick_order_list.each' | t: money: price -}}
                        </span>
                      </li>
                      {%- for price_break in product.selected_or_first_available_variant.quantity_price_breaks -%}
                        {%- assign price_break_price = price_break.price | money_with_currency -%}
                        <li class="{%- if forloop.index >= 3 -%}show-more-item hidden{%- endif -%}">
                          <span>
                            {{- price_break.minimum_quantity -}}
                            <span aria-hidden="true">+</span></span
                          >
                          <span data-text="{{ 'products.product.volume_pricing.price_at_each' | t: price: price_break_price }}">
                            {{- 'sections.quick_order_list.each' | t: money: price_break_price -}}
                          </span>
                        </li>
                      {%- endfor -%}
                    </ul>
                    {%- if product.selected_or_first_available_variant.quantity_price_breaks.size >= 3 -%}
                      <show-more-button>
                        <button
                          class="button-show-more link underlined-link"
                          id="Show-More-{{ section.id }}"
                          type="button"
                        >
                          <span class="label-show-more label-text"
                            ><span aria-hidden="true">+ </span>{{ 'products.facets.show_more' | t }}
                          </span>
                        </button>
                      </show-more-button>
                    {%- endif -%}
                  {%- endif -%}
                </volume-pricing>
              {%- endif -%}
            </div>
            <!-- Qty Selection End -->

            <input
              type="hidden"
              name="id"
              value="{{ product.selected_or_first_available_variant.id }}"
              class="product-variant-id"
              {% if product.selected_or_first_available_variant.available == false %}
                disabled
              {% endif %}
            >

            <button
              id="{{ product_form_id }}-submit"
              type="submit"
              name="add"
              class="quick-add__submit button button--full-width button--secondary{% if horizontal_quick_add %} card--horizontal__quick-add{% endif %}"
              aria-haspopup="dialog"
              aria-labelledby="{{ product_form_id }}-submit title-{{ section_id }}-{{ product.id }}"
              aria-live="polite"
              data-sold-out-message="true"
              {% if product.selected_or_first_available_variant.available == false %}
                disabled
              {% endif %}
            >
              <span>
                {%- if product.selected_or_first_available_variant.available -%}
                  {{ 'products.product.add_to_cart' | t }}
                {%- else -%}
                  {{ 'products.product.sold_out' | t }}
                {%- endif -%}
              </span>
              <span class="sold-out-message hidden">
                {{ 'products.product.sold_out' | t }}
              </span>
              {%- if horizontal_quick_add -%}
                <span class="icon-wrap">{% render 'icon-plus' %}</span>
              {%- endif -%}
              {%- render 'loading-spinner' -%}
            </button>
          {%- endform -%}
        </product-form>
      {%- endif -%}
    </div>

    <!-- Customization for Add to Cart END -->
  </li>
{%- endfor -%}

The Add to Cart button should work properly for all the search result products (especilly the first product result).

How to Fix Invisible/Blank PDF Returned by Postman with 200 Status Code in Node.js?

Basically, I am calling one third-party api which gives an response like 200 with actual pdf that is visible on postman. Third party API Response –

And I have created one endpoint in aws lamda node js in that I am calling the same third-party api and returning data as it is and its showing 200 on postman. But blank pdf is showing in response.

Tried all below approaches –

  1. Using Arraybuffer way, And Postman response –
  2. Convert it into base64 data approach
  3. Returning “isBase64Encoded”: true

Table is showing weird in PDF if table width is more than pdf width using JsPDF Angular library

In html have text, table and plotly chart, but when i export pdf from HTMl then table is not showing with all column in PDF and also not showing Plotly chart using below code.

const doc = new jsPDF('p','pt','a4');
const specialElementHandlers = {
  '#editor': function (element, renderer) {
   return true;
  }
};
const pdfTable = this.conversationsEl.nativeElement;
doc.fromHTML(pdfTable, 10, 10, {
  width: 540,
  elementHandlers: specialElementHandlers,
}, ()=> {
  doc.save(`Report-${currentDate}` + '.pdf');
}, {
  top:10,
  bottom:10,
  left:10,
  right:10
});

Openlayers in laravel

i want to add openlayers in laravel frameworks but it always have an error like this:
openlayers:1 Uncaught TypeError: Failed to resolve module specifier “rbush”. Relative references must start with either “/”, “./”, or “../”.

and another error is like this:
Expected a JavaScript module script but the server responded with a MIME type of “text/html”. Strict MIME type
Expected a JavaScript module script but the server responded with a MIME type of “text/css”. Strict MIME type

can someone help me to fix and solve this so my openlayers and the map is shown webpage so the laravel frameworks is working after adding openlayers library?

thank you

solve this so my openlayers and the map is shown webpage so the laravel frameworks is working after adding openlayers library

Should I store pageSize as a global state or as an URL param?

Right now, pageSize is defined and being used in PersonItems (to set the items per page in a paginated list), which is inside PersonItemsWrapper. But I also need pageSize in PersonModal (to jump to the last pagination page when a new person is added), which is inside PersonAddControls.

<>
  <PersonItemsWrapper /> // PersonItems is inside
  <PersonAddControls /> // PersonModal is inside
</>

I could lift up the state and pass pageSize as a prop … but that means I’d have to pass it down two components. So there are only two other options:

a. Store pageSize in a store (e.g. Zustard)

b. Store pageSize as an URL param (e.g. https://localhost:3000/persons?pageSize?=10?page=8)

What’s the usual way of doing this?

How to add 1 day to current date in JS (UTC)?

I have the date as follows,

let date = '2024-03-11';

I want to add plus 1 day to above date

let newDate = mew Date(date); -> converting to local date -> 2024-03-10 (becoming -1)
newDate.setDate(newDate.getDate() + 1);

It worked well but the problem is I am getting the local date when I am using new Date() method which is converting my date to 2024-03-10

Can some one help me how to add 1 date to UTC date without getting it converted to local time zone.

weird grid results when ‘Puppies’ button is clicked

I have a fake dog adoption site and i am just a beginner, so it is nothing special. I have it set up so that you can click on 1 of 6 buttons and it will display a small picture of each dog that fits the description. If you click the button a 2nd time, the pictures disappear.

It seems that everything is functional EXCEPT the ‘Puppies’ button has a weird affect on the ‘Special Needs’ button. I don’t know why, but the one button changes the position of the other. I have been working on this all weekend and I am so close to getting it to look right.

Please, if you can figure out what I am doing wrong, please let me know!

<!DOCTYPE html>
<html lang="en">
    <header> <!--  ******* HEADER OPEN ********** --> 
    Stack Overflow Help Example <BR>
    <link rel="stylesheet" href="SOFEX.css">
    <script src="SOFEX.js" type="text/javascript"></script>
    </header> <!--  ******* HEADER CLOSED********** -->
<body>  
<main> <br>

    <div class="grid-container6">
        <div class="row"> <!-- **************   GRID OPEN ************  -->
            <div class="column">            
            <button onclick="showMalesFunction()"> Show Male Dogs </button>
            <div id="MalesBtn"> </div>
            </div>
    <!--  ************************************* -->
            <div class="column"> 
        <button onclick="showFemalesFunction()"> Show Female Dogs </button>
        <div id="FemalesBtn"> </div>
        </div>
    <!--  ************************************* -->
        <div class="column">
        <button onclick="showPuppiesFunction()"> 
        Show Puppy Dogs </button>
        <div id="PuppiesBtn"> </div>
        </div>
     <!--  ************************************* -->
        <div class="column"> 
        <button onclick="showAdultFunction()"> Show Adult Dogs </button>
        <div id="AdultBtn"> </div>
        </div>
<!--  ************************************* -->
        <div class="column">  
        <button onclick="showSeniorFunction()"> 
          Show Senior Dogs </button>
        <div id="SeniorBtn"> </div>
        </div>
<!--  ************************************* -->
        <div class="column">  
        <button onclick="SpecialNeedsFunction()"> Dogs With Special Needs </button>
        <div id="SpecialNeedsBtn"> </div>
        </div>
    </div>
  </div> <!-- ************** grid closed ********************-->
<script>

//---------------------------------------------------------//
var MaleArray = [
  "<a href='Boris.html'><img src='BorisGut.jpg' alt='marker.gif' style='width:20%'></a>", 
  "<a href='Harley.html'><img src='Harley Santa hat.jpg' alt='image.gif' style='width:20%'></a>",
  "<a href='Max.html'> <img src='Max.png' alt='image.gif' style='width:20%'></a>",
];

function showMalesFunction() {
  var x = document.getElementById("MalesBtn");
  if (x.style.display === "none") {
    x.style.display = "block"
    document.getElementById("MalesBtn").innerHTML = MaleArray; 
  } else {
    x.style.display = "none";
  } }
//---------------------------------------------------------//
var FemaleArray = [
  "<a href='Lucy.html'><img src='LucyPage.jpg' alt='image.gif' style='width:20%'></a>",
  "<a href='Daisy.html'><img src='DaisyBirthdayHat.jpeg' alt='image.gif' style='width:20%'></a>",
  "<a href='Honey.html'><img src='Honey.png' alt='image.gif' style='width:20%'></a>",
  "<a href='Dolly.html'><img src='Dolly.jpg' alt='image.gif' style='width:20%'></a>",
  "<a href='Birdie.html'> <img src= 'Birdie Girdie.jpg' alt='image.gif' style='width:20%'></a>"
];

function showFemalesFunction() {
  var x = document.getElementById("FemalesBtn");
  if (x.style.display === "none") {
    x.style.display = "block"
    document.getElementById("FemalesBtn").innerHTML = FemaleArray; 
  } else {
    x.style.display = "none";
  } }

//---------------------------------------------------------//
var PuppiesArray = [
  "<a href='Lucy.html'><img src='LucyPage.jpg' alt='image.gif' style='width:20%'></a>",
  "<a href='Honey.html'><img src='Honey.png' alt='image.gif' style='width:20%'></a>",
  "<a href='Dolly.html'><img src='Dolly.jpg' alt='image.gif' style='width:20%'></a>"
];

function showPuppiesFunction() {
  var x = document.getElementById("PuppiesBtn");
  if (x.style.display === "none") {
    x.style.display = "block"
    document.getElementById("PuppiesBtn").innerHTML = PuppiesArray; 
  } else {
    x.style.display = "none";
  } }

//---------------------------------------------------------//
var AdultArray = [
  "<a href='Boris.html'><img src='BorisGut.jpg' alt='marker.gif' style='width:20%'></a>", 
  "<a href='Daisy.html'><img src='DaisyBirthdayHat.jpeg' alt='image.gif' style='width:20%'></a>",
  "<a href='Harley.html'><img src='Harley Santa hat.jpg' alt='image.gif' style='width:20%'></a>",
  "<a href='Birdie.html'> <img src= 'Birdie Girdie.jpg' alt='image.gif' style='width:20%'></a>"
];

function showAdultFunction() {
  var x = document.getElementById("AdultBtn");
  if (x.style.display === "none") {
    x.style.display = "block"
    document.getElementById("AdultBtn").innerHTML = AdultArray; 
  } else {
    x.style.display = "none";
  } }

  //---------------------------------------------------------//
var SeniorArray = [
  "<a href='Max.html'> <img src='Max.png' alt='image.gif' style='width:20%'></a>"
];

function showSeniorFunction() {
  var x = document.getElementById("SeniorBtn");
  if (x.style.display === "none") {
    x.style.display = "block"
    document.getElementById("SeniorBtn").innerHTML = SeniorArray; 
  } else {
    x.style.display = "none";
  } }
  
//---------------------------------------------------------//
var SpecialNeedsArray = [
  "<a href='Dolly.html'><img src='Dolly.jpg' alt='image.gif' style='width:20%'></a>",
  "<a href='Max.html'> <img src='Max.png' alt='image.gif' style='width:20%'></a>"
]
function SpecialNeedsFunction() {
  var x = document.getElementById("SpecialNeedsBtn");
  if (x.style.display === "none") {
    x.style.display = "block"
    document.getElementById("SpecialNeedsBtn").innerHTML = SpecialNeedsArray; 
  } else {
    x.style.display = "none";
  } }
</script>
<style>

* {box-sizing: border-box; }

table {
  border: 2px solid #3399CC; 
  text-align: left;
  margin-left: auto;
  margin-right: auto;
}
td {padding: 0.5em; border: 2px solid #923cb1;text-align: left; }
th {padding: 0.5em; border: 2px solid #3399CC; text-align: center; }
tr:nth-of-type(odd){background-color: #f5fafc;}

.column {
  float: left;
  width: 50%;
  padding: 5px; }

.grid-container6 {  
  display: inline-grid; 
  grid-column: 10px; 
  text-align: center;
  width: 100%; 
  border: 10px; 
  position: relative;
  margin: 0 auto;
  border-color: purple;
  border-style: solid; 
column-gap: 10px;
row-gap: 10px; 
column-rule-color: #e0299a;
background-color: green; 
}

button {
  margin-left: auto;
  margin-right: auto;
  text-align: center;
  position: relative;  
  color: white;
  font-size: 24px;
  border-radius: 40px;
  margin: 0 auto;
  display: inline;
  outline: none;
  padding: 6px 12px;
  background-color:  #002171;
}
</style>

</div>
</div>
<!--  ************************************* -->

<!--  ************************************* -->
<!--  ************************************* -->
</main>            
</body>
</html>

Notification and notification click event with FCM in PWA

I received 2 notifications in background case and can not handle click in foreground case

I am implementing push notification function on PWA using FCM. But I am getting issues

  1. In background case. On firebase-messaging-sw.js file. I implemented
self.addEventListener('notificationclick', function (event) {}

I received 2 notifications. But this event only runs when I click notification is clicked by onBackgroundMessage

messaging.onBackgroundMessage((payload) => {
  const { title, body, icon, tag } = payload.notification;
  self.registration.showNotification(title, {
    body: body
    tag: tag 
    icon: icon
    data: { url: payload.data.link },
  });
});

How to disable default background notification. I want to only show notification 1 time handled by onBackgroundMessage

  1. On foreground case. I call registration.showNotification() to show notification in onMessage event to display notification. How to handle the click event in this case? notificationclick in firebase-messaging-sw.js seem is not work.

This is my sw file:

importScripts(
  'https://www.gstatic.com/firebasejs/10.7.0/firebase-app-compat.js'
);
importScripts(
  'https://www.gstatic.com/firebasejs/10.7.0/firebase-messaging-compat.js'
);

firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();

messaging.onBackgroundMessage((payload) => {
  const { title, body, icon, tag } = payload.notification;
  self.registration.showNotification(title, {
    body: body,
    tag: tag,
    icon: icon,
    data: { url: payload.data.link },
  });
});

self.addEventListener('push', function (event) {
  console.log('Received a push message', event);
});

self.addEventListener('notificationclick', function (event) {
  console.log('On notification click: ', event);
  let data = event.notification.data;
  event.notification.close();
  self.clients.openWindow(data.url);
});

How to stop Webpack from bundling server-side node modules

I am facing an issue with building and serving my Angular webapp. I understand the issue is related to using server-side node modules on the client-side or webpack including those modules in the client-side. I added a webpack.config.js in the root dir to exclude those modules but it was not recognized. So I updated the builder to extend the webpack configurations. This worked successfully:

  • I updated the builder from @angular-devkit/build-angular:browser to @angular-builders/custom-webpack:browser in the angular.json file.
  • Added extra-webpack.config.js and referenced it in the angular.json and tsconfig.json

After doing this, my build is successful but when I serve the app using ng serve there is an error in the browser. The error is within opentelemetry module, which is a server-side module only used in my server-module.ts file. I am not sure why it’s being bundled by webpack.

The structure of my project looks like this

/src
 /app
   (all Angular components and services) 
server.module.ts
server-controller.ts
...  

In my angular.json, I have the index and main attributes pointing to src/index.html and src/main.ts.

I am developing a custom svg map that scrolls from both the x axis and y axis to a region in ReactJs

So I have a map-region.jsx which contains my svg map

And I am using the tag to give it an id

 const MapRegions = () => {
  return (
    <svg
      width="7115"
      height="3000"
      viewBox="0 0 9115 3921"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
//other paths...
      <g id="lagos">
        <path
          d="M4845.35 1925.77L4840.72 1926.7L4822.66 1894.27L4816.64 1893.34L4796.73 1909.55L4776.82 1901.22L4762.93 1899.36L4755.52 1903.53L4740.24 1902.61L4724.96 1915.11L4711.99 1916.04L4680.51 1900.75L4668.47 1907.7L4655.04 1907.24L4645.31 1896.12L4619.38 1885L4591.6 1888.71L4585.12 1895.19L4581.41 1911.87L4574 1923.92L4572.62 1950.32L4571.69 1960.05L4577.25 1977.66L4572.15 1989.24L4574.93 1997.12L4562.43 2015.65L4554.56 2024.45L4549.93 2042.98L4550.39 2061.98L4549 2109.23H4571.69H4591.6L4609.66 2128.69L4618.46 2150L4632.35 2168.07L4653.19 2169L4663.37 2162.51L4673.1 2163.9L4699.95 2153.25L4706.44 2132.4L4718.94 2104.14L4726.35 2103.68L4741.63 2086.53L4751.35 2086.07L4766.17 2098.12L4784.23 2087.92L4786.54 2075.88L4792.1 2063.83L4795.8 2049.01L4809.7 2036.96L4814.79 2016.11L4820.35 2009.63L4823.59 1994.34L4830.53 1975.81L4851.83 1952.64L4853.22 1942.91L4856 1937.82L4845.35 1925.77Z"
          fill="#f00"
          stroke="black"
          stroke-linejoin="round"
        />
      </g>
</svg>
  );
};

export default MapRegions;

I am tracking the id in my code so when I click on a button it scrolls to that id
I did that here in my MapDisplay.jsx

import React, { useState, useRef, useEffect } from "react";
import StateList from "./stateList";
import MapRegions from "./map-regions";

// import map from "../images/main-map.svg";

const Map = () => {
  const mapContainerRef = useRef(null);
  const [zoomLevel, setZoomLevel] = useState(1);

  const [selectedState, setSelectedState] = useState(null);

  // Receive state updates from the StateList
  const handleStateChange = (state) => {
    console.log("Received state in Map:", state);
    scrollToElement(state.name.toLowerCase()); // Scroll to the element
    setSelectedState(state);
  };

  const handleZoom = (event) => {
    const delta = event.deltaY > 0 ? -0.2 : 0.2;
    setZoomLevel(Math.max(0.5, Math.min(zoomLevel + delta, 2)));
  };

  useEffect(() => {
    const mapContainer = mapContainerRef.current;
    if (mapContainer) {
      mapContainer.addEventListener("wheel", handleZoom);

      return () => mapContainer.removeEventListener("wheel", handleZoom);
    }
  }, []);

  const scrollToElement = (id) => {
    const groupElement = document.getElementById(id);
    const pathElement = groupElement.querySelector("path");

    const boundingRect = pathElement.getBoundingClientRect();
    console.log("Bounding Rect:", boundingRect);

    const viewBoxScalingFactor = mapContainerRef.current.clientWidth / 9115;
    const centerOffsetTop =
      (boundingRect.top + boundingRect.height / 2) * viewBoxScalingFactor -
      mapContainerRef.current.clientHeight / 2;
    const centerOffsetLeft =
      (boundingRect.left + boundingRect.width / 2) * viewBoxScalingFactor -
      mapContainerRef.current.clientWidth / 2;

    mapContainerRef.current.scrollTo({
      top: centerOffsetTop,
      left: centerOffsetLeft,
      behavior: "smooth",
    });
    console.log(
      "mapContainerRef Client Height:",
      mapContainerRef.current.clientHeight
    );
    console.log(
      "mapContainerRef Client Width:",
      mapContainerRef.current.clientWidth
    );
  };

  return (
    <div className="relative">
      <div
        ref={mapContainerRef}
        className="w-full h-[500px] overflow-y-scroll overflow-x-scroll"
        // style={{ transform: `scale(${zoomLevel})` }}
      >
        <MapRegions />
      </div>

      <StateList
        scrollToElement={scrollToElement}
        onStateSelected={handleStateChange}
      />
    </div>
  );
};

export default Map;

This is exactly where I am reusing the MapDisplay

import React, { useState } from "react";
import MapDisplay from "./map-display";
import MapForm from "./sections/map-form";
import StateList from "./stateList";
import { statesData } from "./map-data";

const Map = () => {
  return (
    <div className="p-5 py-20 lg:p-20 flex justify-between items-center relative">
      <MapForm />
      <div className="w-[60%]">
        <MapDisplay />
      </div>
    </div>
  );
};

export default Map;

I also have a stateList.jsx where I have the states I want to scroll to when I click on the buttons

const StateList = ({ scrollToElement, onStateSelected }) => {
  const states = [
    {
      name: "Lagos",
      country: "Nigeria",
    },
    {
      name: "Kaduna",
      country: "Nigeria",
    },
    {
      name: "Birmingham",
      country: "UK",
    },
    {
      name: "Florida",
      country: "USA",
    },
    {
      name: "Dakar",
      country: "Senegal",
    },
  ];

  return (
    <div className="mt-8 absolute right-[250px] bottom-[10px]">
      <div className="bg-[#F6F1EE] p-5 rounded-lg">
        <div className="flex justify-between items-center">
          <p className="text-berkeleyBlue">Regional Office</p>
          {/* <button className="border border-berkeleyBlue px-5 p-1 rounded-full">
            View on Map
          </button> */}
        </div>
        <h1 className="text-3xl text-[#B3001B]">Dakar, Senegal</h1>
        <ul className="flex justify-center items-center gap-3 mt-8">
          {states.map((state) => (
            <li
              key={state.name}
              id={state.name.toLowerCase()}
              className="p-2 cursor-pointer border border-[#EEEEF0] bg-black text-white rounded-full px-5"
              onClick={() => {
                scrollToElement(state.name.toLowerCase());
                onStateSelected(state);
              }}
            >
              {state.name}
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
};

export default StateList;

But the scrolling is not working, even when I print to the console. It prints the id of what I am clicking to the console but not scrolling to the region I want to scroll to.

Please how can I make this work

How do I use the number from my database to display that number of images from an array

I cant figure out how to take the database data, a single number between 1-5, to be displayed as an image that many times.
For example,

1  is [star]  
2 is [star][star]  
3 is [star][star][star]

 etc.

I am using MERN and everything is connected and communicating properly. I just don’t know how to call the data from my database and then convert that number into that number of images.

Here is my schema for the database. Im just trying to convert stars number into star images.

    const mongoose = require('mongoose');
    require('mongoose-type-url');
    const Schema  = mongoose.Schema;
    
    const QuestsSchema = new Schema ({
        description:{
            type: String,
            required: true,
        },
        stars:{
            type: Number,
            required: true,
        },
        timeframe:{
            type: String,
            required: true,
        }
    
    })
    
    const Quests = mongoose.model('Quest', QuestsSchema )
    
    module.exports = Quests

Here is my code for my homepage.js file

import React from 'react';
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router';
import myImage from '../images/star-gif.gif'

function Homepage() {

    const navigate = useNavigate();

    const [quests, setQuests] = useState([]);

    useEffect(() => {
        const fetchData = async () => {
            const response = await fetch('http://localhost:3001/quests')
            const resData = await response.json()
            setQuests(resData)
        }
        fetchData()
    }, []);


    // Array of images - works

    const stars = [
        <img id='str' src={myImage} height={80} width={80} alt=''/>, 
        <img id='str' src={myImage} height={80} width={80} alt=''/>,
        <img id='str' src={myImage} height={80} width={80} alt=''/>, 
        <img id='str' src={myImage} height={80} width={80} alt=''/>,
        <img id='str' src={myImage} height={80} width={80} alt=''/>
    ]

    // I want the number from the database to display that number of images in array
    //      ie. 2 = [star][star], 3 = [star][star][star]
    

   
    // this takes the data from the database and display it as:
    //     test
    //     2
    //     Daily

    // I want the 2 to be displayed at [image][image], not 2

    let questsFormatted = quests.map((quest, i) => {
    return (
        <div key={i}>
                <p>
                    {quest.description}
                </p>

            <div>
                    {quest.stars}
                </div>
                   
        <p >
            {quest.timeframe}
            </p>
        </div>
    )
    })
    

   // {stars} is just to see if the array, stars, works, and it does
    return (
        <div>
            <div className='header'>
                iRL
            </div>

            <div>
                <div >
                    <button className='sub-header-button' 
                     onClick={()=>{navigate('/quests')}}>
                         Quests
                    </button>
                </div>
            </div>
            <div>
                {questsFormatted}
            </div>
            <div>
                {stars}
            </div>
        </div> 

    )
   
}


export default Homepage