[IMP] website_sale_aplicoop: signal frontend to reload on deploy

When we ship a JS-only fix, users with a long-lived tab keep running
the old code until they hard-refresh — there is no clean way to push
new code to an already-loaded page. Now /eskaera/check-status returns
the module's installed_version as client_version, and the eskaera
page embeds the same version in data-build-version on the cart
container. The JS captures the page's build version at init; on every
check-status response it compares them and triggers window.location.
reload() on mismatch. A sessionStorage timestamp guards against
reload loops if the versions stay disagreeing (cached HTML upstream).

The version bump in __manifest__.py also invalidates the asset bundle
URL hash, so even users without this signalling path get fresh JS on
their next navigation.

This is forward-looking: clients on the old JS (no check) still need
one manual refresh today, but every future deploy will auto-recover.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
GitHub Copilot 2026-06-06 15:31:37 +02:00
parent bd8d87060f
commit 6e6d1e5256
4 changed files with 71 additions and 2 deletions

View file

@ -45,6 +45,13 @@
console.log("Initializing cart for order:", this.orderId);
// Capture the build version embedded in the rendered HTML. The
// server returns its installed version in /eskaera/check-status,
// and if the two disagree we know a deploy happened and the
// current page is running stale JS — force a one-shot reload.
this._buildVersion = orderIdElement.getAttribute("data-build-version") || null;
console.log("[groupOrderShop] Build version:", this._buildVersion);
// Attach event listeners FIRST (doesn't depend on translations)
this._attachEventListeners();
console.log("[groupOrderShop] Event listeners attached");
@ -513,6 +520,35 @@
console.log("[groupOrderShop] Cart cleared silently for order:", this.orderId);
},
// Avoid a reload loop if for any reason (HTML cached upstream, etc.)
// the build versions keep disagreeing after a reload.
_shouldReloadForNewBuild: function () {
try {
var raw = sessionStorage.getItem("eskaera_build_reload_at");
if (!raw) {
return true;
}
var last = parseInt(raw, 10);
if (isNaN(last)) {
return true;
}
// If we already reloaded in the last 30s, don't try again.
return Date.now() - last > 30000;
} catch (e) {
return true;
}
},
_markReloadAttempt: function () {
try {
sessionStorage.setItem("eskaera_build_reload_at", String(Date.now()));
} catch (e) {
// sessionStorage unavailable — fail open; worst case we get a
// single extra reload, never a loop because the next render
// will carry the new version.
}
},
_isClosedOrderResponse: function (xhr) {
if (!xhr) {
return false;
@ -555,6 +591,27 @@
}
try {
var data = JSON.parse(xhr.responseText || "{}");
// Deploy-detection: server tells us the installed module
// version; if it differs from the version embedded in
// the HTML, we are running stale JS — reload once.
if (
data &&
data.client_version &&
self._buildVersion &&
data.client_version !== self._buildVersion &&
self._shouldReloadForNewBuild()
) {
console.warn(
"[groupOrderShop] Build mismatch (page=" +
self._buildVersion +
", server=" +
data.client_version +
"), reloading"
);
self._markReloadAttempt();
window.location.reload();
return;
}
// Capture current cycle marker so _loadCart can evict a
// localStorage cart that belongs to a previous cycle.
self._currentCutoffDate = data && data.cutoff_date ? data.cutoff_date : null;