Customer chat screen:
- Voice-call header pill (mode == 'call' renders accent-colored pill;
chat mode renders no pill).
- HaloSnackbar fires once per session at 180s remaining ('sisa 3 menit
lagi ya 🤍'), driven by the backend session_warning WS event.
- Last-2-min danger styling: timer pill flips to HaloTokens.danger +
bold JetBrainsMono when remaining <= 120s.
- Floating ChatExpiredBanner widget injected above the input bar when
remaining hits 0 in closing-grace state. perpanjang -> existing
pricing bottom sheet.
- pricing_bottom_sheet.dart rewritten to the 5-option layout with
chat|call mode toggle (mirrors duration-pick from Stage 3).
Mitra chat screen: voice-call header pill only (no countdown UX per PRD).
Backend:
- session.service.js getSessionById JOINs payment_sessions so mode +
expires_at ship in /api/shared/chat/:id/info.
- session-timer.service.js onThreeMinuteWarning now emits expires_at +
remaining_seconds for client resync.
- Dev-only POST /internal/_test/force-session-expires-at clears the
3-min flag, reschedules the timer, and broadcasts WS resync. Lets
the Maestro flow drive 175s -> 90s -> 0s without waiting live.
New chatRemainingSeconds StreamProvider derived from expiresAt, fed by
session_warning / session_timer / session_expired resync messages
(plan referenced a secondsLeftProvider that didn't actually exist).
Maestro 06_chat_countdown.yaml + force_session_expires_at.js helper.
Out of scope: meet.google.com URL launching - url_launcher isn't a
client_app dependency and message bubbles render plain Text. Defer.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
22 lines
1.1 KiB
JavaScript
22 lines
1.1 KiB
JavaScript
// Force-set the expires_at of the most-recent ACTIVE chat_session by hitting
|
|
// the dev-only /internal/_test/force-session-expires-at endpoint. Used by the
|
|
// Stage 6 maestro flow (06_chat_countdown.yaml) to drive the 3-min snackbar,
|
|
// last-2-min danger pill, and expired banner without waiting in real time.
|
|
//
|
|
// Reads BACKEND_INTERNAL_URL + SECONDS_FROM_NOW from env (Maestro injects them
|
|
// from the flow). The backend re-runs startSessionTimer with the new schedule
|
|
// AND clears the per-session "3-min warning fired" flag so the warning fires
|
|
// again on the new schedule.
|
|
const url = BACKEND_INTERNAL_URL || 'http://localhost:3001'
|
|
const seconds = parseInt(SECONDS_FROM_NOW || '175', 10)
|
|
const resp = http.post(`${url}/internal/_test/force-session-expires-at`, {
|
|
body: JSON.stringify({ latest: true, seconds_from_now: seconds }),
|
|
headers: { 'Content-Type': 'application/json' },
|
|
})
|
|
if (resp.status !== 200) {
|
|
throw new Error(`force-session-expires-at failed (${resp.status}): ${resp.body}`)
|
|
}
|
|
const data = json(resp.body)
|
|
output.SESSION_ID = data.session_id
|
|
output.EXPIRES_AT = data.expires_at
|