Skip to content

[Mobile] Board and list views with filters - #23

Merged
wak327 merged 2 commits into
mobile-register-invitesfrom
mobile-board
Sep 11, 2026
Merged

wak327 merged 2 commits into
mobile-register-invitesfrom
mobile-board

Conversation

@wak327

@wak327 wak327 commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Closes #5.

Stacked on #22 → #21 → #20. Review in that order; this PR's diff is only the board work.

What changed

Columns come from the team's own statuses, so nothing is hardcoded — a team that renames "Cancelled" to "Won't do" still gets it collapsed by default, because the rule is by category, not by name.

Filters live in the route's query params, not component state — the same choice the web makes, using the same short keys. That is what makes the board someone is looking at a link they can send, and it means a board URL copied out of the web app narrows this one identically.

Per-column point totals come from the server's own rollup rather than being summed from the loaded page: the issue list is one page (the API caps at 200), so a client-side total would quietly under-report a long column. The blocked marker reads straight off blocked_by_count for the same reason — no per-card link fetch.

The drag

One Pan gesture with activateAfterLongPress rather than a long-press composed with a pan, so a column keeps scrolling vertically until a card actually lifts instead of the card swallowing every touch that starts on it.

Hit-testing converts the finger's screen position into the content coordinates the columns were measured in — that is what makes a drop land correctly while the strip is mid-scroll — and a card held against an edge keeps scrolling from a frame callback rather than waiting for the next movement.

Shared values are written through .set()/.get() rather than .value: the React Compiler treats a property assignment on a prop as a mutation, and the method API is what it accepts.

A tap on any card opens the same move-to-status sheet. That is the fallback the issue asks for, and it is also why the board is fully usable if the gesture misbehaves on real hardware — see below.

Verification

108 unit tests, plus 7 integration tests against a live instance: statuses come back ordered with colours and categories, every filter narrows server-side, unassigned maps onto the flag that overrides assignee_id, the estimate rollup is keyed by status id as a string, and a moved card stays moved with the filtered view agreeing — the acceptance criterion.

The board tree also renders under jest (columns, per-column placement, the collapsed cancelled column, point totals, blocked marker), which needed the react-native-worklets jest resolver.

The drag gesture itself is unverified by touch — there is no device or emulator available here, so pointer tracking, the lift threshold and edge auto-scroll have only been checked as logic, not as a feel. The pure hit-testing and edge-scroll maths are unit tested at the boundaries. Worth a real device pass before this is relied on; the tap path covers the same action meanwhile.

wak327 and others added 2 commits September 11, 2026 21:47
Closes #5.

Columns come from the team's own statuses, so nothing is hardcoded -- a team
that renames "Cancelled" to "Won't do" still gets it collapsed by default,
because the rule is by category.

Filters live in the route's query params rather than component state, the same
choice the web makes and using the same short keys. That is what makes the board
someone is looking at a link they can send, and it means a board URL copied out
of the web app narrows this one the same way.

Per-column point totals come from the server's own rollup rather than being
summed from the loaded page: the issue list is one page, so a client-side total
would quietly under-report a long column. The blocked marker is read straight
off blocked_by_count for the same reason -- no per-card link fetch.

Dragging is one Pan gesture with activateAfterLongPress rather than a long-press
composed with a pan, so a column keeps scrolling vertically until a card
actually lifts. Hit-testing converts the finger's screen position into the
content coordinates the columns were measured in, which is what makes a drop
land correctly while the strip is mid-scroll, and a card held against an edge
keeps scrolling from a frame callback rather than waiting for the next move.
A tap opens the same move-to-status sheet, so the board is usable without the
gesture at all.

Shared values are written through .set()/.get() rather than .value: the React
Compiler treats a property assignment on a prop as a mutation, and the method
API is what it accepts.

Verified against the reference stack -- filters narrow server-side, a moved card
stays moved, and the filtered view agrees -- plus the board tree renders under
jest, which needed the worklets jest resolver.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@wak327
wak327 merged commit d532b1b into mobile-register-invites Sep 11, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant