Files
timmy-tower/the-matrix/js/session.js

563 lines
19 KiB
JavaScript
Raw Normal View History

Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
/**
* session.js Workshop Session Mode UI (Fund once, ask many)
*
* Flow:
* 1. User clicks "⚡ FUND SESSION" left panel slides in
* 2. Picks amount (2005000 sats) POST /api/sessions deposit invoice
* 3. Pays invoice (stub: "Simulate Payment") 2 s polling until state=active
* 4. Macaroon + sessionId stored in localStorage; input bar activates (green border)
* 5. Every Enter/Send in the input bar POST /api/sessions/:id/request
* 6. Timmy's response shown in speech bubble, balance ticks down in HUD
* 7. Balance < 50 sats low-balance notice; Top Up button reopens panel topup step
* 8. On page reload: localStorage is read, session is validated, UI restored
*/
import { setSpeechBubble, setMood } from './agents.js';
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
import { appendSystemMessage, setSessionSendHandler, setInputBarSessionMode } from './ui.js';
import { getOrRefreshToken } from './nostr-identity.js';
import { sentiment } from './edge-worker-client.js';
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
const API = '/api';
const LS_KEY = 'timmy_session_v1';
const POLL_MS = 2000;
const POLL_TIMEOUT = 60_000;
const MIN_BALANCE = 50;
// ── Module state ──────────────────────────────────────────────────────────────
let _panel = null;
let _sessionId = null;
let _macaroon = null;
let _balanceSats = 0;
let _sessionState = null; // null | 'awaiting_payment' | 'active' | 'paused' | 'expired'
let _pollTimer = null;
let _inFlight = false;
let _selectedSats = 500; // deposit amount selection
let _topupSats = 500; // topup amount selection
// ── Public API ────────────────────────────────────────────────────────────────
export function initSessionPanel() {
_panel = document.getElementById('session-panel');
if (!_panel) return;
// Buttons
_on('open-session-btn', 'click', _openPanel);
_on('session-close', 'click', _closePanel);
_on('session-create-btn', 'click', _createSession);
_on('session-pay-btn', 'click', _payDeposit);
_on('session-topup-btn', 'click', () => _setStep('topup'));
_on('session-topup-create-btn','click', _createTopup);
_on('session-topup-pay-btn', 'click', _payTopup);
_on('session-back-btn', 'click', () => _setStep('active'));
_on('topup-quick-btn', 'click', () => { _openPanel(); _setStep('topup'); });
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
_on('session-hud-topup', 'click', (e) => { e.preventDefault(); _openPanel(); _setStep('topup'); });
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
// Amount preset buttons — deposit (quick-fill the number input)
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
_panel.querySelectorAll('[data-session-step="fund"] .session-amount-btn').forEach(btn => {
btn.addEventListener('click', () => {
_panel.querySelectorAll('[data-session-step="fund"] .session-amount-btn')
.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
_selectedSats = parseInt(btn.dataset.sats, 10);
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
const inp = document.getElementById('session-amount-input');
if (inp) inp.value = _selectedSats;
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
});
});
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
// Free-text number input — deposit
document.getElementById('session-amount-input')?.addEventListener('input', () => {
const v = parseInt(document.getElementById('session-amount-input').value, 10);
if (Number.isFinite(v)) {
_selectedSats = v;
_panel.querySelectorAll('[data-session-step="fund"] .session-amount-btn')
.forEach(b => b.classList.toggle('active', parseInt(b.dataset.sats, 10) === v));
}
});
// Amount preset buttons — topup (quick-fill the topup number input)
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
_panel.querySelectorAll('[data-session-step="topup"] .session-amount-btn').forEach(btn => {
btn.addEventListener('click', () => {
_panel.querySelectorAll('[data-session-step="topup"] .session-amount-btn')
.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
_topupSats = parseInt(btn.dataset.sats, 10);
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
const inp = document.getElementById('session-topup-input');
if (inp) inp.value = _topupSats;
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
});
});
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
// Free-text number input — topup
document.getElementById('session-topup-input')?.addEventListener('input', () => {
const v = parseInt(document.getElementById('session-topup-input').value, 10);
if (Number.isFinite(v)) {
_topupSats = v;
_panel.querySelectorAll('[data-session-step="topup"] .session-amount-btn')
.forEach(b => b.classList.toggle('active', parseInt(b.dataset.sats, 10) === v));
}
});
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
// Try to restore from localStorage on init
_tryRestore();
}
export function isSessionActive() {
return _sessionState === 'active' || _sessionState === 'paused';
}
// Called by ui.js when user submits the input bar while session is active
export async function sessionSendHandler(text) {
if (!_sessionId || !_macaroon || _inFlight) return;
_inFlight = true;
_setSendBusy(true);
appendSystemMessage(`you: ${text}`);
// Attach Nostr token if available
const nostrToken = await getOrRefreshToken('/api');
const reqHeaders = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${_macaroon}`,
};
if (nostrToken) reqHeaders['X-Nostr-Token'] = nostrToken;
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
try {
const res = await fetch(`${API}/sessions/${_sessionId}/request`, {
method: 'POST',
headers: reqHeaders,
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
body: JSON.stringify({ request: text }),
});
const data = await res.json();
if (res.status === 402) {
_balanceSats = data.balance ?? 0;
_sessionState = 'paused';
_saveToStorage();
_applySessionUI();
setSpeechBubble('My energy is depleted... top me up to continue!');
appendSystemMessage('⚡ Low balance — tap Top Up');
return;
}
if (res.status === 401) {
// Macaroon rejected — stale session, clear and reset
_clearSession();
appendSystemMessage('Session expired — fund a new one.');
return;
}
if (!res.ok) {
appendSystemMessage('Session error: ' + (data.error || res.status));
return;
}
_balanceSats = data.balanceRemaining ?? 0;
_sessionState = _balanceSats < MIN_BALANCE ? 'paused' : 'active';
_saveToStorage();
_applySessionUI();
const reply = data.result || data.reason || '…';
setSpeechBubble(reply);
appendSystemMessage('Timmy: ' + reply.slice(0, 80));
// Sentiment-driven mood on inbound Timmy reply
sentiment(reply).then(s => {
setMood(s.label);
setTimeout(() => setMood(null), 10_000);
}).catch(() => {});
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
// Update active-step balance if panel is open
_updateActiveStep();
} catch (err) {
appendSystemMessage('Session error: ' + err.message);
} finally {
_inFlight = false;
_setSendBusy(false);
}
}
// ── Panel open/close ──────────────────────────────────────────────────────────
function _openPanel() {
if (!_panel) return;
_panel.classList.add('open');
_clearError();
if (_sessionState === 'active') {
_setStep('active');
_updateActiveStep();
} else if (_sessionState === 'paused') {
_setStep('topup');
} else {
_setStep('fund');
}
}
function _closePanel() {
_panel?.classList.remove('open');
_stopPolling();
}
// ── Create session ────────────────────────────────────────────────────────────
async function _createSession() {
_clearError();
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
// Read from the number input (may differ from the last preset clicked)
const inp = document.getElementById('session-amount-input');
if (inp) {
const v = parseInt(inp.value, 10);
if (Number.isFinite(v)) _selectedSats = v;
}
if (_selectedSats < 200 || _selectedSats > 10_000) {
_setError('Amount must be 20010,000 sats.');
return;
}
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
_setStatus('fund', 'creating session…', '#ffaa00');
_btn('session-create-btn', true);
try {
const nostrToken = await getOrRefreshToken('/api');
const createHeaders = { 'Content-Type': 'application/json' };
if (nostrToken) createHeaders['X-Nostr-Token'] = nostrToken;
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
const res = await fetch(`${API}/sessions`, {
method: 'POST',
headers: createHeaders,
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
body: JSON.stringify({ amount_sats: _selectedSats }),
});
const data = await res.json();
if (!res.ok) { _setError(data.error || 'Failed to create session.'); return; }
_sessionId = data.sessionId;
// Show deposit invoice
const inv = data.invoice;
_el('session-invoice-amount').textContent = inv.amountSats + ' sats';
_el('session-invoice-pr').textContent = inv.paymentRequest || '';
const hashEl = _el('session-invoice-hash');
if (hashEl) hashEl.dataset.hash = inv.paymentHash || '';
_setStep('invoice');
_setStatus('invoice', '⚡ Awaiting deposit…', '#ffaa00');
} catch (err) {
_setError('Network error: ' + err.message);
} finally {
_btn('session-create-btn', false);
}
}
// ── Pay deposit (stub) ────────────────────────────────────────────────────────
async function _payDeposit() {
const hash = _el('session-invoice-hash')?.dataset.hash;
if (!hash) { _setError('No payment hash — use real Lightning?'); return; }
_btn('session-pay-btn', true);
_setStatus('invoice', 'Simulating payment…', '#ffaa00');
try {
const res = await fetch(`${API}/dev/stub/pay/${hash}`, { method: 'POST' });
const ok = (await res.json()).ok;
if (!ok) { _setError('Payment simulation failed.'); return; }
_startDepositPolling();
} catch (err) {
_setError('Payment error: ' + err.message);
} finally {
_btn('session-pay-btn', false);
}
}
// ── Deposit polling ───────────────────────────────────────────────────────────
function _startDepositPolling() {
_stopPolling();
const deadline = Date.now() + POLL_TIMEOUT;
async function poll() {
if (!_sessionId) return;
try {
const res = await fetch(`${API}/sessions/${_sessionId}`);
const data = await res.json();
if (data.state === 'active') {
_macaroon = data.macaroon;
_balanceSats = data.balanceSats;
_sessionState = 'active';
_saveToStorage();
_applySessionUI();
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
_closePanel(); // panel auto-closes; user types in input bar
appendSystemMessage(`Session active — ${_balanceSats} sats`);
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
return;
}
} catch { /* network hiccup */ }
if (Date.now() > deadline) {
_setError('Timed out waiting for payment.');
return;
}
_pollTimer = setTimeout(poll, POLL_MS);
}
_pollTimer = setTimeout(poll, POLL_MS);
}
// ── Topup ─────────────────────────────────────────────────────────────────────
async function _createTopup() {
if (!_sessionId || !_macaroon) return;
_clearError();
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
// Read from the topup number input
const inp = document.getElementById('session-topup-input');
if (inp) {
const v = parseInt(inp.value, 10);
if (Number.isFinite(v)) _topupSats = v;
}
if (_topupSats < 200 || _topupSats > 10_000) {
_setError('Topup amount must be 20010,000 sats.');
return;
}
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
_setStatus('topup', 'creating topup invoice…', '#ffaa00');
_btn('session-topup-create-btn', true);
try {
const res = await fetch(`${API}/sessions/${_sessionId}/topup`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${_macaroon}`,
},
body: JSON.stringify({ amount_sats: _topupSats }),
});
const data = await res.json();
if (!res.ok) {
// Pending topup already exists — surface it
const pending = data.pendingTopup;
if (pending) {
_el('session-topup-pr').textContent = pending.paymentRequest || '';
const th = _el('session-topup-hash');
if (th) th.dataset.hash = pending.paymentHash || '';
_el('session-topup-pr-row').style.display = '';
_setStatus('topup', '⚡ Previous invoice still pending', '#ffaa00');
return;
}
_setError(data.error || 'Failed to create topup.');
return;
}
const inv = data.topup;
_el('session-topup-pr').textContent = inv.paymentRequest || '';
const th = _el('session-topup-hash');
if (th) th.dataset.hash = inv.paymentHash || '';
_el('session-topup-pr-row').style.display = '';
_setStatus('topup', '⚡ Awaiting topup payment…', '#ffaa00');
} catch (err) {
_setError('Topup error: ' + err.message);
} finally {
_btn('session-topup-create-btn', false);
}
}
async function _payTopup() {
const hash = _el('session-topup-hash')?.dataset.hash;
if (!hash) { _setError('No topup hash.'); return; }
_btn('session-topup-pay-btn', true);
_setStatus('topup', 'Simulating topup payment…', '#ffaa00');
try {
const res = await fetch(`${API}/dev/stub/pay/${hash}`, { method: 'POST' });
const ok = (await res.json()).ok;
if (!ok) { _setError('Topup simulation failed.'); return; }
_startTopupPolling();
} catch (err) {
_setError('Topup payment error: ' + err.message);
} finally {
_btn('session-topup-pay-btn', false);
}
}
function _startTopupPolling() {
_stopPolling();
const deadline = Date.now() + POLL_TIMEOUT;
const prevBalance = _balanceSats;
async function poll() {
if (!_sessionId) return;
try {
const res = await fetch(`${API}/sessions/${_sessionId}`);
const data = await res.json();
if (data.balanceSats > prevBalance || data.state === 'active') {
_balanceSats = data.balanceSats;
_macaroon = data.macaroon || _macaroon;
_sessionState = data.state === 'active' ? 'active' : _sessionState;
_saveToStorage();
_applySessionUI();
_setStep('active');
_updateActiveStep();
_setStatus('active', `⚡ Topped up! ${_balanceSats} sats`, '#22aa66');
return;
}
} catch { /* ignore */ }
if (Date.now() > deadline) { _setError('Topup timed out.'); return; }
_pollTimer = setTimeout(poll, POLL_MS);
}
_pollTimer = setTimeout(poll, POLL_MS);
}
// ── Restore from localStorage ─────────────────────────────────────────────────
async function _tryRestore() {
try {
const raw = localStorage.getItem(LS_KEY);
if (!raw) return;
const { sessionId, macaroon, balanceSats } = JSON.parse(raw);
if (!sessionId || !macaroon) return;
// Validate the session is still live
const res = await fetch(`${API}/sessions/${sessionId}`);
if (!res.ok) { localStorage.removeItem(LS_KEY); return; }
const data = await res.json();
if (data.state !== 'active' && data.state !== 'paused') {
localStorage.removeItem(LS_KEY);
return;
}
_sessionId = sessionId;
_macaroon = data.macaroon || macaroon;
_balanceSats = data.balanceSats ?? balanceSats;
_sessionState = data.state;
_saveToStorage();
_applySessionUI();
appendSystemMessage(`Session restored (${_balanceSats} sats)`);
} catch {
// Ignore restore errors silently
}
}
// ── Session UI helpers ────────────────────────────────────────────────────────
function _applySessionUI() {
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
const anyActive = isSessionActive(); // true for both 'active' and 'paused'
const canSend = _sessionState === 'active';
// Show low-balance overlay whenever session exists but balance is too low
const lowBal = anyActive && _balanceSats < MIN_BALANCE;
// HUD balance: "Balance: X sats ⚡ Top Up"
const $hud = document.getElementById('session-hud');
if ($hud) {
$hud.style.display = anyActive ? '' : 'none';
const $span = document.getElementById('session-hud-balance');
if ($span) $span.textContent = `Balance: ${_balanceSats} sats`;
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
}
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
// Top button label
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
const $btn = document.getElementById('open-session-btn');
if ($btn) {
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
$btn.textContent = anyActive
? `SESSION: ${_balanceSats}`
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
: '⚡ FUND SESSION';
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
$btn.style.background = anyActive ? '#1a4a30' : '';
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
}
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
// Input bar green border + placeholder when session can send
setInputBarSessionMode(canSend, 'Ask Timmy (session active)…');
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
// Route input bar to session handler only when active (not paused)
setSessionSendHandler(canSend ? sessionSendHandler : null);
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
// Low balance notice above input bar
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
const $notice = document.getElementById('low-balance-notice');
if ($notice) $notice.style.display = lowBal ? '' : 'none';
}
function _updateActiveStep() {
const el = document.getElementById('session-active-amount');
if (el) {
el.textContent = _balanceSats + ' sats';
el.style.color = _balanceSats < MIN_BALANCE ? '#ff8844' : '#44dd88';
}
// Reset topup pr row visibility
const prRow = document.getElementById('session-topup-pr-row');
if (prRow) prRow.style.display = 'none';
}
function _clearSession() {
_sessionId = null;
_macaroon = null;
_balanceSats = 0;
_sessionState = null;
localStorage.removeItem(LS_KEY);
setInputBarSessionMode(false);
setSessionSendHandler(null);
Task #23: Workshop session mode UI — fund once, ask many (all review issues fixed) ## Changes ### the-matrix/js/session.js (new module) - Full session lifecycle: create → invoice → deposit poll → active → request → topup → restore - Presets + number input for deposit (200–10,000 sats) and topup amounts; reads from input on submit - Input validation: 200–10,000 sats range enforced in JS before API call - Auto-closes panel after deposit payment confirms (closePanel in _startDepositPolling success branch) - Low-balance condition fixed: `isSessionActive()` (covers both 'active' and 'paused') not just `active` - HUD: updates `#session-hud-balance` span with "Balance: X sats"; `#session-hud-topup` link clickable - Topup reads from `#session-topup-input` number field, same validation - localStorage restore: validates session via GET, restores macaroon + balance + UI state on reload - Expired/401 sessions: clears storage, resets all UI - Request in-flight guard prevents double-submit; send button disabled during request ### the-matrix/js/ui.js - `setSessionSendHandler(fn)` — override input bar submit when session active - `setInputBarSessionMode(active, placeholder)` — green border + placeholder swap - `send()` routes to session handler when set, falls back to WS visitor_message ### the-matrix/index.html - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` with `#session-hud-balance` span + `#session-hud-topup` link (pointer-events: all) - `#session-panel` (left slide-in): fund / invoice / active / topup steps - Fund + topup steps each have preset buttons AND a number input (200–10k range) - Added 10k preset button to both step grids - `#visitor-input.session-active` green pulse border animation (3s keyframe) - `#low-balance-notice` strip above input bar with inline Top Up button - CSS: `.session-amount-input` green styled, spin buttons hidden; `.session-amount-row` flex layout - CSS: `.primary-green` / `.muted` panel button variants for session panel theme ### the-matrix/js/main.js - Import + call `initSessionPanel()` in firstInit block ## Verification - npm run build: clean (0 errors, 15 modules) - Testkit: 27/27 PASS (session tests 11–16, 22 all green)
2026-03-19 03:56:34 +00:00
const $hud = document.getElementById('session-hud');
if ($hud) $hud.style.display = 'none';
Task #23: Workshop session mode UI — fund once, ask many ## What was done - **`the-matrix/js/session.js`** (new module): Full session mode UI lifecycle: - Create session flow: amount presets → POST /api/sessions → deposit invoice step - Deposit payment: stub simulate → 2s polling until state=active - macaroon + sessionId stored in localStorage (`timmy_session_v1`) - Request submission: intercepts input bar when session active → POST /api/sessions/:id/request → Timmy speech bubble shows result, balance updates in HUD - Low-balance (< 50 sats): paused state, low-balance notice shown, topup quick-button - Topup flow: preset amount → POST /api/sessions/:id/topup → topup invoice → stub pay → poll - Restore from localStorage on page reload: validates session via GET, restores full UI state - Session expiry / 401 macaroon rejection: clears storage, resets to unfunded state - **`the-matrix/js/ui.js`**: Added `setSessionSendHandler(fn)` + `setInputBarSessionMode(active, placeholder)` exports; send() routes to session handler when active, falls back to WS visitor_message - **`the-matrix/index.html`**: - `#top-buttons` flex container: "⚡ SUBMIT JOB" (blue) + "⚡ FUND SESSION" (teal) side-by-side - `#session-hud` balance line in HUD (green, hidden until session active) - `#session-panel` left-side slide-in panel: fund / invoice / active / topup steps - `.session-amount-btn` presets (200, 500, 1000, 2000, 5000 sats) with active state - `#visitor-input.session-active` CSS: green border + 3s pulse keyframe animation - `#low-balance-notice` strip above input bar with Top Up quick-button - `.primary-green` / `.muted` panel button variants for session panel theme - `#session-panel` inherits shared `.panel-btn`, `.invoice-box`, `.copy-btn` with green overrides - **`the-matrix/js/main.js`**: Import + call `initSessionPanel()` in firstInit block ## Verification - `npm run build` in the-matrix → clean build (0 errors) - Full testkit: 27/27 PASS (all session tests 11–16, 22 still green)
2026-03-19 03:50:34 +00:00
const $btn = document.getElementById('open-session-btn');
if ($btn) { $btn.textContent = '⚡ FUND SESSION'; $btn.style.background = ''; }
const $notice = document.getElementById('low-balance-notice');
if ($notice) $notice.style.display = 'none';
}
function _saveToStorage() {
try {
localStorage.setItem(LS_KEY, JSON.stringify({
sessionId: _sessionId,
macaroon: _macaroon,
balanceSats: _balanceSats,
}));
} catch { /* storage unavailable */ }
}
// ── DOM helpers ───────────────────────────────────────────────────────────────
function _el(id) { return document.getElementById(id); }
function _on(id, ev, fn) {
_el(id)?.addEventListener(ev, fn);
}
function _btn(id, disabled) {
const el = _el(id);
if (el) el.disabled = disabled;
}
function _setSendBusy(busy) {
const btn = document.getElementById('send-btn');
if (btn) btn.disabled = busy;
}
function _setStep(step) {
if (!_panel) return;
_panel.querySelectorAll('[data-session-step]').forEach(el => {
el.style.display = el.dataset.sessionStep === step ? '' : 'none';
});
}
function _setStatus(step, msg, color = '#22aa66') {
const el = document.getElementById(`session-status-${step}`);
if (el) { el.textContent = msg; el.style.color = color; }
}
function _setError(msg) {
const el = _el('session-error');
if (el) el.textContent = msg;
}
function _clearError() {
const el = _el('session-error');
if (el) el.textContent = '';
}
function _stopPolling() {
clearTimeout(_pollTimer);
_pollTimer = null;
}