feat(dashboard): GuruConnect v2 Support Codes view
Some checks failed
Build and Test / Build Server (Linux) (push) Failing after 3m27s
Build and Test / Build Agent (Windows) (push) Successful in 7m11s
Build and Test / Security Audit (push) Successful in 4m32s
Build and Test / Build Summary (push) Has been skipped

Generate, list, and cancel attended-support codes (XXX-XXX-XXX), built
on the v2 codes API and existing UI primitives.

- Codes table: code in mono, status badge (pending+pulse/connected/
  completed/cancelled), bound client/machine, created-by, created
  (relative + absolute tooltip). Sticky header, skeleton load,
  actionable empty/error states.
- Generate opens a focused reveal modal showing the code large in
  JetBrains Mono with copy and a read-aloud instruction; the code is
  announced character-by-character for screen readers. Mint is ref-
  guarded so it creates exactly one code per open (no StrictMode dupe).
- Cancel via confirm dialog (POST /api/codes/:code/cancel), disabled for
  non-cancellable statuses; invalidates the codes query. List polls 7s.
- Shared API client now tolerates non-JSON 200 bodies, so the cancel
  endpoint's plain-text "Code cancelled" success no longer surfaces as a
  failure. Error-envelope handling unchanged.

Passed Code Review (no blockers after fixes) and local gates
(tsc/lint/build green).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 13:59:18 -07:00
parent 67f3722b3c
commit 664f33d5ab
14 changed files with 750 additions and 8 deletions

View File

@@ -46,3 +46,43 @@ export function consentLabel(state: string): string {
return state;
}
}
/**
* Map a support-code lifecycle status to a tone. `pending` is the live,
* waiting-to-be-redeemed state and gets the same `warn` pulse the
* awaiting-consent state uses — it reads as "active, watch this". A redeemed
* (`connected`) code is a positive terminal-for-the-tech outcome -> `ok`.
* `completed`/`cancelled` are spent and read as muted `neutral`.
*/
export function codeTone(status: string): StatusTone {
switch (status) {
case "pending":
return "warn";
case "connected":
return "ok";
case "completed":
case "cancelled":
default:
return "neutral";
}
}
/**
* Human label for a support-code status. Next to `codeTone` so wording and
* color never drift. `pending` is phrased as the active wait (the tech is
* watching for the end user to redeem it).
*/
export function codeLabel(status: string): string {
switch (status) {
case "pending":
return "Awaiting redeem";
case "connected":
return "Redeemed";
case "completed":
return "Completed";
case "cancelled":
return "Cancelled";
default:
return status;
}
}