123 lines
6.2 KiB
Markdown
123 lines
6.2 KiB
Markdown
# Tasks: HP Status Indicators
|
|
|
|
**Input**: Design documents from `/specs/013-hp-status-indicators/`
|
|
**Prerequisites**: plan.md, spec.md, research.md, data-model.md, quickstart.md
|
|
|
|
**Tests**: Included -- domain function requires unit tests per project convention.
|
|
|
|
**Organization**: Tasks grouped by user story. US1 and US2 share the same domain function (foundational), then diverge at the UI layer.
|
|
|
|
## Format: `[ID] [P?] [Story] Description`
|
|
|
|
- **[P]**: Can run in parallel (different files, no dependencies)
|
|
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
|
|
- Include exact file paths in descriptions
|
|
|
|
---
|
|
|
|
## Phase 1: Foundational (Domain Function + Tests)
|
|
|
|
**Purpose**: Create the pure domain function that all user stories depend on
|
|
|
|
**CRITICAL**: No UI work can begin until this phase is complete
|
|
|
|
- [x] T001 Create `HpStatus` type and `deriveHpStatus` pure function in `packages/domain/src/hp-status.ts` -- returns `"healthy" | "bloodied" | "unconscious" | undefined` based on `currentHp` and `maxHp` inputs. Check `currentHp <= 0` first (unconscious), then `currentHp < maxHp / 2` (bloodied), else healthy. Return `undefined` when either input is `undefined`.
|
|
- [x] T002 Write unit tests for `deriveHpStatus` in `packages/domain/src/__tests__/hp-status.test.ts` covering: healthy (currentHp >= maxHp/2), bloodied (0 < currentHp < maxHp/2), unconscious (currentHp <= 0), unconscious with negative HP, undefined when maxHp undefined, undefined when currentHp undefined, undefined when both undefined, edge case maxHp=1 (no bloodied state possible), edge case maxHp=2 (1/2 is healthy not bloodied), odd maxHp=21 (10 is bloodied since 10 < 10.5), currentHp exceeding maxHp (healthy).
|
|
- [x] T003 Export `deriveHpStatus` and `HpStatus` type from `packages/domain/src/index.ts` -- add `export { type HpStatus, deriveHpStatus } from "./hp-status.js";`
|
|
|
|
**Checkpoint**: `pnpm check` passes. Domain function is tested and exported.
|
|
|
|
---
|
|
|
|
## Phase 2: User Story 1 - Bloodied Indicator (Priority: P1) + User Story 2 - Unconscious/Dead Indicator (Priority: P1)
|
|
|
|
**Goal**: Apply visual status indicators to the combatant row -- amber HP text for bloodied, red HP text + muted row for unconscious/dead
|
|
|
|
**Independent Test**: Set a combatant's max HP, reduce current HP below half -- verify amber text. Reduce to 0 -- verify red text and muted row. Heal above half -- verify normal appearance restored.
|
|
|
|
### Implementation
|
|
|
|
- [x] T004 [US1] [US2] Modify `apps/web/src/components/combatant-row.tsx` to import `deriveHpStatus` from `@initiative/domain` and call it with the combatant's `currentHp` and `maxHp` at the top of the `CombatantRow` component. Store result in a `status` variable.
|
|
- [x] T005 [US1] [US2] In `apps/web/src/components/combatant-row.tsx`, apply conditional CSS classes based on `status`: (1) On the `CurrentHpInput` wrapper/value -- add `text-amber-400` when bloodied, `text-red-400` when unconscious. (2) On the row's outer `<div>` -- add `opacity-50` when unconscious. Ensure the active-turn border styling still takes precedence for active combatants. Use the existing `cn()` utility for conditional class merging.
|
|
|
|
**Checkpoint**: `pnpm check` passes. Bloodied and unconscious indicators are visible in the UI.
|
|
|
|
---
|
|
|
|
## Phase 3: User Story 3 - Status Transitions (Priority: P2)
|
|
|
|
**Goal**: Ensure visual indicators update in real time as HP changes through quick HP input, direct entry, and +/- controls
|
|
|
|
**Independent Test**: Use the quick HP input to deal damage across thresholds (healthy -> bloodied -> unconscious) and heal back. Verify indicator changes instantly with no flicker or delay.
|
|
|
|
### Implementation
|
|
|
|
- [x] T006 [US3] Verify in `apps/web/src/components/combatant-row.tsx` that `deriveHpStatus` is called with the current combatant props (not stale state) so status updates in the same render cycle as HP changes. No additional code should be needed if T004-T005 are implemented correctly -- this task is a manual verification and visual QA pass.
|
|
|
|
**Checkpoint**: All transitions (healthy->bloodied->unconscious->healthy) work smoothly.
|
|
|
|
---
|
|
|
|
## Phase 4: Polish & Cross-Cutting Concerns
|
|
|
|
- [x] T007 Run `pnpm check` to validate all automated checks pass (knip, format, lint, typecheck, test)
|
|
- [x] T008 Verify layer boundary test still passes (domain must not import from React/UI) in `packages/domain/src/__tests__/layer-boundaries.test.ts`
|
|
|
|
---
|
|
|
|
## Dependencies & Execution Order
|
|
|
|
### Phase Dependencies
|
|
|
|
- **Foundational (Phase 1)**: No dependencies -- can start immediately
|
|
- **US1+US2 (Phase 2)**: Depends on Phase 1 completion (needs domain function)
|
|
- **US3 (Phase 3)**: Depends on Phase 2 completion (needs UI indicators in place)
|
|
- **Polish (Phase 4)**: Depends on all phases complete
|
|
|
|
### Within Phases
|
|
|
|
- T001 before T002 (need function to test it)
|
|
- T002 before T003 (tests pass before exporting)
|
|
- T004 before T005 (import before styling)
|
|
|
|
### Parallel Opportunities
|
|
|
|
- T001 and T002 can be done together if writing tests alongside implementation (TDD)
|
|
- US1 and US2 are implemented together in Phase 2 since they modify the same file and component
|
|
|
|
---
|
|
|
|
## Parallel Example: Phase 1
|
|
|
|
```bash
|
|
# T001 and T002 can be written together (TDD style):
|
|
Task: "Create deriveHpStatus in packages/domain/src/hp-status.ts"
|
|
Task: "Write tests in packages/domain/src/__tests__/hp-status.test.ts"
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation Strategy
|
|
|
|
### MVP First (Phase 1 + Phase 2)
|
|
|
|
1. Complete Phase 1: Domain function + tests + export
|
|
2. Complete Phase 2: UI styling for both bloodied and unconscious
|
|
3. **STOP and VALIDATE**: Manually test all scenarios from spec
|
|
4. Run `pnpm check`
|
|
|
|
### Full Delivery
|
|
|
|
1. Phase 1: Domain function (T001-T003)
|
|
2. Phase 2: UI indicators (T004-T005)
|
|
3. Phase 3: Transition verification (T006)
|
|
4. Phase 4: Final validation (T007-T008)
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- US1 (bloodied) and US2 (unconscious) are combined into Phase 2 because they modify the same component and the domain function handles both statuses. Implementing them separately would require touching the same lines twice.
|
|
- T006 is a verification task, not a code change -- if the React component re-renders on prop changes (which it does by default), transitions work automatically.
|
|
- Total: 8 tasks across 4 phases. Minimal scope -- no new application layer, no storage changes.
|