Skip to content

feat(ui): mobile card view for issues list (PinPoint-5g0)#1060

Open
timothyfroehlich wants to merge 5 commits intomainfrom
design/mobile-issues-list
Open

feat(ui): mobile card view for issues list (PinPoint-5g0)#1060
timothyfroehlich wants to merge 5 commits intomainfrom
design/mobile-issues-list

Conversation

@timothyfroehlich
Copy link
Owner

Summary

  • Adds a mobile card layout (< md breakpoint) for the issues list page alongside the unchanged desktop table view
  • New MobileIssueCard component renders ID chip, machine name, age, title (line-clamp-2), status badge, severity dot + label, and assignee avatar; urgent (unplayable) cards get red-tinted border
  • New MobileIssueFilterBar provides a search input with clear button and a horizontally scrollable chip row (Sort, Status, Machine, Assigned) with active state on filtered chips
  • New MobileIssueList composes the header with total count badge, filter bar, top/bottom pagination, and the card list

Design Reference

Based on docs/design-inspiration:docs/inspiration/mobile-redesign/mockup-issues-list.html.

Files Changed

  • src/app/(app)/issues/page.tsx — Wraps desktop in hidden md:block, adds md:hidden mobile section
  • src/components/issues/MobileIssueCard.tsx — New: tappable issue card
  • src/components/issues/MobileIssueFilterBar.tsx — New: mobile search + filter chips
  • src/components/issues/MobileIssueList.tsx — New: mobile layout orchestrator

Test plan

  • View /issues on mobile viewport (< 768px): cards appear, table hidden
  • View /issues on desktop viewport (>= 768px): table appears, cards hidden
  • data-testid="mobile-issue-card" present on each card
  • data-testid="mobile-issues-search" on search input
  • data-testid="mobile-filter-chips" on filter chip row
  • Unplayable issues show red border
  • Pagination prev/next works
  • Search clears with X button
  • pnpm run check passes

Closes PinPoint-5g0

Generated with Claude Code

Adds a responsive card-based layout for the issues list page on mobile
(< md breakpoint). Desktop table remains unchanged and is now wrapped in
hidden md:block. The mobile layout renders in md:hidden.

New components:
- MobileIssueCard: tappable card with ID chip, machine name, age, title
  (line-clamp-2), status badge, severity dot + label, assignee avatar.
  Unplayable (urgent) issues get red-tinted border + background.
- MobileIssueFilterBar: search input with clear button, filter icon,
  horizontally scrollable chip row (Sort, Status, Machine, Assigned).
  Chips show active state when filters are applied.
- MobileIssueList: composes header with total count badge, filter bar,
  top/bottom pagination (count + prev/next), card list, empty state.

Key decisions:
- Uses existing IssueBadge, useSearchFilters, getSmartBadgeLabel utilities
- Server Component page unchanged; only client leaf components added
- Severity dots use a static Tailwind class map (not string manipulation)
- data-testid: mobile-issue-card, mobile-issues-search, mobile-filter-chips

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 23, 2026 02:23
@vercel
Copy link

vercel bot commented Feb 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pin-point Ready Ready Preview, Comment Feb 26, 2026 3:41am

@supabase
Copy link

supabase bot commented Feb 23, 2026

This pull request has been ignored for the connected project udhesuizjsgxfeotqybn due to reaching the limit of concurrent preview branches.
Go to Project Integrations Settings ↗︎ if you wish to update this limit.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a mobile-first issues list experience (< md) by introducing a card-based list with a lightweight filter/search bar, while keeping the existing desktop table + filters for md and above.

Changes:

  • Add new mobile components: MobileIssueList, MobileIssueCard, and MobileIssueFilterBar.
  • Update /issues page to render mobile cards under md and the existing desktop table at md+.
  • Add mobile pagination controls and an empty state consistent with the desktop list.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
src/app/(app)/issues/page.tsx Splits rendering into md:hidden (mobile cards) and hidden md:block (desktop table).
src/components/issues/MobileIssueList.tsx Composes mobile header, filter bar, pagination, card list, and empty state.
src/components/issues/MobileIssueFilterBar.tsx Implements mobile search + chip row (sort/status/machine/assignee).
src/components/issues/MobileIssueCard.tsx Renders the tappable mobile issue card layout (ID, machine, age, status, severity, assignee).
Comments suppressed due to low confidence (1)

src/components/issues/MobileIssueList.tsx:146

  • hasActiveIssueFilters(searchParams) is computed three times in this render path. Consider computing it once (e.g., const hasActive = ...) to avoid repeated work and to keep the empty-state logic easier to read/maintain.
          <p className="text-sm font-semibold text-foreground">
            {hasActiveIssueFilters(searchParams)
              ? "No issues found"
              : "No issues yet"}
          </p>
          <p className="text-xs text-muted-foreground mt-1 max-w-[200px]">
            {hasActiveIssueFilters(searchParams)
              ? "Adjust your filters to see more issues."
              : "Issues will appear here once they are reported."}
          </p>
          {!hasActiveIssueFilters(searchParams) && (
            <Button variant="outline" size="sm" className="mt-3" asChild>
              <Link href="/report">Report an Issue</Link>
            </Button>

…terBar

- Fix status chip label: empty status array (All) now shows "All" via ALL_STATUS_OPTIONS
- Replace hardcoded closed-status list with shared CLOSED_STATUSES constant
- Remove non-functional SlidersHorizontal filter button (deferred to PinPoint-eddl)
- Machine/Assignee chips now only render when filter is active, acting as clear chips

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mobile redesign added a second search input (mobile-issues-search) alongside
the desktop one (issue-search). Playwright strict mode rejected
getByPlaceholder("Search issues...") since it matched both. Added
getIssueSearchInput() helper that selects by testid based on viewport.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

e2e/smoke/issue-list.spec.ts:38

  • This test still uses desktop-only UI/ARIA assumptions (e.g. "Showing 1 of 1 issues", table role=row, and the "Clear" button). With the new md:hidden mobile layout, those elements aren’t visible in Mobile Chrome/Safari projects and the test will fail. Either skip this test on mobile (as done for the inline-edit test) or branch assertions/interactions to use the mobile card UI (data-testid="mobile-issue-card", aria-label="Clear search", and the mobile pagination text).
  test("should filter and search issues", async ({ page }, testInfo) => {
    // 1. Setup: Use seeded issues
    // Issue 1: "Thing flips the bird" (TAF-01)
    // Issue 2: "Bookcase not registering" (TAF-02)
    const title1 = seededIssues.TAF[0].title;

Comment on lines +54 to +58
const start = totalCount === 0 ? 0 : (page - 1) * pageSize + 1;
const end = Math.min(totalCount, page * pageSize);
const isFirstPage = page <= 1;
const isLastPage = end >= totalCount;

Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

start/end are derived from page and totalCount only. If the user lands on an out-of-range page (common after changing filters), issues can be empty while totalCount > 0, producing a backwards range like “31–30 of 30”. Consider deriving end from issues.length (or clamping page to the last page) and showing 0 issues when issues.length === 0.

Copilot uses AI. Check for mistakes.
Comment on lines 318 to 329
@@ -326,7 +328,7 @@ test.describe("Issue List Features", () => {
await page.waitForURL(/severity=major/);

Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test applies severity filters via filter-severity, which is part of the desktop IssueFilters UI. Since the page now hides desktop filters on < md, this flow won’t work on the Mobile projects in Playwright and will fail. Either skip this test on mobile viewports or add a mobile-specific equivalent once the mobile filter sheet is implemented.

Copilot uses AI. Check for mistakes.
@timothyfroehlich timothyfroehlich added the claude-review Triggers Claude Code Review GitHub Action label Feb 26, 2026
…list

# Conflicts:
#	e2e/smoke/issue-list.spec.ts
@github-actions
Copy link
Contributor

Claude Code Review: No issues found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claude-review Triggers Claude Code Review GitHub Action

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants