taskflow/frontend
kiro-frontend 75ee6ce3d8 Fix QA blockers: rebuild the frontend TypeScript layer
The committed .ts/.tsx files were written through a shell heredoc that stripped
every quote character, so types.ts, App.tsx, api.ts, TaskList.tsx, TaskRow.tsx,
TaskCard.tsx and AppShell.tsx were not valid TypeScript. Nothing surfaced this
because index.js imported ./App, which resolved to the Create React App template
App.js ahead of App.tsx, and typescript was never added as a dependency, so the
broken files were never compiled. The preview was showing the CRA starter page.

Rewritten and transferred as a binary archive rather than through a shell, with
tsc and the test suite as the check that the files actually parse.

Priority 1 (blocking)
- TaskForm.tsx implemented: title, description, assignee, status, due date and
  priority, validated with react-hook-form and actionable messages.
- App.tsx is now a real container wired to the service layer, replacing the
  hardcoded mock markup. Filtering by My Tasks / All Tasks / Blocked is driven
  by the signed-in user instead of a hardcoded id.
- Edit, delete and inline status changes work from both the table and the cards.

Priority 2
- Accessibility: skip link, ARIA tablist with arrow keys, table roles, dialog
  with focus trap and restore, aria-invalid and aria-describedby on fields,
  polite live region, 44px targets. Contrast corrected to meet AA: buttons use
  #2563eb and accent text #1d4ed8, since the mockup #3b82f6 reaches only 3.7:1
  behind white text.
- Error handling: ErrorBoundary, load failure with retry, per-filter empty
  states, blocked guidance, and save failures that keep the dialog and the
  user's input on screen.
- 17 integration tests replace the CRA placeholder test.

Removed the dead CRA template files (App.js, index.js, logo.svg,
reportWebVitals.js, App_temp.css) and added tsconfig.json plus typescript.

Verified in devbox 306: tsc --noEmit clean, 17/17 tests pass, CI build compiles
with no lint warnings. Screenshots of all six states are in frontend/preview/.
2026-09-05 14:38:38 +00:00
..
preview Fix QA blockers: rebuild the frontend TypeScript layer 2026-09-05 14:38:38 +00:00
public Frontend-initial-implementation 2026-09-05 13:04:52 +00:00
src Fix QA blockers: rebuild the frontend TypeScript layer 2026-09-05 14:38:38 +00:00
.gitignore Frontend-initial-implementation 2026-09-05 13:04:52 +00:00
package-lock.json Fix QA blockers: rebuild the frontend TypeScript layer 2026-09-05 14:38:38 +00:00
package.json Fix QA blockers: rebuild the frontend TypeScript layer 2026-09-05 14:38:38 +00:00
README.md Fix QA blockers: rebuild the frontend TypeScript layer 2026-09-05 14:38:38 +00:00
tsconfig.json Fix QA blockers: rebuild the frontend TypeScript layer 2026-09-05 14:38:38 +00:00

TaskFlow frontend

React 19 + TypeScript single-page app built with Create React App, implementing the approved mockups in architect/01-mockups/ and the contract in architect/03-feasibility/frontend-handoff.md.

Commands

Run these from frontend/:

Command What it does
npm install Install dependencies
npm start Dev server with hot reload (HOST=0.0.0.0 PORT=5173 to expose it)
npm run build Production build into build/
npm test Jest + React Testing Library, watch mode
npm run test:ci Single non-interactive test run
npm run typecheck tsc --noEmit

CI=true npm run build treats lint warnings as errors, which is how the build is verified before hand-off.

Layout

src/
├── App.tsx                     container: data loading, filtering, save/delete
├── App.css                     reset, design tokens, shared primitives
├── types.ts                    Task/User types and the labels used in the UI
├── services/api.ts             REST client (currently an in-memory stand-in)
└── components/
    ├── common/
    │   ├── AppShell.tsx        header, team sidebar, main region
    │   ├── TaskFields.tsx      avatar, priority, status control, due date
    │   └── ErrorBoundary.tsx   render-crash recovery screen
    ├── TaskList/
    │   ├── TaskList.tsx        filter tabs, empty states, blocked guidance
    │   ├── TaskRow.tsx         desktop table row
    │   └── TaskCard.tsx        mobile card
    └── TaskForm/TaskForm.tsx   create/edit dialog with validation

Backend contract

src/services/api.ts is the only file that talks to the server. It is an in-memory stand-in whose method names and payloads match the documented endpoints, so the Backend phase can replace the method bodies with fetch or axios calls without touching a component:

Method Endpoint
getCurrentUser() GET /api/auth/me
getUsers() GET /api/users
getTasks() GET /api/tasks
createTask(draft) POST /api/tasks
updateTask(id, changes) PUT /api/tasks/:id
deleteTask(id) DELETE /api/tasks/:id

Draft validation lives in validateDraft inside that module as well as in the form, because the server is the real trust boundary and the same rules have to hold there.

States covered

Screenshots of each are in preview/.

  • Loading — spinner with role="status" while the first fetch runs.
  • Load failure — role="alert" with the reason and a Try again button.
  • Empty — distinct copy for no tasks at all, nothing assigned to you, and nothing blocked, so an active filter is never mistaken for an empty account.
  • Blocked — explanatory notice above the list, per the blocked-state mockup.
  • Validation — per-field messages tied to inputs with aria-describedby.
  • Save failure — the dialog stays open with the user's input intact.

Accessibility

Targeting WCAG 2.1 AA.

  • Skip link to the task list; single visible focus style via :focus-visible.
  • Filter tabs are an ARIA tablist with arrow-key navigation and counts in the accessible name.
  • The task table exposes table/rowgroup/row/columnheader/cell roles.
  • The dialog is role="dialog" aria-modal="true", focuses the title field on open, traps Tab, closes on Escape, and returns focus to whatever opened it.
  • Errors use role="alert" and aria-invalid; confirmations go to a polite live region.
  • Interactive targets are at least 44px.
  • Contrast: the mockup accent #3b82f6 only reaches 3.7:1 behind white text, so filled buttons use #2563eb (5.2:1) and accent text #1d4ed8 (6.4:1). Amber status text was darkened to #92400e for the same reason.

Still to do by hand, since they cannot be automated here: screen reader passes (NVDA/VoiceOver), 200% browser zoom, and cross-browser checks on Firefox, Safari and Edge. Note that @axe-core/react is listed as a dependency but is not wired up: version 4 relies on ReactDOM.findDOMNode, which React 19 removed.

Responsive behaviour

One breakpoint at 768px. The desktop table and the mobile cards are both rendered and CSS picks one, so the hidden view is also removed from the accessibility tree and no task is announced twice. Below 768px the team sidebar is hidden and Create Task becomes a floating action button.