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 notdisabled 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.
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.
## 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
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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
divso it stays reachable by keyboard and announces itself as an action. It opens an antdDraweron 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.tsxalready importsItemfrom../api, the same type the storefront uses, so the row object goes straight intoItemCardwith no adapter and nothing to drift.The part that needs care: ItemCard is not a passive component
ItemCardwires intoCartContextandFavoritesContextand has working Add to cart and favorite buttons. Both providers are live in the admin, because they wrap the whole app frommain.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
ItemCardgains one optional prop,preview. When set, the two click handlers —handleAddClickandhandleFavoriteClick— 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
disabledon 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.
Implemented on
feature/89-item-preview-panel— one commit, not pushedClicking 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.tsxgains thepreviewprop,Admin.tsxgains the link, the state and the drawer, and a new end-to-end spec.The inertness, and how it is proved
previewshort-circuitshandleAddClickandhandleFavoriteClick. 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
disabledon 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 todisabledwould defeat the feature while looking like an implementation of it.Four end-to-end tests, two of which carry the weight
$42.00— the storefront's cents-formatted price, so it only passes if the card actually rendered rather than an empty paneldisabledThe 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
previewhad 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 nowReadonlyand 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.