TenantAtlas/public/js/tenantpilot/livewire-intercept-shim.js
ahmido 9f5c99317b Fix Review Pack generation UX + notifications (#133)
## Summary
- Fixes misleading “queued / running in background” message when Review Pack generation request reuses an existing ready pack (fingerprint dedupe).
- Improves resilience of Filament/Livewire interactions by ensuring the Livewire intercept shim applies after Livewire initializes.
- Aligns Review Pack operation notifications with Ops-UX patterns (queued + completed notifications) and removes the old ReviewPackStatusNotification.

## Key Changes
- Review Pack generate action now:
  - Shows queued toast only when a new pack is actually created/queued.
  - Shows a “Review pack already available” success notification with a link when dedupe returns an existing pack.

## Tests
- `vendor/bin/sail artisan test --compact tests/Feature/ReviewPack/ReviewPackGenerationTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/ReviewPack/ReviewPackResourceTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/LivewireInterceptShimTest.php`

## Notes
- No global search behavior changes for ReviewPacks (still excluded).
- Destructive actions remain confirmation-gated (`->requiresConfirmation()`).

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #133
2026-02-23 19:42:52 +00:00

99 lines
3.0 KiB
JavaScript

(() => {
// TenantPilot shim: ensure Livewire interceptMessage callbacks run in a safe order.
// This prevents Filament's notifications asset (and others) from calling an undefined
// animation callback when onSuccess fires before onFinish.
if (typeof window === 'undefined') {
return;
}
const applyShim = () => {
const Livewire = window.Livewire;
if (!Livewire || typeof Livewire.interceptMessage !== 'function') {
return false;
}
if (Livewire.__tenantpilotInterceptMessageShimApplied) {
return true;
}
const original = Livewire.interceptMessage.bind(Livewire);
Livewire.interceptMessage = (handler) => {
if (typeof handler !== 'function') {
return original(handler);
}
return original((context) => {
if (!context || typeof context !== 'object') {
return handler(context);
}
const originalOnFinish = context.onFinish;
const originalOnSuccess = context.onSuccess;
if (typeof originalOnFinish !== 'function' || typeof originalOnSuccess !== 'function') {
return handler(context);
}
const finishCallbacks = [];
const onFinish = (callback) => {
if (typeof callback === 'function') {
finishCallbacks.push(callback);
}
return originalOnFinish(callback);
};
const onSuccess = (callback) => {
return originalOnSuccess((...args) => {
// Ensure any registered finish callbacks are run before success callbacks.
// We don't swallow errors; we just stabilize ordering.
for (const finishCallback of finishCallbacks) {
finishCallback(...args);
}
if (typeof callback === 'function') {
return callback(...args);
}
});
};
return handler({
...context,
onFinish,
onSuccess,
});
});
};
Livewire.__tenantpilotInterceptMessageShimApplied = true;
return true;
};
if (applyShim()) {
return;
}
// Livewire may not be initialized yet when this script runs (depending on
// script tag order). Try again on `livewire:init` and with a short fallback poll.
const onInit = () => {
applyShim();
};
window.addEventListener('livewire:init', onInit, { once: true });
document.addEventListener('livewire:init', onInit, { once: true });
let tries = 0;
const maxTries = 50;
const timer = setInterval(() => {
tries += 1;
if (applyShim() || tries >= maxTries) {
clearInterval(timer);
}
}, 100);
})();