Preview an inventory item as a customer sees it, from the admin panel #89

Closed
opened 2026-08-21 11:32:34 -05:00 by bermudalamb · 1 comment
Owner

There is no way to see how an item will look on the storefront without publishing it and going to look. Clicking an item's Name in the Inventory table should open a panel rendering that item exactly as the storefront renders it.

Design

The Name cell becomes a link-styled button rather than plain text — a button rather than a clickable div so it stays reachable by keyboard and announces itself as an action. It opens an antd Drawer on the right containing the real storefront <ItemCard> for that item, constrained to a realistic card width so the proportions match what the grid actually produces.

frontend/src/admin/Admin.tsx already imports Item from ../api, the same type the storefront uses, so the row object goes straight into ItemCard with no adapter and nothing to drift.

The part that needs care: ItemCard is not a passive component

ItemCard wires into CartContext and FavoritesContext and has working Add to cart and favorite buttons. Both providers are live in the admin, because they wrap the whole app from main.tsx. A naive preview would therefore be fully functional — and an admin browsing inventory could silently add their own stock to their own cart. On a one-of-a-kind catalogue that reserves the item and takes it off sale.

So ItemCard gains one optional prop, preview. When set, the two click handlers — handleAddClick and handleFavoriteClick — return early. Those two are the only entry points, so guarding them also covers the shared auth modal and the favorite-alerts consent prompt that hang off them.

Deliberately not disabled on the buttons. A disabled antd button renders differently — different colour, different cursor, no hover. The entire point of this panel is to show what a customer will see, so the controls have to keep their exact normal appearance and their correct enabled/disabled state for the item's status. Making them look inert would defeat the feature while appearing to implement it.

Scope

Frontend only. No API change, no database change, nothing touching the storefront's behaviour for customers.

Related to the Pending-status work in the sibling issue — previewing before publishing is the natural pairing — but independent of it and shippable on its own.

Verification

The panel opens from the Name cell and renders the card; the buttons appear exactly as they do on the storefront; clicking Add to cart in the preview leaves the cart badge unchanged. That last one is the assertion that matters, because it is the failure a reviewer cannot see by looking at the screen.

Severity

Low — a convenience, not a defect. Worth doing because the alternative is publishing something to production to find out how it looks.

There is no way to see how an item will look on the storefront without publishing it and going to look. Clicking an item's **Name** in the Inventory table should open a panel rendering that item exactly as the storefront renders it. ## Design The Name cell becomes a link-styled button rather than plain text — a button rather than a clickable `div` so it stays reachable by keyboard and announces itself as an action. It opens an antd `Drawer` on the right containing the real storefront `<ItemCard>` for that item, constrained to a realistic card width so the proportions match what the grid actually produces. `frontend/src/admin/Admin.tsx` already imports `Item` from `../api`, the same type the storefront uses, so the row object goes straight into `ItemCard` with no adapter and nothing to drift. ## The part that needs care: ItemCard is not a passive component `ItemCard` wires into `CartContext` and `FavoritesContext` and has working **Add to cart** and **favorite** buttons. Both providers are live in the admin, because they wrap the whole app from `main.tsx`. A naive preview would therefore be fully functional — and an admin browsing inventory could silently add their own stock to their own cart. On a one-of-a-kind catalogue that reserves the item and takes it off sale. So `ItemCard` gains one optional prop, `preview`. When set, the two click handlers — `handleAddClick` and `handleFavoriteClick` — return early. Those two are the only entry points, so guarding them also covers the shared auth modal and the favorite-alerts consent prompt that hang off them. Deliberately *not* `disabled` on the buttons. A disabled antd button renders differently — different colour, different cursor, no hover. The entire point of this panel is to show what a customer will see, so the controls have to keep their exact normal appearance and their correct enabled/disabled state for the item's status. Making them look inert would defeat the feature while appearing to implement it. ## Scope Frontend only. No API change, no database change, nothing touching the storefront's behaviour for customers. Related to the Pending-status work in the sibling issue — previewing before publishing is the natural pairing — but independent of it and shippable on its own. ## Verification The panel opens from the Name cell and renders the card; the buttons appear exactly as they do on the storefront; clicking Add to cart in the preview leaves the cart badge unchanged. That last one is the assertion that matters, because it is the failure a reviewer cannot see by looking at the screen. ## Severity Low — a convenience, not a defect. Worth doing because the alternative is publishing something to production to find out how it looks.
Author
Owner

Implemented on feature/89-item-preview-panel — one commit, not pushed

Clicking an item's name in the Inventory opens a drawer with the real storefront ItemCard, pinned to a card-sized width so the proportions match what the grid produces rather than stretching to fill the panel.

Three files: ItemCard.tsx gains the preview prop, Admin.tsx gains the link, the state and the drawer, and a new end-to-end spec.

The inertness, and how it is proved

preview short-circuits handleAddClick and handleFavoriteClick. Those two turned out to be the only entry points, so guarding them also covers the shared auth modal and the favorite-alerts consent prompt that hang off them — no third place to miss.

Still not disabled on the buttons, as designed. A disabled antd button renders in a different colour with a different cursor and no hover, and showing what a customer sees is the whole point. The comment on the prop says this explicitly, because simplifying it to disabled would defeat the feature while looking like an implementation of it.

Four end-to-end tests, two of which carry the weight

Test Asserts
Opens from the name The drawer appears and contains $42.00 — the storefront's cents-formatted price, so it only passes if the card actually rendered rather than an empty panel
Button state Add to Cart is visible and enabled, catching a regression to disabled
Does not act Clicking Add to Cart raises no sign-in prompt
Storefront still live The same click on the real storefront card does raise the prompt

The third is the assertion a reviewer cannot make by looking at the screen. Signed out, a real Add to Cart opens the sign-in prompt before it can add anything — so the prompt never appearing is positive evidence that the handler stopped before doing any work, rather than the weaker "nothing visibly happened".

The fourth exists because the first three would all still pass if preview had accidentally been left on everywhere, which would have quietly broken buying things. A test that only checks the new path cannot see that.

Verification

Build clean, lint 0 errors and 30 warnings — down from 31, because ItemCard's props are now Readonly and that was a pre-existing warning on a file this change already touches. 91 end-to-end tests passing (87 + 4 new), run once against a freshly created database.

Note on scope

No separate design document — the design is this issue, and duplicating it into docs/superpowers/specs/ would leave two records of the same decisions to drift apart. The change is one prop, one drawer and a spec file.

Next: #90, the Pending status.

Not pushed, per the usual arrangement.

## Implemented on `feature/89-item-preview-panel` — one commit, not pushed Clicking an item's name in the Inventory opens a drawer with the real storefront `ItemCard`, pinned to a card-sized width so the proportions match what the grid produces rather than stretching to fill the panel. Three files: `ItemCard.tsx` gains the `preview` prop, `Admin.tsx` gains the link, the state and the drawer, and a new end-to-end spec. ## The inertness, and how it is proved `preview` short-circuits `handleAddClick` and `handleFavoriteClick`. Those two turned out to be the only entry points, so guarding them also covers the shared auth modal and the favorite-alerts consent prompt that hang off them — no third place to miss. Still not `disabled` on the buttons, as designed. A disabled antd button renders in a different colour with a different cursor and no hover, and showing what a customer sees is the whole point. The comment on the prop says this explicitly, because simplifying it to `disabled` would defeat the feature while looking like an implementation of it. ## Four end-to-end tests, two of which carry the weight | Test | Asserts | | --- | --- | | Opens from the name | The drawer appears and contains `$42.00` — the storefront's cents-formatted price, so it only passes if the card actually rendered rather than an empty panel | | Button state | Add to Cart is visible **and enabled**, catching a regression to `disabled` | | **Does not act** | Clicking Add to Cart raises no sign-in prompt | | **Storefront still live** | The same click on the real storefront card *does* raise the prompt | The third is the assertion a reviewer cannot make by looking at the screen. Signed out, a real Add to Cart opens the sign-in prompt before it can add anything — so the prompt never appearing is positive evidence that the handler stopped before doing any work, rather than the weaker "nothing visibly happened". The fourth exists because the first three would all still pass if `preview` had accidentally been left on everywhere, which would have quietly broken buying things. A test that only checks the new path cannot see that. ## Verification Build clean, lint **0 errors and 30 warnings** — down from 31, because `ItemCard`'s props are now `Readonly` and that was a pre-existing warning on a file this change already touches. **91 end-to-end tests** passing (87 + 4 new), run once against a freshly created database. ## Note on scope No separate design document — the design is this issue, and duplicating it into `docs/superpowers/specs/` would leave two records of the same decisions to drift apart. The change is one prop, one drawer and a spec file. Next: #90, the Pending status. Not pushed, per the usual arrangement.
bermudalamb self-assigned this 2026-08-21 11:42:31 -05:00
bermudalamb added this to the Code Quality and Hardening project 2026-08-21 11:42:38 -05:00
bermudalamb moved this to In Progress in Code Quality and Hardening on 2026-08-21 11:44:15 -05:00
bermudalamb added reference feature/89-item-preview-panel 2026-08-21 11:46:37 -05:00
bermudalamb moved this to Review in Code Quality and Hardening on 2026-08-21 12:11:37 -05:00
bermudalamb moved this to Ready for Release in Code Quality and Hardening on 2026-08-21 12:12:30 -05:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bermudalamb/redefined-designs#89