How do we provide additional data to a ’s Server Action, in React, without hidden inputs or bind?

The React docs state the following:

You can use hidden form fields to provide data to the <form>’s action.
The Server Action will be called with the hidden form field data as an
instance of FormData.

…and:

In lieu of using hidden form fields to provide data to the <form>’s
action, you can call the bind method to supply it with extra arguments.

Here is the code example they use:

import { updateCart } from './lib.js';

function AddToCart({productId}) {
  async function addToCart(formData) {
    'use server'
    const productId = formData.get('productId')
    await updateCart(productId)
  }

  return (
    <form action={addToCart}>
        <input type="hidden" name="productId" value={productId} />
        <button type="submit">Add to Cart</button>
    </form>
  )
}

Using the example above, can we not just pass in the productId using an intermediary async function (see below)? If not, why not?

Attempt at passing in data via an intermediary function:

import { updateCart } from './lib.js';

function AddToCart({productId}) {
  async function addToCart(formData, productId) {
    'use server'
    await updateCart(productId)
  }

  async function formAction(formData) {
    // ...
    await addToCart(formData, productId);
  }

  return (
    <form action={formAction}>
        <input type="hidden" name="productId" value={productId} />
        <button type="submit">Add to Cart</button>
    </form>
  )
}

There is an example in the React docs, under <form>, showing the use of an intermediary async function, so it should technically work.

I do not understand why they mention hidden form fields and bind, if an intermediary closure can be used instead.

My initial guess is that a form will not be progressively enhanced (i.e. usable without JS) if the Server Action is not passed in directly. Though I am not sure if that is the only reason.

Relevant docs snippet:

Passing a Server Action to <form action> allow users to submit forms
without JavaScript enabled or before the code has loaded.

Cannot provide border after clip-path usage

I have this as required design:

enter image description here

All 6 figures you see are buttons and they must have different title. The design however is almost identical except bg-color. So I created my styled-btn component:

interface StyledBtnProps {
  title: string;
  transaction?: boolean;
}

const ScreenBtn: React.FC<StyledBtnProps> = ({
  title,
  transaction = false,
}) => {
  return (
    <button
      className={clsx(
        "relative  p-6 w-96 h-1/3 text-2xl flex justify-center gap-4 mt-20",
        "clip-trapezoid",
        {
          "bg-red-600 text-white": transaction,
          "bg-white text-red-600 border border-red-600": !transaction,
        }
      )}
    >
      <div className="">
        <InboxArrowDownIcon className="w-8 h-8" />
      </div>
      <span className="uppercase">{title}</span>
    </button>
  );
};

I use additional created class in my globals.css to create the polygon:

.clip-trapezoid {
  position: relative;
  clip-path: polygon(15px 0%, 100% 0%, 100% calc(100% - 25px), calc(100% - 25px) 100%, 0% 100%, 0% 15px);
}

.clip-trapezoid::before {
  content: '';
  position: absolute;
  top: -4px;
  left: -4px;
  right: -4px;
  bottom: -4px;
  border: 4px solid red;
  clip-path: "inherit";
  z-index: -1;
}

The problem is that the pseudo class is not working. I again cannot see the red border for the cropped corners. This is the actual result:
enter image description here

How to fix that?

multifact-pivottable.js negative number format

I’m using the multifact-pivottable.js/PivotTable.js for multiple column Pivot aggregations. I wish to show the negative numbers within brackets in red. Any ideas how can I implement this?

I tried

<style>
  .pvtNumber.negative { color: red; }
</style>

var config = {
  numberFormat: $.pivotUtilities.numberFormat("[#;[red](#)]"),
  // ...
}

No success thus far.

Redirect to home after window.print

I’m using Vue 3 but it’s not a Vue issue. I have an app when the user creates a ticket, the print dialog box appears and the user prints the ticket. This is on a kiosk btw, so there will be no selecting of a printer or anything.

Once the ticket is printed, the ticket screen should automatically take you to the home screen. What i’m doing right now is this:

  setTimeout(() => {
    window.location.href = "/";
  }, 6500);

I have it in my function right after the dialog appears. Of course, If the user is slow to click print, the page redirects regardless.

Is there a way to print without a dialog (auto print) or capture the event when the print button is clicked? Option 2 I believe doesn’t exist, but you never know. Thanks

How to Integrate Google Cloud Speech-to-Text with Pusher in a Laravel Application?

I’m working on a Laravel 11 application where I need to stream audio from the frontend to Google Cloud Speech-to-Text and then broadcast the transcriptions using Pusher.

Frontend Code:

let mediaRecorder;
let audioChunks = [];

document.getElementById('record').addEventListener('click', async () => {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    mediaRecorder = new MediaRecorder(stream);

    mediaRecorder.ondataavailable = event => {
        audioChunks.push(event.data);
        sendData(event.data); // Sending data to the server
    };

    mediaRecorder.start(250); // Sending chunks every 250ms
});

document.getElementById('stop').addEventListener('click', () => {
    mediaRecorder.stop();
});

function sendData(audioData) {
    fetch('/stream-audio', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/octet-stream',
            'X-CSRF-TOKEN': '{{ csrf_token() }}',
        },
        body: audioData
    });
}

// Pusher integration
Pusher.logToConsole = true;
var pusher = new Pusher('{{ env('PUSHER_APP_KEY') }}', { cluster: 'eu' });
var channel = pusher.subscribe('speech-transcript-created-channel');
var pusherTextArea = document.getElementById('pusherTextArea');
channel.bind('speech-transcript-created', function(data) {
    pusherTextArea.value += JSON.stringify(data) + 'n';
});

Backend Code (SpeechController.php):

protected $speechClient;
protected $stream;

public function __construct()
{
    $this->speechClient = new SpeechClient([
        'transport' => 'grpc',
        'credentials' => base_path(env('GOOGLE_APPLICATION_CREDENTIALS'))
    ]);

    $config = new StreamingRecognitionConfig([
        'config' => new RecognitionConfig([
            'encoding' => RecognitionConfigAudioEncoding::WEBM_OPUS,
            'sample_rate_hertz' => 48000,
            'language_code' => 'sk-SK',
        ]),
    ]);

    $this->stream = $this->speechClient->streamingRecognize();
    $this->stream->write(new StreamingRecognizeRequest(['streaming_config' => $config]));
}

public function streamAudio(Request $request)
{
    $audioContent = $request->getContent();
    $this->stream->write(new StreamingRecognizeRequest(['audio_content' => $audioContent]));

    while ($response = $this->stream->read()) {
        foreach ($response->getResults() as $result) {
            $transcript = $result->getAlternatives()[0]->getTranscript();
            event(new SpeechTranscriptCreated($transcript));
        }
    }

    return response()->json(['message' => 'Audio streamed successfully']);
}

Issue:

I’m using Pusher to broadcast the transcriptions back to the frontend, but I’m encountering an issue where I can’t successfully connect to Google Cloud Speech due to the following error:

{
  "message": "Audio Timeout Error: Long duration elapsed without audio. Audio should be sent close to real time.",
  "code": 11,
  "status": "OUT_OF_RANGE",
  "details": [ { "@type": "pc-high-bwd-bin", "data": "<Unknown Binary Data>" } ]
}

I suspect that using WebSockets might be necessary to maintain a real-time connection with Google Cloud Speech-to-Text, but I’m unsure how to implement this properly in Laravel. How can I integrate Google Cloud Speech-to-Text with Pusher effectively, or how can I resolve this timeout error?

Note:

  1. If I’m mixing incompatible approaches (such as using fetch to send audio data while expecting real-time processing with Pusher), I’d appreciate a brief explanation of what is wrong with this approach and how I might better structure this integration.
  2. The goal is to create a real-time translation solution, so relying on an HTTP API where the request is only sent after clicking “Stop Recording” is not ideal.

Does `location.href` intentionally omit username/password when included in URL?

When I open a URL to a website using HTTP Basic Auth that contains username/password, for example:

https://foo:[email protected]/basic-auth/foo/bar

Checking via browser console shows that location.href returns the URL without credentials (ie. https://httpbin.org/basic-auth/foo/bar).

However document.URL returns the URL with credentials (https://foo:[email protected]/basic-auth/foo/bar).

I haven’t found any mentions of this being intentional difference between these two accessors. Is this a browser bug, an implementation detail or stable standard-defined behavior?

Form validation triggers after required prop is set to false

After setting the required prop to false using $( '#field' ).prop( 'required', false );, form.checkValidity() still returns false on the field and form.reportValidity() tries to focus on the element.

An invalid form control with name='' is not focusable.

The element of input type date does not have a name and is hidden, while other elements of type select do not seem to have this issue.

Full error message (name attribute added):

An invalid form control with name='' is not focusable.
<input id="ipt-arrival-date" name="arrival" type="date" onfocus="this.showPicker()" min="2024-09-04" max="2024-09-08" class="">

From the error it shows that the required prop is not there at the time the error shows.

The form is too large to post the complete code.

Any ideas?

How to get the maximum rectangle drawn inside polygon

I am using three.js and I draw polygons inside viewer this polygon represented as Vector2[].

I want to get the maximum rectangle can be drawn inside that polygon represented as Vector2[]

I want to have a function that I pass a Vector2[] that represents a polygon and it returns back Vector2[] that represents the max rectangle can be drawn inside that polygon.

This is the function i use but it someetimes draw the rectangle outside the polygon

findLargestRectangle(polygon: Vector2[]): Vector2[] | null {
    let maxArea = 0;
    let bestRectangle: Vector2[] | null = null;
    
    for (let i = 0; i < polygon.length - 1; i++) { // Skip the last point
      for (let j = i + 1; j < polygon.length - 1; j++) { // Skip the last point
        const base1 = polygon[i];
        const base2 = polygon[j];
        const baseVector = new Vector2().subVectors(base2, base1);
        
        for (let k = 0; k < polygon.length - 1; k++) { // Skip the last point
          if (k === i || k === j) continue;
          
          const perpVector = new Vector2(-baseVector.y, baseVector.x).normalize();
          const height = perpVector.dot(new Vector2().subVectors(polygon[k], base1));
          
          const corner1 = base1.clone().add(perpVector.clone().multiplyScalar(height));
          const corner2 = base2.clone().add(perpVector.clone().multiplyScalar(height));
          
          // Check if both corner points are within the polygon
          if (PolygonHelperFunctions.isPointInPolygon(corner1, polygon) && PolygonHelperFunctions.isPointInPolygon(corner2, polygon)) {
            const rectangleArea = PolygonHelperFunctions.getRectangleArea(base1, base2, corner2, corner1);
            if (rectangleArea > maxArea) {
              maxArea = rectangleArea;
              bestRectangle = [base1, base2, corner2, corner1];
            }
          } else {
            // Handle the case where corners are outside the polygon
            const smallestEdge = PolygonHelperFunctions.findSmallestEdge(polygon);
            const smallBase1 = polygon[smallestEdge.index1];
            const smallBase2 = polygon[smallestEdge.index2];
            
            const smallBaseVector = new Vector2().subVectors(smallBase2, smallBase1);
            const smallHeight = perpVector.dot(new Vector2().subVectors(polygon[k], smallBase1));
            
            const smallCorner1 = smallBase1.clone().add(perpVector.clone().multiplyScalar(smallHeight));
            const smallCorner2 = smallBase2.clone().add(perpVector.clone().multiplyScalar(smallHeight));
            
            // Ensure it's a pure rectangle
            const smallBaseLength = smallBaseVector.length();
            const smallSide1 = smallCorner1.distanceTo(smallBase1);
            const smallSide2 = smallCorner2.distanceTo(smallBase2);
            
            if (
              smallBaseLength === smallBaseVector.length() &&
              smallSide1 === smallSide2 &&
              Math.abs(perpVector.dot(smallBaseVector)) < 1e-10 // Check that vectors are perpendicular
            ) {
              const smallRectangleArea = PolygonHelperFunctions.getRectangleArea(smallBase1, smallBase2, smallCorner2, smallCorner1);
              if (smallRectangleArea > maxArea) {
                maxArea = smallRectangleArea;
                bestRectangle = [smallBase1, smallBase2, smallCorner2, smallCorner1];
              }
            }
          }
        }
      }
    }

Changing Ag Chart background color

Trying to set a custom background color for my charts generated with Ag Charts. Setting the color of the chart container itself via CSS didn’t work so instead I tried to set the color within the chart options but I still see no change in the chart background color. Here’s a condensed snippet for a bar chart for example:

const options = {
  container: document.getElementById("myChart"),
  data: getData(),
  theme: 'ag-material-dark',
  chartThemeOverrides: {
    overrides: {
      common: {
        background: {
          fill: "#000000"
        }
      }
    }
  }
};

To be clear, this isn’t about the color of the bars themselves, but the main background for the entire chart.

File replacement not working in angular 18

I am having env.js and env.prod.js
I try switching between the env to env.prod using the given angular.json file

but the content of env.js didn’t change at all… although environment file changed successfully.
I have similar implementation in older versions and it is working.

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "my-project": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {
        "@schematics/angular:component": {
          "style": "sass"
        }
      },
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": ["zone.js"],
            "tsConfig": "src/tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/assets",
              "src/env.js",
              "src/env.prod.js"
            ],
            "styles": [
              "src/styles.css",
              "node_modules/bootstrap/dist/css/bootstrap.min.css",
  "node_modules/bootstrap-icons/font/bootstrap-icons.css"
            ],
            "scripts": [
              "./node_modules/bootstrap/dist/js/bootstrap.min.js",
              "./node_modules/jquery/dist/jquery.min.js",
              "./node_modules/popper.js/dist/umd/popper.min.js",
              "node_modules/@fortawesome/fontawesome-free/js/all.js"        ]
          },
          "configurations": {
            "production": {

              "fileReplacements": [
          {
            "replace": "src/environments/environment.ts",
            "with": "src/environments/environment.prod.ts"
          },
          {
            "replace": "src/env.js",
            "with": "src/env-prod.js"
          }
        ],
              "optimization": false,
              "outputHashing": "all",
              "sourceMap": false,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "10mb",
                  "maximumError": "15mb"
                }
              ]
            },
            "development": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.prod.ts",
                  "with": "src/environments/environment.ts"
                },
                {
                  "replace": "src/env.prod.js",
                  "with": "src/env.js"
                }
              ]
            }
          },
            "defaultConfiguration": "production"
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "buildTarget": "my-project:build:development"
          },
          "configurations": {
            "production": {
              "buildTarget": "my-project:build:production"
            },
            "development": {
              "buildTarget": "my-project:build:development"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": ["zone.js"],
            "tsConfig": "src/tsconfig.spec.json",
            "karmaConfig": "src/karma.conf.js",
            "styles": [
              "src/styles.scss"
            ],
            "scripts": [],
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ]
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "src/tsconfig.app.json",
              "src/tsconfig.spec.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    },
    "my-project-e2e": {
      "root": "e2e/",
      "projectType": "application",
      "prefix": "",
      "architect": {
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "my-project:serve"
          },
          "configurations": {
            "production": {
              "devServerTarget": "my-project:serve:production"
            }
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": "e2e/tsconfig.e2e.json",
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    }
  },
  "cli": {
    "analytics": false
  }
}

I tried above with no hope.

How to change dynamic content in a popup window without refreshing the page so the popup stays opened

I’ve been learning the basics of programming for a while and now I’m doing my little project to try out my knowledge of SQL and some EJS with it.

Basically, I’m trying to simply show tasks that a user creates, which you can open by clicking on them into a popup window. In that popup, I want the user to be able to add/remove notes by clicking on buttons but without refreshing the page so the popup stays opened. After the user want to update or create the task, the app should check if there are any notes(elements created by those buttons) and store them into a SQL table so they appear there next time the user opens the task popup.

I’ve tried to create a notes SQL table, but after the add note button was clicked and it wanted to update the table, the page was refreshed and the popup would close.

I’m thinking of making an array that would store the SQL table data and dynamically push into the array an input value that the user has entered and maybe after the update task button was clicked it would then update the sql tables but I am not sure where to create the table, if in the index.js file or in the home.ejs file in a script tag..

main page where all of the tasks created are displayed

displayed task

]

Outlook Add-in: Failed to Open .docx File in MS Word from iFrame Due to URL Scheme Error

I’m developing an Outlook add-in where I need to open a .docx file stored on a cloud server directly in Microsoft Word, specifically in edit mode. The process involves the following steps:

  1. I open an iframe within the Outlook add-in.
  2. In the iframe, I select the .docx file stored on a cloud server.
  3. After selecting the file, a dialog opens with a blank screen.

The issue arises with the following error in the console log of the new dialog:

Failed to load resource: Redirection to URL with a scheme that is not HTTP(S)

The URL causing the issue is in the following format:

ms-word:ofe%7Cu%7Chttps://<Url of the document in cloud server>

It seems that the ms-word protocol is not being handled correctly, leading to the dialog opening blank.

What I’ve Tried:

  • Ensuring that the URL is correctly encoded.
  • Confirming that the file is accessible via a standard HTTP(S) URL.
  • Unfortunately, I cannot listen to any events when the dialog is opened, and I don’t have access to the code inside the iframe—only to the original add-in.

Questions:

  • How can I correctly open the .docx file in MS Word from the iframe in edit mode?
  • Is there a way to bypass or handle the “Redirection to URL with a scheme that is not HTTP(S)” error within an Outlook add-in?

Any insights or suggestions on resolving this issue would be greatly appreciated!

How to convert each audio stream chunk to mp3 or wav or webm? Audio is not playing for all chunks except first one

I have an usecase where each chunk of audio stream is being sent to server for transcription, but except first chunk every other audio chunk(blob) are not working.

So I did a small prototype to see if all chunks are playing fine using audio element by generating blob url

Code Example

import React, { useState, useRef } from 'react'

const RecordAudio: React.FC = () => {
  const [isRecording, setIsRecording] = useState(false)
  const mediaRecorderRef = useRef<MediaRecorder | null>(null)
  const audioChunksRef = useRef<Blob[]>([])

  const startRecording = async () => {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
    const mediaRecorder = new MediaRecorder(stream)
    mediaRecorderRef.current = mediaRecorder
    audioChunksRef.current = []
    mediaRecorder.ondataavailable = async (event) => {
      if (event.data.size > 0) {
        console.log('event.data', event.data)
        audioChunksRef.current.push(event.data)
      }
    }

    mediaRecorder.start(5000) // Capture audio in chunks every 500ms
    setIsRecording(true)
  }

  const stopRecording = () => {
    if (mediaRecorderRef.current) {
      mediaRecorderRef.current.stop()
      setIsRecording(false)
      // sendAudioChunk(audioChunksRef.current)
    }
  }

  const getAudioBlobUrl = (chunk: Blob) => {
    const audioBlob = new Blob([chunk], {
      type: 'audio/wav',
    })
    const blobUrl = URL.createObjectURL(audioBlob)

    return blobUrl
  }
  return (
    <div>
      <button onClick={isRecording ? stopRecording : startRecording}>
        {isRecording ? 'Stop Recording' : 'Start Recording'}
      </button>
      <div>
        {audioChunksRef.current.map((blob) => {
          return (
            <>
              <audio
                style={{ marginLeft: '16px' }}
                src={getAudioBlobUrl(blob)}
                controls
              />
            </>
          )
        })}
      </div>
    </div>
  )
}

export default RecordAudio

However except first audio chunk, every other player is not playing, attaching screenshot for reference
enter image description here

What is the issue here? how to make each chunk to be streamed to server?

Deep linking web pages

i’m working on a website. it has a component called product category. and this component has 5 products type as a slick sliders format. and thiws website has another page called product page. this porduct page has horizontal products tab. those product types are listed with their description in the products tab. when we click the specific product type in the home page that link should goes to the same exact product in the products tab and open the exact product and its description. also the url should be change respect to the product type name.

this is the code for product type category homepage component code

<div class="slick-track" style="opacity: 1; width: 1410px; transform: translate3d(0px, 0px, 0px);">
   <div class="slick-slide slick-current slick-active" data-slick-index="0" aria-hidden="false" style="width: 242px;">
      <div>
         <li class="xList-item" style="width: 100%; display: inline-block;">
            <a href="/ceylon-tea-products/#black-tea" tabindex="0">
               <picture>
                  <img class="" src="/images/site-specific/home/tea-collection.png"                            title="Black Tea" alt="Black Tea" varid="var-1573120738681" loading="lazy">
               </picture>
               <h4>Black Tea<br><br></h4>
            </a>
         </li>
      </div>
   </div>
   <div class="slick-slide slick-active" data-slick-index="1" aria-hidden="false" style="width: 242px;">
      <div>
         <li class="xList-item" style="width: 100%; display: inline-block;">
            <a href="/ceylon-tea-products/#flavoured-tea" tabindex="0">
               <picture>
                  <img class="" src="/images/site-specific/home/tea-collection.png" title="Flavoured Tea" alt="Flavoured Tea" varid="var-1573120738681" loading="lazy">
               </picture>
               <h4>Flavoured Tea<br><br></h4>
            </a>
         </li>
      </div>
   </div>
   <div class="slick-slide slick-active" data-slick-index="2" aria-hidden="false" style="width: 242px;">
      <div>
         <li class="xList-item" style="width: 100%; display: inline-block;">
            <a href="/ceylon-tea-products/#green-tea" tabindex="0">
               <picture>
                  <img class="" src="/images/site-specific/home/tea-collection.png" title="Green Tea" alt="Green Tea" varid="var-1573120738681" loading="lazy">
               </picture>
               <h4>Green Tea<br><br></h4>
            </a>
         </li>
      </div>
   </div>
   <div class="slick-slide slick-active" data-slick-index="3" aria-hidden="false" style="width: 242px;">
      <div>
         <li class="xList-item" style="width: 100%; display: inline-block;">
            <a href="/ceylon-tea-products/#herbal-tea" tabindex="0">
               <picture>
                  <img class="" src="/images/site-specific/home/tea-collection.png" title="Herbal Tea" alt="Herbal Tea" varid="var-1573120738681" loading="lazy">
               </picture>
               <h4>Herbal Tea<br><br></h4>
            </a>
         </li>
      </div>
   </div>
   <div class="slick-slide slick-active" data-slick-index="4" aria-hidden="false" style="width: 242px;">
      <div>
         <li class="xList-item" style="width: 100%; display: inline-block;">
            <a href="/ceylon-tea-products/#red-tea" tabindex="0">
               <picture>
                  <img class="" src="/images/site-specific/home/tea-collection.png" title="Red Tea" alt="Red Tea" varid="var-1573120738681" loading="lazy">
               </picture>
               <h4>Red Tea<br><br></h4>
            </a>
         </li>
      </div>
   </div>
</div>

this is the code for the products in the product tabs

<div class="slick-track" style="opacity: 1; width: 880px; transform: translate3d(0px, 0px, 0px);">
   <div class="slick-slide slick-current slick-active" data-slick-index="0" aria-hidden="false" style="width: 126px;">
      <div>
         <li id="item_0" class="" style="width: 100%; display: inline-block;"><span>Black Tea</span></li>
      </div>
   </div>
   <div class="slick-slide slick-active" data-slick-index="1" aria-hidden="false" style="width: 126px;">
      <div>
         <li id="item_1" style="width: 100%; display: inline-block;" class="active"><span>Flavoured Tea</span></li>
      </div>
55555   </div>
   <div class="slick-slide slick-active" data-slick-index="2" aria-hidden="false" style="width: 126px;">
      <div>
         <li id="item_2" style="width: 100%; display: inline-block;"><span>Green Tea</span></li>
      </div>
   </div>
   <div class="slick-slide slick-active" data-slick-index="3" aria-hidden="false" style="width: 126px;">
      <div>
         <li id="item_3" style="width: 100%; display: inline-block;"><span>Herbal Tea</span></li>
      </div>
   </div>
   <div class="slick-slide slick-active" data-slick-index="4" aria-hidden="false" style="width: 126px;">
      <div>
         <li id="item_4" style="width: 100%; display: inline-block;"><span>Red Tea</span></li>
      </div>
   </div>
</div>

this is the code for the products description for the each products which are in the product tabs(I have mentioned only the necessary codes)

<li class="xList-item item_0" data-title="Black Tea" data-category="black-tea">//product description will come here</li>
<li class="xList-item item_1 active" data-title="Flavoured Tea" data-category="flavoured-tea">//product description will come here</li>
<li class="xList-item item_2" data-title="Green Tea" data-category="green-tea">//product description will come here</li>
<li class="xList-item item_3" data-title="Herbal Tea" data-category="herbal-tea">//product description will come here</li>
<li class="xList-item item_4" data-title="Red Tea" data-category="red-tea">//product description will come here</li>

this is the javascript code

$( document ).ready(function() {
  const tabs = document.querySelectorAll('.slick-slide');
const tabContent = document.querySelectorAll('.xList-item');

// Set the first tab as active by default
tabContent[0].classList.add('active');


tabs.forEach((tab) => {
  tab.addEventListener('click', (e) => {
    e.preventDefault();
    const target = tab.getAttribute('href');
    const tabId = tab.getAttribute('id');
    let currentTab = document.querySelector('.xList-item.active');
    if (currentTab) {
      currentTab.classList.remove('active');
    }
    document.querySelector(`#${tabId}`).classList.add('active');
    window.location.hash = target;
  });
});




console.log(window.location.hash);

// Parse the URL hash and activate the corresponding tab
const hash = window.location.hash;
if (hash) {
  const tabId = hash.replace('#', '');
  const tabLink = document.querySelector(`a[href="${hash}"]`);
  if (tabLink) {
    const tabPane = document.querySelector(`#${tabId}`);
    if (tabPane) {
      // Remove active class from all tabs
      tabContent.forEach((tab) => tab.classList.remove('active'));
      // Add active class to the selected tab
      tabPane.classList.add('active');
    }
  }
}
});



// Tab Activation By Hash

addToAutoLoadLibs('/vendor-lib/slick/slick.min.js', scrollToTab);

function scrollToTab(){
    
    const windowHash = window.location.hash;

    if (windowHash) {
    
        const windowHashValue = windowHash.replace('#', '');
    
        const $tabListItem = $('.r2g-two-level-tab-horizontal').find(`.products-list[data-hash="${windowHashValue}"]`);
    
        const $xList = $tabListItem.closest('.xList-item');
    
        const classList = $xList[0].classList;
    
        tabId = classList[1];
    
        if (tabId) {
            
            const $tabEl =  $(`.tabs-horizontal .title-wrapper li[id="${tabId}"]`);
            
            if($tabEl.length){
    
                $tabEl.click();
    
                $('html, body').animate({
                    scrollTop: $tabEl.offset().top - 100
                }, 1000);
    
            }
    
        }
    }
$('.tabs-horizontal .title-wrapper .slick-slide').on('click', function() {
    const tabIndex = $(this).attr('data-slick-index');
    const tabContent = document.querySelector(`.xList-item.item_${tabIndex}`);
    if (tabContent) {
        const hashTag = tabContent.getAttribute('data-category');
        if (hashTag) {
            // Update the URL hash
            window.location.hash = hashTag;
        }
    }

});
    
    
    
}

these are working well. i mean in the desktop view these js codes are working well. but in mobile view it does not work. i used drop down list for showing the product and it’s description instead of products tab in the product page.

this is the code for drop down that used instead of the product tabs

<select class="form-control mobile-only">
   <option value="item_0">Black Tea</option>
   <option value="item_1">Flavoured Tea</option>
   <option value="item_2">Green Tea</option>
   <option value="item_3">Herbal Tea</option>
   <option value="item_4">Red Tea</option>
</select>

so for this code the the functionalities doesn’t work. means when i click the specific product in the homepage that link only goes to the product page only. it does not go tho the exact product and does not open the exact product and it’s description and url also not updated

i need to work this functionalities also in the mobile view same as desktop.

React native iris scanning

does anyone have any idea about iris recognition with React Native, is there any package for that? I see a package named @iriscan/biometric-sdk-react-native, but it focuses on face detection.

I tried using the @iriscan/biometric-sdk-react-native package with React Native for iris recognition. However, it seems that the package is primarily focused on face detection and related features. I was expecting it to provide functionality specifically for iris recognition, but it appears to be more geared towards facial biometrics, And it’s not working for me.