diff --git a/.Jules/changelog.md b/.Jules/changelog.md index fd3f3c5..7788cc4 100644 --- a/.Jules/changelog.md +++ b/.Jules/changelog.md @@ -11,6 +11,7 @@ - Dashboard skeleton loading state (`DashboardSkeleton`) to improve perceived performance during data fetch. - Comprehensive `EmptyState` component for Groups and Friends pages to better guide new users. - Toast notification system (`ToastContext`, `Toast` component) for providing non-blocking user feedback. +- Keyboard navigation support for Groups page, enabling accessibility for power users. ### Planned - See `todo.md` for queued tasks @@ -39,36 +40,3 @@ - `.jules/todo.md` - `.jules/knowledge.md` - `.jules/changelog.md` - ---- - - diff --git a/.Jules/knowledge.md b/.Jules/knowledge.md index 606cb38..5949d67 100644 --- a/.Jules/knowledge.md +++ b/.Jules/knowledge.md @@ -38,6 +38,7 @@ mobile/ ├── context/ # AuthContext ├── api/ # API client and service functions └── utils/ # Helpers (currency, balance calculations) +``` --- @@ -103,6 +104,34 @@ colors: { ``` +### Clickable Cards & Accessibility + +**Date:** 2026-01-01 +**Context:** Making `motion.div` or non-button elements accessible + +When making a div clickable (like a card), you must ensure it's accessible: +1. **Role**: Add `role="button"`. +2. **TabIndex**: Add `tabIndex={0}` so it's focusable. +3. **Keyboard Handler**: Add `onKeyDown` to handle 'Enter' and 'Space'. +4. **Label**: Add `aria-label` to describe the action. +5. **Focus Styles**: Add visible focus styles (e.g., `focus:ring`). + +```tsx + { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + handleClick(); + } + }} + className="... focus:outline-none focus:ring-4 focus:ring-blue-500" +> +``` + ### Card Component with Title/Action **Date:** 2026-01-01 @@ -251,6 +280,20 @@ interface BalanceSummary { --- +## Testing & Verification + +### Playwright Verification Patterns +**Date:** 2026-01-01 +**Context:** Verifying accessibility changes with Playwright scripts + +When writing Playwright scripts to verify frontend changes without backend: + +1. **Auth Mocking:** You must mock `/users/me` persistently. If this call fails or returns 401, `AuthContext` will force a redirect to login, breaking navigation tests. +2. **Route Matching:** Use specific route patterns (e.g., `**/users/me`) and ensure they don't accidentally swallow longer paths (like `**/users/me/balance-summary`) if using wildcards carelessly. Register specific paths before general ones if using `page.route` order dependence, or use specific globs. +3. **Response Structure:** Mocks must match the structure expected by `axios` interceptors and components. If `axios` returns `res.data` as the body, and the component expects `res.data.groups`, the mock body should be `{"groups": [...]}` (not `{"data": {"groups": ...}}`). + +--- + ## Known Issues & Gotchas ### Image URL Validation diff --git a/.Jules/todo.md b/.Jules/todo.md index 310000d..894e27f 100644 --- a/.Jules/todo.md +++ b/.Jules/todo.md @@ -20,19 +20,19 @@ - Files modified: `web/contexts/ToastContext.tsx`, `web/components/ui/Toast.tsx`, `web/App.tsx`, `web/pages/Auth.tsx` - Impact: Modern feedback system that supports both themes -- [ ] **[a11y]** Complete keyboard navigation for Groups page +- [x] **[a11y]** Complete keyboard navigation for Groups page + - Completed: 2026-01-01 - File: `web/pages/Groups.tsx` - Context: Add keyboard handling to group cards + search + modals - Impact: Full keyboard accessibility for power users - Size: ~50 lines - - Added: 2026-01-01 - [x] **[ux]** Comprehensive empty states with illustrations + - Completed: 2026-01-01 - Files: `web/pages/Groups.tsx`, `web/pages/Friends.tsx` - Context: Create illustrated empty states with CTAs (not just text) - Impact: Guides new users, makes app feel polished - Size: ~70 lines - - Added: 2026-01-01 - [ ] **[ux]** Error boundary with retry for API failures - Files: Create `web/components/ErrorBoundary.tsx`, wrap app @@ -146,8 +146,12 @@ - Files modified: `web/components/ui/EmptyState.tsx`, `web/pages/Groups.tsx`, `web/pages/Friends.tsx` - Impact: Users now see a polished, illustrated empty state with clear CTAs when they have no groups or friends, instead of plain text. +- [x] **[a11y]** Complete keyboard navigation for Groups page + - Completed: 2026-01-12 + - File: `web/pages/Groups.tsx` + - Impact: Users can now navigate groups, join/create buttons, and search using only the keyboard with proper focus indicators. - [x] **[ux]** Form validation with inline feedback - - Completed: 2026-01-01 + - Completed: 2026-01-11 - Files modified: `web/pages/Auth.tsx` - Impact: Users know immediately if input is valid via inline error messages and red borders. diff --git a/web/pages/Groups.tsx b/web/pages/Groups.tsx index fb93a52..9073ad0 100644 --- a/web/pages/Groups.tsx +++ b/web/pages/Groups.tsx @@ -134,6 +134,7 @@ export const Groups = () => { setSearchTerm(e.target.value)} @@ -164,16 +165,17 @@ export const Groups = () => { const balanceAmount = groupBalance?.amount || 0; return ( - navigate(`/groups/${group._id}`)} - className={`group cursor-pointer transition-all duration-300 relative overflow-hidden flex flex-col h-full + aria-label={`View details for group ${group.name}`} + className={`group cursor-pointer transition-all duration-300 relative overflow-hidden flex flex-col h-full w-full text-left focus:outline-none focus:ring-4 focus:ring-blue-500/50 ${isNeo - ? `bg-white border-2 border-black shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] hover:shadow-[6px_6px_0px_0px_rgba(0,0,0,1)] rounded-none` + ? `bg-white border-2 border-black shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] hover:shadow-[6px_6px_0px_0px_rgba(0,0,0,1)] rounded-none focus:shadow-[6px_6px_0px_0px_rgba(0,0,0,1)]` : `rounded-3xl border shadow-lg backdrop-blur-md ${mode === 'dark' ? 'border-white/20 bg-white/5 hover:bg-white/10' : 'border-black/5 bg-white/60 hover:bg-white/80'}`} `} > @@ -206,7 +208,7 @@ export const Groups = () => { - + ); }) )}