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.
- package/knowledge/2.0/apps/toga2-commerce/INDEX.md +1 -0
- package/knowledge/2.0/apps/toga2-commerce/features/cart-notification-emails.md +3 -1
- package/knowledge/2.0/apps/toga2-commerce/features/cart-page-config-architecture.md +155 -0
- package/knowledge/2.0/apps/toga2-commerce/features/client-fields.md +1 -0
- package/knowledge/INDEX.md +1 -1
- package/knowledge/clients/quad/profile.md +1 -0
- package/package.json +1 -1
|
@@ -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
|
package/knowledge/INDEX.md
CHANGED
|
@@ -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) —
|
|
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
|
|
package/package.json
CHANGED