toga-ai 1.0.185 → 1.0.186

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,7 @@
4
4
  |-----|---------|-------|
5
5
  | [TOGa Commerce (toga2-commerce / commerce2-react) Architecture](architecture.md) | `toga2-commerce` (npm package name **`commerce2-react`**, product name **TOGa Commerce**) is the customer-facing **B2B commerce storefront** of the 2.0 platform | src/main.tsx, src/App.tsx, src/routes.tsx, src/contexts/AuthContext.tsx, src/contexts/helpers/getLoginSettings.ts, src/api/axiosInstance.ts, src/stores/, src/themeConfig/ThemeContext.tsx, src/fieldsConfig/index.ts, src/hooks/useAssignClientFields.ts, vite.config.ts, package.json |
6
6
  | [Cart Notification Emails — duplicate prevention](features/cart-notification-emails.md) | On the cart "Notifications" section a user can add CC email addresses to an order. | src/pages/Cart/CartPage.tsx, src/pages/Cart/view/cartForm/CartForm.tsx, src/stores/useEmailOptionsStore.ts, src/stores/useCartSalesQuoteZu.ts, src/pages/Cart/viewModel/FIELDS/*/*/*/CARTPAGE.ts |
7
+ | [Cart Page — config-driven form architecture (current state + planned refactor)](features/cart-page-config-architecture.md) | The Cart page (`src/pages/Cart/`) is the most config-heavy page in `toga2-commerce`. | src/pages/Cart/CartPage.tsx, src/pages/Cart/view/cartForm/CartForm.tsx, src/pages/Cart/view/cartForm/CartFormSection.tsx, src/pages/Cart/view/cartForm/CartFormRenderer.tsx, src/pages/Cart/view/EditCart.tsx, src/pages/Cart/view/EditOrder.tsx, src/pages/Cart/viewModel/useEditOrderOrEditCartViewModel.ts, src/pages/Cart/viewModel/FIELDS/*/*/*/CARTPAGE.ts, src/hooks/useAssignClientFields.ts |
7
8
  | [Client Fields — per-tenant / language / role content & config](features/client-fields.md) | Almost no user-facing text, field layout, or page config is hard-coded in `toga2-commerce`. | src/fieldsConfig/index.ts, src/fieldsConfig/getClientLoginFields.ts, src/fieldsConfig/clientFields/COMPASS.json, src/fieldsConfig/clientFields/COMPASSCANADA.json, src/fieldsConfig/clientFields/QUAD.json, src/hooks/useAssignClientFields.ts, src/hooks/useDynamicConditionalFieldOptions.ts, src/stores/useFieldsStore.ts, src/components/BaseDetailField/BaseDetailField.tsx |
8
9
  | [Multi-Tenant Resolution & Theming](features/multi-tenant-theming.md) | `toga2-commerce` serves multiple clients from one codebase. | src/themeConfig/themes.json, src/themeConfig/ThemeContext.tsx, src/themeConfig/types.ts, src/components/ThemeSwitcher/ThemeSwitcher.tsx, src/components/AuthLayout/AuthLayout.tsx, src/api/axiosInstance.ts, src/contexts/AuthContext.tsx, tailwind.config.js |
9
10
  | [AWS Amplify Build & Deploy (non-prod environments)](workflows/amplify-build-and-deploy.md) | How `toga2-commerce` (React + Vite, "commerce2-react") builds and deploys on **AWS Amplify**. | toga2-commerce/amplify.yml, toga2-commerce/.gitattributes, toga2-commerce/package.json, toga2-commerce/.github/workflows/sync-stage-environments.yml |
@@ -14,7 +14,9 @@ files:
14
14
  - src/stores/useEmailOptionsStore.ts
15
15
  - src/stores/useCartSalesQuoteZu.ts
16
16
  - src/pages/Cart/viewModel/FIELDS/*/*/*/CARTPAGE.ts
17
- related: []
17
+ related:
18
+ - 2.0/apps/toga2-commerce/features/cart-page-config-architecture.md
19
+ - 2.0/apps/toga2-commerce/features/client-fields.md
18
20
  ---
19
21
 
20
22
  ## Summary
@@ -0,0 +1,155 @@
1
+ ---
2
+ title: Cart Page — config-driven form architecture (current state + planned refactor)
3
+ framework: "2.0"
4
+ repo: toga2-commerce
5
+ project: TOGa Commerce
6
+ client: shared
7
+ type: feature
8
+ status: active
9
+ updated: 2026-06-24
10
+ owners: ["apeterson"]
11
+ files:
12
+ - src/pages/Cart/CartPage.tsx
13
+ - src/pages/Cart/view/cartForm/CartForm.tsx
14
+ - src/pages/Cart/view/cartForm/CartFormSection.tsx
15
+ - src/pages/Cart/view/cartForm/CartFormRenderer.tsx
16
+ - src/pages/Cart/view/EditCart.tsx
17
+ - src/pages/Cart/view/EditOrder.tsx
18
+ - src/pages/Cart/viewModel/useEditOrderOrEditCartViewModel.ts
19
+ - src/pages/Cart/viewModel/FIELDS/*/*/*/CARTPAGE.ts
20
+ - src/hooks/useAssignClientFields.ts
21
+ related:
22
+ - 2.0/apps/toga2-commerce/architecture.md
23
+ - 2.0/apps/toga2-commerce/features/client-fields.md
24
+ - 2.0/apps/toga2-commerce/features/cart-notification-emails.md
25
+ - 2.0/apps/toga25-supply/features/client-configurable-fields.md
26
+ ---
27
+
28
+ ## Summary
29
+
30
+ The Cart page (`src/pages/Cart/`) is the most config-heavy page in `toga2-commerce`. As of
31
+ `_production` it is **config-driven at the field level but hardcoded at the section level**, and it
32
+ renders the cart through **two near-duplicate dual-mode forms** (cart-checkout vs edit-order). A
33
+ config-driven refactor is **planned but not yet implemented** (see *Planned refactor* below). This
34
+ doc records both the current architecture and the agreed target so the work can be picked up without
35
+ re-deriving it. The cart consumes the per-tenant `CARTPAGE.ts` config resolved through
36
+ `useAssignClientFields` — see [client-fields](client-fields.md) for that resolution model.
37
+
38
+ ## Current architecture (`_production`)
39
+
40
+ ```
41
+ CartPage.tsx (~1052 lines) owns useForm(), watched values, all handlers; picks EditCart vs EditOrder
42
+ ├─ EditCart.tsx (~596) cart-checkout mode: sync useEffects + renders <CartForm> (~30 props)
43
+ └─ EditOrder.tsx (~665) edit-order mode: near-duplicate sync useEffects + renders <CartForm>
44
+ └─ CartForm.tsx (~1074) HARDCODED section layout (summary / orderFor / shippingAddress /
45
+ costCenter / notifications / confirm) as JSX; calls CartFormSection per section
46
+ └─ CartFormSection.tsx (~296) ALREADY config-driven: renders inputs from a `fields` prop,
47
+ honoring visibleWhen / inputButtons / labelButton / isEditable / inputType
48
+ ```
49
+
50
+ `useEditOrderOrEditCartViewModel.ts` is a dispatcher hook that returns one view-model or the other
51
+ based on `inEditMode`. `CartFormRenderer.tsx` exists only on the `implement-config` spike branch
52
+ (reads `section.fields`); it is **not on `_production`**.
53
+
54
+ ### What is already config-driven (keep it)
55
+ - **Field-level rendering** — `CartFormSection` maps over a section's input array and interprets
56
+ `visibleWhen`, `inputButtons`, `labelButton`, `isEditable`/`isVisible`, `inputType`
57
+ (advancedSelect / BaseInput / display variants). This mirrors toga2.5's `renderField`/`BaseInput`.
58
+ - **Per-tenant `CARTPAGE.ts`** per client/language/role, resolved via `useAssignClientFields`
59
+ (React-Query cached) — the same resolution model as toga2.5's `useClientFields`.
60
+
61
+ ### What is NOT config-driven / is duplicated (the refactor target)
62
+ - **Section layout is code, not config** — `CartForm.tsx` (~1074 lines) hardcodes which sections
63
+ exist and their order in JSX.
64
+ - **The form is built twice** — `EditCart` and `EditOrder` share ~80% of their logic but are
65
+ separate files, each holding its own copy of the mount / orderFor-cascade / form-sync effects.
66
+ - **Prop drilling** — `CartPage → EditCart/EditOrder → CartForm → CartFormSection` passes ~30 props
67
+ by hand.
68
+
69
+ ## Gotchas (current state — all pre-existing on `_production`)
70
+
71
+ - **Config-key naming drift.** `CARTPAGE.ts` uses `inputs:` for the `orderFor` section but
72
+ `formFields:` for `shippingAddress` / `costCenter` / `notifications`, while `CartFormSection`
73
+ reads a `fields` prop. Three names for one concept; `CartForm` hand-maps each section's array into
74
+ the `fields` prop. This pre-existing drift is what tripped the prior spike. (Target: rename all to
75
+ a single `fields` key.)
76
+ - **`useForm` is seeded with a hardcoded union of every client's fields.** `CartPage.tsx`
77
+ (~lines 230–258) calls `useForm` with one static `defaultValues` object that is the **union** of
78
+ all clients' fields, with the **COMPASS-only magic shipping-method UUID `087a9d0b-…` baked in**.
79
+ Two mode-change `reset()` effects (~lines 267, 282) re-seed from that same union shape. This is
80
+ wrong for per-client field sets: it registers fields a client never renders and bakes one client's
81
+ default into all of them, and risks RHF controlled/uncontrolled warnings.
82
+ - **Client differences are hardcoded, not config.** Examples observed: COMPASS renders
83
+ `DuplicateKitGuardrail`, QUAD does not; COMPASS seeds the cart form (cost center / manager / emails)
84
+ from the order-for user, QUAD does not. These are per-client conditionals in cart code today.
85
+ - `useAssignClientFields.ts` returns `FIELDS?.[clientName]?.[language]?.[role]` with no transform —
86
+ there is no fallback (a missing combo renders empty). See [client-fields](client-fields.md).
87
+
88
+ ## Planned refactor (DECIDED 2026-06-24 — plan only, not implemented)
89
+
90
+ **Approach (Route B): rebuild the config-driven cart from the working `_production` branch**, using
91
+ the broken `implement-config` spike branch only as a *reference blueprint* (its target-shaped files
92
+ — `CartFormContext`, `CartFormRenderer`, `useCartFormViewModel`, `useCartFormSync`, standalone
93
+ sections — are architecturally sound but mid-rename and non-functional; lift code where correct,
94
+ do not finish that branch). Rationale: the spike's −3,940-line deletion silently dropped real
95
+ behavior (email seeding, duplicate-email validation, edit-order cost-center/address). The risk is
96
+ **behavior parity, not architecture**, so migrate in verifiable slices against the running
97
+ `_production` app as the oracle. Target pattern = toga2.5 (`toga25-supply`): one form, section
98
+ layout from config, state via context, consolidated sync effects.
99
+
100
+ Plan document (in the toga2-commerce repo, not in the KB):
101
+ `docs/reviews/implement-config-cart-refactor-PLAN.md`.
102
+
103
+ Phases: **P0** pin a behavior oracle + inventory hardcoded client branches · **P1** behavior-neutral
104
+ config-key rename (`inputs`/`formFields` → single `fields`) · **P2** `CartFormContext` to kill
105
+ prop-drilling + config-derived form defaults · **P3** consolidate the dual view-models and the three
106
+ sync effects into `useCartFormViewModel` + `useCartFormSync`, branching on `inEditMode` once · **P4**
107
+ drive section layout from config (`type` + dispatch map with explicit fallback) + capability flags,
108
+ then delete `CartForm`/`EditCart`/`EditOrder` · **P5** hydration memo + standards sweep (magic UUID
109
+ removed from code, lives in config).
110
+
111
+ ### Key principle established — client behavior comes from config, never `if (client === ...)`
112
+
113
+ A new client must be onboarded by **editing `CARTPAGE.ts`**, not by adding `clientSlug` branches to
114
+ cart code. Two flavors, modeled exactly on toga2.5's SalesOrder approval pattern (config carries
115
+ `approvalActionStatuses` + `approveButtonRule:{type:"requireStepTwoAssigned"}`; a pure
116
+ `evaluateApproveRule(rule, ctx)` switch over a discriminated union in `useApprovalModalViewModel.tsx`
117
+ interprets it — the component never knows it is COMPASS):
118
+
119
+ 1. **Capability flags** — pure on/off presence, no runtime data:
120
+ `capabilities.duplicateKitGuardrail.isEnabled` (COMPASS true, QUAD omits). The renderer reads the
121
+ flag to decide whether to mount `DuplicateKitGuardrail`.
122
+ 2. **Named rules** — conditional logic depending on runtime data, declared as `{ type }` and
123
+ evaluated generically: e.g. `orderForSeedRules: [{type:"seedCostCenterFromUser"}, …]` iterated by
124
+ an `applySeedRule` evaluator in `useCartFormSync` (mirrors `evaluateApproveRule`). QUAD omits the
125
+ rules → seeds nothing, no branch.
126
+
127
+ ### Config-derived form defaults (cart-specific extension of the toga2.5 pattern)
128
+
129
+ The config already enumerates exactly the fields a client renders, so derive `useForm`
130
+ `defaultValues` from it via a `buildCartDefaultValues(fields, ctx)` builder with three sources:
131
+ - per-field `defaultValue` in config (where the COMPASS shipping UUID **moves to**; QUAD omits it);
132
+ - type-derived empties (`text`/`textArea`→`""`, `checkbox`→`false`,
133
+ `select`/`advancedSelect`→`{uuid:"",name:""}`);
134
+ - dynamic `defaultValueRules` reusing the same `{type}` rule shape
135
+ (e.g. `currentUserWhenNotEditable`, `fromSalesOrderErpEntity`).
136
+
137
+ The two mode-change `reset()` effects call the **same builder** so defaults and rendered inputs can
138
+ never drift. Noted honestly: toga2.5 uses a *static* `emptyItemDefaults` because its item-create form
139
+ is a single shape; the cart is genuinely multi-shape per client, so config-derived defaults is a
140
+ **cart-specific extension** of toga2.5's philosophy, not a literal copy.
141
+
142
+ > The general "no `if (client === ...)` — drive client behavior from config via capability flags and
143
+ > named rules evaluated by a generic evaluator" rule, applied across 2.0 React frontends beyond just
144
+ > the cart, is being proposed as a team **standard** separately (senior-owned / pending approval).
145
+
146
+ ## Change history
147
+ - 2026-06-24 — Initial: documented the current `_production` Cart architecture (field-level config
148
+ via `CartFormSection`, hardcoded section layout in `CartForm`, dual `EditCart`/`EditOrder` forms +
149
+ dispatcher VM, prop-drilling), its gotchas (config-key drift `inputs`/`formFields`/`fields`,
150
+ hardcoded union `defaultValues` with the COMPASS magic shipping UUID, hardcoded per-client
151
+ branches), and the DECIDED config-driven refactor approach (rebuild from `_production`, branch as
152
+ blueprint; capability flags + named rules à la toga2.5 approval; config-derived
153
+ `buildCartDefaultValues`). Plan only — not implemented (apeterson)
154
+ </content>
155
+ </invoke>
@@ -22,6 +22,7 @@ related:
22
22
  - 2.0/apps/toga2-commerce/architecture.md
23
23
  - 2.0/apps/toga2-commerce/features/multi-tenant-theming.md
24
24
  - 2.0/apps/toga2-commerce/features/cart-notification-emails.md
25
+ - 2.0/apps/toga2-commerce/features/cart-page-config-architecture.md
25
26
  ---
26
27
 
27
28
  ## Summary
@@ -26,7 +26,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
26
26
  - **talos** (TOGa IQ) — 6 doc(s) → [2.0/apps/talos/INDEX.md](2.0/apps/talos/INDEX.md)
27
27
  - **voice-to-voice** (TOGa Voice) — 4 doc(s) → [2.0/apps/voice-to-voice/INDEX.md](2.0/apps/voice-to-voice/INDEX.md)
28
28
  - **ai-bdr** (AI-BDR) — 4 doc(s) → [2.0/apps/ai-bdr/INDEX.md](2.0/apps/ai-bdr/INDEX.md)
29
- - **toga2-commerce** (TOGa Commerce) — 5 doc(s) → [2.0/apps/toga2-commerce/INDEX.md](2.0/apps/toga2-commerce/INDEX.md)
29
+ - **toga2-commerce** (TOGa Commerce) — 6 doc(s) → [2.0/apps/toga2-commerce/INDEX.md](2.0/apps/toga2-commerce/INDEX.md)
30
30
  - **toga25-supply** (TOGa 2.5 Supply) — 5 doc(s) → [2.0/apps/toga25-supply/INDEX.md](2.0/apps/toga25-supply/INDEX.md)
31
31
  - **toga-blox** (TOGa Blox) — 7 doc(s) → [2.0/apps/toga-blox/INDEX.md](2.0/apps/toga-blox/INDEX.md)
32
32
 
@@ -5,6 +5,7 @@ apps:
5
5
  - _underscore
6
6
  - api2
7
7
  - toga2-supply
8
+ - toga2-commerce
8
9
  - dbchanges2
9
10
  project: _Underscore
10
11
  client: quad
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.185",
3
+ "version": "1.0.186",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",