Javascript converting a set into an array returns an empty array caused by a website

I came across a site named “FurAffinity“, and was toying around with userscripts. I discovered something strange with while being on that site that this JS code does not work (it happens on both on a userscript, and on the devtool’s console):

Array.from(new Set([1,2,2,3]))
// returns "[]" instead of "(3) [1, 2, 3]"

Entering that code on the default page of the browser (appears when you create a new tab) will do the latter result as expected, but not while on FurAffinity.

Is there any explanation of why this occurs? If so, is there any way to re-override it to do the default array method? Also if so, is there any way to prevent websites from overriding any JS methods of the userscript? I already know you can convert a set into an array using a spread syntax ([...ExampleSet]) as a workaround, however I’m concerned about other commonly-used JS methods and functions like String.<Insert method name here> and /<regex>/.test(String) could get altered and not behave as it supposed to do.

Angular and coros

Title: CORS Policy Issue: Blocked XMLHttpRequest Access from localhost:4200 to localhost:5000


Problem:
I’m encountering an issue where I keep getting bombarded with the following error:

Access to XMLHttpRequest at 'http://localhost:5000/compare-with-csv' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. :5000/compare-with-csv:1
Failed to load resource: net::ERR_FAILED
core.mjs:7494 ERROR HttpErrorResponse

Context:
I’m currently working on a project where I have a frontend running on localhost:4200 and a backend on localhost:5000. The frontend is attempting to make a request to the backend, specifically to the endpoint compare-with-csv.

What I’ve Tried:
I’ve already implemented CORS handling on my backend, yet the error persists. I’ve ensured that the CORS middleware is correctly configured to allow requests from localhost:4200. Despite this, the error continues to occur, causing the XMLHttpRequest to fail.

Code Snippets:
Here’s a snippet of my CORS middleware configuration on the backend:

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import Chart from 'chart.js/auto';


@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
  //declaring
// Overview Data
  
  // Demographics Section
 

  // Academic Performance Section
  


  // Intervention Insights Section
 
  constructor(private http: HttpClient) { }

  ngOnInit(): void {
    this.fetchData();
  }

  fetchData(): void {
    this.http.get<any>('http://localhost:5000/compare-with-csv')
      .subscribe((data: any) => {
        // Overview Data


// Demographics Section

//assing data 
// Academic Performance Section


// Intervention Insights Section


        // Intervention Insights Section
        // Assuming studentsAtRiskData, studentsAtRiskLabels, interventionTrendsData, 
      });

    // Assigning values fetched from backend to variables
consolloging data

// Overview Data

// Demographics Section

// Academic Performance Section

// Intervention Insights Section

  }
}

Question:
What else could be causing this CORS policy error even after ensuring that CORS is correctly implemented on my backend? Is there any additional configuration or troubleshooting step I might be missing?

Any insights or guidance would be greatly appreciated! Thank you in advance.
send me dm if you want the full code

I attempted to resolve the CORS policy error by implementing CORS middleware in the backend code. Specifically, I configured the CORS middleware to allow requests from localhost:4200, which is where my frontend is hosted. Additionally, I ensured that the CORS middleware is correctly configured to allow the appropriate HTTP methods and headers.

My expectation was that by implementing CORS correctly, the error message indicating that the XMLHttpRequest is blocked due to CORS policy would no longer occur. I expected the frontend request to the backend endpoint compare-with-csv to be successfully processed without encountering any CORS-related issues. However, despite implementing CORS, the error persisted, which led me to seek further assistance in troubleshooting the issue.

Can we use shadcn without framework?

Is there a way to use Shadcn components in a simple project without any framework?

I tried Vite and manual installation structures. They create .vue and .tsx files for components. I want to know if there is a way to have .js files for components.

How to switch an svg to anothe svg after clicking on it?

I have this sun svg image that switches the page to dark mode:

<svg onclick="myFunction()" width="24" height="24" viewBox="0 0 24 24" fill="#000" xmlns="http://www.w3.org/2000/svg">
    <path d="M12 3V5.25M18.364 5.63604L16.773 7.22703M21 12H18.75M18.364 18.364L16.773 16.773M12 18.75V21M7.22703 16.773L5.63604 18.364M5.25 12H3M7.22703 7.22703L5.63604 5.63604M15.75 12C15.75 14.0711 14.0711 15.75 12 15.75C9.92893 15.75 8.25 14.0711 8.25 12C8.25 9.92893 9.92893 8.25 12 8.25C14.0711 8.25 15.75 9.92893 15.75 12Z" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
  </path>
</svg>

this is the JavaScript:

function myFunction() {
  var element = document.body;
  element.classList.toggle("dark-mode");
}

and this is some CSS:

.dark-mode {
  background: #333;
}

.dark-mode path {
  fill: #fff;
  stroke: #fff;
}

however, I want the svg itself to be switched, too, after clicking on it as a replacement. This is the other svg to be switched to, which is a moon svg image:

<svg width="24" height="24" viewBox="0 0 24 24" fill="#000" xmlns="http://www.w3.org/2000/svg">
  <path d="M21.7519 15.0019C20.597 15.4839 19.3296 15.75 18 15.75C12.6152 15.75 8.25 11.3848 8.25 5.99999C8.25 4.67039 8.51614 3.40296 8.99806 2.24805C5.47566 3.71785 3 7.19481 3 11.25C3 16.6348 7.36522 21 12.75 21C16.8052 21 20.2821 18.5243 21.7519 15.0019Z" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
  </path>
</svg>

how can this be done, please?

Avoiding Automatic Movement (“Pan”) When Dissolving Clusters with MarkerClustererPlus in Google Maps

I’m developing a web application that uses the Google Maps API along with the MarkerClustererPlus library to group markers. I’m experiencing an unwanted behavior: whenever I zoom into the map and several clusters dissolve at once, especially when it involves large volumes of markers, the map automatically moves (“pans”) towards the largest sets of ungrouped points. This results in a less than pleasant user experience, as the map moves without direct user intervention.

I want to be able to zoom in on the map and dissolve clusters without the map making automatic movements (“pan”). Is there a way to disable or manually control this behavior so that the map remains static while users zoom in, allowing them to explicitly control the map movement for a smooth and pleasant navigation experience?

Why is my stopwatch adding fixed amount of time when I refresh?

I have a Vue.js Script is Adding time to my stopwatch once I refresh the page – Always adds an additional 6 hours. The script is simply a button that tracks time when clicked, and post the time to a django model once stopped. I am able to track time fine, but when I refresh the page, I come back to seeing 6 hours added to my stopwatch:

Vue.js Script:

var NavbarApp = {
            data() {
                return {
                    seconds: {{ active_entry_seconds }},
                    trackingTime: false,
                    showTrackingModal: false,
                    timer: null,
                    entryID: 0,
                    startTime: '{{ start_time }}'
                }
            },
            delimiters: ['[[', ']]'],
            methods: {
                startTimer() {
                    fetch('/apps/api/start_timer/', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'X-CSRFToken': '{{ csrf_token }}'
                        }
                    })
                    .then((response) => {
                        return response.json()
                    })
                    .then((result) => {
                        this.startTime = new Date()
                        this.trackingTime = true

                        this.timer = setInterval(() => {
                            this.seconds = (new Date() - this.startTime) / 1000
                        }, 1000)
                    })
                },
                stopTimer() {
                    fetch('/apps/api/stop_timer/', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'X-CSRFToken': '{{ csrf_token }}'
                        }
                    })
                    .then((response) => {
                        return response.json()
                    })
                    .then((result) => {
                        this.entryID = result.entryID
                        this.showTrackingModal = true
                        this.trackingTime = false

                        window.clearTimeout(this.timer)
                    })
                },
                discardTimer() {
                    fetch('/apps/api/discard_timer/', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'X-CSRFToken': '{{ csrf_token }}'
                        }
                    })
                    .then((response) => {
                        this.seconds = 0
                        this.showTrackingModal = false
                    })
                },
                addLater() {
                    this.seconds = 0
                    this.showTrackingModal = false
                },
                addToTask() {
                    console.log('addToTask')
                    window.location.href = '/apps/track_entry/' + this.entryID + '/'
                }
            },
            mounted() {
                if (this.seconds !== 0) {
                    this.trackingTime = true
                    this.timer = setInterval(() => {
                        this.seconds = (new Date() - new Date(this.startTime)) / 1000
                    }, 1000)
                }
            },
            computed: {
                readableSeconds() {
                    const d = Number(this.seconds);
                    const h = Math.floor(d / 3600);
                    const m = Math.floor(d % 3600 / 60);
                    const s = Math.floor(d % 3600 % 60);

                    const hDisplay = h > 0 ? h + (h == 1 ? "h, " : "h, ") : "";
                    const mDisplay = m > 0 ? m + (m == 1 ? "m, " : "m, ") : "";
                    const sDisplay = s >= 0 ? s + (s == 1 ? "s" : "s") : "";

                    return hDisplay + mDisplay + sDisplay; 
                }
            }
        }

        Vue.createApp(NavbarApp).mount('#navbar-app')

HTML:

                                                <div class="col-md-auto mt-md-0 mt-4" id="navbar-app">
                                                    <div class="hstack gap-1 flex-wrap">
                                                        <div class="navbar-item" v-if="!trackingTime">
                                                            <div class="buttons">
                                                                <button class="btn btn-success add-btn" @click="startTimer()">
                                                                   Start Timer
                                                                </button>
                                                            </div>
                                                        </div>
                            
                                                        <div class="navbar-item" v-else>
                                                            <div class="buttons">
                                                                <div class="buttons">
                                                                    <button class="btn btn-warning add-btn" @click="stopTimer()">
                                                                        [[ readableSeconds ]] (stop)
                                                                    </button>
                                                                </div>
                                                            </div>
                                                        </div>

When I click the button – time is tracking:
enter image description here

When I refresh the page, 6 additional hours have been added:
enter image description here

Let me know if I am missing any information or code you may need

PDF.js v4-Open findBar by default

I embedded a PDF using pdfjs-4.0.379, and in the previous version (version 2) I had something similar to this:

...
key: "setHash",
    value: function setHash(hash) {
        //aqui
      var pageNumber, dest;      

      if (hash.includes("=")) {
        var params = (0, _ui_utils.parseQueryString)(hash);
        
        if ("search" in params) {
          this.eventBus.dispatch("findfromurlhash", {
            source: this,
            query: params.search.replace(/"/g, ""),
            phraseSearch: params.phrase === "true"
          });
        }
        
         if ('search' in params) { 
              PDFViewerApplication.findBar.open(); 
              PDFViewerApplication.findBar.findField.value = params.search; 
              PDFViewerApplication.findBar.highlightAll.checked = true; 
              PDFViewerApplication.findBar.findNextButton.click(); 
        }
...

But how can i implement that in the current version?

I found a similar answer in this link, but it didn’t really answer my question.

NextJs Unhandled Runtime Error TypeError: Cannot read properties of null (reading ‘removeChild’) on using third party blog post library

I am trying to use https://dropinblog.com/ with nextjs, the page works fine and loads perfectly with no error the problem is when I click the navigation links to navigate to some other pages using Next Link it throws this error:
enter image description here

my page is /blog which the code is:

import Script from "next/script";

export default function Blog() {
  return (
    <div>
      <Script
        src="your-dropin-blog-source"
        strategy="lazyOnload"
      ></Script>
      <div id="dib-posts"></div>
    </div>
  );
}

Application using Python and Javascript

I am creating a project that uses Electron to create the application interface (HTML, CSS, Javascript) and I am also using Selenium (Python) for the backend.

Question 1) How would I create a virtual environment for these 2 technologies? Since they are different.

Question 2) How would I communicate between these two? Basically I would need to send a string from Python to Javascript and vice versa.

Question 3) How would I transform this application that uses Python and Javascript into an executable? Since they are different.

NOTE: I want to use Selenium from Python, because I know more Python than Javascript.

Sandboxed JavaScript for CMP (Consent Mode v2) cannot write to dataLayer

I have set up a custom template using code from my CMP provider, which works fine for consent setting. We have had to make several additions and edits to the CMP as provided. I want to send a custom event when consent is updated to use as a trigger for certain tags, but I keep getting “‘dataLayer’ is not defined” errors. It seems that I can’t get the sandboxed javascript to talk to my dataLayer at all, as any reference to it or the window creates issues.

I assume this is an issue with the custom template limitations. I want to understand why it’s not working and how to be able to send custom events to the dataLayer in sandboxed javascript.

I have tried different methods of trying to make this work, but everything I tried results in either a ‘window is not defined’ or ‘dataLayer’ is not defined error. My provider is unwilling to help as they believe it’s a Google issue. Note: the script works fine if I remove the references to window and dataLayer and does update consent as it should. However, I need to send custom events as part of ‘updateConsentState’ too to trigger other tags.

Please see my code below:

// Initialize dataLayer
window.dataLayer = window.dataLayer || [];

// Enter your template code here.
const log = require('logToConsole');
const setDefaultConsentState = require('setDefaultConsentState');
const updateConsentState = require('updateConsentState');
const injectScript = require('injectScript');
const queryPermission = require('queryPermission');
const copyFromWindow = require('copyFromWindow');
log('data =', data);

// set default consent
setDefaultConsentState({
    'ad_storage': 'denied',
    'analytics_storage': 'denied',
    'ad_user_data': 'denied',
    'ad_personalization':'denied',
    'functionality_storage': data.functional,
    'personalization_storage': data.functional,
    'security_storage': 'granted'
});

// start of config
var config = {
    apiKey: data.apiKey,
    logConsent: true,
    product: data.product,
    optionalCookies: [
        {
            name : 'Analytics',
            label: "<strong>Analytics cookies</strong>",
            description: "<p>Analytics cookies help us to improve our website by collecting data about how you use it.</p>",
            cookies: ['_gid', '_ga*', 'nmstat', '__utma', '__utmc', '__utmz', '__utmt', '__utmb', '_hj*', 'CLID', 'SRM_B', 'uid', '_vwo*', '_gat',],
            onAccept : function(){
                updateConsentState({
                    'analytics_storage': 'granted',
                });
                // Push event to dataLayer
                window.dataLayer.push({
                    'event': 'analytics_granted',
                    'category': 'Analytics',
                    'action': 'Granted'
                });
            },
            onRevoke: function(){
                updateConsentState({
                    'analytics_storage': 'denied',
                });
            }
        },
        {
            name : 'marketing',
            label: "<strong>Marketing cookies</strong>",
            description: "<p>Marketing cookies help us show you adverts that are more relevant to you.</p>",
            cookies: ['X-AB', '_gcl*', 'uid', 'test_cookie', 'YSC', 'VISITOR_INFO1*', '_ttp', '_scid', '_scid_r', '_scid*', '_uet*', 'muc_ads', 'li_sugr', 'bcookie', 'lidc', 'personaliza*', 'MUID', 'UserMatch*', 'AnalyticsSync*', '_fbp*', '_tt_enable*', 'bscookie', 'li_gc', 'MR', 'SM', 'ANONCHK', 'MSPTC', 'IDE', 'suid', 'uid*', 'TapAd*', 'XANDR*', 'receive-cookie*', 'uuid2', '_rxuuid', 'ab', 'anHistory', 'anj', 'anProfile', 'u', 'bku', 'bkpa', '__141_cid', '__io_cid', 'A3', 'utm_*', 'NID', 'cf_clearance', '_cfuvid', '_fbc'],
            onAccept : function(){
                updateConsentState({
                    'ad_storage': 'granted',
                    'ad_user_data': 'granted',
                    'ad_personalization':'granted',
                });
                // Push event to dataLayer
                window.dataLayer.push({
                    'event': 'marketing_granted',
                    'category': 'Marketing',
                    'action': 'Granted'
                });
            },
            onRevoke: function(){
                updateConsentState({
                    'ad_storage': 'denied',
                    'ad_user_data': 'denied',
                    'ad_personalization': 'denied',
                });
            }
        }
    ],
    text: {
        title: "<div class='u-text-h4 u-font-bold u-font-serif u-mb-1'>Control your cookies</div>",
        notifyTitle: "<div class='u-text-h4 u-font-bold u-font-serif u-mb-1'>Control your cookies</div>",
        notifyText: "<p>We need some essential cookies to make this website work. We want to set other cookies to understand how you use the site and give you the best experience. If you change your mind, you can change your settings.</p>",
        acceptSettings: "Accept all",
        rejectSettings: "Reject non-essential",
        accept: "Accept all",
        reject: "Reject non-essential",
        settings: "More options",
        necessaryTitle:"<strong>Essential cookies</strong>",
        necessaryDescription:"<p>We need some essential cookies to make this website work. They help you move between pages, interact with the website and access secure areas. You can only reject essential cookies in your browser settings. Some parts of the site may not work if you do.</p>",
        closeLabel: "<span>Save and close cookie control</span>",
        notifyDescription : "<p>We need some essential cookies to make this website work. We want to set other cookies to understand how you use the site and give you the best experience.</p>",
    },
    consentCookieExpiry: 365,
    theme: 'light',
    subDomains: true,
    statement: {
        description: 'For more detailed information, please check our',
        name: 'Cookie Policy',
        url: 'https://www.mmu.ac.uk/cookie-policy',
        updated: '04/03/2024',
    },
    excludedCountries: 'all',
    position: 'left',
    layout: 'popup',
    toggleType: 'slider',
    branding: {
        'backgroundColor': '#ffffff',
        'fontColor': '#000000',
        'acceptBackground':'#ffcd00',
        'rejectBackground':'#ffffff',
        'acceptText':'#000000',
        'rejectText':'#000000',
        'removeAbout': true,
        'removeIcon': true,
        'toggleBackground':'#A9A3AD',
        'toggleText':'#ffffff',
    }
};

// end of config

const onSuccess = () => {
    const CookieControl = copyFromWindow('CookieControl');
    log(config);
    CookieControl.load(config);
    data.gtmOnSuccess();
};

const onFailure = () => {
    log("fail");
    data.gtmOnFailure();
};

injectScript('https://cc.cdn.civiccomputing.com/9/cookieControl-9.x.min.js', onSuccess, onFailure);

// Call data.gtmOnSuccess when the tag is finished.
data.gtmOnSuccess();

How to add the chart in excel using handlebars?

I need to add the chart in excel. From table data ,need a chart to be drawn in the excel.I have add xlsxAdd to append chart in excel, but its throwing *Missing helper: “xlsxAdd*
error. So table is already there in the excel but chart is not rendering using this handlebars.This is the correct way to add chart in excel ?


<!DOCTYPE html>
<html>

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Report</title>
    <link rel="stylesheet" href="/stylesheets/style.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
</head>
<style>
    table, th, td {
        border: 1px solid black;
        border-collapse: collapse;
    }

    table {
        width: 100%
    }

    td {
        text-align: center
    }
</style>
<body>
     <div>
        <img src="https://icicipruamcdev.azureedge.net/static/media/logo.86f7e0e9.svg" style="height: 150px;">
    </div>


    <canvas id="canvas" style="width:90vw"></canvas>
    <script>
         document.addEventListener('DOMContentLoaded', function() {
            // Extract data from the table
            const table = document.getElementById('report-table');
            const rows = table.querySelectorAll('tr');
            const labels = [];
            const navData = [];
            rows.forEach((row, index) => {
                if (index > 0) { // Skip header row
                    const cells = row.querySelectorAll('td');
                    labels.push(cells[1].textContent); // Assuming date is in the second column
                    navData.push(parseFloat(cells[0].textContent)); // Assuming nav is in the first column
                }
            });
            
            // Chart data
            const chartData = {
                labels: labels,
                datasets: [{
                    label: "NAV_HISTORY",
                    type: 'line',
                    data: navData,
                    backgroundColor: 'transparent',
                    borderColor: 'blue',
                    borderWidth: 1,
                    lineTension: 0,
                    pointBackgroundColor: 'blue',
                    pointBackgroundColor: 'transparent',
                    borderColor: 'navy',
                    pointRadius: 3
                }]
            };

            // Chart initialization
            const ctx = document.getElementById('canvas').getContext('2d');
            const chart = new Chart(ctx, {
                type: 'line',
                data: chartData,
                options: {
                    responsive: false,
                    animation: false,
                    maintainAspectRatio: false,
                    devicePixelRatio: 1,
                    scales: {
                        yAxes: [{
                            ticks: {
                                beginAtZero: true,
                                stepSize: 20
                            }
                        }],
                        xAxes: [{
                            ticks: {
                                autoSkip: true,
                                maxTicksLimit: 8,
                                maxRotation: 0,
                                minRotation: 0
                            }
                        }]
                    }
                }
            });
        });
    </script>   
    <div><br/></div>
    <div class="invoice-box">
       <!-- Assuming you have a table structure like this -->
<table>
    <thead>
        <tr>
            <th>NAV</th>
            <th>Date</th>
        </tr>
    </thead>
    <tbody>
        {{#each data}}
        <tr>
            <td>{{this.Name}}</td>
            <td>{{this.Amount}}</td>
        </tr>
        {{/each}}
    </tbody>
</table>

<!-- Now, let's add the xlsxAdd functionality -->
{{#xlsxAdd "xl/drawings/drawing1.xml" "xdr:wsDr.twoCellAnchor"}}
{{#each data}}
<row>
    <c t="inlineStr"><is><t>{{this.Name}}</t></is></c>
    <c><v>{{this.Amount}}</v></c>
</row>
{{/each}}
{{/xlsxAdd}}

    </div>
</body>

</html>

Adding new object to mongoDB changes the previously added object

I’m using AWS S3 and MongoDB in a full-stack react application.

When I add a new recept in front-end it works normally. But once in a while it changes the rndImageName which I create on back-end. Images uploads to S3 fine.

Is there better way to do this?

multer.js

const randomImageName = (bytes = 32) => crypto.randomBytes(bytes).toString('hex')
let rndImageName = randomImageName();

awsRouter.post('/recipeImages', upload.single('file'), async (req, res) => {

  const buffer = await sharp(req.file.buffer).resize({ height: 1920, width: 1080, fit: 'contain' }).toBuffer()

  const params = {
    Bucket: bucketName,
    Key: 'recipeImages/' + rndImageName, 
    Body: buffer,
    ContentType: req.file.mimetype
  }

  const command = new PutObjectCommand(params)

  await s3.send(command)

})


recipes.js 

const { rndImageName } = require('./multer')

recipesRouter.post('/', async (request, response, next) => {

  const body = request.body

  const decodedToken = jwt.verify(getTokenFrom(request), process.env.SECRET)

  if (!decodedToken.id) {
    return response.status(401).json({ error: 'token invalid' })
  }
  const user = await User.findById(decodedToken.id)


  const recipe = new Recipe({
    id: body.id,
    recipe_name: body.recipe_name,
    ingredients: body.ingredients,
    instructions: body.instructions,
    speed: body.speed,
    category: body.category,
    main_ingredient: body.main_ingredient,
    diet: body.diet,
    likes: body.likes || 0,
    comments: body.comments || [],
    created: new Date(),
    imageName: rndImageName,
    user: user._id
  })

  const savedRecipe = await recipe.save()
  user.recipes = user.recipes.concat(savedRecipe._id)
  await user.save()

})

I want to insert the rndImageName (which I set up for S3 file name) to mongoDB objects so I can create signedUrl for a specific recipe.

Now it seems to use the same randomImageName again. Also changing the previously added recipe’s imageName.

Why some functions not working when navigate to the payment gateway?

I am developing website to navigate a sample Mastercard payment gateway and I want detect order id after the payment. In my code I set functions (callbacks) beforeRedirect , afterRedirect and completeCallback (Javascript functions) mentioned in documentation. I add js alerts for all functions to check they are working. But afterRedirect function is not working (other call backs are working) .The code seems to be correct. I have doubt that its because of security issues or running on localhost. Have you any idea why afterRidirect not working? Please help to solve this problem.

Here is the sample code.
This method is specifically for the full payment page option. Because we leave this page and return to it, we need to preserve the
state of successIndicator and orderId using the beforeRedirect/afterRedirect option

function afterRedirect(data) {
console.log("afterRedirect", data);
// Compare with the resultIndicator saved in the completeCallback() method
if(resultIndicator === "CANCELED"){
    return;
}    
else if (resultIndicator) {
    var result = (resultIndicator === data.successIndicator) ? "SUCCESS" : "ERROR";
    window.location.href = "/hostedCheckout/" + data.orderId + "/" + result;
}
else {
    successIndicator = data.successIndicator;
    orderId = data.orderId;
    sessionId = data.sessionId;
    sessionVersion = data.sessionVersion;
    merchantId = data.merchantId;

    window.location.href = "/hostedCheckout/" + data.orderId + "/" + data.successIndicator + "/" + data.sessionId;
}

This method preserves the current state of successIndicator and orderId, so they’re not overwritten when we return to this page after redirect

function beforeRedirect() { console.log("beforeRedirect");
return {
    successIndicator: successIndicator,
    orderId: orderId
};

}

Geoblocking; How to limit access to a website to within a physical establishment only?

We have created a website whose users must be limited to within the confines of a physical establishment or building. If they leave the building they should not be able to load and interact with the website.

We are at an impasse as to what solution to use to solve this issue with.

We’ve explored doing this with bluetooth low energy by having a desktop computer configured as a beacon to send out signals to visitors of the website whose mobile devices will have javascript code scanning for this particular bleutooth beacon device. ble web API is marked as experimental so users must go to chrome flags to enable to feature before javascript ble code will run, though – the flow of navigating away and enabling the flag, then relaunching chrome is not a good user experience at all. This messing with flags is not something everyday users should be doing all the time anyways.

Another option is to have the website’s javascript scan wifi and somehow check if the wifi is the one at the establishment, maybe?

My proposal was this option; to use navigator.geolocation to get the coordinates of the user and the reading’s accuracy rating, and checking if this is within the coordinates of the establishment. I’ve been told that the accuracy is too low for this use case by another engineer on the team. I don’t know enough about its accuracy to refute this. Can someone more experienced weigh in on this assessment?

Another option is checking user IP as mentioned in (Is it possible/feasible to limit website access to a geographic area?) this post but if the accuracy is city-level, that would be too inaccurate for this use case.

What’s the best path forward? Any other options we haven’t considered? Thoughts on options we have considered?