From d38b9745a4e2ac772b55fa3de0de90bdf4090d48 Mon Sep 17 00:00:00 2001 From: OpenAI Codex Date: Tue, 5 May 2026 00:53:43 -0700 Subject: [PATCH] feat(web): wire settings feedback submission --- docs/AGENTIC_AI_ROADMAP.md | 8 ++--- web/src/app/settings/page.tsx | 59 ++++++++++++++++++++++++++--------- web/src/lib/feedback.ts | 2 +- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/docs/AGENTIC_AI_ROADMAP.md b/docs/AGENTIC_AI_ROADMAP.md index 55da2ec..617a728 100644 --- a/docs/AGENTIC_AI_ROADMAP.md +++ b/docs/AGENTIC_AI_ROADMAP.md @@ -17,7 +17,7 @@ | TODO | Priority | Phase | File(s) | Summary | |------|----------|-------|---------|---------| | **TODO-001** | medium | 0 | `web/src/app/providers.tsx` | Kill switch maintenance banner — create ``, set React state when `checkKillSwitch()` returns `disabled=true`, disable timer creation buttons | -| **TODO-002** | medium | 0 | `web/src/app/(app)/settings/page.tsx` (create) | Wire feedback button into settings page (or floating FAB) using `feedbackClient` from `web/src/lib/feedback.ts` | +| ✅ **TODO-002** | medium | 0 | `web/src/app/settings/page.tsx` | ~~Wire feedback button into settings page using `feedbackClient`~~ — settings feedback form submits through `@bytelyst/feedback-client`; verification blocked locally by missing `GITEA_NPM_TOKEN` for private `@bytelyst/*` install (df670d9) | | **TODO-003** | medium | 0 | `web/src/components/CreateTimerModal.tsx`, `web/src/components/AlarmOverlay.tsx` | Apply `@bytelyst/accessibility` focus trap + screen reader announcements. Ensure `--cm-*` color tokens meet WCAG AA contrast | | ✅ **TODO-004** | medium | A.1 | `backend/src/modules/routines/routes.ts` | ~~Clone template~~ — templates now cloned via `crypto.randomUUID()`, original stays reusable (0e7c1ae) | | ✅ **TODO-005** | high | A.4 | `backend/src/lib/ai-context.ts` | ~~Wire LLM~~ — dual-path: extraction-service → Ollama `/api/generate` (5s timeout, feature-gated) (229ce4f) | @@ -64,7 +64,7 @@ | `@bytelyst/design-tokens` | ✅ Used | `--cm-*` CSS props in globals.css | | `@bytelyst/ui` | ✅ Used | Imported in providers.tsx | | `@bytelyst/kill-switch-client` | ❌ **MISSING** | Every other product has this — critical for prod safety | -| `@bytelyst/feedback-client` | ❌ **MISSING** | No in-app feedback mechanism | +| `@bytelyst/feedback-client` | ✅ Used | Settings feedback form submits via shared SDK | | `@bytelyst/event-store` | ❌ **MISSING** | Domain events not persisted — needed for webhooks + audit | | `@bytelyst/webhook-dispatch` | ❌ **MISSING** | Backend uses hand-rolled dispatcher instead of shared package | | `@bytelyst/accessibility` | ❌ **MISSING** | Shared accessibility helpers not consumed | @@ -124,7 +124,7 @@ These proxy to `chronomind-backend` (port 4011) via `chronomind-client.ts`. - [x] `web/src/lib/feedback.ts` — integrate `@bytelyst/feedback-client` (commit: f3e14e2) - `createFeedbackClient({ baseUrl, productId, getAccessToken })` -- [ ] Add feedback button to settings page (or floating FAB) (commit: ) +- [x] Add feedback button to settings page (or floating FAB) (commit: df670d9; status: implemented, verification blocked locally because `pnpm install` requires `GITEA_NPM_TOKEN` for private `@bytelyst/*` packages) - TODO-002: Wire feedback button into settings page using `feedbackClient` from `web/src/lib/feedback.ts` ### 0.3 — Accessibility Package (Web) @@ -642,7 +642,7 @@ Systematic audit against `learning_ai_common_plat/packages/` (58 packages) revea | Gap | Severity | Fixed In | |-----|----------|----------| | No `@bytelyst/kill-switch-client` | **Critical** | Phase 0.1 | -| No `@bytelyst/feedback-client` | Medium | Phase 0.2 | +| No settings feedback entry point using `@bytelyst/feedback-client` | Medium | Phase 0.2 — complete (df670d9) | | No `@bytelyst/accessibility` helpers | Medium | Phase 0.3 | | No feature flags for new features | **Critical** | Phase 0.4 | | No telemetry events for new features | Medium | Phase 0.5 | diff --git a/web/src/app/settings/page.tsx b/web/src/app/settings/page.tsx index 1a52f98..8803b9b 100644 --- a/web/src/app/settings/page.tsx +++ b/web/src/app/settings/page.tsx @@ -38,6 +38,7 @@ export default function SettingsPage() { const [feedbackText, setFeedbackText] = useState(''); const [feedbackSubmitting, setFeedbackSubmitting] = useState(false); const [feedbackSuccess, setFeedbackSuccess] = useState(false); + const [feedbackError, setFeedbackError] = useState(''); useEffect(() => { setMounted(true); @@ -106,6 +107,38 @@ export default function SettingsPage() { .forEach((t) => removeTimer(t.id)); }; + const handleFeedbackSubmit = async () => { + const body = feedbackText.trim(); + if (!body) return; + + setFeedbackSubmitting(true); + setFeedbackError(''); + try { + await feedbackClient.submitWithScreenshot({ + type: feedbackType, + title: body.slice(0, 100), + body, + screen: 'settings', + appVersion: '0.1.0', + platform: 'web', + deviceContext: { + osVersion: navigator.userAgent, + appVersion: '0.1.0', + deviceModel: navigator.platform || 'web', + screenResolution: `${window.screen.width}x${window.screen.height}`, + locale: navigator.language, + }, + }); + setFeedbackSuccess(true); + setFeedbackText(''); + setTimeout(() => setFeedbackSuccess(false), 4000); + } catch { + setFeedbackError('Feedback could not be sent right now. Please try again in a moment.'); + } finally { + setFeedbackSubmitting(false); + } + }; + return (
@@ -526,8 +559,12 @@ export default function SettingsPage() { ))}