@capillarytech/creatives-library 8.0.290-alpha.4 → 8.0.290
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/constants/unified.js +1 -3
- package/initialState.js +2 -0
- package/package.json +1 -1
- package/utils/common.js +8 -5
- package/utils/commonUtils.js +85 -4
- package/utils/tagValidations.js +223 -83
- package/utils/tests/commonUtil.test.js +124 -147
- package/utils/tests/tagValidations.test.js +358 -441
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +33 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +397 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.scss +35 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/TECH_DETAILING_DELIVERY_SETTINGS.md +725 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +92 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +243 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +111 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +91 -0
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +33 -1
- package/v2Components/CommonTestAndPreview/actions.js +20 -0
- package/v2Components/CommonTestAndPreview/constants.js +10 -0
- package/v2Components/CommonTestAndPreview/index.js +133 -15
- package/v2Components/CommonTestAndPreview/reducer.js +47 -0
- package/v2Components/CommonTestAndPreview/sagas.js +60 -0
- package/v2Components/CommonTestAndPreview/selectors.js +51 -0
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +782 -0
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +200 -0
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +235 -0
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +127 -0
- package/v2Components/CommonTestAndPreview/tests/actions.test.js +50 -0
- package/v2Components/CommonTestAndPreview/tests/constants.test.js +18 -0
- package/v2Components/CommonTestAndPreview/tests/index.test.js +214 -1
- package/v2Components/CommonTestAndPreview/tests/reducer.test.js +118 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +145 -0
- package/v2Components/CommonTestAndPreview/tests/selectors.test.js +146 -0
- package/v2Components/ErrorInfoNote/index.js +5 -2
- package/v2Components/FormBuilder/index.js +201 -132
- package/v2Components/FormBuilder/messages.js +8 -0
- package/v2Components/HtmlEditor/HTMLEditor.js +5 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +15 -0
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +2 -1
- package/v2Components/TestAndPreviewSlidebox/index.js +14 -0
- package/v2Containers/Cap/mockData.js +14 -0
- package/v2Containers/Cap/reducer.js +55 -3
- package/v2Containers/Cap/tests/reducer.test.js +102 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +1 -5
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +5 -13
- package/v2Containers/CreativesContainer/index.js +7 -30
- package/v2Containers/Email/index.js +5 -1
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +70 -23
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +137 -29
- package/v2Containers/FTP/index.js +51 -2
- package/v2Containers/FTP/messages.js +4 -0
- package/v2Containers/InApp/index.js +104 -4
- package/v2Containers/InApp/tests/index.test.js +6 -17
- package/v2Containers/InappAdvance/index.js +108 -4
- package/v2Containers/InappAdvance/tests/index.test.js +0 -2
- package/v2Containers/Line/Container/Text/index.js +1 -0
- package/v2Containers/MobilePush/Create/index.js +19 -42
- package/v2Containers/MobilePush/Edit/index.js +19 -42
- package/v2Containers/MobilePushNew/index.js +32 -12
- package/v2Containers/MobilepushWrapper/index.js +1 -3
- package/v2Containers/Rcs/index.js +37 -12
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +649 -12
- package/v2Containers/Sms/Create/index.js +3 -39
- package/v2Containers/Sms/Create/messages.js +0 -4
- package/v2Containers/Sms/Edit/index.js +3 -35
- package/v2Containers/Sms/commonMethods.js +6 -3
- package/v2Containers/SmsTrai/Edit/index.js +47 -11
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +147 -6
- package/v2Containers/SmsWrapper/index.js +0 -2
- package/v2Containers/Viber/index.js +1 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +3 -1
- package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +7 -0
- package/v2Containers/WebPush/Create/index.js +2 -2
- package/v2Containers/WebPush/Create/utils/validation.js +2 -17
- package/v2Containers/WebPush/Create/utils/validation.test.js +24 -59
- package/v2Containers/Whatsapp/index.js +18 -10
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +26174 -4225
- package/v2Containers/Zalo/index.js +11 -3
- package/v2Containers/Sms/tests/commonMethods.test.js +0 -122
package/v2Components/CommonTestAndPreview/DeliverySettings/TECH_DETAILING_DELIVERY_SETTINGS.md
ADDED
|
@@ -0,0 +1,725 @@
|
|
|
1
|
+
# Technical Detailing: Delivery Settings & Sender ID Support in Test and Preview
|
|
2
|
+
|
|
3
|
+
**Scope:** cap-creatives-ui — CommonTestAndPreview (SMS, Email, WhatsApp only)
|
|
4
|
+
**Reference:** cap-campaigns-v2 DeliverySettingsV2 & ModifyDeliverySettings (design/UX only; no cross-repo imports)
|
|
5
|
+
**Status:** Planning — Implementation not started
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Overview
|
|
10
|
+
|
|
11
|
+
### 1.1 Goal
|
|
12
|
+
Replace dummy delivery settings in the Test and Preview flow with **selectable** delivery settings and sender IDs for **SMS**, **Email**, and **WhatsApp**, so that when a user sends a test message, the payload uses the chosen domain/account and sender (e.g. GSM sender, email sender, reply-to, WhatsApp sender number).
|
|
13
|
+
|
|
14
|
+
### 1.2 Current vs Target
|
|
15
|
+
| Aspect | Current | Target |
|
|
16
|
+
|--------|--------|--------|
|
|
17
|
+
| Delivery settings in payload | Hardcoded empty/default in `prepareTestMessagePayload` | Populated from user selection in Delivery Settings UI |
|
|
18
|
+
| UI | No delivery settings block in Send Test Message | Summary line + edit (pencil) → **CapSlideBox** (cap-ui-library) with channel-specific fields |
|
|
19
|
+
| APIs | Not used for test flow | `getSenderDetails(channel, orgUnitId)` and (for WhatsApp) `fetchWeCrmAccounts(sourceName)` — **called via Redux (actions + redux-saga)** using existing CommonTestAndPreview `actions.js`, `sagas.js`, `reducer.js`, `selectors.js` |
|
|
20
|
+
|
|
21
|
+
### 1.3 Out of Scope
|
|
22
|
+
- RCS, Viber, Zalo, InApp, MobilePush, etc. (only SMS, Email, WhatsApp).
|
|
23
|
+
- Campaigns repo: no imports from cap-campaigns-v2; reference for UI/UX and field names only.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 2. Architecture Decisions
|
|
28
|
+
|
|
29
|
+
### 2.1 State Ownership (Redux + Local)
|
|
30
|
+
- **API-derived data (sender details, WeCRM accounts) lives in Redux** — using the existing CommonTestAndPreview slice: `actions.js`, `sagas.js`, `reducer.js`, `selectors.js`. The two APIs **getSenderDetails** and **fetchWeCrmAccounts** are called via **Redux actions and redux-saga** (not directly from the component).
|
|
31
|
+
- **User-selected delivery settings** (the values the user picks in the Delivery Settings **CapSlideBox**) live in **local component state** in CommonTestAndPreview (`index.js`), e.g. `testPreviewDeliverySettings`. This state feeds the Delivery Settings summary, the modal’s initial selection, and `prepareTestMessagePayload` when building the test message payload.
|
|
32
|
+
- **Summary:** Redux holds sender-details options and WeCRM accounts (and loading/error); component holds only the current channel’s selected delivery settings and dispatches actions to fetch options.
|
|
33
|
+
|
|
34
|
+
### 2.2 Redux Usage (Existing Files)
|
|
35
|
+
- **Constants** (`CommonTestAndPreview/constants.js`): Add new action types for Get Sender Details and Get WeCRM Accounts (REQUESTED, SUCCESS, FAILURE each).
|
|
36
|
+
- **Actions** (`CommonTestAndPreview/actions.js`): Add `getSenderDetailsRequested({ channel, orgUnitId })` and `getWeCrmAccountsRequested({ sourceName })`. These are dispatched by CommonTestAndPreview (e.g. in `useEffect` when Test & Preview opens for SMS/Email/WhatsApp).
|
|
37
|
+
- **Sagas** (`CommonTestAndPreview/sagas.js`): Add saga workers that call `Api.getSenderDetails(channel, orgUnitId)` and `Api.fetchWeCrmAccounts(sourceName)`; parse response (using DeliverySettings parser utility); then `put` SUCCESS with normalized data or FAILURE with error. Register watchers and include them in `commonTestAndPreviewSaga()`.
|
|
38
|
+
- **Reducer** (`CommonTestAndPreview/reducer.js`): Add initial state for `senderDetailsByChannel` (e.g. `{ SMS: [], EMAIL: [], WHATSAPP: [] }`), `wecrmAccounts: []`, `isLoadingSenderDetails: false`, `fetchSenderDetailsError: null`, `fetchWeCrmAccountsError: null`. Handle GET_SENDER_DETAILS_* and GET_WECRM_ACCOUNTS_* actions (store parsed data, set loading/error).
|
|
39
|
+
- **Selectors** (`CommonTestAndPreview/selectors.js`): Add `makeSelectSenderDetailsForChannel(channel)`, `makeSelectWeCrmAccounts()`, `makeSelectIsLoadingSenderDetails()`, `makeSelectFetchSenderDetailsError()`, `makeSelectFetchWeCrmAccountsError()`. Export them.
|
|
40
|
+
- **TestAndPreviewSlidebox** (wrapper): Already connects Redux to CommonTestAndPreview via `mapStateToProps` and `mapDispatchToProps`. Extend `mapStateToProps` to pass the new selectors’ values (e.g. `senderDetailsForChannel`, `wecrmAccounts`, `isLoadingSenderDetails`). Extend `mapDispatchToProps` so `actions` includes `getSenderDetailsRequested` and `getWeCrmAccountsRequested`. CommonTestAndPreview receives these as props and uses them instead of calling APIs directly.
|
|
41
|
+
|
|
42
|
+
### 2.4 UI Library — cap-ui-library Only
|
|
43
|
+
- **All implementation must use common components from `@capillarytech/cap-ui-library`.** No custom modal or generic HTML form elements for the delivery settings flow.
|
|
44
|
+
- **Delivery settings panel (edit view):** Use **CapSlideBox** from cap-ui-library. When the user clicks the pencil icon, open a **CapSlideBox** (not CapModal) with header “Delivery settings”, close (X), channel-specific form content, and Done button. This matches the slidebox pattern used elsewhere in the app (e.g. Test and Preview itself).
|
|
45
|
+
- **Other UI:** Use cap-ui-library components throughout — e.g. CapRow, CapColumn, CapHeader, CapLabel, CapSelect / CapCustomSelect, CapButton, CapIcon, CapSlideBox, etc. Reuse existing CommonTestAndPreview and creatives patterns that already rely on cap-ui-library.
|
|
46
|
+
|
|
47
|
+
### 2.5 New Folder and Components
|
|
48
|
+
- **New folder:** `app/v2Components/CommonTestAndPreview/DeliverySettings/`
|
|
49
|
+
- **Components:**
|
|
50
|
+
- **DeliverySettings** (or **TestPreviewDeliverySettings**): Summary line + edit icon (CapIcon); on edit, opens **CapSlideBox** (from cap-ui-library).
|
|
51
|
+
- **ModifyDeliverySettings** (or **DeliverySettingsSlideBox**): **CapSlideBox** with header “Delivery settings”, X to close, channel-specific fields and Done. All form controls (dropdowns, buttons) from cap-ui-library.
|
|
52
|
+
- **Data flow:** CommonTestAndPreview holds **local state** `testPreviewDeliverySettings` (user’s selection); **Redux** holds sender-details options and WeCRM accounts. Component dispatches `getSenderDetailsRequested` / `getWeCrmAccountsRequested` when Test & Preview opens; reads options from Redux via selectors (passed as props from TestAndPreviewSlidebox); passes options and callbacks to DeliverySettings → ModifyDeliverySettings.
|
|
53
|
+
|
|
54
|
+
### 2.6 API Usage (Called from Saga Only)
|
|
55
|
+
- **getSenderDetails(channel, orgUnitId)** — `app/services/api.js`
|
|
56
|
+
- Called **per channel** (SMS, EMAIL, WHATSAPP) when Test & Preview opens for that channel.
|
|
57
|
+
- `orgUnitId`: from parent prop where available (e.g. CreativesContainer → SlideBoxContent → TestAndPreviewSlidebox → CommonTestAndPreview); default `-1` if not passed.
|
|
58
|
+
- **fetchWeCrmAccounts(sourceName)** — used for **WhatsApp** account list (e.g. `sourceName: 'WHATSAPP'`) so user can pick account; then sender numbers come from `getSenderDetails('WHATSAPP', orgUnitId)` for the selected account (or first account if single).
|
|
59
|
+
- **Response shape:** Creatives API uses `getSenderDetails(channel, orgUnitId)` (single channel). Response must be normalized to the same structure as in campaigns (list of domains with `domainId`, `domainName`, `gsmSenders`, `emailSenders`, `emailRepliers`, etc.). If the backend returns a different shape for single-channel call, add a small **parser/normalizer** in creatives (no dependency on campaigns’ `parseSenderDetails`). The **saga** calls this parser before dispatching SUCCESS so the reducer stores normalized data.
|
|
60
|
+
|
|
61
|
+
### 2.7 Payload Mapping (prepareTestMessagePayload)
|
|
62
|
+
- **EMAIL:**
|
|
63
|
+
`emailDeliverySettings.channelSettings`: `senderLabel`, `senderId` (value of selected sender email), `replyToId` (value of selected reply-to). Optionally `domainId` if backend expects it.
|
|
64
|
+
- **SMS:**
|
|
65
|
+
`smsDeliverySettings.channelSettings`: `gsmSenderId`, `domainId`.
|
|
66
|
+
- **WHATSAPP:**
|
|
67
|
+
`whatsappDeliverySettings.channelSettings`: `senderMobNum`, `domainId`.
|
|
68
|
+
`whatsappMessageContent`: `accountId` / `sourceAccountIdentifier` / `accountName` from selected WhatsApp account where applicable.
|
|
69
|
+
|
|
70
|
+
### 2.8 Default Delivery Setting on Open & Empty Values (Campaigns Compatibility)
|
|
71
|
+
- **Always show one delivery setting row:** When the user opens the Test and Preview page (for SMS, Email, or WhatsApp), **always display one “Delivery settings” summary row** above the Send test message button. The user can then click the edit (pencil) button to change it. This matches the expectation that a delivery setting block is visible by default.
|
|
72
|
+
- **Default when options are available (campaigns-style):** In **cap-campaigns-v2** `DeliverySettingsV2/index.js`, when sender details are loaded, they **auto-populate** the channel’s delivery setting from the **first domain** and the **default sender** (or first sender) using:
|
|
73
|
+
- `findDefault(array) => find(array, { default: true }) || {}` — prefer the option marked `default: true`, else use first item.
|
|
74
|
+
- **SMS:** First domain from `senderDetails.data.SMS[0]`; `gsmSenderId` = `findDefault(gsmSenders).value` or `gsmSenders?.[0]?.value`.
|
|
75
|
+
- **EMAIL:** First domain; `senderEmail`/`senderLabel` = `findDefault(emailSenders)`; `senderReplyTo` = `findDefault(emailRepliers).value`.
|
|
76
|
+
- **WHATSAPP:** Match by `sourceAccountIdentifier` (or use first entry); `senderMobNum` = `gsmSenders[0]?.value`.
|
|
77
|
+
- **Creatives behaviour:** Once Redux has loaded `senderDetailsByChannel[channel]` (and for WhatsApp optionally WeCRM account list), if the current channel’s `testPreviewDeliverySettings` is still empty/initial, **set a default** from the first domain and default/first sender (same logic as campaigns: first domain, `findDefault(gsmSenders)` / `findDefault(emailSenders)` / `findDefault(emailRepliers)` / first WhatsApp sender). That way the summary row shows a **default delivery setting** (e.g. “Account: Cequens, Sender number: 8123456789”) as soon as options are available.
|
|
78
|
+
- **When delivery setting is not present or options are empty:** If the API returns no domains/senders (empty list) or the user has not selected anything and no default could be set, **show empty values** in the summary row. Do **not** hide the row. Display placeholders such as:
|
|
79
|
+
- “Account: —”, “Sender number: —” (or “Sender domain: —”, “Sender ID: —” for Email), or
|
|
80
|
+
- A single “Not configured” / “No delivery setting” message (e.g. from `messages.notConfigured` like in campaigns).
|
|
81
|
+
- **Summary:** (1) One delivery setting row is always visible above the Send test message button. (2) When options load, auto-set default from first domain + default/first sender so the row shows a default. (3) When no options or no selection, show empty values or “Not configured” in that same row. (4) User can edit at any time via the pencil button.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 3. Implementation Steps (Phase-Wise)
|
|
86
|
+
|
|
87
|
+
### Phase 1: Foundation (APIs, types, folder)
|
|
88
|
+
1. **Ensure APIs in creatives-ui**
|
|
89
|
+
- Confirm `getSenderDetails(channel, orgUnitId)` and `fetchWeCrmAccounts(sourceName)` in `app/services/api.js` are used as-is (no changes if already correct).
|
|
90
|
+
2. **Add parser for sender details**
|
|
91
|
+
- Create `app/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js` (or similar) to normalize `getSenderDetails` response per channel to a structure like: `{ domains: [{ domainId, domainName, gsmSenders, emailSenders, emailRepliers, ... }] }` so UI can consume it like campaigns.
|
|
92
|
+
3. **Create folder and entry files**
|
|
93
|
+
- `CommonTestAndPreview/DeliverySettings/index.js` — re-export or main container.
|
|
94
|
+
- `DeliverySettings/constants.js` — channel keys, default values.
|
|
95
|
+
- `DeliverySettings/messages.js` — copy/adapt labels (Delivery settings, Account, Sender number, Sender domain, Sender ID, Reply-to ID, Done, **notConfigured** for empty-value display when no delivery setting is present, per campaigns `DeliverySettingsV2/messages`).
|
|
96
|
+
|
|
97
|
+
### Phase 2a: Redux — Constants, actions, saga, reducer, selectors
|
|
98
|
+
4. **Constants** (`CommonTestAndPreview/constants.js`)
|
|
99
|
+
- Add: `GET_SENDER_DETAILS_REQUESTED`, `GET_SENDER_DETAILS_SUCCESS`, `GET_SENDER_DETAILS_FAILURE`.
|
|
100
|
+
- Add: `GET_WECRM_ACCOUNTS_REQUESTED`, `GET_WECRM_ACCOUNTS_SUCCESS`, `GET_WECRM_ACCOUNTS_FAILURE`.
|
|
101
|
+
5. **Actions** (`CommonTestAndPreview/actions.js`)
|
|
102
|
+
- Add `getSenderDetailsRequested({ channel, orgUnitId })` — payload: `{ channel, orgUnitId }`.
|
|
103
|
+
- Add `getWeCrmAccountsRequested({ sourceName })` — payload: `{ sourceName }` (e.g. `'WHATSAPP'`).
|
|
104
|
+
6. **Sagas** (`CommonTestAndPreview/sagas.js`)
|
|
105
|
+
- Import `Api.getSenderDetails`, `Api.fetchWeCrmAccounts`, and the parser from `DeliverySettings/utils/parseSenderDetailsResponse`.
|
|
106
|
+
- Add `getSenderDetailsSaga(action)`: call `Api.getSenderDetails(channel, orgUnitId)`; on success parse with parser; `put(GET_SENDER_DETAILS_SUCCESS, { channel, domains })`; on failure `put(GET_SENDER_DETAILS_FAILURE, { channel, error })`.
|
|
107
|
+
- Add `getWeCrmAccountsSaga(action)`: call `Api.fetchWeCrmAccounts(sourceName)`; `put(GET_WECRM_ACCOUNTS_SUCCESS, { accounts })` or FAILURE.
|
|
108
|
+
- Add `watchGetSenderDetails`, `watchGetWeCrmAccounts` (takeLatest); register both in `commonTestAndPreviewSaga()`.
|
|
109
|
+
7. **Reducer** (`CommonTestAndPreview/reducer.js`)
|
|
110
|
+
- Add to initial state (fromJS): `senderDetailsByChannel: { SMS: [], EMAIL: [], WHATSAPP: [] }`, `wecrmAccounts: []`, `isLoadingSenderDetails: false`, `fetchSenderDetailsError: null`, `fetchWeCrmAccountsError: null`.
|
|
111
|
+
- Handle REQUESTED: set loading true, clear error for that request.
|
|
112
|
+
- Handle SUCCESS: set `senderDetailsByChannel[channel]` from payload (or wecrmAccounts), set loading false, clear error.
|
|
113
|
+
- Handle FAILURE: set loading false, set error from payload.
|
|
114
|
+
8. **Selectors** (`CommonTestAndPreview/selectors.js`)
|
|
115
|
+
- Add `makeSelectSenderDetailsForChannel(channel)` — returns `state.commonTestAndPreview.get('senderDetailsByChannel')?.get(channel)` (or toJS for plain array).
|
|
116
|
+
- Add `makeSelectWeCrmAccounts()` — returns wecrmAccounts from state (toJS if Immutable).
|
|
117
|
+
- Add `makeSelectIsLoadingSenderDetails()`, `makeSelectFetchSenderDetailsError()`, `makeSelectFetchWeCrmAccountsError()`.
|
|
118
|
+
- Export all new selectors.
|
|
119
|
+
9. **TestAndPreviewSlidebox** (`TestAndPreviewSlidebox/index.js`)
|
|
120
|
+
- In `mapStateToProps`: add `senderDetailsForChannel: makeSelectSenderDetailsForChannel(state, props.channel)` (or pass channel to selector factory), `wecrmAccounts: makeSelectWeCrmAccounts()(state)`, `isLoadingSenderDetails: makeSelectIsLoadingSenderDetails()(state)`, and error selectors if needed.
|
|
121
|
+
- In `mapDispatchToProps`: ensure `actions` from `bindActionCreators(commonTestAndPreviewActions, dispatch)` includes the new action creators (they will be included once added to actions.js).
|
|
122
|
+
|
|
123
|
+
### Phase 2b: State and data loading in CommonTestAndPreview
|
|
124
|
+
10. **Local state in CommonTestAndPreview (`index.js`)**
|
|
125
|
+
- Add **local** state only for user selection: `testPreviewDeliverySettings` — one object per channel (SMS, EMAIL, WHATSAPP) with shape as in 12.2. Initialize with **empty values** (null/'' ) so that when no options have loaded, the summary row shows **empty values** (Section 2.7). Do **not** store API response in local state; that comes from Redux.
|
|
126
|
+
10a. **Default delivery setting when options load**
|
|
127
|
+
- When Redux `senderDetailsByChannel[channel]` has at least one domain, **auto-set default** into `testPreviewDeliverySettings[channel]` (first domain + `findDefault(senders)` like campaigns DeliverySettingsV2). If API returns empty, leave empty so summary shows empty values. Only set default when current selection is still empty (do not overwrite user’s edit).
|
|
128
|
+
11. **Dispatch Redux actions when Test & Preview opens**
|
|
129
|
+
- In `useEffect` (when `show && channel` is SMS/Email/WhatsApp), dispatch `actions.getSenderDetailsRequested({ channel, orgUnitId: orgUnitId ?? -1 })`. For WhatsApp only, also dispatch `actions.getWeCrmAccountsRequested({ sourceName: 'WHATSAPP' })`. Do not call APIs directly.
|
|
130
|
+
12. **Read sender details and WeCRM accounts from props**
|
|
131
|
+
- Component receives `senderDetailsForChannel` (or per-channel from Redux), `wecrmAccounts`, `isLoadingSenderDetails` from mapStateToProps (via TestAndPreviewSlidebox). Use these when rendering DeliverySettings and when optionally auto-selecting first domain/sender.
|
|
132
|
+
13. **Pass props to SendTestMessage**
|
|
133
|
+
- Pass `channel`, `deliverySettings` (from local state `testPreviewDeliverySettings[channel]`), `senderDetailsOptions` (from Redux prop, e.g. `senderDetailsForChannel`), `wecrmAccounts` (from Redux prop), `onSaveDeliverySettings` (callback that updates local state), `isLoadingSenderDetails` (from Redux prop).
|
|
134
|
+
|
|
135
|
+
### Phase 3: UI — Summary and modal in SendTestMessage
|
|
136
|
+
14. **SendTestMessage.js**
|
|
137
|
+
- Above the “Send test message” button (around lines 46–49), add:
|
|
138
|
+
- **One “Delivery settings” row** that is **always visible** when channel is SMS, EMAIL, or WHATSAPP (do not hide when no selection). Summary shows either: (a) default/selected values (e.g. “Account: X, Sender number: Y”), or (b) **empty values** (“Account: —”, “Sender number: —” or “Not configured”) when no delivery setting is present or options are empty.
|
|
139
|
+
- Pencil (edit) icon; on click open the Delivery Settings **CapSlideBox** (cap-ui-library).
|
|
140
|
+
- Render the DeliverySettings component (summary + CapSlideBox) for SMS, EMAIL, WHATSAPP only; the summary row is always shown for these channels (with default or empty values).
|
|
141
|
+
15. **DeliverySettings component (summary + CapSlideBox trigger)**
|
|
142
|
+
- File: `DeliverySettings/index.js` (or `DeliverySettings/SummaryAndSlideBox.js`).
|
|
143
|
+
- **Always render the summary line** (one row) with either: selected/default values or empty placeholders / “Not configured” when `deliverySettings` has no values or options are empty. Show edit icon (CapIcon); on edit, set “slideBox open” and render **CapSlideBox** with content component (ModifyDeliverySettings). Use **cap-ui-library** components only (CapRow, CapHeader, CapIcon, etc.).
|
|
144
|
+
16. **ModifyDeliverySettings (CapSlideBox content)**
|
|
145
|
+
- File: `DeliverySettings/ModifyDeliverySettings.js` (or `DeliverySettingsSlideBox.js`).
|
|
146
|
+
- **CapSlideBox** (from cap-ui-library) with header “Delivery settings”, close (X), and channel-specific fields:
|
|
147
|
+
- **SMS:** Account (domain) dropdown, Sender number (GSM sender) dropdown.
|
|
148
|
+
- **Email:** Email domain dropdown, Sender name (or Sender ID), Sender ID, Reply-to ID (as in screenshots).
|
|
149
|
+
- **WhatsApp:** Account dropdown (from WeCRM accounts), Sender number dropdown (from sender details for selected account).
|
|
150
|
+
- “Done” button (CapButton): call `onSaveDeliverySettings(selectedValues)` and close CapSlideBox.
|
|
151
|
+
|
|
152
|
+
### Phase 4: Wire payload in prepareTestMessagePayload
|
|
153
|
+
17. **Pass selected delivery settings into payload**
|
|
154
|
+
- In `CommonTestAndPreview`, when building the payload for send test (where `prepareTestMessagePayload` is called), pass the current channel’s `testPreviewDeliverySettings` (or a flat object) as an extra argument or via a closure so that:
|
|
155
|
+
- **EMAIL:** `emailDeliverySettings.channelSettings.senderLabel`, `senderId`, `replyToId` (and `domainId` if needed) come from state.
|
|
156
|
+
- **SMS:** `smsDeliverySettings.channelSettings.gsmSenderId`, `domainId` from state.
|
|
157
|
+
- **WHATSAPP:** `whatsappDeliverySettings.channelSettings.senderMobNum`, `domainId` and `whatsappMessageContent.accountId`/`sourceAccountIdentifier`/`accountName` from state.
|
|
158
|
+
18. **Keep backward compatibility**
|
|
159
|
+
- If user never opens Delivery Settings, keep existing dummy/empty defaults in `prepareTestMessagePayload` so behavior remains as today when no selection is made.
|
|
160
|
+
|
|
161
|
+
### Phase 5: orgUnitId and parent wiring
|
|
162
|
+
19. **orgUnitId propagation**
|
|
163
|
+
- Ensure `orgUnitId` is passed from CreativesContainer (or wherever TestAndPreviewSlidebox is used) down to CommonTestAndPreview (e.g. via TestAndPreviewSlidebox). In SlideBoxContent / parent containers that render TestAndPreviewSlidebox, pass `orgUnitId` when available; default to `-1` in CommonTestAndPreview if undefined.
|
|
164
|
+
20. **Styling and i18n**
|
|
165
|
+
- Use **cap-ui-library** only: **CapSlideBox** for the delivery settings panel, CapSelect/CapCustomSelect for dropdowns, CapButton for Done, CapRow/CapHeader/CapIcon for summary row. Add any new keys to `DeliverySettings/messages.js` and CommonTestAndPreview `messages.js` if needed.
|
|
166
|
+
|
|
167
|
+
### Phase 6: Testing and cleanup
|
|
168
|
+
21. **Unit tests**
|
|
169
|
+
- Update or add tests for: SendTestMessage (delivery settings summary + conditional render), DeliverySettings open/close and callback, `prepareTestMessagePayload` when delivery settings are provided (SMS, Email, WhatsApp), and **Redux**: saga tests for getSenderDetailsSaga and getWeCrmAccountsSaga (mock Api and parser), reducer tests for new action types, selector tests.
|
|
170
|
+
22. **Manual verification**
|
|
171
|
+
- For SMS, Email, WhatsApp: open Test & Preview → set delivery settings → send test message and confirm payload and delivery use selected sender/domain/account.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 4. Critical Files Checklist
|
|
176
|
+
|
|
177
|
+
### New files (to create)
|
|
178
|
+
| Path | Purpose |
|
|
179
|
+
|------|--------|
|
|
180
|
+
| `CommonTestAndPreview/DeliverySettings/index.js` | Export or main DeliverySettings wrapper (summary + CapSlideBox trigger) |
|
|
181
|
+
| `CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js` | **CapSlideBox** (cap-ui-library) content with channel-specific fields and Done |
|
|
182
|
+
| `CommonTestAndPreview/DeliverySettings/constants.js` | Channel keys, default structures |
|
|
183
|
+
| `CommonTestAndPreview/DeliverySettings/messages.js` | Copy/adapt labels (Delivery settings, Account, Sender number, etc.) |
|
|
184
|
+
| `CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js` | Normalize getSenderDetails response per channel |
|
|
185
|
+
| Optional: `CommonTestAndPreview/DeliverySettings/DeliverySettingsSummary.js` | Summary line + edit icon only (if split from index) |
|
|
186
|
+
|
|
187
|
+
### Files to modify
|
|
188
|
+
| Path | Changes |
|
|
189
|
+
|------|--------|
|
|
190
|
+
| `CommonTestAndPreview/constants.js` | Add GET_SENDER_DETAILS_REQUESTED/SUCCESS/FAILURE, GET_WECRM_ACCOUNTS_REQUESTED/SUCCESS/FAILURE |
|
|
191
|
+
| `CommonTestAndPreview/actions.js` | Add getSenderDetailsRequested({ channel, orgUnitId }), getWeCrmAccountsRequested({ sourceName }) |
|
|
192
|
+
| `CommonTestAndPreview/sagas.js` | Add getSenderDetailsSaga (call Api.getSenderDetails, parse, put SUCCESS/FAILURE), getWeCrmAccountsSaga (call Api.fetchWeCrmAccounts, put SUCCESS/FAILURE); watchGetSenderDetails, watchGetWeCrmAccounts; register in commonTestAndPreviewSaga() |
|
|
193
|
+
| `CommonTestAndPreview/reducer.js` | Add initial state: senderDetailsByChannel, wecrmAccounts, isLoadingSenderDetails, fetchSenderDetailsError, fetchWeCrmAccountsError; handle all six new action types |
|
|
194
|
+
| `CommonTestAndPreview/selectors.js` | Add makeSelectSenderDetailsForChannel, makeSelectWeCrmAccounts, makeSelectIsLoadingSenderDetails, makeSelectFetchSenderDetailsError, makeSelectFetchWeCrmAccountsError; export them |
|
|
195
|
+
| `TestAndPreviewSlidebox/index.js` | In mapStateToProps add senderDetailsForChannel, wecrmAccounts, isLoadingSenderDetails (using new selectors); actions already get new creators via bindActionCreators |
|
|
196
|
+
| `CommonTestAndPreview/index.js` | Add **local** state only for testPreviewDeliverySettings (user selection); in useEffect dispatch actions.getSenderDetailsRequested and actions.getWeCrmAccountsRequested (no direct API calls); read senderDetailsForChannel, wecrmAccounts, isLoadingSenderDetails from props; pass props to SendTestMessage; pass delivery settings into prepareTestMessagePayload; accept orgUnitId prop |
|
|
197
|
+
| `CommonTestAndPreview/SendTestMessage.js` | Add Delivery settings summary row + edit icon above Send button; render DeliverySettings component (only for SMS, EMAIL, WHATSAPP); pass channel, deliverySettings, senderDetailsOptions (from Redux), wecrmAccounts, onSaveDeliverySettings, isLoadingSenderDetails |
|
|
198
|
+
| `CommonTestAndPreview/index.js` (prepareTestMessagePayload) | In EMAIL/SMS/WHATSAPP branches, override channelSettings (and WhatsApp account fields) from the selected delivery settings (local state) instead of empty strings/null |
|
|
199
|
+
|
|
200
|
+
### Files referenced (no edits)
|
|
201
|
+
| Path | Use |
|
|
202
|
+
|------|-----|
|
|
203
|
+
| `app/services/api.js` | getSenderDetails(channel, orgUnitId), fetchWeCrmAccounts(sourceName) |
|
|
204
|
+
| cap-campaigns-v2 DeliverySettingsV2, ModifyDeliverySettings, SenderDetails | Reference only for UI layout and field names (Account, Sender number, Sender domain, Sender ID, Reply-to ID) |
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 5. UI Component Patterns to Follow
|
|
209
|
+
|
|
210
|
+
- **Summary row (always visible):** **Always show one** “Delivery settings” summary row above the Send test message button when channel is SMS/Email/WhatsApp. Single line (or short block) of text: either (a) selected/default values (e.g. “Account: Cequens, Sender number: 8123456789”) or (b) **empty values** when no delivery setting is present — e.g. “Account: —”, “Sender number: —” or a single “Not configured” message (campaigns use `notConfigured` from messages). Pencil (edit) icon next to it; same line or next line as “Delivery settings” label (see screenshots).
|
|
211
|
+
- **Delivery settings panel:** Use **CapSlideBox** from **cap-ui-library** (not CapModal). Title “Delivery settings”, X to close, then:
|
|
212
|
+
- **SMS:** Account (domain) dropdown, Sender number dropdown, Done.
|
|
213
|
+
- **Email:** Email domain, Sender name, Sender ID, Reply-to ID dropdowns, Done.
|
|
214
|
+
- **WhatsApp:** Account dropdown (WeCRM), Sender number dropdown, Done.
|
|
215
|
+
- **All UI from cap-ui-library:** Use **CapSlideBox**, **CapSelect** / **CapCustomSelect**, **CapButton**, **CapRow**, **CapHeader**, **CapLabel**, **CapIcon**, etc. No custom modals or non-library form elements. Reuse existing CommonTestAndPreview styling (e.g. `_commonTestAndPreview.scss` or `_deliverySettings.scss` under DeliverySettings folder).
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## 6. Validation Logic Summary
|
|
220
|
+
|
|
221
|
+
- **Modal Done:**
|
|
222
|
+
- For SMS/Email: require at least domain and main sender selected (gsmSenderId / senderEmail) before enabling Done (or allow Done and validate on send).
|
|
223
|
+
- For WhatsApp: require account and sender number when list is non-empty.
|
|
224
|
+
- **Send test message:**
|
|
225
|
+
- Keep existing validation (e.g. test entities selected). Optionally: if channel is SMS/Email/WhatsApp and delivery settings are still “empty” (user never opened the CapSlideBox), either block send with a message “Please configure delivery settings” or keep current behavior (send with defaults) per product decision. Recommendation: allow send with defaults for backward compatibility; show warning if desired.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## 7. Testing & Verification
|
|
230
|
+
|
|
231
|
+
- **Unit:** SendTestMessage shows delivery summary and edit only for SMS/EMAIL/WHATSAPP; ModifyDeliverySettings receives options and calls onSave with selected values; prepareTestMessagePayload uses passed delivery settings for EMAIL/SMS/WHATSAPP branches.
|
|
232
|
+
- **Integration:** Open Test & Preview for SMS, Email, WhatsApp; open Delivery settings → select domain/sender → Done; send test message; verify request payload contains selected gsmSenderId/domainId (SMS), senderId/replyToId/domainId (Email), senderMobNum/domainId and account info (WhatsApp).
|
|
233
|
+
- **Regression:** Other channels (RCS, InApp, etc.) unchanged; no delivery settings block shown; send test still works with existing payload.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## 8. Backward Compatibility
|
|
238
|
+
|
|
239
|
+
- **Channels other than SMS, Email, WhatsApp:** No UI change; no new state; prepareTestMessagePayload unchanged for those channels.
|
|
240
|
+
- **No selection:** If user does not open Delivery Settings, keep existing default/empty values in payload (ouId: -1, empty sender IDs, etc.) so current behavior is preserved. When options have loaded, the **default** delivery setting (first domain + default sender) is shown in the summary; when options are empty, **empty values** are shown in the same row (Section 2.7).
|
|
241
|
+
- **Empty delivery setting:** If no options or no selection, the **one** delivery setting row is still visible with empty values / “Not configured”; user can click edit to open the **CapSlideBox** (which may show empty dropdowns until options exist).
|
|
242
|
+
- **orgUnitId:** Default to `-1` when not passed from parent; getSenderDetails and backend should tolerate -1 as “global” or default org.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## 9. Notes & Constraints
|
|
247
|
+
|
|
248
|
+
- **UI library:** Use **cap-ui-library** (`@capillarytech/cap-ui-library`) for all delivery-settings UI. The edit panel must be **CapSlideBox** (not CapModal). Use CapRow, CapHeader, CapLabel, CapIcon, CapSelect/CapCustomSelect, CapButton, etc. from the same library. No custom modals or non-library form elements.
|
|
249
|
+
- **No cross-repo imports:** Do not import from cap-campaigns-v2; only reference their UI/flow for design.
|
|
250
|
+
- **Single channel per screen:** Test & Preview is always for one channel at a time; delivery settings state can be a single object for “current channel” or keyed by channel for simplicity.
|
|
251
|
+
- **API response shape:** If creatives backend returns a different structure for `getSenderDetails(channel, orgUnitId)` (e.g. single object instead of array), the parser in DeliverySettings utils must normalize it to the expected shape (list of domains with senders).
|
|
252
|
+
- **WhatsApp account:** If fetchWeCrmAccounts is used, map response to a dropdown; then use selected account’s identifier to filter or select sender numbers from getSenderDetails('WHATSAPP') if the API returns per-account data; otherwise use first domain / first sender as default.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## 10. Architecture Diagram
|
|
257
|
+
|
|
258
|
+
```text
|
|
259
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
260
|
+
│ CommonTestAndPreview (index.js) │
|
|
261
|
+
│ • State: testPreviewDeliverySettings, senderDetailsOptions, loading │
|
|
262
|
+
│ • useEffect: getSenderDetails(channel, orgUnitId) [+ fetchWeCrmAccounts │
|
|
263
|
+
│ for WHATSAPP] when show && channel in [SMS,EMAIL,WHATSAPP] │
|
|
264
|
+
│ • prepareTestMessagePayload(..., deliverySettings) → uses state for │
|
|
265
|
+
│ emailDeliverySettings / smsDeliverySettings / whatsappDeliverySettings │
|
|
266
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
267
|
+
│
|
|
268
|
+
│ props: channel, deliverySettings, senderDetailsOptions,
|
|
269
|
+
│ onOpenDeliverySettings, onSaveDeliverySettings, orgUnitId
|
|
270
|
+
▼
|
|
271
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
272
|
+
│ SendTestMessage.js │
|
|
273
|
+
│ • Test customers TreeSelect │
|
|
274
|
+
│ • [NEW] Delivery settings summary row + pencil icon (only SMS/EMAIL/WA) │
|
|
275
|
+
│ • [NEW] <DeliverySettings ... /> (renders summary + CapSlideBox) │
|
|
276
|
+
│ • Send test message button │
|
|
277
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
278
|
+
│
|
|
279
|
+
│ when pencil clicked → open CapSlideBox
|
|
280
|
+
▼
|
|
281
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
282
|
+
│ DeliverySettings/ (new folder) │
|
|
283
|
+
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
284
|
+
│ │ index.js (summary + CapSlideBox trigger) │ │
|
|
285
|
+
│ │ • Summary line: "Account: X, Sender number: Y" / "Sender domain: │ │
|
|
286
|
+
│ │ X, Sender ID: Y" (cap-ui-library: CapRow, CapHeader, CapIcon) │ │
|
|
287
|
+
│ │ • Pencil icon → setState(slideBoxOpen true) → render CapSlideBox │ │
|
|
288
|
+
│ │ with ModifyDeliverySettings content │ │
|
|
289
|
+
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
290
|
+
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
291
|
+
│ │ ModifyDeliverySettings.js (CapSlideBox content, cap-ui-library) │ │
|
|
292
|
+
│ │ • SMS: Account dropdown, Sender number dropdown │ │
|
|
293
|
+
│ │ • Email: Email domain, Sender name, Sender ID, Reply-to ID │ │
|
|
294
|
+
│ │ • WhatsApp: Account dropdown (WeCRM), Sender number dropdown │ │
|
|
295
|
+
│ │ • Done → onSaveDeliverySettings(values) → parent updates state │ │
|
|
296
|
+
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
297
|
+
│ utils/parseSenderDetailsResponse.js → normalize getSenderDetails response │
|
|
298
|
+
│ constants.js, messages.js │
|
|
299
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
300
|
+
│
|
|
301
|
+
│ onSaveDeliverySettings(selected)
|
|
302
|
+
▼
|
|
303
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
304
|
+
│ CommonTestAndPreview: setState(testPreviewDeliverySettings) │
|
|
305
|
+
│ → next prepareTestMessagePayload() uses updated state for payload │
|
|
306
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
307
|
+
|
|
308
|
+
External APIs (app/services/api.js)
|
|
309
|
+
───────────────────────────────────
|
|
310
|
+
getSenderDetails(channel, orgUnitId)
|
|
311
|
+
fetchWeCrmAccounts(sourceName) [WhatsApp account list]
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## 11. Architecture Diagram (Mermaid)
|
|
317
|
+
|
|
318
|
+
```mermaid
|
|
319
|
+
flowchart TB
|
|
320
|
+
subgraph Root["CommonTestAndPreview (index.js)"]
|
|
321
|
+
State["State: testPreviewDeliverySettings,\nsenderDetailsOptions, loading"]
|
|
322
|
+
Fetch["useEffect: getSenderDetails(channel, orgUnitId)\n+ fetchWeCrmAccounts for WHATSAPP"]
|
|
323
|
+
Payload["prepareTestMessagePayload(..., deliverySettings)"]
|
|
324
|
+
State --> Fetch
|
|
325
|
+
Fetch --> State
|
|
326
|
+
State --> Payload
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
subgraph SendTest["SendTestMessage.js"]
|
|
330
|
+
TreeSelect["Test customers TreeSelect"]
|
|
331
|
+
Summary["Delivery settings summary + pencil icon"]
|
|
332
|
+
DSComponent["<DeliverySettings />"]
|
|
333
|
+
Button["Send test message button"]
|
|
334
|
+
TreeSelect --> Summary
|
|
335
|
+
Summary --> DSComponent
|
|
336
|
+
DSComponent --> Button
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
subgraph DeliveryFolder["DeliverySettings/ (new folder, cap-ui-library)"]
|
|
340
|
+
SummarySlideBox["index.js: Summary line + open CapSlideBox"]
|
|
341
|
+
SlideBoxContent["ModifyDeliverySettings.js: CapSlideBox content"]
|
|
342
|
+
SMSFields["SMS: Account, Sender number"]
|
|
343
|
+
EmailFields["Email: Domain, Sender name, Sender ID, Reply-to"]
|
|
344
|
+
WAFields["WhatsApp: Account, Sender number"]
|
|
345
|
+
Done["Done → onSaveDeliverySettings"]
|
|
346
|
+
SummarySlideBox --> SlideBoxContent
|
|
347
|
+
SlideBoxContent --> SMSFields
|
|
348
|
+
SlideBoxContent --> EmailFields
|
|
349
|
+
SlideBoxContent --> WAFields
|
|
350
|
+
SMSFields --> Done
|
|
351
|
+
EmailFields --> Done
|
|
352
|
+
WAFields --> Done
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
subgraph API["app/services/api.js"]
|
|
356
|
+
getSender["getSenderDetails(channel, orgUnitId)"]
|
|
357
|
+
wecrm["fetchWeCrmAccounts(sourceName)"]
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
Root -->|channel, deliverySettings, callbacks| SendTest
|
|
361
|
+
SendTest -->|pencil click| DeliveryFolder
|
|
362
|
+
Done -->|update state| Root
|
|
363
|
+
Fetch --> getSender
|
|
364
|
+
Fetch --> wecrm
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## 12. HIGH-LEVEL DETAILED FULL PLAN (Line-by-Line)
|
|
370
|
+
|
|
371
|
+
This section provides a broad, exhaustive breakdown of the entire implementation so that every step, data shape, and touchpoint is explicit. Use it as the single source of truth when implementing.
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
### 12.1 Business and User-Flow Context
|
|
376
|
+
|
|
377
|
+
1. **User journey (high level)**
|
|
378
|
+
User is in Creatives (e.g. SMS/Email/WhatsApp template create or edit) → clicks “Preview and Test” → Test and Preview slidebox opens → user sees left panel (customer, custom values, **Send test message** section).
|
|
379
|
+
Today: under “Send test message” there is only “Test customers” and “Send test message” button.
|
|
380
|
+
Target: above the button we add a **Delivery settings** row (summary text + pencil).
|
|
381
|
+
User can leave it as-is (defaults) or click pencil → **Delivery settings** **CapSlideBox** (cap-ui-library) opens → user selects Account/Domain and Sender (number or email/reply-to per channel) → Done → CapSlideBox closes, summary updates.
|
|
382
|
+
When user clicks “Send test message”, the payload sent to the backend must include the **selected** delivery settings (domain, sender IDs) for that channel, not dummy values.
|
|
383
|
+
|
|
384
|
+
2. **Channels in scope**
|
|
385
|
+
Only **SMS**, **Email**, **WhatsApp**. All other channels (RCS, Viber, Zalo, InApp, MobilePush, etc.) must show no delivery settings block and must retain current payload behaviour.
|
|
386
|
+
|
|
387
|
+
3. **APIs involved**
|
|
388
|
+
- **getSenderDetails(channel, orgUnitId)** in `app/services/api.js`: returns domain properties for one channel (list of domains with senders). Used for all three channels.
|
|
389
|
+
- **fetchWeCrmAccounts(sourceName)** in `app/services/api.js`: returns WeCRM/Meta accounts; used for **WhatsApp** to show “Account” dropdown (e.g. sourceName `'WHATSAPP'`).
|
|
390
|
+
- Both are existing; no new API creation. Only consumption and response normalization in creatives.
|
|
391
|
+
|
|
392
|
+
4. **Where state lives**
|
|
393
|
+
- **Redux (existing CommonTestAndPreview slice):** Sender-details options (per channel) and WeCRM accounts, plus loading/error flags. The two APIs **getSenderDetails** and **fetchWeCrmAccounts** are invoked only via **Redux actions and redux-saga** (see Section 2.2). Use existing files: `constants.js`, `actions.js`, `sagas.js`, `reducer.js`, `selectors.js`.
|
|
394
|
+
- **Local state in CommonTestAndPreview (`index.js`):** Only the **user-selected** delivery settings (`testPreviewDeliverySettings` keyed by channel) used for the summary, CapSlideBox default selection, and `prepareTestMessagePayload`.
|
|
395
|
+
- Child components (SendTestMessage → DeliverySettings → ModifyDeliverySettings) receive API-derived data from Redux (via props from TestAndPreviewSlidebox) and user selection + callbacks from CommonTestAndPreview.
|
|
396
|
+
|
|
397
|
+
5. **Where payload is built**
|
|
398
|
+
**prepareTestMessagePayload** inside `CommonTestAndPreview/index.js` (same file). Today it builds `emailDeliverySettings`, `smsDeliverySettings`, `whatsappDeliverySettings` with empty/default values. After implementation it must read from the component’s delivery-settings state and merge those values into the same payload structures.
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
### 12.2 Data Structures (Exact Shapes)
|
|
403
|
+
|
|
404
|
+
6. **Normalized sender-details options (after parsing API response)**
|
|
405
|
+
Stored in **Redux** as `senderDetailsByChannel` (reducer state). Structure keyed by channel:
|
|
406
|
+
|
|
407
|
+
- **SMS:**
|
|
408
|
+
`senderDetailsOptions.SMS` = array of domain objects:
|
|
409
|
+
`{ domainId, domainName, dgmId?, gsmSenders: [{ value, label, default? }], cdmaSenders?: [...] }`
|
|
410
|
+
|
|
411
|
+
- **EMAIL:**
|
|
412
|
+
`senderDetailsOptions.EMAIL` = array of domain objects:
|
|
413
|
+
`{ domainId, domainName, dgmId?, emailSenders: [{ value, label, default? }], emailRepliers: [{ value, label, default? }] }`
|
|
414
|
+
|
|
415
|
+
- **WHATSAPP:**
|
|
416
|
+
`senderDetailsOptions.WHATSAPP` = array of domain/account objects:
|
|
417
|
+
`{ domainId, domainName?, sourceAccountIdentifier?, gsmSenders: [{ value, label }], ... }`
|
|
418
|
+
Plus optionally a separate list for WeCRM accounts:
|
|
419
|
+
`wecrmAccounts` = `[{ id, name, sourceAccountIdentifier?, ... }]` for the Account dropdown.
|
|
420
|
+
|
|
421
|
+
7. **Selected delivery settings (user’s choice)**
|
|
422
|
+
Stored in **local component state** in CommonTestAndPreview as `testPreviewDeliverySettings` (keyed by channel). One object per channel; for the current screen only the current channel’s object is used. Suggested shape:
|
|
423
|
+
|
|
424
|
+
- **SMS:**
|
|
425
|
+
`{ domainId: number | null, gsmSenderId: string, domainName?: string }`
|
|
426
|
+
|
|
427
|
+
- **EMAIL:**
|
|
428
|
+
`{ domainId: number | null, senderId: string, senderLabel: string, replyToId: string, domainName?: string }`
|
|
429
|
+
(senderId = selected sender email value; replyToId = selected reply-to value)
|
|
430
|
+
|
|
431
|
+
- **WHATSAPP:**
|
|
432
|
+
`{ domainId: number | null, senderMobNum: string, accountId?: string, sourceAccountIdentifier?: string, accountName?: string, domainName?: string }`
|
|
433
|
+
|
|
434
|
+
8. **Defaults when user never opens CapSlideBox**
|
|
435
|
+
Keep existing behaviour: empty string for sender IDs, null for domainId. So initial state can be e.g.
|
|
436
|
+
`testPreviewDeliverySettings = { SMS: { domainId: null, gsmSenderId: '' }, EMAIL: { ... }, WHATSAPP: { ... } }`
|
|
437
|
+
or lazy-initialized when channel is first set.
|
|
438
|
+
|
|
439
|
+
9. **Payload mapping (what goes into API request)**
|
|
440
|
+
- **EMAIL:**
|
|
441
|
+
`emailDeliverySettings.channelSettings.senderLabel` ← state.senderLabel
|
|
442
|
+
`emailDeliverySettings.channelSettings.senderId` ← state.senderId
|
|
443
|
+
`emailDeliverySettings.channelSettings.replyToId` ← state.replyToId
|
|
444
|
+
`emailDeliverySettings.channelSettings.domainId` ← state.domainId (if API expects it)
|
|
445
|
+
|
|
446
|
+
- **SMS:**
|
|
447
|
+
`smsDeliverySettings.channelSettings.gsmSenderId` ← state.gsmSenderId
|
|
448
|
+
`smsDeliverySettings.channelSettings.domainId` ← state.domainId
|
|
449
|
+
|
|
450
|
+
- **WHATSAPP:**
|
|
451
|
+
`whatsappDeliverySettings.channelSettings.senderMobNum` ← state.senderMobNum
|
|
452
|
+
`whatsappDeliverySettings.channelSettings.domainId` ← state.domainId
|
|
453
|
+
`whatsappMessageContent.accountId` / `sourceAccountIdentifier` / `accountName` ← from state when available (so backend can associate test with correct WhatsApp account).
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
### 12.3 Phase 1 — Foundation (Detailed Steps)
|
|
458
|
+
|
|
459
|
+
10. **Verify APIs**
|
|
460
|
+
- Open `app/services/api.js`.
|
|
461
|
+
- Confirm `getSenderDetails(channel, orgUnitId)` exists and signature is `(channel, orgUnitId)` (single channel).
|
|
462
|
+
- Confirm `fetchWeCrmAccounts(sourceName)` exists and accepts e.g. `'WHATSAPP'`.
|
|
463
|
+
- No code change if already correct; these will be called from **redux-saga** (getSenderDetailsSaga, getWeCrmAccountsSaga), not from the component. Responses will be parsed in the saga (using DeliverySettings parser) before dispatching SUCCESS.
|
|
464
|
+
|
|
465
|
+
11. **Create parser utility**
|
|
466
|
+
- **New file:** `app/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js`.
|
|
467
|
+
- **Input:** Raw response from `getSenderDetails(channel, orgUnitId)`. Backend might return e.g. `{ entity: { SMS: [...] } }` or `{ entity: [ { id, domainProperties, ... } ] }` or a single-channel array.
|
|
468
|
+
- **Output:** A normalized structure for that channel: `{ domains: [ { domainId, domainName, gsmSenders, emailSenders, emailRepliers, ... } ] }` so that UI can assume the same shape for SMS, EMAIL, WHATSAPP (with channel-specific sender arrays).
|
|
469
|
+
- **Logic:** If response is array of domain-gateway objects (like campaigns), map each to domainId, domainName, and extract contactInfo into gsmSenders / emailSenders / emailRepliers using type keys (e.g. gsm_sender_id, sender_id, reply_to_id). If response is already a list of domains, map similarly. Export a single function e.g. `parseSenderDetailsResponse(channel, rawResponse)`.
|
|
470
|
+
|
|
471
|
+
12. **Create DeliverySettings folder and constants**
|
|
472
|
+
- **New file:** `CommonTestAndPreview/DeliverySettings/constants.js`.
|
|
473
|
+
- Export: `CHANNELS_WITH_DELIVERY_SETTINGS = ['SMS', 'EMAIL', 'WHATSAPP']`.
|
|
474
|
+
- Export default structures for each channel, e.g. `DEFAULT_SMS_DELIVERY_SETTINGS`, `DEFAULT_EMAIL_DELIVERY_SETTINGS`, `DEFAULT_WHATSAPP_DELIVERY_SETTINGS` (null/empty values).
|
|
475
|
+
- Export any key names used in payload (e.g. gsmSenderId, senderId, replyToId) so both UI and payload builder use the same keys.
|
|
476
|
+
|
|
477
|
+
13. **Create messages (i18n)**
|
|
478
|
+
- **New file:** `CommonTestAndPreview/DeliverySettings/messages.js`.
|
|
479
|
+
- Use `defineMessages` (react-intl). Add: deliverySettings (title), account, senderNumber, senderDomain, senderId, senderName, replyToId, done, notConfigured, reset (if needed).
|
|
480
|
+
- Scope id e.g. `app.v2Components.CommonTestAndPreview.DeliverySettings.*`.
|
|
481
|
+
- These will be used in both the summary line and the modal.
|
|
482
|
+
|
|
483
|
+
14. **Create DeliverySettings index (shell)**
|
|
484
|
+
- **New file:** `CommonTestAndPreview/DeliverySettings/index.js`.
|
|
485
|
+
- Initially export a simple component that accepts props: `channel`, `deliverySettings`, `senderDetailsOptions`, `onSaveDeliverySettings`, `formatMessage` (or intl).
|
|
486
|
+
- Component **always** renders: (1) **one** summary row (label “Delivery settings” + summary text + pencil icon; use **cap-ui-library** CapRow, CapHeader, CapIcon), (2) when pencil is clicked, state `isSlideBoxOpen = true` and render **CapSlideBox** (cap-ui-library) with content component (ModifyDeliverySettings).
|
|
487
|
+
- Summary text: when values exist — for SMS/WhatsApp “Account: {domainName or accountName}, Sender number: {gsmSenderId or senderMobNum}”; for Email “Sender domain: {domainName}, Sender ID: {senderId}” (and optionally Reply-to). When **no delivery setting is present or values are empty**, show **empty values** (e.g. “Account: —”, “Sender number: —”) or a single “Not configured” message from messages (campaigns use `messages.notConfigured`). Do not hide the row when empty.
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
### 12.4 Phase 2a — Redux: Constants, Actions, Saga, Reducer, Selectors (Detailed Steps)
|
|
492
|
+
|
|
493
|
+
15. **Constants** (`CommonTestAndPreview/constants.js`)
|
|
494
|
+
- Add: `GET_SENDER_DETAILS_REQUESTED = 'app/CommonTestAndPreview/GET_SENDER_DETAILS_REQUESTED'`, `GET_SENDER_DETAILS_SUCCESS`, `GET_SENDER_DETAILS_FAILURE`.
|
|
495
|
+
- Add: `GET_WECRM_ACCOUNTS_REQUESTED`, `GET_WECRM_ACCOUNTS_SUCCESS`, `GET_WECRM_ACCOUNTS_FAILURE`.
|
|
496
|
+
- Follow existing naming pattern (e.g. same prefix as other action types in the file).
|
|
497
|
+
|
|
498
|
+
16. **Actions** (`CommonTestAndPreview/actions.js`)
|
|
499
|
+
- Import the new constants.
|
|
500
|
+
- Add `getSenderDetailsRequested({ channel, orgUnitId })` returning `{ type: GET_SENDER_DETAILS_REQUESTED, payload: { channel, orgUnitId } }`.
|
|
501
|
+
- Add `getWeCrmAccountsRequested({ sourceName })` returning `{ type: GET_WECRM_ACCOUNTS_REQUESTED, payload: { sourceName } }`.
|
|
502
|
+
|
|
503
|
+
17. **Sagas** (`CommonTestAndPreview/sagas.js`)
|
|
504
|
+
- Import `Api.getSenderDetails`, `Api.fetchWeCrmAccounts` from `../../services/api`.
|
|
505
|
+
- Import parser: `parseSenderDetailsResponse` from `./DeliverySettings/utils/parseSenderDetailsResponse` (or relative path from sagas.js to the utils file).
|
|
506
|
+
- **getSenderDetailsSaga(action):** From action.payload take `channel`, `orgUnitId`. `yield call(Api.getSenderDetails, channel, orgUnitId ?? -1)`. On success: `parsed = parseSenderDetailsResponse(channel, response)` (adapt to actual API response shape, e.g. response.entity). `yield put({ type: GET_SENDER_DETAILS_SUCCESS, payload: { channel, domains: parsed.domains } })`. On catch or API error: `yield put({ type: GET_SENDER_DETAILS_FAILURE, payload: { channel, error } })`.
|
|
507
|
+
- **getWeCrmAccountsSaga(action):** Take `sourceName` from payload. `yield call(Api.fetchWeCrmAccounts, sourceName)`. On success map response to list of accounts and `yield put(GET_WECRM_ACCOUNTS_SUCCESS, { accounts })`; on failure `yield put(GET_WECRM_ACCOUNTS_FAILURE, { error })`.
|
|
508
|
+
- Add **watchGetSenderDetails**: `yield takeLatest(GET_SENDER_DETAILS_REQUESTED, getSenderDetailsSaga)`.
|
|
509
|
+
- Add **watchGetWeCrmAccounts**: `yield takeLatest(GET_WECRM_ACCOUNTS_REQUESTED, getWeCrmAccountsSaga)`.
|
|
510
|
+
- In **commonTestAndPreviewSaga()**, add `watchGetSenderDetails()`, `watchGetWeCrmAccounts()` to the `all([...])` array.
|
|
511
|
+
|
|
512
|
+
18. **Reducer** (`CommonTestAndPreview/reducer.js`)
|
|
513
|
+
- Import the six new action type constants.
|
|
514
|
+
- In **initialState** (fromJS): add `senderDetailsByChannel: fromJS({ SMS: [], EMAIL: [], WHATSAPP: [] })`, `wecrmAccounts: fromJS([])`, `isLoadingSenderDetails: false`, `fetchSenderDetailsError: null`, `fetchWeCrmAccountsError: null`.
|
|
515
|
+
- **GET_SENDER_DETAILS_REQUESTED:** `return state.set('isLoadingSenderDetails', true).set('fetchSenderDetailsError', null)`.
|
|
516
|
+
- **GET_SENDER_DETAILS_SUCCESS:** `return state.setIn(['senderDetailsByChannel', action.payload.channel], fromJS(action.payload.domains)).set('isLoadingSenderDetails', false).set('fetchSenderDetailsError', null)`.
|
|
517
|
+
- **GET_SENDER_DETAILS_FAILURE:** `return state.set('isLoadingSenderDetails', false).set('fetchSenderDetailsError', action.payload.error)`.
|
|
518
|
+
- **GET_WECRM_ACCOUNTS_REQUESTED:** set loading or a separate flag if desired; clear fetchWeCrmAccountsError.
|
|
519
|
+
- **GET_WECRM_ACCOUNTS_SUCCESS:** `return state.set('wecrmAccounts', fromJS(action.payload.accounts)).set('fetchWeCrmAccountsError', null)`.
|
|
520
|
+
- **GET_WECRM_ACCOUNTS_FAILURE:** set fetchWeCrmAccountsError. (If using a single loading flag for both APIs, clear it on both SUCCESS/FAILURE.)
|
|
521
|
+
|
|
522
|
+
19. **Selectors** (`CommonTestAndPreview/selectors.js`)
|
|
523
|
+
- **makeSelectSenderDetailsForChannel:** Factory that takes `channel` and returns a selector: `createSelector(selectCommonTestAndPreviewDomain, (substate) => substate?.get('senderDetailsByChannel')?.get(channel)?.toJS?.() ?? [])`.
|
|
524
|
+
- **makeSelectWeCrmAccounts:** `createSelector(selectCommonTestAndPreviewDomain, (substate) => substate?.get('wecrmAccounts')?.toJS?.() ?? [])`.
|
|
525
|
+
- **makeSelectIsLoadingSenderDetails:** `createSelector(selectCommonTestAndPreviewDomain, (substate) => substate?.get('isLoadingSenderDetails') ?? false)`.
|
|
526
|
+
- **makeSelectFetchSenderDetailsError**, **makeSelectFetchWeCrmAccountsError** similarly.
|
|
527
|
+
- Export all new selectors at the bottom of the file.
|
|
528
|
+
|
|
529
|
+
20. **TestAndPreviewSlidebox** (`TestAndPreviewSlidebox/index.js`)
|
|
530
|
+
- In **mapStateToProps:** Add `senderDetailsForChannel: makeSelectSenderDetailsForChannel(state, props?.channel)(state)` — note: if the selector is a factory that needs channel, pass current channel (from props) so the selected channel’s data is passed to CommonTestAndPreview. Alternatively use a selector that takes state and returns an object keyed by channel and let the component pick by channel. E.g. `senderDetailsByChannel: makeSelectSenderDetailsByChannel()(state)` and pass the whole object; then in CommonTestAndPreview use `senderDetailsByChannel[channel]`. Define **makeSelectSenderDetailsByChannel** to return the full senderDetailsByChannel map (toJS).
|
|
531
|
+
- Add `wecrmAccounts: makeSelectWeCrmAccounts()(state)`, `isLoadingSenderDetails: makeSelectIsLoadingSenderDetails()(state)`.
|
|
532
|
+
- Pass these as props to CommonTestAndPreview. The existing `bindActionCreators(commonTestAndPreviewActions, dispatch)` will automatically include the new action creators once they are added to actions.js.
|
|
533
|
+
|
|
534
|
+
### 12.5 Phase 2b — Component: Local State, Dispatch, Pass Props (Detailed Steps)
|
|
535
|
+
|
|
536
|
+
21. **Local state in CommonTestAndPreview**
|
|
537
|
+
- Add only **local** state: `testPreviewDeliverySettings` — object keyed by channel (SMS, EMAIL, WHATSAPP), each value the shape in step 7. Initialize with **empty defaults** (null/'' for ids and sender values) so that when no options have loaded yet, the summary can show **empty values** (see Section 2.7). Do **not** add local state for senderDetailsOptions or wecrmAccounts; those come from Redux via props.
|
|
538
|
+
|
|
539
|
+
21a. **Auto-set default delivery setting when options load (campaigns-style)**
|
|
540
|
+
- When `senderDetailsByChannel[channel]` (from Redux) becomes available and has at least one domain, **set a default** into `testPreviewDeliverySettings[channel]` so the **one delivery setting row shows a default** above the Send test message button. Use the same logic as **campaigns** `DeliverySettingsV2/index.js`: take the **first domain**; for SMS use `findDefault(gsmSenders).value` or `gsmSenders?.[0]?.value`; for EMAIL use `findDefault(emailSenders)` and `findDefault(emailRepliers).value`; for WHATSAPP use first matching entry and `gsmSenders[0]?.value`. Helper: `findDefault(array) => find(array, { default: true }) || array?.[0]`. Run this in a `useEffect` that depends on `senderDetailsByChannel[channel]` and channel; only set default if current `testPreviewDeliverySettings[channel]` is still empty (so user’s edit is not overwritten). If the API returns **no domains** (empty array), do **not** set a default; leave empty so the summary shows **empty values** (Section 2.7).
|
|
541
|
+
|
|
542
|
+
22. **Dispatch Redux actions on mount**
|
|
543
|
+
- In a `useEffect` that depends on `show`, `channel`, `orgUnitId`:
|
|
544
|
+
- If `!show` or channel not in `['SMS','EMAIL','WHATSAPP']`, do nothing.
|
|
545
|
+
- Else: `actions.getSenderDetailsRequested({ channel, orgUnitId: orgUnitId ?? -1 })`.
|
|
546
|
+
- If channel === 'WHATSAPP': `actions.getWeCrmAccountsRequested({ sourceName: 'WHATSAPP' })`.
|
|
547
|
+
- Do not call Api.getSenderDetails or Api.fetchWeCrmAccounts directly; only dispatch actions.
|
|
548
|
+
|
|
549
|
+
23. **Read from Redux via props**
|
|
550
|
+
- Component receives `senderDetailsForChannel` (or `senderDetailsByChannel`), `wecrmAccounts`, `isLoadingSenderDetails` from TestAndPreviewSlidebox mapStateToProps. Use e.g. `senderDetailsOptions = senderDetailsByChannel?.[channel] ?? []` when passing to SendTestMessage.
|
|
551
|
+
|
|
552
|
+
24. **Pass props from CommonTestAndPreview to SendTestMessage**
|
|
553
|
+
- `deliverySettings={testPreviewDeliverySettings[channel] ?? defaultForChannel}` (local state).
|
|
554
|
+
- `senderDetailsOptions={senderDetailsByChannel?.[channel] ?? []}` (from Redux prop).
|
|
555
|
+
- `wecrmAccounts={wecrmAccounts}` (from Redux prop).
|
|
556
|
+
- `onSaveDeliverySettings={(values) => setTestPreviewDeliverySettings(prev => ({ ...prev, [channel]: values }))}`.
|
|
557
|
+
- `isLoadingSenderDetails={isLoadingSenderDetails}` (from Redux prop).
|
|
558
|
+
- Only pass these when channel is SMS, EMAIL, or WHATSAPP.
|
|
559
|
+
|
|
560
|
+
25. **PropTypes**
|
|
561
|
+
- Update SendTestMessage PropTypes to include: deliverySettings (object), senderDetailsOptions (array), onSaveDeliverySettings (func), wecrmAccounts (array), isLoadingSenderDetails (bool). All optional so other channels remain valid.
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
### 12.6 Phase 3 — UI: Summary and Modal (Detailed Steps)
|
|
566
|
+
|
|
567
|
+
20. **SendTestMessage.js layout change**
|
|
568
|
+
- In the accordion content, order of elements: (1) Test customers label + TreeSelect, (2) **NEW:** Delivery settings row, (3) Send test message button.
|
|
569
|
+
- Delivery settings row: only render when `channel` is one of SMS, EMAIL, WHATSAPP.
|
|
570
|
+
- Render: `<DeliverySettings ... />` (from `../DeliverySettings` or `./DeliverySettings`) with all props passed from parent (channel, deliverySettings, senderDetailsOptions, onSaveDeliverySettings, wecrmAccounts, formatMessage, etc.).
|
|
571
|
+
- Use **cap-ui-library** components (CapRow, CapIcon); place the pencil icon next to the summary text; on click, DeliverySettings opens the **CapSlideBox** internally.
|
|
572
|
+
|
|
573
|
+
21. **DeliverySettings/index.js — summary line**
|
|
574
|
+
- Display a label “Delivery settings” (from messages).
|
|
575
|
+
- Next to it: summary string. Build from `deliverySettings`:
|
|
576
|
+
- SMS: “Account: {domainName}, Sender number: {gsmSenderId}” or “Not configured”.
|
|
577
|
+
- Email: “Sender domain: {domainName}, Sender ID: {senderId}, Reply-to: {replyToId}” or “Not configured”.
|
|
578
|
+
- WhatsApp: “Account: {accountName or domainName}, Sender number: {senderMobNum}” or “Not configured”.
|
|
579
|
+
- Use CapIcon type “edit” or “pencil” for the edit icon; onClick set local state `isModalOpen = true`.
|
|
580
|
+
|
|
581
|
+
22. **DeliverySettings/index.js — CapSlideBox**
|
|
582
|
+
- When `isSlideBoxOpen` is true, render **CapSlideBox** (from cap-ui-library) with:
|
|
583
|
+
- header “Delivery settings”,
|
|
584
|
+
- onClose: set `isSlideBoxOpen = false`,
|
|
585
|
+
- content: channel-specific form (ModifyDeliverySettings; use CapSelect, CapButton, CapRow, etc. from cap-ui-library),
|
|
586
|
+
- footer: “Done” button (CapButton) that calls `onSaveDeliverySettings(selectedValues)` and then set `isSlideBoxOpen = false`.
|
|
587
|
+
- Pass into the slidebox content: `channel`, `deliverySettings` (current selection), `senderDetailsOptions`, `wecrmAccounts` (WhatsApp), `onSaveDeliverySettings`. **Use only cap-ui-library components** for all form elements.
|
|
588
|
+
|
|
589
|
+
23. **ModifyDeliverySettings — SMS**
|
|
590
|
+
- Two dropdowns: (1) Account (domain) — options from `senderDetailsOptions` mapped to `{ label: domainName, value: domainId }`; (2) Sender number — options from the selected domain’s `gsmSenders` (label and value).
|
|
591
|
+
- When domain changes, reset sender to first/default of that domain’s gsmSenders.
|
|
592
|
+
- Controlled: value for domain = `deliverySettings.domainId`, value for sender = `deliverySettings.gsmSenderId`.
|
|
593
|
+
- On Done: call `onSaveDeliverySettings({ domainId, gsmSenderId, domainName })`.
|
|
594
|
+
|
|
595
|
+
24. **ModifyDeliverySettings — Email**
|
|
596
|
+
- Dropdowns: (1) Email domain, (2) Sender name / Sender ID (emailSenders), (3) Sender ID (if different from sender name per design), (4) Reply-to ID (emailRepliers).
|
|
597
|
+
- Match campaigns UI: “Email domain”, “Sender name”, “Sender ID”, “Reply-to ID”. Options from selected domain’s emailSenders and emailRepliers.
|
|
598
|
+
- On domain change, set default sender and reply-to from that domain.
|
|
599
|
+
- On Done: call `onSaveDeliverySettings({ domainId, senderId, senderLabel, replyToId, domainName })`.
|
|
600
|
+
|
|
601
|
+
25. **ModifyDeliverySettings — WhatsApp**
|
|
602
|
+
- Dropdowns: (1) Account — from `wecrmAccounts` (label: account name, value: sourceAccountIdentifier or id); (2) Sender number — from `senderDetailsOptions.WHATSAPP` (filter by selected account if API returns per-account; else show all gsmSenders from first or matching domain).
|
|
603
|
+
- On Done: call `onSaveDeliverySettings({ domainId, senderMobNum, accountId, sourceAccountIdentifier, accountName })`.
|
|
604
|
+
|
|
605
|
+
26. **Styling and component library**
|
|
606
|
+
- Use **CapSlideBox** from **cap-ui-library** for the delivery settings panel (no CapModal). Use **CapSelect** / **CapCustomSelect** for dropdowns, **CapButton** for Done, **CapRow**, **CapHeader**, **CapLabel**, **CapIcon** for layout and summary — all from cap-ui-library. Add minimal SCSS in `DeliverySettings/_deliverySettings.scss` if needed (margin, alignment with pencil icon). Import in DeliverySettings index.
|
|
607
|
+
|
|
608
|
+
---
|
|
609
|
+
|
|
610
|
+
### 12.7 Phase 4 — Payload Wiring (Detailed Steps)
|
|
611
|
+
|
|
612
|
+
27. **Pass delivery settings into prepareTestMessagePayload**
|
|
613
|
+
- Locate the call to `prepareTestMessagePayload` in CommonTestAndPreview (inside handleSendTestMessage or equivalent).
|
|
614
|
+
- Add an argument, e.g. `deliverySettingsOverride`, and pass `testPreviewDeliverySettings[channel]` (or null when channel not in scope).
|
|
615
|
+
- Signature change: `prepareTestMessagePayload(channelType, formDataObj, contentStr, customValuesObj, recipientDetails, previewDataObj, deliverySettingsOverride)`.
|
|
616
|
+
|
|
617
|
+
28. **Inside prepareTestMessagePayload — EMAIL branch**
|
|
618
|
+
- After building the initial `emailDeliverySettings` object with dummy values, if `deliverySettingsOverride` exists and has senderId/senderLabel/replyToId/domainId, override:
|
|
619
|
+
`channelSettings.senderLabel = deliverySettingsOverride.senderLabel`,
|
|
620
|
+
`channelSettings.senderId = deliverySettingsOverride.senderId`,
|
|
621
|
+
`channelSettings.replyToId = deliverySettingsOverride.replyToId`,
|
|
622
|
+
and optionally `channelSettings.domainId`.
|
|
623
|
+
- If override is null or empty, leave existing dummy values (backward compatible).
|
|
624
|
+
|
|
625
|
+
29. **Inside prepareTestMessagePayload — SMS branch**
|
|
626
|
+
- Similarly, if `deliverySettingsOverride` present, set
|
|
627
|
+
`smsDeliverySettings.channelSettings.gsmSenderId = deliverySettingsOverride.gsmSenderId`,
|
|
628
|
+
`smsDeliverySettings.channelSettings.domainId = deliverySettingsOverride.domainId`.
|
|
629
|
+
- Otherwise keep current defaults.
|
|
630
|
+
|
|
631
|
+
30. **Inside prepareTestMessagePayload — WHATSAPP branch**
|
|
632
|
+
- If `deliverySettingsOverride` present:
|
|
633
|
+
- Set `whatsappDeliverySettings.channelSettings.senderMobNum`, `domainId` from override.
|
|
634
|
+
- Set `whatsappMessageContent.accountId`, `sourceAccountIdentifier`, `accountName` from override when available.
|
|
635
|
+
- Otherwise keep existing behaviour (e.g. from formData/additionalProps).
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
639
|
+
### 12.8 Phase 5 — orgUnitId and Parent Wiring (Detailed Steps)
|
|
640
|
+
|
|
641
|
+
31. **CommonTestAndPreview props**
|
|
642
|
+
- Add prop `orgUnitId` (number, optional). In defaultProps set `orgUnitId: -1`. Use it in the useEffect that calls getSenderDetails.
|
|
643
|
+
|
|
644
|
+
32. **TestAndPreviewSlidebox**
|
|
645
|
+
- Ensure it passes through `orgUnitId` from its props to CommonTestAndPreview. So wherever TestAndPreviewSlidebox is used, parents should pass `orgUnitId` when available (e.g. from CreativesContainer).
|
|
646
|
+
|
|
647
|
+
33. **CreativesContainer / SlideBoxContent**
|
|
648
|
+
- When rendering TestAndPreviewSlidebox (or the component that wraps CommonTestAndPreview), pass `orgUnitId={orgUnitId}` so that when user is in a specific org context, sender details are org-scoped.
|
|
649
|
+
|
|
650
|
+
34. **Standalone containers (WhatsApp, Zalo, etc.)**
|
|
651
|
+
- If they render TestAndPreviewSlidebox without orgUnitId, CommonTestAndPreview will use -1; document that -1 means global/default org for API.
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
### 12.9 Phase 6 — Testing and Verification (Detailed Steps)
|
|
656
|
+
|
|
657
|
+
35. **Unit tests — SendTestMessage**
|
|
658
|
+
- Test that when channel is SMS/EMAIL/WHATSAPP, a “Delivery settings” section is rendered and that it receives deliverySettings and callbacks.
|
|
659
|
+
- Test that when channel is RCS or another channel, no delivery settings block is rendered.
|
|
660
|
+
|
|
661
|
+
36. **Unit tests — DeliverySettings / ModifyDeliverySettings**
|
|
662
|
+
- Test that summary text shows “Not configured” when deliverySettings are empty.
|
|
663
|
+
- Test that when deliverySettings have values, summary shows correct labels.
|
|
664
|
+
- Test that clicking Done calls onSaveDeliverySettings with the selected values (mock dropdowns or fire change events).
|
|
665
|
+
|
|
666
|
+
37. **Unit tests — prepareTestMessagePayload**
|
|
667
|
+
- For EMAIL, SMS, WHATSAPP: call prepareTestMessagePayload with a mock deliverySettingsOverride and assert that the returned payload’s channelSettings (and WhatsApp account fields) contain those values.
|
|
668
|
+
- Call with null/undefined override and assert payload still has previous default structure (backward compatibility).
|
|
669
|
+
|
|
670
|
+
38. **Integration / manual**
|
|
671
|
+
- Open Test & Preview for SMS: open Delivery settings, select domain and sender, Done. Send test message; verify in network tab that request payload includes smsDeliverySettings.channelSettings.gsmSenderId and domainId.
|
|
672
|
+
- Same for Email (senderId, replyToId) and WhatsApp (senderMobNum, domainId, account info).
|
|
673
|
+
- Verify other channels (e.g. RCS) still work and show no delivery settings.
|
|
674
|
+
|
|
675
|
+
39. **Regression**
|
|
676
|
+
- Ensure existing tests for CommonTestAndPreview (e.g. test and preview flow, send test message) still pass; update mocks if new props are required.
|
|
677
|
+
|
|
678
|
+
---
|
|
679
|
+
|
|
680
|
+
### 12.10 File-Level Summary (Quick Reference)
|
|
681
|
+
|
|
682
|
+
| Action | File path | What to do |
|
|
683
|
+
|--------|-----------|------------|
|
|
684
|
+
| **Redux (use existing CommonTestAndPreview slice)** |
|
|
685
|
+
| MODIFY | `CommonTestAndPreview/constants.js` | Add GET_SENDER_DETAILS_* and GET_WECRM_ACCOUNTS_* (REQUESTED, SUCCESS, FAILURE). |
|
|
686
|
+
| MODIFY | `CommonTestAndPreview/actions.js` | Add getSenderDetailsRequested({ channel, orgUnitId }), getWeCrmAccountsRequested({ sourceName }). |
|
|
687
|
+
| MODIFY | `CommonTestAndPreview/sagas.js` | Add getSenderDetailsSaga (call Api.getSenderDetails, parse, put SUCCESS/FAILURE), getWeCrmAccountsSaga; watchGetSenderDetails, watchGetWeCrmAccounts; register in commonTestAndPreviewSaga(). |
|
|
688
|
+
| MODIFY | `CommonTestAndPreview/reducer.js` | Add senderDetailsByChannel, wecrmAccounts, isLoadingSenderDetails, errors; handle all six new action types. |
|
|
689
|
+
| MODIFY | `CommonTestAndPreview/selectors.js` | Add makeSelectSenderDetailsByChannel (or makeSelectSenderDetailsForChannel), makeSelectWeCrmAccounts, makeSelectIsLoadingSenderDetails, error selectors; export. |
|
|
690
|
+
| MODIFY | `TestAndPreviewSlidebox/index.js` | mapStateToProps: add senderDetailsByChannel, wecrmAccounts, isLoadingSenderDetails (from new selectors). Pass orgUnitId through to CommonTestAndPreview. |
|
|
691
|
+
| **DeliverySettings folder and component** |
|
|
692
|
+
| CREATE | `CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js` | Normalize getSenderDetails response to { domains: [...] } per channel; used in saga. |
|
|
693
|
+
| CREATE | `CommonTestAndPreview/DeliverySettings/constants.js` | CHANNELS_WITH_DELIVERY_SETTINGS, default delivery-setting shapes. |
|
|
694
|
+
| CREATE | `CommonTestAndPreview/DeliverySettings/messages.js` | defineMessages for delivery settings, account, sender number, domain, done, not configured. |
|
|
695
|
+
| CREATE | `CommonTestAndPreview/DeliverySettings/index.js` | Summary row + pencil (cap-ui-library); state isSlideBoxOpen; render **CapSlideBox** with ModifyDeliverySettings content when open; pass props. |
|
|
696
|
+
| CREATE | `CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js` | **CapSlideBox** (cap-ui-library) content with channel-specific dropdowns (CapSelect) and Done (CapButton); call onSaveDeliverySettings. All from cap-ui-library. |
|
|
697
|
+
| CREATE | `CommonTestAndPreview/DeliverySettings/_deliverySettings.scss` (optional) | Minor layout/spacing for summary and CapSlideBox. All UI components from cap-ui-library. |
|
|
698
|
+
| **CommonTestAndPreview and SendTestMessage** |
|
|
699
|
+
| MODIFY | `CommonTestAndPreview/index.js` | Add **local** state only: testPreviewDeliverySettings. In useEffect **dispatch** actions.getSenderDetailsRequested and actions.getWeCrmAccountsRequested (no direct API calls). Read senderDetailsByChannel, wecrmAccounts, isLoadingSenderDetails from **props** (Redux). Pass deliverySettings, senderDetailsOptions (from Redux prop), wecrmAccounts, onSaveDeliverySettings to SendTestMessage; pass deliverySettingsOverride into prepareTestMessagePayload; add orgUnitId prop. |
|
|
700
|
+
| MODIFY | `CommonTestAndPreview/index.js` (prepareTestMessagePayload) | Add 7th parameter deliverySettingsOverride; in EMAIL/SMS/WHATSAPP branches merge override into channelSettings (and WhatsApp account fields). |
|
|
701
|
+
| MODIFY | `CommonTestAndPreview/SendTestMessage.js` | Insert Delivery settings row above Send button; conditionally render <DeliverySettings /> for SMS/EMAIL/WHATSAPP; pass channel, deliverySettings, senderDetailsOptions (from Redux), wecrmAccounts, onSaveDeliverySettings, isLoadingSenderDetails, formatMessage. |
|
|
702
|
+
| MODIFY | Parent(s) that render TestAndPreviewSlidebox (e.g. SlideBoxContent) | Pass orgUnitId when available. |
|
|
703
|
+
| MODIFY | CommonTestAndPreview tests | Update defaultProps/mocks to include orgUnitId, deliverySettings, senderDetailsByChannel, wecrmAccounts, onSaveDeliverySettings, actions (with getSenderDetailsRequested, getWeCrmAccountsRequested); add tests for delivery settings visibility and prepareTestMessagePayload with override. Add saga/reducer/selector tests for new delivery-settings actions. |
|
|
704
|
+
|
|
705
|
+
---
|
|
706
|
+
|
|
707
|
+
### 12.11 Risk and Edge Cases
|
|
708
|
+
|
|
709
|
+
40. **Empty options**
|
|
710
|
+
- If getSenderDetails returns empty or fails, senderDetailsByChannel[channel] stays []. Do **not** auto-set a default; leave `testPreviewDeliverySettings[channel]` empty. The **one** delivery setting row remains visible; summary shows **empty values** (e.g. “Account: —”, “Sender number: —”) or “Not configured” (campaigns-style). **CapSlideBox** content should show empty dropdowns (CapSelect) or “No options”; Done (CapButton) can still be allowed (no selection) or disabled.
|
|
711
|
+
|
|
712
|
+
41. **WhatsApp account vs sender details**
|
|
713
|
+
- getSenderDetails('WHATSAPP') may return multiple entries (one per account/domain). Match by sourceAccountIdentifier when user selects an account from WeCRM so that sender number dropdown shows only numbers for that account.
|
|
714
|
+
|
|
715
|
+
42. **orgUnitId -1**
|
|
716
|
+
- Backend must accept orgUnitId -1 for getSenderDetails; document and test. If backend requires a valid org, parents must always pass orgUnitId when in org context.
|
|
717
|
+
|
|
718
|
+
43. **No selection**
|
|
719
|
+
- User opens CapSlideBox but does not select anything and clicks Done: either save empty selection (summary “Not configured”) or keep previous selection. Recommend: allow saving empty and show “Not configured”; on send test, payload still uses empty defaults (backward compatible).
|
|
720
|
+
|
|
721
|
+
---
|
|
722
|
+
|
|
723
|
+
**Document version:** 1.4
|
|
724
|
+
**Last updated:** Delivery settings panel must use **CapSlideBox** from **cap-ui-library** (not CapModal). All implementation must use **cap-ui-library** common components (CapSlideBox, CapSelect, CapButton, CapRow, CapHeader, CapIcon, etc.).
|
|
725
|
+
**Next step:** Proceed phase-by-phase; start with Phase 1 (APIs, parser, folder and constants/messages), then Phase 2 (state and data loading), then Phase 3 (UI), then Phase 4 (payload wiring), then Phase 5–6 (orgUnitId, tests, verification).
|