refactor(theme): share apiSend/apiErrorMsg between post-form and trip-publish
Address the P1 maintainability finding that trip-publish.js reimplemented post-form.js's apiSend + login-expired error copy verbatim. Extract both into js/src/api-utils.js and import from both entry points; esbuild inlines the module into each bundle so there is no runtime coupling. Also drops the stale data-trip-route reference from trip-publish.js's markup-contract comment. Rebuilt js/trip-publish.js and js/post/post-form.js. Verified: trip-publish suite 8/8; post suite unchanged (34 pass, same 6 owner-gate environmental fails as baseline — photo-editor specs that exercise post-form's apiSend/apiErrorMsg all green). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
This commit is contained in:
@@ -11,11 +11,13 @@
|
||||
* (no reload); on failure re-enable and surface a VISIBLE page-level toast.
|
||||
*
|
||||
* Markup contract (data-* on button.trip-publish-toggle):
|
||||
* data-trip-slug, data-trip-route, data-published ("true"|"false"),
|
||||
* data-trip-slug, data-published ("true"|"false"),
|
||||
* data-active ("true" when this is site.active_trip); aria-checked mirrors
|
||||
* data-published. The sibling .trip-draft-badge is shown iff not published.
|
||||
*/
|
||||
|
||||
import { apiSend, apiErrorMsg } from './api-utils.js';
|
||||
|
||||
var TOAST_TIMEOUT_MS = 5000;
|
||||
var toastTimer = null;
|
||||
|
||||
@@ -62,26 +64,6 @@ function hideToast() {
|
||||
if (toastTimer) { clearTimeout(toastTimer); toastTimer = null; }
|
||||
}
|
||||
|
||||
// A 401/403 almost always means the login session lapsed — say so; anything else
|
||||
// is a generic retry (mirrors post-form.js editErrorMsg copy).
|
||||
function errorMessage(status) {
|
||||
return (status === 401 || status === 403)
|
||||
? 'Your login session expired — sign in again, then retry.'
|
||||
: "Couldn't update — try again.";
|
||||
}
|
||||
|
||||
// Mutation fetch that resolves on success and rejects with a status-bearing Error
|
||||
// otherwise (modelled on post-form.js apiSend), so the caller can tell an expired
|
||||
// login apart from a generic failure. Cookies auto-included.
|
||||
function apiSend(url, opts) {
|
||||
return fetch(url, Object.assign({ credentials: 'include' }, opts)).then(function (r) {
|
||||
if (r.ok) return r; // 204 is within r.ok
|
||||
var e = new Error('HTTP ' + r.status);
|
||||
e.status = r.status;
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
function setPublishedUI(btn, published) {
|
||||
btn.setAttribute('aria-checked', published ? 'true' : 'false');
|
||||
btn.setAttribute('data-published', published ? 'true' : 'false');
|
||||
@@ -128,7 +110,7 @@ function onToggle(btn) {
|
||||
}).catch(function (err) {
|
||||
// Failure: the UI never flipped, so revert is just re-enable (R15).
|
||||
setPending(btn, false);
|
||||
showToast(errorMessage(err && err.status));
|
||||
showToast(apiErrorMsg(err, "Couldn't update — try again."));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user