Automatic printing with js and php [closed]

I want a complete js php code that generates a PDF report (for example an invoice) and then prints it automatically without displaying a print preview.
Help me find a solution

I tried this

 window.print()

but it only displays the web page (web page preview)

My fpdf2 PDF is blank when I try to download it from the browser after passing it to the front end

I cannot for the life of me figure out why this PDF won’t display. I’m using fpdf2 to create a pdf that looks good when saving it from the python script. However, something must be going wrong when passing the data to the front end.

Here is the pdf representation that I’m ending up with:

"%PDF-1.3
1 0 obj
<<
/Count 1
/Kids [3 0 R]
/MediaBox [0 0 595.28 841.89]
/Type /Pages
>>
endobj
2 0 obj
<<
/OpenAction [3 0 R /FitH null]
/PageLayout /OneColumn
/Pages 1 0 R
/Type /Catalog
>>
endobj
3 0 obj
<<
/Contents 4 0 R
/Parent 1 0 R
/Resources 6 0 R
/Type /Page
>>
endobj
4 0 obj
<<
/Filter /FlateDecode
/Length 72
>>
stream
x�3R��2�35W(�r
Q�w3T04�30PISp
    �Z(�[����(hx����+���(j*�d��V
endstream
endobj
5 0 obj
<<
/BaseFont /Helvetica-Bold
/Encoding /WinAnsiEncoding
/Subtype /Type1
/Type /Font
>>
endobj
6 0 obj
<<
/Font <</F1 5 0 R>>
/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
>>
endobj
7 0 obj
<<
/CreationDate (D:20250708064952Z)
>>
endobj
xref
0 8
0000000000 65535 f 
0000000009 00000 n 
0000000096 00000 n 
0000000199 00000 n 
0000000279 00000 n 
0000000422 00000 n 
0000000524 00000 n 
0000000611 00000 n 
trailer
<<
/Size 8
/Root 2 0 R
/Info 7 0 R
/ID [<119889D12E2230568C66D2CFBCFCE0FB><119889D12E2230568C66D2CFBCFCE0FB>]
>>
startxref
666
%%EOF
"

I can verify that this is the data getting downloaded when I change the type to text/plain. When the type is set to application/pdf, I end up with a blank pdf. I can also tell that part of it is working properly because adding more pages to the pdf results in a download with the proper amount of pages.

Running out of ideas, so I’d really appreciate if anyone had any insight.
Thanks in advance!

I’ve tried converting to different types, using a Blob() vs a File(), changing headers to include “Content-Disposition”: “attachment; filename=myfilename.pdf” and more.

Some of these ideas came from previous posts, but none of them quite did the trick.

ReactJS – Javascript addEventListener does not remove the listener function at component’s unMount

I have added an event listener to “keydown” event in my ReactJS application. Because of a third party library, I’m adding it via setTimeout in a useEffect, this component is like a popup, so it mounts-unmounts lots of times in the app lifecycle. Its like below;

      useEffect(() => {
        const timeoutID = setTimeout(() => {
          clearTimeout(timeoutID);
            window.addEventListener("keydown", theFunction, true);
          
        }, 500);
        
        function theFunction(event: KeyboardEvent) {
           // do something
        }

        return () => {
          window.removeEventListener("keydown", theFunction, true);
        };
      }, []);

It’s a typical usage, to remove event listener using removeEventListener method. The problem is, when the component unMounts, the event stays and stacks up on top of another. I’m actually seeing it on the Event Listeners tab on Devtools.

I was suspecting that, every time this component mounts, theFunction changes in the memory, so it’s not the same function and therefore React can’t remove it. I took theFunction from the useEffect and put it to the top of the component (outside of the functional component definition, just below the imports).

// imports

function theFunction(event: KeyboardEvent) {
               // do something
            }

const Component = () => {
          useEffect(() => {
            const timeoutID = setTimeout(() => {
              clearTimeout(timeoutID);
                window.addEventListener("keydown", theFunction, true);
              
            }, 500);
            
            return () => {
              window.removeEventListener("keydown", theFunction, true);
            };
          }, []);

And voila! The event is now adding just once and does not stack.

I’m not sure is it really beacuse theFunction was not same each time (as I thought) the component unMounts, or is there another React thing that I’m missing. Why React does not removes this eventListener on unMount in this case?

Browser extension fails to reliably update favicon on SPA pages despite correct in DOM

I’m developing a browser extension that changes the favicon on a Single Page Application (SPA).. specifically Roblox.com. The extension injects code to replace the existing favicon with a custom SVG base64 data URI.

When the page initially loads, the extension successfully changes the favicon, and the DOM shows the new <link rel="icon"> tag. However, when navigating to other SPA routes (e.g., /trades), although the DOM still has the updated favicon tag inserted by my extension, the browser sometimes reverts to the default Roblox favicon.

I’ve confirmed via DevTools that:

  • The <link rel="icon"> element’s href attribute is correctly set to my custom SVG data URI on all routes.
  • There are no conflicting multiple favicon tags in the DOM.
  • The extension’s console logs indicate the favicon set function runs on route changes.

What I’ve tried:

  • Removing and re-adding the <link rel="icon"> element programmatically on every SPA route change.
  • Adding a random query parameter to the favicon href as a cache buster.
  • Monitoring DOM mutations to reactively reset the favicon.
  • Tested on FireFox

Question:

How can a browser extension reliably update the favicon on SPA sites where the page does not do full reloads, and the favicon sometimes reverts despite the DOM containing the correct <link rel="icon">? Are there known tricks or workarounds for favicon caching or SPA dynamic page handling specifically for extensions?

Current Code:

const f = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iNzJweCIgaGVpZ2h0PSI3MnB4IiB2aWV3Qm94PSIwIDAgNzIgNzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDcyIDcyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDojRTIyMzFBO30NCgkuc3Qxe2ZpbGw6I0ZGRkZGRjt9DQo8L3N0eWxlPg0KPGcgaWQ9IlJfMV8iPg0KCTxnPg0KCQk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNNjkuMyw2Ny4zQzU5LDU3LjgsNTAuMSw1MC4xLDQwLjcsNDIuMmM1LjYtMC4yLDExLjctMC41LDE3LjMtMWMwLjYtMC4xLDEuMi0wLjMsMS43LTAuNw0KCQkJYzIuMS0xLjcsNS4xLTQuNyw3LTcuM2MwLjMtMC41LDAuNS0xLDAuMy0xLjZjLTItOS01LjQtMTkuOC0xMC4zLTI5LjRjLTAuNC0wLjctMS4yLTEuMi0yLTEuMkMzNi42LDIuMSwxOS4zLDQuNiw0LDcuNw0KCQkJQzMsNy45LDIuMyw4LjgsMi4zLDkuOEMyLjYsMjguNCwzLjYsNDcuNiw1LDY2LjVjMC4xLDEsMC44LDEuOCwxLjgsMmM2LjEsMC45LDEyLjEsMS43LDIwLjMsMi4yYzAuNywwLDEuMy0wLjcsMS0xLjQNCgkJCWMtMi44LTcuOS03LjItMjMuNi03LjktMjYuNGMwLjcsMCwxLTAuMSwxLjYtMC4xYzMuNyw3LjUsOS4zLDE3LjksMTMuMywyNi41YzAuNSwxLjEsMS42LDEuOCwyLjgsMS44YzkuNSwwLjIsMTkuOS0wLjIsMzAuOC0xLjgNCgkJCUM2OS42LDY5LDcwLDY3LjksNjkuMyw2Ny4zeiBNMzQuMSwyNi44Yy0zLjYsMC40LTkuMSwwLjgtMTIuNiwxYy0wLjMtMi4yLTAuNi01LjQtMC43LTcuN2M0LjMsMC4xLDguNywwLjIsMTMuMywwLjYNCgkJCUMzNC4xLDIyLjcsMzQuMSwyNC43LDM0LjEsMjYuOHoiLz4NCgk8L2c+DQoJPGc+DQoJCTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik01Ny42LDM3LjVjMS44LTEuNiwzLjktMy42LDUuMy01LjlDNjEsMjMuMiw1OCwxNCw1My45LDUuNEMzOC4yLDYuNSwyMS4yLDguNyw2LjQsMTEuNWMwLjYsMTkuOCwxLjUsMzYsMyw1Mw0KCQkJYzQuNywwLjcsNy45LDEuMSwxMy4yLDEuNUMyMCw1Ni44LDE4LDQ5LjMsMTYuMSw0MGMyLjUtMC4xLDUuMS0wLjIsNy43LTAuM2M2LjIsMTAsOS44LDE3LjIsMTUuOCwyN2M3LjQsMCwxNC4yLTAuMiwyMS4xLTAuOA0KCQkJYy05LjktOS43LTE5LjEtMTguMy0yOC41LTI2LjZDNDEuMiwzOC44LDUwLjMsMzguMiw1Ny42LDM3LjV6IE0xNy45LDMxLjZjLTAuNy01LTAuOS0xMC0xLjEtMTVjNywwLDE0LjQsMC4zLDIxLjMsMC45DQoJCQljMC4yLDMuNCwwLjIsOSwwLDEyLjVDMzEuNiwzMC43LDI0LjgsMzEuMiwxNy45LDMxLjZ6Ii8+DQoJPC9nPg0KPC9nPg0KPC9zdmc+DQo=";
function setF() {
  let link = document.querySelector('link[rel="icon"], link[rel="shortcut icon"]');
  if (!link) {
    link = document.createElement('link');
    link.rel = 'icon';
    document.head.appendChild(link);
  }
  if (link.href !== f) {
    link.href = f;
    link.type = 'image/svg+xml';
    console.log('[POM] favicon set');
  }
}
function watchFaviconAndURL() {
  setF();
  const observer = new MutationObserver(mutations => {
    for (const m of mutations) {
      if (
        m.type === 'childList' &&
        [...m.removedNodes].some(n =>
          n.tagName === 'LINK' && (n.rel === 'icon' || n.rel === 'shortcut icon')
        )
      ) {
        setF();
      }
      if (
        m.type === 'attributes' &&
        m.target.tagName === 'LINK' &&
        (m.target.rel === 'icon' || m.target.rel === 'shortcut icon') &&
        m.attributeName === 'href' &&
        m.target.href !== f
      ) {
        setF();
      }
    }
  });
  observer.observe(document.head, {
    childList: true,
    subtree: true,
    attributes: true,
    attributeFilter: ['href', 'rel', 'href'],
  });
  let lastURL = location.href;
  ['pushState', 'replaceState'].forEach(fnName => {
    const original = history[fnName];
    history[fnName] = function () {
      const result = original.apply(this, arguments);
      checkURLChange();
      return result;
    };
  });
  window.addEventListener('popstate', checkURLChange);
  function checkURLChange() {
    if (location.href !== lastURL) {
      lastURL = location.href;
      setF();
    }
  }
  setInterval(() => {
    if (location.href !== lastURL) {
      lastURL = location.href;
      setF();
    }
  }, 500);
  setInterval(setF, 2000);
}

watchFaviconAndURL();

How to stop main from closing when clicking an within it

Ran into a snag and hoping the community can provide some insight to help enlighten a fellow coder. Here is a breakdown:

Setup:

  • 3 tier menu with jQuery click handlers to display/hide the second and third tier menus.

Issue:

  • I have a click handler in jQuery for menu and sub menu items however when clicking on a sub menu item it closes the main menu item hiding the submenu.

Code Sample: https://codepen.io/DigitalDesigner/pen/azvozOP

Objective:

  • Main Menu Items with submenu display/hide submenu on click (Working)
  • Opening a Main menus submenu closes all other sub menus (Working)
  • Submenu Items with submenu display/hide submenu on click

This last objective is working except closes Main Submenu.

How can I successfully have the display/hide work on the various tiered menu items when clicking within one another?

$(function () {
    $('.nav-container').each(function () {
        let nav = new Nav($(this));
    });
});

let Nav = function Nav(this$obj) {
    this.$obj = this$obj; // .nav-container

    this.primaryNavTriggers();
};

Nav.prototype.primaryNavTriggers = function primaryNavTriggers() {
  $('.menu-has-children').each(function(){
        $(this).on('click', function() {
            if($(this).hasClass('menu-level-1')) {
                if($(this).find('.sub-sub-menu').hasClass('sub-sub-menu--active')){
                    $(this).find('.sub-sub-menu').removeClass('sub-sub-menu--active');
                } else {
                    $(this).find('.sub-sub-menu').addClass('sub-sub-menu--active');
                }
            } else if($(this).hasClass('menu-level-0') ) {
                if($(this).find('.sub-menu').hasClass('sub-menu--active')){
                    $(this).find('.sub-menu').removeClass('sub-menu--active');
                } else {
                  $('.sub-menu').each(function(){
                    $(this).removeClass('sub-menu--active');
                  });
                    $(this).find('.sub-menu').addClass('sub-menu--active');
                }
            }
        });
    });
};
.nav-container {
     background: #f2f2f2;
     padding: 32px 24px;
}
 .nav-container .menu, .nav-container .sub-menu, .nav-container .sub-sub-menu {
     list-style-type: none;
     margin: 0;
     padding: 0;
}
 .nav-container .menu .menu-item, .nav-container .sub-menu .menu-item, .nav-container .sub-sub-menu .menu-item {
     padding: 12px 0;
}
 .nav-container .menu .menu-item:not(:last-of-type), .nav-container .sub-menu .menu-item:not(:last-of-type), .nav-container .sub-sub-menu .menu-item:not(:last-of-type) {
     border-bottom: 1px solid #9e9e9e;
}
 .nav-container .menu .menu-item .menu-link, .nav-container .sub-menu .menu-item .menu-link, .nav-container .sub-sub-menu .menu-item .menu-link {
     color: #000;
     font-family: sans-serif;
     text-decoration: none;
}
 .nav-container .sub-menu, .nav-container .sub-sub-menu {
     display: none;
}
 .nav-container .sub-menu--active, .nav-container .sub-sub-menu--active {
     display: block;
}
 .nav-container .sub-menu {
     padding-left: 8px;
}
 .nav-container .sub-sub-menu {
     padding-left: 16px;
}
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<nav class="nav-container">
  <ul class="menu main-menu">
    <li class="menu-item menu-level-0">
      <a href="#" class="menu-link">Menu Item 1</a>
    </li>
    <li class="menu-item menu-level-0 menu-has-children">
      <a href="#" class="menu-link">Menu Item 2</a>
      <ul class="sub-menu">
        <li class="menu-item menu-level-1">
          <a href="#" class="menu-link">Submenu Item 1</a>
        </li>
        <li class="menu-item menu-level-1  menu-has-children">
          <a href="#" class="menu-link">Submenu Item 2</a>
          <ul class="sub-sub-menu">
            <li class="menu-item menu-level-2">
              <a href="#" class="menu-link">Sub Submenu Item 1</a>
            </li>
            <li class="menu-item menu-level-2">
              <a href="#" class="menu-link">Sub Submenu Item 2</a>
            </li>
            <li class="menu-item menu-level-2">
              <a href="#" class="menu-link">Sub Submenu Item 3</a>
            </li>
          </ul>
        </li>
        <li class="menu-item menu-level-1">
          <a href="#" class="menu-link">Submenu Item 3</a>
        </li>
        <li class="menu-item menu-level-1">
          <a href="#" class="menu-link">Submenu Item 4</a>
        </li>
      </ul>
    </li>
     <li class="menu-item menu-level-0">
      <a href="#" class="menu-link">Menu Item 3</a>
    </li>
    <li class="menu-item menu-level-0 menu-has-children">
      <a href="#" class="menu-link">Menu Item 4</a>
      <ul class="sub-menu">
        <li class="menu-item menu-level-1">
          <a href="#" class="menu-link">Submenu Item 1</a>
        </li>
        <li class="menu-item menu-level-1  menu-has-children">
          <a href="#" class="menu-link">Submenu Item 2</a>
          <ul class="sub-sub-menu">
            <li class="menu-item menu-level-2">
              <a href="#" class="menu-link">Sub Submenu Item 1</a>
            </li>
            <li class="menu-item menu-level-2">
              <a href="#" class="menu-link">Sub Submenu Item 2</a>
            </li>
            <li class="menu-item menu-level-2">
              <a href="#" class="menu-link">Sub Submenu Item 3</a>
            </li>
          </ul>
        </li>
        <li class="menu-item menu-level-1">
          <a href="#" class="menu-link">Submenu Item 3</a>
        </li>
        <li class="menu-item menu-level-1">
          <a href="#" class="menu-link">Submenu Item 4</a>
        </li>
      </ul>
    </li>
  </ul>
</nav>

How to return both early result and final async result using Promise?

When I make a POST request, the server responds immediately with an id, but the actual result is delivered later via a server push event (e.g., WebSocket or Pusher).

Here’s what I’m trying to do:

When the API responds with the id, I want to immediately notify the user that the push event has started.

Then, I want to wait for the actual result (delivered later through a server-side push) and resolve the promise with that final result.

The challenge is that I can only call resolve() once in a Promise.

So far, I’m using a workaround like this:

function handleAsync(payload, endpoint, callBack) {
  return new Promise((resolve, reject) => {
    // Step 1: POST call and returns id
    callAPI(payload).then((response) => {
      if (response.jobId) {
        callBack(response.id); // notify caller early
        // Wait for server push (via WebSocket or similar) and then resolve
      }
    });

    // Step 2: Push listener will receive final result later and call resolve/reject
    // ...
  });
}

I feel like using a callback just to communicate the id is a bit hacky.
Is there a better pattern to handle this case — maybe returning both values in a more structured way? For example:

return {
  id,
  result: new Promise(...),
};

But then it feels awkward to break the single Promise flow.

Question:

Is there a clean, Promise-based way to return both:

an immediate value (id), and a final result that resolves later (e.g., from a WebSocket or server push)? Or is using a callback the only reasonable way?

Notification count not updating correctly for consultants in PHP + JS notification system

I am building a PHP + JavaScript notification system for my MedConnect web app. Users and consultants have separate dashboards (user_consult.php, consultant_consult.php), each with its own notification dropdown and notification count badge.

Problem:

When a consultation request or other notification is created for a consultant, it is inserted into the notifications table correctly with recipient_role = ‘consultant’ and is_read = 0.

My notification count badge on the consultant side does not update or increment when a new notification is added.

The user side works correctly.

I only want the notification count for consultants to increment for consultant-specific notifications until the dropdown is opened, at which point it should reset.

Database:

notifications table structure:

  • id
  • user_id
  • consultant_id
  • consultation_id
  • type (enum)
  • message
  • recipient_role (enum ‘user’, ‘consultant’)
  • is_read (tinyint(1), default 0)
  • created_at

user_consult.php JS:

function fetchNotifications() {
          fetch('notifications.php?action=fetch')
          .then(response => response.json())
          .then(data => {
              const notificationList = document.getElementById("notification-list");
              notificationList.innerHTML = '';

              if (data.length === 0) {
                  notificationList.innerHTML = '<p style="padding: 12px;">No notifications.</p>';
                  return;
              }

              data.forEach(notification => {
                  const div = document.createElement('div');
                  div.classList.add('notification-item');
                  div.innerHTML = `
                      <p>${notification.message}</p>
                      <small>${new Date(notification.created_at).toLocaleString()}</small>
                  `;
                  notificationList.appendChild(div);
              });
          })
          .catch(err => console.error(err));
      }

      function clearAllNotifications() {
          fetch('notifications.php?action=clear')
              .then(() => {
                  fetchNotifications();      // refresh the notification list
                  fetchNotificationCount();  // refresh the count immediately
              })
              .catch(err => console.error(err));
      }

      function toggleNotifications() {
          const dropdown = document.getElementById('notificationsDropdown');
          dropdown.style.display = (dropdown.style.display === 'block') ? 'none' : 'block';

          if (dropdown.style.display === 'block') {
              fetchNotifications();
              fetch('notifications.php?action=markAllRead')
                  .then(() => fetchNotificationCount()); // refresh count after marking as read
          }
      }

      function fetchNotificationCount() {
          fetch('notifications.php?action=count')
              .then(response => response.json())
              .then(data => {
                  const count = data.count || 0;
                  document.getElementById("notification-count").innerText = count;
              })
              .catch(error => console.error("Error fetching notification count:", error));
      }

      // Initial load
      document.addEventListener("DOMContentLoaded", () => {
          fetchNotifications();
          fetchNotificationCount();
      });

consultant_consult.php JS:

    function clearAllNotifications() {
        fetch('notifications.php?action=clear')
            .then(() => {
                fetchNotifications();      // refresh the notification list
                fetchNotificationCount();  // refresh the count immediately
            })
            .catch(err => console.error(err));
    }

    function toggleNotifications() {
        const dropdown = document.getElementById('notificationsDropdown');
        dropdown.style.display = (dropdown.style.display === 'block') ? 'none' : 'block';

        if (dropdown.style.display === 'block') {
            fetchNotifications();
            fetch('notifications.php?action=markAllRead')
                .then(() => fetchNotificationCount()); // refresh count after marking as read
        }
    }

    function fetchNotificationCount() {
        fetch('notifications.php?action=count')
            .then(response => response.json())
            .then(data => {
                const count = data.count || 0;
                document.getElementById("notification-count").innerText = count;
            })
            .catch(error => console.error("Error fetching notification count:", error));
    }

    // Initial load
    document.addEventListener("DOMContentLoaded", () => {
        fetchNotifications();
        fetchNotificationCount();
    });

    function toggleNotifications() {
        const dropdown = document.getElementById('notificationsDropdown');

        // Toggle Dropdown Visibility
        const isVisible = dropdown.style.display === 'block';
        dropdown.style.display = isVisible ? 'none' : 'block';

        // If opening, fetch notifications & reset unread count
        if (!isVisible) {
            fetch('notifications.php?action=markAllRead')
                .then(() => fetchNotificationCount()); // refresh count

            fetch('consultant_consult.php?fetchConsultations=true')
            .then(response => response.json())
            .then(data => {
                const notificationList = document.getElementById("notification-list");
                notificationList.innerHTML = "";

                if (data.length === 0) {
                    notificationList.innerHTML = '<p style="padding: 12px;">No notifications.</p>';
                    return;
                }

                if (data.error) {
                    notificationList.innerHTML = `<p style="color: red;">${data.error}</p>`;
                    return;
                }

                // Display consultations in the dropdown
                data.forEach(item => {
                    let html = "";
                    if (item.is_notification) {
                        // Render user activity notifications
                        html = `
                            <div class="notification-item">
                                <p>${item.message}</p>
                                <small>${new Date(item.created_at).toLocaleString()}</small>
                            </div>
                        `;
                    } else {
                        // Render pending consultation requests (existing)
                        html = `
                            <div class="notification-item">
                                <p><strong>From:</strong> ${item.user_name}</p>
                                <p><strong>Symptoms:</strong> ${item.symptoms}</p>
                                <p><strong>Date:</strong> ${item.date} | <strong>Time:</strong> ${item.time}</p>
                                ${item.medical_docs ? `<p><a href="${item.medical_docs}" target="_blank">View Medical Documents</a></p>` : ""}
                                <div class="button-group">
                                    <button class="accept-btn" onclick="processConsultation(${item.id}, 'accept')">Accept</button>
                                    <button type='button' class="reject-btn" onclick="openRejectionPopup(${item.id})">Reject</button>
                                </div>
                            </div>
                        `;
                    }
                    notificationList.innerHTML += html;
                });

                // Reset unread count to zero (since the user has now read them)
                unreadNotificationCount = 0;
                document.getElementById("notification-count").innerText = unreadNotificationCount;
            })
            .catch(error => console.error("Error fetching consultations:", error));
        }
    }

    // Allow clicking on overlay to close the dropdown
    document.getElementById('overlay').addEventListener('click', function() {
        document.getElementById('notificationsDropdown').style.display = 'none';
        this.style.display = 'none';
    });

notifications.php (COUNT action):

// COUNT unread notifications
if ($action === 'count') {
    if ($role === 'user') {
        $stmt = $connection->prepare("SELECT COUNT(*) FROM notifications WHERE user_id = ? AND recipient_role = 'user' AND is_read = 0");
    } elseif ($role === 'consultant') {
        $stmt = $connection->prepare("SELECT COUNT(*) FROM notifications WHERE consultant_id = ? AND recipient_role = 'consultant' AND is_read = 0");
    } else {
        echo json_encode(['count' => 0]);
        exit;
    }

    if (!$stmt) {
        echo json_encode(['error' => 'Prepare failed: ' . $connection->error]);
        exit;
    }

    $stmt->bind_param("i", $id);
    $stmt->execute();
    $stmt->bind_result($count);
    $stmt->fetch();
    echo json_encode(['count' => $count]);
    $stmt->close();
    exit;
}

What I’ve tried:
✅ Verified notifications are inserted with recipient_role = ‘consultant’ and is_read = 0.
✅ Checked that manual SQL queries return the correct count.
✅ The fetch call returns { count: 1 } in the console, but the badge sometimes does not update, or resets to 0 unexpectedly.
✅ I’ve removed conflicting intervals.

What I need:
✅ Help identifying why the consultant notification count badge is not updating reliably.
✅ Best practice for clean, reliable updating of the count when a notification is added and resetting it only when the dropdown is opened.

Display Hidden Table Cell on Click of Another Table Cell in HTML and CSS (Advanced Version)

(NOTE: This is a follow-up to my previous question, which can be found here: Display Hidden Table Cell on click of another Table Cell in HTML, CSS, and JavaScript))

Since I last posted my previous question, it seems I didn’t do a good enough job of explaining myself. One person mistakenly thought I was trying to create a Minesweeper clone (I am not), and another person wasn’t sure how exactly I wanted to go about revealing the hidden cells in my table. So I’m here to hopefully try and correct that mistake.
So, here’s my problem and the best explanation I can currently give as to what I’m trying to do…

As stated previously, I’m trying to create an “avoid the mines”-style game.
The objective is to reach the end of a given level (represented by a table with cells) by clicking on the cells in the grid (called “tiles”) in a sequential order.

Clicking on a revealed cell should change the background color of that cell to dark gray, and should also reveal its neighboring cells (the ones that are hidden) by changing their visibility status to “visible”, and changing the color of their borders to white.

Again, this needs to be done in sequential order.

For example, let’s say I have a 5 by 5 table of cells, with each cell having id’s ranging from A1 to E5. And let’s assume that cell “A1” (the starting tile) is already revealed and has been clicked on.

When I click on A1’s neighboring cell with the id “A2”, I want A2 to have its background color changed to dark gray, and I want the cells neighboring A2 (in this case, cells “A3” and “B2”) to have their visibility changed to “visible”, and their border colors to change to white (to show that they have been revealed).

This process should be repeated for all cells that are clicked on by the player that have the “.Tile” and “.TileFinish” classes assigned to them.

To try and help y’all visualize what I’m trying to do, here are some screenshots of the table grid in various states…

Figure 1

This is a shot of the sample table with all relevant cells. Only those with their corresponding classes (“.Tile”, “.TileStart”, etc.) and their corresponding id’s (“A2”, “B3”, etc.) are highlighted.

Figure 2

This is a shot of the grid with all other cells hidden except A1 and A2, the latter of which has been highlighted with a white border. This is an example of a cell that I want to be visible and clickable when the game first loads.

Figure 3

This is a shot of what I want to happen when I click on cell A2. A2 gets its background color changed to dark gray, and its neighboring cell, “B2”, gets revealed and highlighted with a white border.

Again, just like last time, I understand that what I’m asking is rather complicated. If I need to use JavaScript to make this work, then I won’t complain.
But if I can do it without JavaScript, then all the better.

Hope that clears up any ambiguity from my previous question. And I look forward to y’all’s answers.

Also, here’s the HTML and CSS code I already have for this project…

body {
    background-color: black;
}

table {
    border-collapse: collapse;
    position: absolute;
}

td {
    width: 64px;
    height: 64px;
    text-align: center;
    justify-content: center;
}

.TileStart {
    border: 1px solid white;
    color: black;
    background-color: white;
}

.Tile {
    color: white;
    background-color: black;
    cursor: pointer;
    display: none;
}

.TileFinish {
    color: black;
    background-color: white;
    cursor: pointer;
    display: none;
}

#A2, #B2 {
    display: table-cell;
}

#A2 {
    border: 1px solid darkgray;
}

#B2 {
    border: 1px solid white;
}
<!DOCTYPE html>
<html>
<head>
    <title>Hidden Tiles Advanced Test</title>
    <link rel="stylesheet" href="hidden-tiles-advanced-styles.css">
    <meta charset="utf-8">
    <meta name="description" content="Testing advanced use of hidden cells in tables.">
</head>
<body>
    <table>
        <tr>
            <td class="TileStart" id="A1">Start</td>
            <td class="Tile" id="A2" onclick="style='background-color: darkgray; color: border: 1px solid white;'"></td>
            <td id="A3"></td>
            <td id="A4"></td>
            <td id="A5"></td>
        </tr>
        <tr>
            <td id="B1"></td>
            <td class="Tile" id="B2" onclick="style='background-color: darkgray; color: border: 1px solid white;'"></td>
            <td class="Tile" id="B3" onclick="style='background-color: darkgray; color: border: 1px solid white;'"></td>
            <td class="Tile" id="B4" onclick="style='background-color: darkgray; color: border: 1px solid white;'"></td>
            <td id="B5"></td>
        </tr>
        <tr>
            <td id="C1"></td>
            <td class="Tile" id="C2" onclick="style='background-color: darkgray; color: border: 1px solid white;'"></td>
            <td id="C3"></td>
            <td class="Tile" id="C4" onclick="style='background-color: darkgray; color: border: 1px solid white;'"></td>
            <td id="C5"></td>
        </tr>
        <tr>
            <td id="D1"></td>
            <td class="Tile" id="D2" onclick="style='background-color: darkgray; color: border: 1px solid white;'"></td>
            <td class="Tile" id="D3" onclick="style='background-color: darkgray; color: border: 1px solid white;'"></td>
            <td class="Tile" id="D4" onclick="style='background-color: darkgray; color: border: 1px solid white;'"></td>
            <td id="D5"></td>
        </tr>
        <tr>
            <td id="E1"></td>
            <td id="E2"></td>
            <td id="E3"></td>
            <td class="Tile" id="E4" onclick="style='background-color: darkgray; color: border: 1px solid white;'"></td>
            <td class="TileFinish" id="E5"></td>
        </tr>
    </table>
</body>
</html>

Cropper.js image is too small in Vue 3 component

I’m new to Vue and Cropper.js, and I’m working on a project where I let users upload and crop their avatar.

The problem is that the image inside the cropper appears extremely small (sometimes like 10×10 pixels), even though I tried to style it via CSS. No matter what I do, the cropper is tiny and unusable.

I’ve tried different configurations (Setting fixed width and height on both .image-container and the tag), and even on a clean test project the problem remains.

Here’s my base Vue component:

<template>
    <div>
        <div class="image-container">
            <img ref="image" :src="src"/>
        </div>
    </div>
</template>

<script>
    import Cropper from 'cropperjs'
    import '../assets/cropper.css'

    export default {
        name: 'ImageCropper',
        props: {
            src: String
        },

        data() {
            return {
                cropper: {},
                destination: {},
                image: {}
            } 
        },

        mounted() {
            this.image = this.$refs.image;
            this.cropper = new Cropper(this.image, {
                zoomable: false,
                scalable: false,
                aspectRatio: 1
            });
        }
    }

</script>

<style lang="scss" scoped>
    .image-container {
        width: 800px;
        height: 800px;
        position: relative;

        img {
            width: 100%;
            height: 100%;
            object-fit: cover;
            display: block;
        }
    }
</style>

Here’s what it looks like:
sample

Anyone experienced with bug with css’s scale function? [closed]

Context: I have a canvas element on screen for a simple game and I want it to scale with the screen. I calculate the ratio and apply a css scale function through js. When I resize the window, everything works fine. Except if I maximize the window all at once or if I close the developer tools. Then the new size doesn’t apply and I got a tiny display. Even if I wait before applying the scale, it doesn’t work. Both on firefox and chromium the behavior is the same. But eventually I did fix it, by setting width and height instead of using the scale css function. Now, to be fair, this happened on a somewhat old version of firefox, 102, but I was curious if anyone else experienced this or if this was fixed later on.

React App / Google Firebase Auth not working on live domain

I’m having an issue getting my React app to authenticate users on the live site via Google Firebase redirect sign-in method.

I’ve followed the documentation for redirect best practises, and created a custom domain (auth.mydomain.com) to point to my firebaseapp.com url, in which I’ve created a CNAME record in the DNS.

I have the domain (mydomain.com & auth.mydomain.com) listed in Authorised Domains under Firebase Auth.

I’ve also added the domains to Google Cloud’s 0Auth2 Credentials under –

Authorised Javascript Origins:

  • auth.mydomain.com
  • mydomain.com

Authorised Redirect URIs:

  • auth.mydomain.com/__/auth/handler

And finally I’ve updated firebase config to include auth.mydomain.com as the authDomain value.

My problem is that if I test it locally using Firebase Studio preview browser, the redirect works successfully, and the user is signed in. But if I then build for the live server and try it there, there is no user signed in/created when redirected back from the consent screen – It simply logs ‘No result from redirect’.

In my firebase service –

import { initializeApp } from 'firebase/app';

//import { getAuth, initializeAuth, browserLocalPersistence } from 'firebase/auth'; 
import {getAuth, setPersistence, initializeAuth, browserLocalPersistence, browserPopupRedirectResolver, indexedDBLocalPersistence, signInWithRedirect, GoogleAuthProvider, signInWithPopup, getRedirectResult } from "firebase/auth";

const firebaseConfig = {
  apiKey: "XXXX",
  authDomain: "auth.mydomain.com",
  projectId: "userapp-XXXX",
  storageBucket: "userapp-XXXX.firebasestorage.app",
  messagingSenderId: "1234",
  appId: "1234",
  measurementId: "XXXX"
};

// Use a global flag to avoid re-initialization
const app = initializeApp(firebaseConfig);

const auth = initializeAuth(app, {
  persistence: [indexedDBLocalPersistence],
  popupRedirectResolver: browserPopupRedirectResolver
});

export async function loginRedirect() {
  const provider = new GoogleAuthProvider();
  await signInWithRedirect(auth, provider);
}

export async function handleRedirectLogin(setUser){

  await getRedirectResult(auth)
  .then((result) => {
    if(result){
        // This gives you a Google Access Token. You can use it to access Google APIs.
        const credential = GoogleAuthProvider.credentialFromResult(result);
        const token = credential.accessToken;

        // The signed-in user info.
        const user = result.user;
        
        // IdP data available using getAdditionalUserInfo(result)
        console.log('Redirect success', user);
        setUser(user);
        return user;
    } else {
        console.log('No result from redirect', result);
    }
  
  }).catch((error) => {
    // Handle Errors here.
    const errorCode = error.code;
    const errorMessage = error.message;
    // The email of the user's account used.
    const email = error.customData.email;
    // The AuthCredential type that was used.
    const credential = GoogleAuthProvider.credentialFromError(error);
    console.log('Redirect fail', errorMessage);
    throw error;
  });
}

What is the correct syntax for removing blur overlay and div.preview message? [closed]

pls assist to use uBlock Origin correct filter syntax to remove the following from the chrome MaxFocus extension preview window on Windows 11 Chrome 137.0.7151.122.

-div.preview-should-pay message within the preview window (not the preview window itself) from all sites

-blur overlay within the preview window (not the preview window itself) from all sites

So far I was able to use

! Jul 7, 2025 https://cnet.com

cnet.com##div.preview-should-pay

to remove the message but I dont have the correct syntax to remove the background blur and I dont know how to write the filter to automatically apply to all sites once the preview window is invoked.

I have tried the uBO zapper and picker but it doesnt specifically get only the background blur, it will only remove the entire ##preview-frame-ui.

Also Behind the Overlay wont work within the preview window. Using “cntrl shift c” I can see the syntax for the background blur but I need more guidance to make a good filter.

I actually got it to work on my first try somehow using uBO when I first installed MaxFocus so I know it’s possible. I uninstalled MaxFocus then reinstalled to ensure I could replicate the procedure on another computer but I haven’t been able to do it again.

Any assistance you can provide would be greatly appreciated.

Thanks

Overlay blur and text to be removed

better-sqlite3 – compiled against a different Node.js – Electron.js [duplicate]

So basically when I build the electron app from my development pc and install the .exe from dist folder it works fine but as soon as I try to install on other pc I get this error on every single one of them

Hasan Here Exam Portalresourcesappnode_modulesbetter-sqlite3buildReleasebetter_sqlite3.node'
was compiled against a different Node.js version using
NODE_MODULE_VERSION 135. This version of Node.js requires
NODE_MODULE_VERSION 115. Please try re-compiling or re-installing
the module (for instance, using npm rebuild or npm install).

I tried npm rebuild like it says in the error message but that only works for my development pc but not any other pc. Anyone has any solution to this?

Note: I am using next.js as fullstack and sqlLite as database for this project.

update json file with HTML script [closed]

I can update JSON file (“room.json”) with PHP with the following function,
How can I update this JSON file via HTML script?
My goal is to update the JSON file via script; The JSON file (‘room.json’) is in the same folder as index.html; The JSON file (‘room.json’) will move with index.html anyway

how can I run it via a script?

Regards..

  editJsonRoom(2,"Deposit",222);

function editJsonRoom(int $id, string $title, $value) {
    
    $file ="room.json";
    $db = getJsonData($file);

    foreach($db["rooms"] as &$room) {
        if ($room["id"] == $id) {

            $room[$title] = $value;

            $myfile = fopen($file,"w");
            fwrite($myfile, json_encode($db, JSON_PRETTY_PRINT));
            fclose($myfile);

            break;
        }
    }
}

better-sqlite3 – compiled against a different Node.js – Electron.js

So basically when I build the electron app from my development pc and install the .exe from dist folder it works fine but as soon as I try to install on other pc I get this error on every single one of them

Hasan Here Exam Portalresourcesappnode_modulesbetter-sqlite3buildReleasebetter_sqlite3.node'
was compiled against a different Node.js version using
NODE_MODULE_VERSION 135. This version of Node.js requires
NODE_MODULE_VERSION 115. Please try re-compiling or re-installing
the module (for instance, using npm rebuild or npm install).

I tried npm rebuild like it says in the error message but that only works for my development pc but not any other pc. Anyone has any solution to this?

Note: I am using next.js as fullstack and sqlLite as database for this project.