Skip to content

feat(client): replace Mantine's Table in the business trip report - #4445

Open
gilgardosh wants to merge 2 commits into
mainfrom
feat/mantine-trip-report-tables
Open

feat(client): replace Mantine's Table in the business trip report#4445
gilgardosh wants to merge 2 commits into
mainfrom
feat/mantine-trip-report-tables

Conversation

@gilgardosh

Copy link
Copy Markdown
Collaborator

Part of the Mantine removal, and the last of the business trip report after #4435 (buttons/) and #4439 (rows + header). The subtree now imports no Mantine at all.

Why the row components are in here too

The eight table shells could not move alone. Mantine's Table styles its descendants from the root — & thead tr th, & tbody tr td — while shadcn's styling lives on TableRow/TableCell. Dropping raw <tr>/<td> into a shadcn <Table> gets you a completely unstyled table: no padding, no borders, no hover. So the seven row components' <tr>/<td> convert in the same commit, CoreExpenseHeader's <th>s included.

The swap

Mantine Replacement
<Table highlightOnHover withBorder> <Table className="border">highlightOnHover is TableRow's default, withBorder is the added class
<thead> / <tbody> / <tr> / <th> / <td> TableHeader / TableBody / TableRow / TableHead / TableCell
Paper shadow="xs" p="md" ui/card + p-4 — Mantine's paper carried its own padding, shadcn's carries none
List withPadding <ul className="… pl-8">, matching the 32px (theme.spacing.xl) it indented by
Grid Tailwind grid on Mantine's breakpoints, as in the header
Text <div>

A bonus from ui/table: every one of these now sits in a overflow-x-auto container. Mantine's table had none, so the wider ones (uncategorized transactions, summary) previously just overflowed.

The ErrorsPopover, and a type fix it needed

uncategorized-transactions.tsx had a Mantine Popover held open by onMouseEnter/onMouseLeave with pointerEvents: 'none' on the dropdown — a tooltip in all but name. It's a Tooltip now, so the hand-rolled useState and both handlers go away, and it picks up the keyboard and touch behaviour Radix gives you for free.

That surfaced a real bug in common/tooltip.tsx. Its props were:

React.ComponentProps<typeof TooltipContent> & { content: ReactNode }

React's HTMLAttributes carries an RDFa content?: string, so the intersection narrowed the wrapper's own content to string & ReactNode — meaning it silently accepted only strings, despite the declaration saying ReactNode. Every existing caller passes a string, so nobody had hit it. Omit-ing content from the base props before redeclaring gives the wrapper the type it always documented. I verified it by reverting the Omit: the build fails on exactly the new call site.

Verification

Added a Summary story — self-contained, no urql needed — and measured the rendered table in Chromium against the built Storybook:

cell padding 8px
header row height 40px
row bottom border 1px
hover highlight fires (transparent → oklab(0.967 … / 0.5))
container overflow-x auto
raw td/tr left inside the component none
page errors none

(My first pass at that probe reported 12 stray <td>s — those turned out to be Storybook's own docs-panel markup, all outside the component.)

Check Result
yarn test:client 46 files, 366 passed, 1 skipped
yarn workspace @accounter/client build typechecks + builds
yarn workspace @accounter/client storybook:build completes
yarn lint 0 errors
yarn prettier:check clean

ESLint ratchet widened from business-trip-report/buttons/** to the whole business-trip-report/**.

Mantine burn-down: 46 → 38 imports across 45 → 37 files.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QGLamjMKnUa7d4AedKw3XR


Generated by Claude Code

The last eight files under common/business-trip-report/parts, plus the seven row
components they render. Those had to move together: Mantine's `Table` styled its
descendants from the root (`& tbody tr td`), while shadcn's styling lives on
TableRow/TableCell, so converting the shells alone would have left every row
unstyled.

- `<Table highlightOnHover withBorder>` -> `<Table className="border">`.
  `highlightOnHover` is TableRow's default; `withBorder` is the added class.
- `<thead>/<tbody>/<tr>/<th>/<td>` -> TableHeader/TableBody/TableRow/TableHead/
  TableCell throughout, including the rows and `CoreExpenseHeader`.
- summary.tsx: `Paper shadow="xs" p="md"` -> `ui/card` plus `p-4` (Mantine's
  paper carried its own padding), `List withPadding` -> a `pl-8` ul matching the
  32px it indented by, and its `Grid` -> a Tailwind grid on Mantine's own
  breakpoints, as in the header.
- uncategorized-transactions.tsx: `ErrorsPopover` was a Mantine `Popover` held
  open by mouseenter/mouseleave with `pointerEvents: 'none'` on the dropdown — a
  tooltip in all but name. It is a `Tooltip` now, so the hand-rolled open state
  and both handlers go, and it picks up Radix's keyboard and touch behaviour.

That last one needed a fix in `common/tooltip.tsx`: its props were
`ComponentProps<typeof TooltipContent> & { content: ReactNode }`, and React's
HTMLAttributes carries an RDFa `content?: string`, so the intersection narrowed
`content` to `string & ReactNode` and rejected any JSX body. Omitting it from the
base props before redeclaring gives the wrapper the type it always documented.
Verified by reverting the Omit, which fails the build on exactly that line.

Verified the table in Chromium against a built Storybook, via a new Summary
story: cells padded 8px, header row 40px, 1px row borders, hover highlight
firing, and no raw td/tr left in the component. Also gains a horizontal scroll
container, which Mantine's table did not have.

The subtree now imports no Mantine at all, so the ESLint ratchet widens from
buttons/ to the whole of common/business-trip-report/.

Mantine burn-down: 46 -> 38 imports across 45 -> 37 files.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QGLamjMKnUa7d4AedKw3XR
@gilgardosh
gilgardosh temporarily deployed to accounter-fullstack September 10, 2026 17:23 — with GitHub Actions Inactive
@gilgardosh
gilgardosh temporarily deployed to accounter-fullstack September 10, 2026 17:23 — with GitHub Actions Inactive
@github-actions

Copy link
Copy Markdown
Contributor

The latest changes of this PR are not available as alpha, since there are no linked changesets for this PR.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Moderate issues remain with summary footer alignment, legacy table-cell styling, and tooltip trigger accessibility.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This pull request replaces Mantine components in the business-trip report with shadcn/Tailwind equivalents.

Changes:

  • Migrates report tables and row components.
  • Replaces related cards, grids, lists, and popovers.
  • Adds Summary stories and fixes tooltip content typing.
  • Expands lint coverage and adds a changeset.
File summaries
File Description
packages/client/src/components/common/tooltip.tsx Fixes tooltip content typing.
packages/client/src/components/common/business-trip-report/parts/uncategorized-transactions.tsx Migrates the transactions table and error tooltip.
packages/client/src/components/common/business-trip-report/parts/travel-and-subsistence.tsx Migrates the table shell.
packages/client/src/components/common/business-trip-report/parts/travel-and-subsistence-row.tsx Migrates row cells.
packages/client/src/components/common/business-trip-report/parts/summary.tsx Migrates summary layout and table components.
packages/client/src/components/common/business-trip-report/parts/summary.stories.tsx Adds Summary stories.
packages/client/src/components/common/business-trip-report/parts/other.tsx Migrates the table shell.
packages/client/src/components/common/business-trip-report/parts/other-row.tsx Migrates row cells.
packages/client/src/components/common/business-trip-report/parts/flights-table.tsx Migrates the flights table.
packages/client/src/components/common/business-trip-report/parts/flights-row.tsx Migrates flight row cells.
packages/client/src/components/common/business-trip-report/parts/core-expense-row.tsx Migrates shared expense cells and headers.
packages/client/src/components/common/business-trip-report/parts/car-rental.tsx Migrates the car-rental table.
packages/client/src/components/common/business-trip-report/parts/car-rental-row.tsx Migrates car-rental row cells.
packages/client/src/components/common/business-trip-report/parts/attendees.tsx Migrates the attendees table.
packages/client/src/components/common/business-trip-report/parts/attendee-row.tsx Migrates attendee rows and expanded content.
packages/client/src/components/common/business-trip-report/parts/accommodations-table.tsx Migrates the accommodations table.
packages/client/src/components/common/business-trip-report/parts/accommodations-row.tsx Migrates accommodation row cells.
eslint.config.mjs Expands business-trip-report lint coverage.
.changeset/olive-otters-tap.md Documents the client changes.
Review details
  • Files reviewed: 19/19 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/client/src/components/common/business-trip-report/parts/summary.tsx Outdated
…name the tooltip trigger

All three review comments were right; the first two are the same class of bug
this PR set out to avoid, and I missed them.

- summary.tsx's footer lost its right alignment. Mantine's Grid is flexbox, so
  `justify="flex-end"` worked; `grid-cols-12` makes twelve 1fr tracks that
  consume the whole width, so `justify-content` had no free space to distribute
  and both cells auto-placed from column 1. Measured before the fix: 397px of
  empty space to the right at 1000px wide, 835px at 1300px. Right alignment is
  explicit `col-start` now — 6 and 10 at md, 9 and 11 at lg — and measures flush
  to the right edge at every width.

- Six of uncategorized-transactions' nine columns come from
  transactions-table/cells-legacy, which still emitted raw <td>. Mantine styled
  those from the table root; ui/table puts the styling on TableCell, so they
  rendered with no padding at all. Converted, which is safe because this table
  is their only consumer. All nine cells now measure 8px.

- The errors tooltip's trigger was an unnamed focusable button: without
  `asChild`, TooltipTrigger renders a bare <button> around the icon, and a lone
  SVG gives it no accessible name. It is now an explicit labelled button. The
  Mantine popover was not focusable at all, so this keyboard path is new and
  had to be named.

Adds an UncategorizedTransactions story, which is what made the last two
checkable. Its first draft wrapped the harness in a MemoryRouter and hit the
nested-<Router> throw that .storybook/preview.tsx's global one causes — the same
trap recorded when that decorator was hoisted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QGLamjMKnUa7d4AedKw3XR
@gilgardosh
gilgardosh deployed to accounter-fullstack September 12, 2026 12:48 — with GitHub Actions Active
@gilgardosh
gilgardosh deployed to accounter-fullstack September 12, 2026 12:48 — with GitHub Actions Active
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.

3 participants