Skip to content

Commit 7b058db

Browse files
UI nuance fixes — error handling, stale localStorage, misleading copy
- pricing.html: POST /billing/create-order error path no longer paints a raw response body; only a safe body.message or a generic string. Razorpay payment.failed description bounded to 140 chars before surfacing. Outer catch shows a friendly-only string. - pricing.html: footnote "Cancel anytime from the dashboard" replaced with a mailto link — there is no cancel endpoint today, so the old copy was a false promise. - terms.html: same — cancellation goes through admin@instanode.dev. - dashboard.html: migrate() catches network errors so a dropped claim doesn't nuke the whole dashboard boot. localStorage.instanode_token is cleared after any claim attempt (success or fail) so a later visitor on a shared device doesn't try to re-claim someone else's token. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 397e460 commit 7b058db

3 files changed

Lines changed: 43 additions & 8 deletions

File tree

dashboard.html

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,11 @@ <h2 id="apikey-heading">API token for CLI / agent</h2>
509509
.then(function (res) {
510510
if (res.status === 401) { goStart(); return false; }
511511
return res.ok;
512-
});
512+
})
513+
// Network failure here must not blow away the dashboard. The
514+
// outer boot .catch() would render a full-page error otherwise;
515+
// we just return false so the caller shows a toast.
516+
.catch(function () { return false; });
513517
}
514518

515519
document.getElementById('logoutBtn').addEventListener('click', function () {
@@ -561,6 +565,10 @@ <h2 id="apikey-heading">API token for CLI / agent</h2>
561565
}
562566
var next = Promise.resolve();
563567
if (claimToken) next = migrate(claimToken).then(function (ok) {
568+
// Clear the token either way — stale localStorage would otherwise
569+
// cause the next visitor on a shared device to try to re-claim
570+
// somebody else's resource.
571+
try { localStorage.removeItem('instanode_token'); } catch (e) {}
564572
toast(ok ? 'Resource claimed to your account.' : 'Could not claim resource.', ok ? '' : 'err');
565573
});
566574
next.then(loadResources);

pricing.html

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ <h1>Upgrade to Developer</h1>
268268
</div>
269269

270270
<p class="footnote">
271-
Secure checkout by Razorpay. Cancel anytime from the <a href="/dashboard">dashboard</a>.
271+
Secure checkout by Razorpay. Questions? Email <a href="mailto:admin@instanode.dev">admin@instanode.dev</a>.
272272
</p>
273273

274274
<footer class="site">
@@ -352,8 +352,18 @@ <h1>Upgrade to Developer</h1>
352352
return null;
353353
}
354354
if (!res.ok) {
355-
return res.text().then(function (t) {
356-
throw new Error(t && t.length < 200 ? t : ('HTTP ' + res.status));
355+
// Parse JSON body for a safe `message` from our own API; never
356+
// surface raw text() (could be an HTML error page from a
357+
// reverse proxy, or contain internal detail from an upstream).
358+
return res.json().then(function (body) {
359+
var safe = body && typeof body.message === 'string' ? body.message : '';
360+
var e = new Error(safe || 'Checkout could not be started. Please try again in a moment.');
361+
e.friendly = true;
362+
throw e;
363+
}, function () {
364+
var e = new Error('Checkout could not be started. Please try again in a moment.');
365+
e.friendly = true;
366+
throw e;
357367
});
358368
}
359369
return res.json();
@@ -389,15 +399,32 @@ <h1>Upgrade to Developer</h1>
389399
rzp.on('payment.failed', function (resp) {
390400
btn.disabled = false;
391401
btn.textContent = resetLabel;
392-
var reason = (resp && resp.error && (resp.error.description || resp.error.reason)) || 'Payment failed.';
393-
showMsg(planID, 'error', reason + ' Please try again.');
402+
// Razorpay's resp.error.description is gateway-controlled text.
403+
// Only surface it when it's a short, human-ish string; otherwise
404+
// fall back to a generic message so we never paint long SDK
405+
// stack traces or vendor error codes into the UI.
406+
var raw = resp && resp.error && (resp.error.description || resp.error.reason);
407+
var safe = '';
408+
if (typeof raw === 'string' && raw.length > 0 && raw.length <= 140) {
409+
safe = raw;
410+
}
411+
showMsg(planID, 'error', safe
412+
? (safe + ' Please try again.')
413+
: 'Payment failed. Please try a different card or retry in a moment.');
394414
});
395415
rzp.open();
396416
})
397417
.catch(function (err) {
398418
btn.disabled = false;
399419
btn.textContent = resetLabel;
400-
showMsg(planID, 'error', 'Could not start checkout: ' + (err && err.message ? err.message : 'unknown error'));
420+
// err.friendly === true means the message came from our own API
421+
// via a safe `message` field. Anything else (network failure,
422+
// browser block) we render as a generic retry prompt so we
423+
// never paint stack traces or CORS strings at the user.
424+
var text = (err && err.friendly && err.message)
425+
? err.message
426+
: 'Could not reach the checkout service. Please check your connection and retry.';
427+
showMsg(planID, 'error', text);
401428
});
402429
}
403430

terms.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ <h2>Developer tier — $12/month or $120/year</h2>
118118
<ul>
119119
<li>Billed in advance via Razorpay. Monthly plan renews each month. Annual plan renews once a year and is discounted to $120 (equivalent to $10/month).</li>
120120
<li>Resources persist until you delete them or cancel.</li>
121-
<li>Cancel anytime from the dashboard. Cancellation stops the next renewal; the current billing period remains active.</li>
121+
<li>Cancel anytime by emailing <a href="mailto:admin@instanode.dev">admin@instanode.dev</a>. Cancellation stops the next renewal; the current billing period remains active.</li>
122122
<li>Higher quotas — see <a href="/pricing.html">pricing</a> for exact limits.</li>
123123
</ul>
124124

0 commit comments

Comments
 (0)