toga-ai 1.0.123 → 1.0.124

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.
@@ -0,0 +1,5 @@
1
+ # toga2-commerce (TOGa Commerce) — 2.0 knowledge
2
+
3
+ | Doc | Summary | Files |
4
+ |-----|---------|-------|
5
+ | [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 |
@@ -0,0 +1,79 @@
1
+ ---
2
+ title: Cart Notification Emails — duplicate prevention
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-18
10
+ owners: ["bala"]
11
+ files:
12
+ - src/pages/Cart/CartPage.tsx
13
+ - src/pages/Cart/view/cartForm/CartForm.tsx
14
+ - src/stores/useEmailOptionsStore.ts
15
+ - src/stores/useCartSalesQuoteZu.ts
16
+ - src/pages/Cart/viewModel/FIELDS/*/*/*/CARTPAGE.ts
17
+ related: []
18
+ ---
19
+
20
+ ## Summary
21
+ On the cart "Notifications" section a user can add CC email addresses to an order. Adding the
22
+ same address twice (often with different casing) used to slip through to the API and blow up on
23
+ submit with a MySQL 1062 duplicate-key error on the `SalesOrderEmailAddresses.salesOrderId_emailAddress`
24
+ unique index (whose collation `utf8mb4_0900_ai_ci` is case-insensitive). This feature blocks
25
+ duplicates case-insensitively in the frontend and shows a sapphire info message instead of letting
26
+ the error reach the user.
27
+
28
+ ## Key files / entry points
29
+ - `CartPage.tsx` — `handleAddEmail`: validates the email regex, then on success calls
30
+ `addEmailOption` (UI options list) and `addEmail` (the cart sales-quote store that builds the
31
+ `salesOrderEmailAddresses` payload). Normalizes the input once with `.trim()`.
32
+ - `CartForm.tsx` — owns the duplicate UX. `handleAddEmailWithDuplicateCheck` wraps the passed-in
33
+ `handleAddEmail`: it case-insensitively checks the existing `emails` list and, on a match, shows
34
+ the message instead of adding. The **Add Email** button calls this wrapper.
35
+ - `useEmailOptionsStore.ts` — `addEmailOption` de-dupes the checkbox list.
36
+ - `useCartSalesQuoteZu.ts` — `addEmail` de-dupes the actual `salesOrderEmailAddresses` payload.
37
+
38
+ ## How it works
39
+ 1. **Before (manual add):** clicking Add Email runs `handleAddEmailWithDuplicateCheck` in
40
+ `CartForm`. It compares `(e.email ?? "").trim().toLowerCase()` against the normalized input. On a
41
+ match it sets `duplicateEmailMessage` and returns (does not add).
42
+ 2. **After (auto-add on user select):** when the order user is chosen, their email (and manager's)
43
+ is auto-added via `addEmailOption`. Both stores de-dupe case-insensitively, so a case-variant of
44
+ an already-present address is silently dropped rather than duplicated.
45
+ 3. **Display:** the message renders via the shared `InfoBanner` component (the same one used for the
46
+ "view as" / "edit order" banners), styled `text-sapphire-700 text-xs`, no icon. It is NOT a
47
+ toaster and NOT a red `setError` validation — it is a sapphire info message.
48
+ 4. The message text comes from the `notifications.duplicateEmailAddressError.label` field config,
49
+ present in every `CARTPAGE.ts` (all client/role/language variants, English + French).
50
+ 5. A `useEffect` clears the message when the input, selected user (`orderForUser?.uuid`), or email
51
+ list (`emails.length`) changes.
52
+
53
+ ## Data model
54
+ Frontend only. The payload list maps to the `SalesOrderEmailAddresses` table (api2/backend), which
55
+ has a case-insensitive unique index on `(salesOrderId, emailAddress)`.
56
+
57
+ ## Client variations
58
+ The de-dupe mechanism is uniform across clients. Only the message label text differs per client
59
+ config: English `"This email has already been added"`; French (Compass Canada)
60
+ `"Cette adresse e-mail a déjà été ajoutée"`. The label must exist in every `CARTPAGE.ts` variant or
61
+ the message resolves to `undefined` and renders blank.
62
+
63
+ ## Gotchas / known issues
64
+ - The real source of the 1062 was `useCartSalesQuoteZu.addEmail` comparing with `===`
65
+ (case-sensitive). Both stores must compare case-insensitively; fixing only the UI list is not
66
+ enough because `addEmail` builds the payload.
67
+ - Normalize with `(x ?? "").trim().toLowerCase()`, not `x?.trim().toLowerCase()` — both are
68
+ nullish-safe (optional chaining short-circuits the whole chain, it does not throw), but `(x ?? "")`
69
+ guarantees a string and avoids an `undefined === undefined` match edge.
70
+ - Adding the label to only some `CARTPAGE.ts` files leaves other client/role/language users with a
71
+ blank message.
72
+ - Do not use a toaster or `setError` (red) for this — product wants the sapphire info style.
73
+
74
+ ## Change history
75
+ - 2026-06-18 — Initial: case-insensitive de-dupe in both cart stores, sapphire `InfoBanner` message in
76
+ CartForm, `duplicateEmailAddressError` label added to all CARTPAGE.ts variants (bala)
77
+
78
+ ## Related docs
79
+ None yet.
@@ -25,6 +25,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
25
25
  - **talos** (TOGa IQ) — 6 doc(s) → [2.0/apps/talos/INDEX.md](2.0/apps/talos/INDEX.md)
26
26
  - **voice-to-voice** (TOGa Voice) — 4 doc(s) → [2.0/apps/voice-to-voice/INDEX.md](2.0/apps/voice-to-voice/INDEX.md)
27
27
  - **ai-bdr** (AI-BDR) — 4 doc(s) → [2.0/apps/ai-bdr/INDEX.md](2.0/apps/ai-bdr/INDEX.md)
28
+ - **toga2-commerce** (TOGa Commerce) — 1 doc(s) → [2.0/apps/toga2-commerce/INDEX.md](2.0/apps/toga2-commerce/INDEX.md)
28
29
 
29
30
  ## standalone framework
30
31
 
@@ -5,14 +5,15 @@ apps:
5
5
  - _underscore
6
6
  - api2
7
7
  - toga2-supply
8
+ - toga2-commerce
8
9
  - worker
9
10
  - dbchanges2
10
11
  project: _Underscore
11
12
  client: compass-canada
12
13
  type: profile
13
14
  status: active
14
- updated: 2026-06-08
15
- owners: [jcardinal]
15
+ updated: 2026-06-18
16
+ owners: [jcardinal, bala]
16
17
  files: []
17
18
  related:
18
19
  - ../compass-usa/profile.md
@@ -5,14 +5,15 @@ apps:
5
5
  - _underscore
6
6
  - api2
7
7
  - toga2-supply
8
+ - toga2-commerce
8
9
  - worker
9
10
  - dbchanges2
10
11
  project: _Underscore
11
12
  client: compass-usa
12
13
  type: profile
13
14
  status: active
14
- updated: 2026-06-08
15
- owners: [jcardinal]
15
+ updated: 2026-06-18
16
+ owners: [jcardinal, bala]
16
17
  files: []
17
18
  related:
18
19
  - features/asn-to-item-fulfillment.md
@@ -152,5 +152,12 @@
152
152
  "framework": "standalone",
153
153
  "role": "app",
154
154
  "dependsOn": []
155
+ },
156
+ {
157
+ "repo": "toga2-commerce",
158
+ "project": "TOGa Commerce",
159
+ "framework": "2.0",
160
+ "role": "app",
161
+ "dependsOn": ["api2"]
155
162
  }
156
163
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.123",
3
+ "version": "1.0.124",
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",