Admin Category and Tag UI issues #27

Closed
opened 2026-08-17 13:49:12 -05:00 by bermudalamb · 2 comments
Owner

In the admin interface I'm seeing the following issues

  • In dark mode the selected tab name is not visible (no contrast)
  • When adding/editing an item the category selector interface doesn't follow the selected theme UI
  • The Category tab doesn't follow the selected theme UI
  • The Tag tab doesn't follow the selected theme UI
  • The tab tab also shows that the UI is not in American english (colour vs color). The UI should be in American english
  • On the Customers tab I need to know the number of items that customer currently has in Reserved status. That should be a link with a popup that displays the item name, and a button to release the item.
  • The Inventory tab should also support the same filtering that the main UI does, and it should also allow for Reserved filtering
    • Category
    • Tag(s)
    • Price Arrange
image.png image.png image.png
In the admin interface I'm seeing the following issues - In dark mode the selected tab name is not visible (no contrast) - When adding/editing an item the category selector interface doesn't follow the selected theme UI - The Category tab doesn't follow the selected theme UI - The Tag tab doesn't follow the selected theme UI - The tab tab also shows that the UI is not in American english (colour vs color). The UI should be in American english - On the Customers tab I need to know the number of items that customer currently has in `Reserved` status. That should be a link with a popup that displays the item name, and a button to release the item. - The Inventory tab should also support the same filtering that the main UI does, and it should also allow for `Reserved` filtering - Category - Tag(s) - Price Arrange <img width="1440" alt="image.png" src="attachments/3abbdfb3-6a7a-45d7-a348-21f0ac63230c"> <img width="1440" alt="image.png" src="attachments/4b4ee04c-7230-41a2-a685-ff51d1352fdb"> <img width="1440" alt="image.png" src="attachments/e9f3bbad-79e6-4d2f-8c17-02f08aba0d30">
bermudalamb added this to the Initial Build project 2026-08-17 13:59:43 -05:00
bermudalamb self-assigned this 2026-08-17 13:59:49 -05:00
Author
Owner

Root causes and design decisions

Bullets 1–4 are two root causes, not four bugs

Both confirmed by measuring computed styles in dark mode rather than by inspection:

Measurement Value Meaning
Active tab label color rgb(25,25,25) colorPrimary: '#1a1a1a' applied in both themes — near-black text on a dark background
Categories tree background rgb(255,255,255) Pure white while in dark mode
Categories tree text rgba(0,0,0,0.88) Light theme, so the component never saw ConfigProvider

Bullet 1 — dark tab invisible. colorPrimary is hardcoded to #1a1a1a regardless of theme.

Bullets 2, 3, 4 — category selector, Category tab, Tag tab don't follow the theme. One cause for all three. antd's package.json declares main: lib/index.js and module: es/index.js, so import … from 'antd' resolves to the ES build while import … from 'antd/lib/…' loads the CommonJS build. Two copies of antd, two React context instances — components imported from antd/lib/* never receive the theme from ConfigProvider.

The affected files are exactly the reported ones, plus two on the storefront that have the same latent bug and hadn't been noticed:

src/admin/Categories.tsx          <- Category tab
src/admin/Tags.tsx                <- Tag tab
src/admin/CategoryTreeSelect.tsx  <- category selector in the item form
src/components/FilterDrawer.tsx        <- storefront (unreported)
src/components/ActiveFilterChips.tsx   <- storefront (unreported)
src/customer/VerifyEmail.tsx           <- pre-existing, same bug

Fix is antd/lib/*antd/es/*, which keeps the deep-import convention and shares the module instance. Stating it plainly: this was introduced by my own use of the lib path when applying the deep-import convention; es is the correct path for a Vite build.

Bullet 5 — American English. Three occurrences of "Colour", two of them user-visible (the Tags column header and the edit-modal label).


Decisions on the remaining items

Q1 — dark mode accent colour

Option
A. Light neutral in dark mode #1a1a1a in light, #f0f0f0 in dark — the accent inverts, keeping the monochrome brand in both themes
B. One mid-gray for both Single token, but primary buttons look washed out on white
C. antd default blue in dark High contrast, but introduces a hue the brand doesn't use

Answer: A.

Q2 — Inventory tab filter UI, and how Reserved is handled

Option
A. Inline filter row + Status dropdown Controls sit above the table, always visible; Reserved becomes one option in a Status filter (All / Available / Reserved / Sold) rather than a standalone toggle
B. Reuse the storefront drawer + chips Consistent, but hides controls behind a click and overlays a wide table
C. antd per-column filter dropdowns Compact, but price range doesn't fit the pattern

Answer: A. Filtering is server-side, reusing the same query builder as the storefront, so results stay correct across pagination.

Q3 — what Release does

Option
A. Return to available, no email Removes the cart row and sets the item back to available — same effect as the customer removing it or the expiry sweep firing
B. Also email the customer Emails about an action they didn't take, and SMTP is optional so it may silently not send
C. Only allow releasing expired reservations The 5-minute sweep already handles those, so the button would rarely do anything

Answer: A.


Work

  • Theme-aware colorPrimary (bullet 1)
  • antd/lib/*antd/es/* across six files (bullets 2–4)
  • "Colour" → "Color" (bullet 5)
  • Customers tab: reserved count as a link, popup listing items with Release (bullet 6)
  • Inventory tab: category / tags / price / status filtering, server-side (bullet 7)
## Root causes and design decisions ### Bullets 1–4 are two root causes, not four bugs Both confirmed by measuring computed styles in dark mode rather than by inspection: | Measurement | Value | Meaning | | --- | --- | --- | | Active tab label color | `rgb(25,25,25)` | `colorPrimary: '#1a1a1a'` applied in *both* themes — near-black text on a dark background | | Categories tree background | `rgb(255,255,255)` | Pure white while in dark mode | | Categories tree text | `rgba(0,0,0,0.88)` | Light theme, so the component never saw `ConfigProvider` | **Bullet 1 — dark tab invisible.** `colorPrimary` is hardcoded to `#1a1a1a` regardless of theme. **Bullets 2, 3, 4 — category selector, Category tab, Tag tab don't follow the theme.** One cause for all three. `antd`'s `package.json` declares `main: lib/index.js` and `module: es/index.js`, so `import … from 'antd'` resolves to the **ES** build while `import … from 'antd/lib/…'` loads the **CommonJS** build. Two copies of antd, two React context instances — components imported from `antd/lib/*` never receive the theme from `ConfigProvider`. The affected files are exactly the reported ones, plus two on the storefront that have the same latent bug and hadn't been noticed: ``` src/admin/Categories.tsx <- Category tab src/admin/Tags.tsx <- Tag tab src/admin/CategoryTreeSelect.tsx <- category selector in the item form src/components/FilterDrawer.tsx <- storefront (unreported) src/components/ActiveFilterChips.tsx <- storefront (unreported) src/customer/VerifyEmail.tsx <- pre-existing, same bug ``` Fix is `antd/lib/*` → `antd/es/*`, which keeps the deep-import convention *and* shares the module instance. Stating it plainly: this was introduced by my own use of the `lib` path when applying the deep-import convention; `es` is the correct path for a Vite build. **Bullet 5 — American English.** Three occurrences of "Colour", two of them user-visible (the Tags column header and the edit-modal label). --- ### Decisions on the remaining items **Q1 — dark mode accent colour** | Option | | | --- | --- | | **A. Light neutral in dark mode** | `#1a1a1a` in light, `#f0f0f0` in dark — the accent inverts, keeping the monochrome brand in both themes | | B. One mid-gray for both | Single token, but primary buttons look washed out on white | | C. antd default blue in dark | High contrast, but introduces a hue the brand doesn't use | **Answer: A.** **Q2 — Inventory tab filter UI, and how Reserved is handled** | Option | | | --- | --- | | **A. Inline filter row + Status dropdown** | Controls sit above the table, always visible; Reserved becomes one option in a Status filter (All / Available / Reserved / Sold) rather than a standalone toggle | | B. Reuse the storefront drawer + chips | Consistent, but hides controls behind a click and overlays a wide table | | C. antd per-column filter dropdowns | Compact, but price range doesn't fit the pattern | **Answer: A.** Filtering is server-side, reusing the same query builder as the storefront, so results stay correct across pagination. **Q3 — what Release does** | Option | | | --- | --- | | **A. Return to available, no email** | Removes the cart row and sets the item back to available — same effect as the customer removing it or the expiry sweep firing | | B. Also email the customer | Emails about an action they didn't take, and SMTP is optional so it may silently not send | | C. Only allow releasing expired reservations | The 5-minute sweep already handles those, so the button would rarely do anything | **Answer: A.** --- ### Work - [ ] Theme-aware `colorPrimary` (bullet 1) - [ ] `antd/lib/*` → `antd/es/*` across six files (bullets 2–4) - [ ] "Colour" → "Color" (bullet 5) - [ ] Customers tab: reserved count as a link, popup listing items with Release (bullet 6) - [ ] Inventory tab: category / tags / price / status filtering, server-side (bullet 7)
Author
Owner

All seven items implemented

Branch fix/admin-theme-and-filters, one commit, not yet pushed.

# Item Status
1 Dark mode selected tab invisible Fixed
2 Category selector ignores theme Fixed
3 Category tab ignores theme Fixed
4 Tag tab ignores theme Fixed
5 "Colour" → "Color" Fixed
6 Customers: reserved count, popup, Release Implemented
7 Inventory: category / tag / price / Reserved filtering Implemented

Bullet 1 — dark tab contrast

colorPrimary was #1a1a1a in both themes. The accent now inverts with the theme. colorTextLightSolid had to invert with it — otherwise a near-white accent gets antd's default white label on primary buttons and disappears in the opposite direction.

Bullets 2–4 — one root cause

antd/lib/* loaded a second copy of antd with its own React context, so nothing deep-imported ever saw ConfigProvider. Six files moved to antd/es/*, which preserves the deep-import convention and shares the module instance. Two of those were storefront components with the same latent bug that hadn't been noticed yet.

Bullet 6 — reserved items

Release mirrors the customer's own cart removal: drop the cart_items row and return the item to available, in one transaction, guarded on status = 'reserved' so it can never resurrect a sold item. No email, per the decision above.

The count is a scalar subquery rather than another LEFT JOIN — joining a second one-to-many relation alongside orders would have multiplied rows and inflated the existing order_count and total_spent_cents columns.

Bullet 7 — inventory filtering

GET /api/admin/items now takes category, tags, min_price, max_price, and status, reusing the storefront's parser and query builder so admin and customer filtering cannot drift. Category matching still walks descendants; tags still require all. Filtering is server-side, so results stay correct across pagination.

Two further defects the screenshots exposed

Neither was reported, both found while verifying:

  • The reserved-count link bubbled to the row's click handler, so clicking it opened the customer detail drawer behind the dialog it had just opened.
  • .admin-category-node was referenced in Categories.tsx but the CSS class never existed, so each tree node rendered as one unbroken string: Decor fmsxpc67051 item Add child Rename Delete. Now the name, muted item count, and right-aligned actions are laid out properly.

Verification

Suite Result
Backend unit 52 passed
Backend integration 74 passed (17 new)
Frontend e2e 46 passed, stable over 3 consecutive runs
tsc --noEmit backend / frontend clean
npm run build clean

The theme fixes have real regression tests rather than screenshots: they measure computed WCAG relative luminance, so they assert readability rather than exact hex values and won't break on a palette tweak. Each was confirmed failing against the old code first.

Note

Running the backend integration suite truncated the shared local dev database again mid-session — it defaults to the same redefined_test database the README uses for local development. Harmless locally, but it's a standing footgun worth its own issue.

## All seven items implemented Branch `fix/admin-theme-and-filters`, one commit, not yet pushed. | # | Item | Status | | --- | --- | --- | | 1 | Dark mode selected tab invisible | Fixed | | 2 | Category selector ignores theme | Fixed | | 3 | Category tab ignores theme | Fixed | | 4 | Tag tab ignores theme | Fixed | | 5 | "Colour" → "Color" | Fixed | | 6 | Customers: reserved count, popup, Release | Implemented | | 7 | Inventory: category / tag / price / Reserved filtering | Implemented | ### Bullet 1 — dark tab contrast `colorPrimary` was `#1a1a1a` in both themes. The accent now inverts with the theme. `colorTextLightSolid` had to invert with it — otherwise a near-white accent gets antd's default white label on primary buttons and disappears in the opposite direction. ### Bullets 2–4 — one root cause `antd/lib/*` loaded a second copy of antd with its own React context, so nothing deep-imported ever saw `ConfigProvider`. Six files moved to `antd/es/*`, which preserves the deep-import convention and shares the module instance. Two of those were storefront components with the same latent bug that hadn't been noticed yet. ### Bullet 6 — reserved items Release mirrors the customer's own cart removal: drop the `cart_items` row and return the item to available, in one transaction, guarded on `status = 'reserved'` so it can never resurrect a sold item. No email, per the decision above. The count is a scalar subquery rather than another `LEFT JOIN` — joining a second one-to-many relation alongside `orders` would have multiplied rows and inflated the existing `order_count` and `total_spent_cents` columns. ### Bullet 7 — inventory filtering `GET /api/admin/items` now takes `category`, `tags`, `min_price`, `max_price`, and `status`, reusing the storefront's parser and query builder so admin and customer filtering cannot drift. Category matching still walks descendants; tags still require all. Filtering is server-side, so results stay correct across pagination. ### Two further defects the screenshots exposed Neither was reported, both found while verifying: - The reserved-count link bubbled to the row's click handler, so clicking it opened the customer detail drawer *behind* the dialog it had just opened. - `.admin-category-node` was referenced in `Categories.tsx` but the CSS class never existed, so each tree node rendered as one unbroken string: `Decor fmsxpc67051 item Add child Rename Delete`. Now the name, muted item count, and right-aligned actions are laid out properly. ### Verification | Suite | Result | | --- | --- | | Backend unit | 52 passed | | Backend integration | 74 passed (17 new) | | Frontend e2e | 46 passed, stable over 3 consecutive runs | | `tsc --noEmit` backend / frontend | clean | | `npm run build` | clean | The theme fixes have real regression tests rather than screenshots: they measure computed WCAG relative luminance, so they assert readability rather than exact hex values and won't break on a palette tweak. Each was confirmed failing against the old code first. ### Note Running the backend integration suite truncated the shared local dev database again mid-session — it defaults to the same `redefined_test` database the README uses for local development. Harmless locally, but it's a standing footgun worth its own issue.
bermudalamb moved this to In Progress in Initial Build on 2026-08-17 15:55:03 -05:00
bermudalamb moved this to Ready for Review in Initial Build on 2026-08-17 16:30:28 -05:00
bermudalamb moved this to Review in Initial Build on 2026-08-17 16:30:35 -05:00
bermudalamb moved this to Ready for Release in Initial Build on 2026-08-17 16:30:42 -05:00
bermudalamb moved this to Released in Initial Build on 2026-08-17 16:30:51 -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#27