@explorer02/cfm-survey-sdk 0.2.3 → 0.2.5
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/dist/cli/index.js +141 -33
- package/dist/cli/index.mjs +141 -33
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +3 -1
- package/postinstall.js +9 -5
- package/templates/AGENT.md +60 -19
- package/templates/deploy-wizard-to-s3.sh +52 -0
- package/templates/docs/00-integration/agent-execution-flow.md +293 -0
- package/templates/docs/00-integration/agent-operating-contract.md +268 -0
- package/templates/docs/00-integration/apply-ui-config.md +390 -0
- package/templates/docs/00-integration/aws-deploy.md +117 -3
- package/templates/docs/00-integration/canonical-survey-fixtures.md +94 -0
- package/templates/docs/00-integration/client-integration-guide.md +9 -7
- package/templates/docs/00-integration/client-lib-folder.md +115 -0
- package/templates/docs/00-integration/component-checklist.md +90 -62
- package/templates/docs/00-integration/constraints.md +14 -5
- package/templates/docs/00-integration/custom-field-logic-and-navigation.md +56 -0
- package/templates/docs/00-integration/mockup-ui-extraction.md +113 -0
- package/templates/docs/00-integration/placeholders-and-custom-fields-wiring.md +192 -0
- package/templates/docs/00-integration/placeholders-and-tokens.md +2 -1
- package/templates/docs/00-integration/progress.md +4 -2
- package/templates/docs/00-integration/setup.md +12 -0
- package/templates/docs/00-integration/ui-customization-wizard.md +123 -0
- package/templates/docs/00-integration/useSurveySDK.md +35 -1
- package/templates/docs/00-integration/wizard-api.md +126 -0
- package/templates/docs/00-integration/wizard-config-handoff.md +292 -0
- package/templates/docs/00-integration/wizard-preview-build-guide.md +405 -0
- package/templates/docs/00-integration/wizard-question-type-styling.md +197 -0
- package/templates/docs/00-integration/wizard-troubleshooting.md +80 -0
- package/templates/docs/01-components/01-survey-page.md +18 -8
- package/templates/docs/01-components/02-question.md +2 -2
- package/templates/docs/01-components/03-rating-scale.md +12 -18
- package/templates/docs/01-components/05-csat-matrix-scale.md +18 -26
- package/templates/docs/01-components/06-likert-matrix-scale.md +19 -39
- package/templates/docs/01-components/07-slider-matrix-scale.md +48 -33
- package/templates/docs/01-components/09-custom-slider-track.md +15 -25
- package/templates/docs/01-components/10-header-footer.md +23 -4
- package/templates/docs/01-components/11-progress-bar.md +14 -6
- package/templates/docs/01-components/19-survey-sticky-chrome.md +79 -0
- package/templates/docs/01-components/README.md +2 -2
- package/templates/docs/02-reference/question-types/10-slider-matrix.md +38 -26
- package/templates/docs/02-reference/routing-table.md +1 -0
- package/templates/docs/02-reference/value-derivation.md +1 -1
- package/templates/docs/03-ui-specs/00-question-shell.md +10 -0
- package/templates/docs/03-ui-specs/01-rating.md +18 -0
- package/templates/docs/03-ui-specs/02-radio.md +16 -1
- package/templates/docs/03-ui-specs/03-text.md +12 -1
- package/templates/docs/03-ui-specs/04-csat.md +84 -50
- package/templates/docs/03-ui-specs/06-slider.md +3 -1
- package/templates/docs/03-ui-specs/07-matrix-cfm.md +71 -48
- package/templates/docs/03-ui-specs/08-matrix-csat-rating.md +48 -18
- package/templates/docs/03-ui-specs/09-slider-matrix.md +59 -32
- package/templates/docs/03-ui-specs/10-file-upload.md +11 -0
- package/templates/docs/03-ui-specs/11-text-and-media.md +4 -0
- package/templates/docs/03-ui-specs/12-survey-chrome.md +54 -5
- package/templates/docs/03-ui-specs/13-heatmap.md +12 -1
- package/templates/docs/03-ui-specs/14-rank-order.md +11 -0
- package/templates/docs/03-ui-specs/README.md +4 -2
- package/templates/docs/03-ui-specs/shared/matrix-dropdown.md +1 -1
- package/templates/docs/MANIFEST.json +180 -7
- package/templates/docs/index.md +114 -117
- package/templates/docs/templates/CsatMatrixScale.tsx +637 -0
- package/templates/docs/templates/FileUploadScale.tsx +262 -0
- package/templates/docs/templates/HeatmapScale.tsx +114 -0
- package/templates/docs/templates/LikertMatrixScale.tsx +414 -0
- package/templates/docs/templates/Question.tsx +3 -0
- package/templates/docs/templates/RatingScale.tsx +129 -0
- package/templates/docs/templates/SliderMatrixScale.tsx +248 -0
- package/templates/docs/templates/SurveyStickyChrome.tsx +24 -0
- package/templates/docs/templates/customFieldValues.ts +36 -0
- package/templates/docs/templates/deploy-to-aws.sh +74 -0
- package/templates/docs/templates/implementation_plan.md +64 -10
- package/templates/docs/templates/labelStyles.ts +33 -0
- package/templates/docs/templates/selectionStyles.ts +100 -0
- package/templates/docs/templates/surveyUiIcons.tsx +11 -0
- package/templates/docs/templates/surveyUiScaleUtils.ts +51 -0
- package/templates/docs/templates/verify-agent-build.sh +119 -0
- package/templates/preview-harness/preview-bridge.inline.js +201 -0
- package/templates/preview-harness/previewPages.js +108 -0
- package/templates/preview-harness/previewPages.ts +298 -0
- package/templates/preview-harness/vite-app/src/PreviewConfigContext.tsx +67 -0
- package/templates/preview-harness/vite-app/src/QuestionPreview.tsx +122 -0
- package/templates/preview-harness/vite-app/src/SurveyPagePreview.tsx +75 -0
- package/templates/preview-harness/vite-app/src/fixtures/questions.ts +311 -0
- package/templates/preview-harness/vite-app/src/globals.css +16 -0
- package/templates/preview-harness/vite-app/src/mount.tsx +9 -0
- package/templates/preview-harness/vite-app/src/preview-live-overrides.css +101 -0
- package/templates/preview-harness/vite-app/stubs/next-dynamic.tsx +25 -0
- package/templates/preview-harness/vite-app/stubs/next-image.tsx +29 -0
- package/templates/previewBridge.ts +153 -0
- package/templates/survey-theme.css +295 -0
- package/templates/survey-ui-config.schema.json +213 -0
- package/templates/wizard-dist/assets/PreviewMock-AoZdAEPZ.js +1 -0
- package/templates/wizard-dist/assets/TypePanel-39FnbtvG.js +1 -0
- package/templates/wizard-dist/assets/index-BhWM50Yu.css +1 -0
- package/templates/wizard-dist/assets/index-CWKdsJOp.js +34 -0
- package/templates/wizard-dist/assets/vendor-BwkXDkd3.js +17 -0
- package/templates/wizard-dist/index.html +20 -0
- package/templates/wizard.html +13 -1129
|
@@ -18,6 +18,61 @@ Survey logic rules may reference **custom fields** instead of survey questions:
|
|
|
18
18
|
|
|
19
19
|
Inspect fetched survey data: any `skipLogics`, `displayLogic`, or `answerLogic` with `entityType: 'CUSTOM_FIELD'` requires client-supplied values.
|
|
20
20
|
|
|
21
|
+
Copy portable template: [`templates/customFieldValues.ts`](../templates/customFieldValues.ts) → `src/lib/customFieldValues.ts`. See [`client-lib-folder.md`](client-lib-folder.md) and **[`placeholders-and-custom-fields-wiring.md`](placeholders-and-custom-fields-wiring.md)** for precise key discovery and two-point wiring.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Agent implementation recipe
|
|
26
|
+
|
|
27
|
+
1. **After fetch** — scan `survey.pages` (and `endPages` logic) for `conditionEntity.entityType === 'CUSTOM_FIELD'`. Collect every `conditionEntity.id` (`_c_…`).
|
|
28
|
+
2. **Record** each id in `implementation_plan.md` §3d with `fieldType`, logic kind (skip/display/answer/end), and expected CRM value shape.
|
|
29
|
+
3. **Copy** [`templates/customFieldValues.ts`](../templates/customFieldValues.ts) → `src/lib/customFieldValues.ts`. Populate from CRM/transaction API — **not** inline in `SurveyPage`.
|
|
30
|
+
4. **Wire hook** — import map and pass in stable `useMemo` options:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { CUSTOM_FIELD_VALUES } from '@/lib/customFieldValues';
|
|
34
|
+
|
|
35
|
+
const surveyOptions = useMemo(
|
|
36
|
+
() => ({
|
|
37
|
+
instanceId,
|
|
38
|
+
placeholders: SURVEY_PLACEHOLDERS,
|
|
39
|
+
customFieldValues: CUSTOM_FIELD_VALUES,
|
|
40
|
+
}),
|
|
41
|
+
[instanceId, selectedLanguage]
|
|
42
|
+
);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
5. **Wire Question** — pass the **same** map as `customFieldValues` prop (template `Question.tsx` already forwards it to `getVisible*ForAnswers`).
|
|
46
|
+
6. **Verify** — trigger a custom-field skip rule on Next; no per-question client evaluator code needed.
|
|
47
|
+
|
|
48
|
+
**Blocking gate:** if any `_c_…` id exists in fetched survey → `src/lib/customFieldValues.ts` must exist before Phase 5 BUILD.
|
|
49
|
+
|
|
50
|
+
### Fixture example (integration-test survey)
|
|
51
|
+
|
|
52
|
+
Page 2 `SLIDER_MATRIX` has a skip rule:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"conditionEntity": {
|
|
57
|
+
"id": "_c_67199096d294be011a2b4773",
|
|
58
|
+
"entityType": "CUSTOM_FIELD",
|
|
59
|
+
"fieldType": "TEXT"
|
|
60
|
+
},
|
|
61
|
+
"field": "CASE_SENSITIVE_TEXT",
|
|
62
|
+
"values": ["abc"]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Client map:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
export const CUSTOM_FIELD_VALUES: CustomFieldValueMap = {
|
|
70
|
+
'_c_67199096d294be011a2b4773': 'abc',
|
|
71
|
+
};
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
When this value matches, SDK skip logic runs on Next — values must be in **hook options**, not typed by the respondent.
|
|
75
|
+
|
|
21
76
|
---
|
|
22
77
|
|
|
23
78
|
## Client value map
|
|
@@ -172,3 +227,4 @@ When a question has several `skipLogics[]` entries (including custom-field rules
|
|
|
172
227
|
- [`display-logic-and-navigation.md`](display-logic-and-navigation.md) — question-level gating
|
|
173
228
|
- [`answer-logic-and-navigation.md`](answer-logic-and-navigation.md) — option/row/column gating + visibility helpers
|
|
174
229
|
- [`client-integration-guide.md`](client-integration-guide.md) — full wiring map
|
|
230
|
+
- [`client-lib-folder.md`](client-lib-folder.md) — lib folder layout + portable templates
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Mockup & Client Prompt — UI-Only Extraction
|
|
2
|
+
|
|
3
|
+
> **Read in Phase 0–4** before fetch and before filling `implementation_plan.md`.
|
|
4
|
+
> Pipeline: [`agent-operating-contract.md`](agent-operating-contract.md) · [`agent-execution-flow.md`](agent-execution-flow.md)
|
|
5
|
+
|
|
6
|
+
Client mockup images and prompts are **visual references** for chrome and styling. They are **not** the survey definition. Logic, language, question inventory, and CRM data come **only** from the fetched survey (JWT) and host-app context.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Prime rule
|
|
11
|
+
|
|
12
|
+
| Source | Authoritative for |
|
|
13
|
+
|--------|-----------------|
|
|
14
|
+
| **Mockup image / prompt** | UI look-and-feel only (see table below) |
|
|
15
|
+
| **Fetched survey (JWT)** | Question types, text, logic, languages, placeholders in question copy, custom-field ids |
|
|
16
|
+
| **Host / CRM / transaction** | `customFieldValues` runtime values |
|
|
17
|
+
| **Client (explicit)** | JWT, wizard yes/no, deploy yes/no |
|
|
18
|
+
|
|
19
|
+
**Never invent survey behavior from a mockup.** A single NPS screenshot does not mean the survey has only NPS, one language, or specific skip rules.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Extract from mockup (UI only)
|
|
24
|
+
|
|
25
|
+
Use mockup / prompt for **chrome and tokens** — record in `implementation_plan.md` §0 and draft `survey-theme.css` / `survey-ui-config.json`:
|
|
26
|
+
|
|
27
|
+
| Extract | Examples | Where it goes |
|
|
28
|
+
|---------|----------|---------------|
|
|
29
|
+
| **Brand colors** | Primary pink, footer dark gray, page background | `--cfm-primary`, `--cfm-footer-bg`, `global.colorScheme` |
|
|
30
|
+
| **Logo style** | Image vs text/CSS logo, placement | `Header.tsx` pattern (`data-cfm-logo` or `data-cfm-logo-text`) |
|
|
31
|
+
| **Header layout** | Logo left, company name, sticky bar | `global.header.*`, header CSS vars |
|
|
32
|
+
| **Footer layout** | Logo, links row, copyright | `global.footer.*`, `data-cfm-footer-links` |
|
|
33
|
+
| **Chrome copy (display text)** | Survey title, company name, button labels, thank-you line, footer link labels | `global.surveyTitle`, `global.companyName`, `global.buttons`, `global.footer.links` — **wording only** |
|
|
34
|
+
| **Progress bar presence** | Visible track under header | `global.layout.showProgressBar` default |
|
|
35
|
+
| **Typography / corners** | Rounded cards, font family | `global.layout.borderStyle`, `global.layout.fontStyle` |
|
|
36
|
+
| **Question card feel** | Card background, border, shadow | `global.theme.*` |
|
|
37
|
+
| **Scale visual style (reference)** | NPS traffic-light, star vs numbered — as **styling hint** | Per-type tokens in `questionTypes.*` after you know types from fetch |
|
|
38
|
+
|
|
39
|
+
Chrome text from mockup (e.g. "Telekom Umfrage", "Impressum") is **UI copy** — safe to seed branding. It does **not** replace question text from the API.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Do NOT extract from mockup (survey myths)
|
|
44
|
+
|
|
45
|
+
| Do not infer | Why | Correct source |
|
|
46
|
+
|--------------|-----|----------------|
|
|
47
|
+
| **Question types** in survey | Image shows one screen (e.g. NPS) | Unique `question.type` from **fetched** `survey.pages` |
|
|
48
|
+
| **Question count / order** | Mockup is one page | Fetched survey structure |
|
|
49
|
+
| **Question text / labels** | May be sample or translated | `question.questionText`, `options`, matrix rows from fetch |
|
|
50
|
+
| **Language** (`de` vs `en`) | UI locale in screenshot ≠ survey language | `survey.language`, `supportedLanguages` from fetch; `useSurveySDK({ language })` |
|
|
51
|
+
| **Skip / display / answer logic** | Not visible in static image | `skipLogics`, `displayLogic`, `answerLogic` on fetched pages |
|
|
52
|
+
| **Custom field ids or values** | CRM data not in mockup | Scan fetch for `_c_…` ids — [`custom-field-logic-and-navigation.md`](custom-field-logic-and-navigation.md) |
|
|
53
|
+
| **Placeholder keys** (`{{FIRST_NAME}}`) | Tokens in mockup may be examples | Scan **fetched** question text for `{{…}}` tokens |
|
|
54
|
+
| **Validation rules** | Not shown in design | SDK + fetched `validation` |
|
|
55
|
+
| **End pages / intro copy** | Unless clearly labeled as chrome | `survey.pages` / `endPages` from fetch |
|
|
56
|
+
| **`surveyTypes` for wizard** | Mockup ≠ wizard inventory | All **11** types for wizard; fetched types for dispatch only |
|
|
57
|
+
|
|
58
|
+
**Blocking rule:** `implementation_plan.md` §3b inventory table is filled from **fetch**, not from mockup filename or image content.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Agent workflow
|
|
63
|
+
|
|
64
|
+
### Phase 0 — Mockup pass (UI notebook only)
|
|
65
|
+
|
|
66
|
+
1. Note colors, header/footer structure, logo mode, button style, card chrome.
|
|
67
|
+
2. Write **Branding source** in `implementation_plan.md` §0 — describe UI only.
|
|
68
|
+
3. Do **not** write question-type rows or logic rows yet.
|
|
69
|
+
|
|
70
|
+
### Phase 2–4 — Fetch pass (survey truth)
|
|
71
|
+
|
|
72
|
+
1. Ask client for JWT; fetch survey.
|
|
73
|
+
2. List unique `question.type` values → §3b (from API).
|
|
74
|
+
3. Scan logic → §3d custom fields, §3e logic inventory (from API).
|
|
75
|
+
4. Scan question text for `{{TOKEN}}` → placeholder keys (from API).
|
|
76
|
+
5. Override mockup only where client **explicitly** contradicts fetch in written prompt (rare — prefer fetch for survey content).
|
|
77
|
+
|
|
78
|
+
### Phase 5 — Merge
|
|
79
|
+
|
|
80
|
+
| From mockup | From fetch |
|
|
81
|
+
|-------------|------------|
|
|
82
|
+
| CSS vars, chrome layout, default button labels | `Question.tsx` branches, scale fixtures, logic wiring |
|
|
83
|
+
| `data-cfm-*` hooks | `getVisible*ForAnswers`, `customFieldValues` |
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Common myths (avoid)
|
|
88
|
+
|
|
89
|
+
| Myth | Reality |
|
|
90
|
+
|------|---------|
|
|
91
|
+
| "Mockup shows NPS → build only NPS" | Build all types in **fetch**; wizard still shows all 11 for customization |
|
|
92
|
+
| "German text in image → hardcode `language: 'de'`" | Set language from survey + selector; mockup language is not authoritative |
|
|
93
|
+
| "Footer says Datenschutz → survey has privacy logic" | Footer link is chrome — wire `global.footer.links`; no extra SDK logic |
|
|
94
|
+
| "Question 6 in image → survey has 6 questions" | Numbering is path-scoped; count pages from fetch |
|
|
95
|
+
| "Red asterisk in mockup → question.required on that id" | Required flags come from fetched questions |
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Wizard note
|
|
100
|
+
|
|
101
|
+
Mockup drives **seed** colors and chrome text in `survey-ui-config.json`. Wizard **Question Types** step still lists all 11 literals — see [`wizard-troubleshooting.md`](wizard-troubleshooting.md) §4.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Related docs
|
|
106
|
+
|
|
107
|
+
| Doc | Role |
|
|
108
|
+
|-----|------|
|
|
109
|
+
| [`placeholders-and-tokens.md`](placeholders-and-tokens.md) | Placeholder keys from fetch |
|
|
110
|
+
| [`custom-field-logic-and-navigation.md`](custom-field-logic-and-navigation.md) | `_c_…` ids from fetch |
|
|
111
|
+
| [`logic-fields-catalog.md`](logic-fields-catalog.md) | Logic fields (do not invent) |
|
|
112
|
+
| [`canonical-survey-fixtures.md`](canonical-survey-fixtures.md) | Matrix/slider shapes from fetch |
|
|
113
|
+
| [`wizard-preview-build-guide.md`](wizard-preview-build-guide.md) | Tokenize UI for live preview |
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Placeholders & Custom Fields — Precise SDK Wiring
|
|
2
|
+
|
|
3
|
+
> **Read in Phase 4–5** after survey fetch. Companion: [`placeholders-and-tokens.md`](placeholders-and-tokens.md), [`custom-field-logic-and-navigation.md`](custom-field-logic-and-navigation.md), [`mockup-ui-extraction.md`](mockup-ui-extraction.md).
|
|
4
|
+
|
|
5
|
+
Agents must pass **exact keys** from the fetched survey and CRM context into `useSurveySDK` — not guesses from mockup text.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Two different maps (do not conflate)
|
|
10
|
+
|
|
11
|
+
| Map | Key format | Purpose | Value source |
|
|
12
|
+
|-----|------------|---------|----------------|
|
|
13
|
+
| **`placeholders`** | `FIRST_NAME`, `COMPANY` (no braces) | Replace `{{FIRST_NAME}}` in question copy at map time | CRM / marketing context or wizard `placeholders.*` |
|
|
14
|
+
| **`customFieldValues`** | `_c_…` ids from logic rules | Skip, display, answer, end, progress evaluation | CRM / transaction API — **not** respondent UI |
|
|
15
|
+
|
|
16
|
+
Mockup images do **not** define either map. Discover keys from **fetched survey JSON**.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Step 1 — Discover placeholder keys (after fetch)
|
|
21
|
+
|
|
22
|
+
Scan all `questionText`, `questionDescription`, display variant bodies, intro/end copy for tokens:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
{{FIRST_NAME}}
|
|
26
|
+
{{COMPANY}}
|
|
27
|
+
{{SURVEY_QUESTION-:-<questionId>}}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**CRM placeholders** — add to `SURVEY_PLACEHOLDERS`:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// src/lib/placeholders.ts (or module scope in SurveyPage.tsx)
|
|
34
|
+
export const SURVEY_PLACEHOLDERS = {
|
|
35
|
+
FIRST_NAME: 'Alex', // key = token name without {{ }}
|
|
36
|
+
COMPANY: 'Acme Corp',
|
|
37
|
+
} as const;
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Rules:
|
|
41
|
+
|
|
42
|
+
- Key must match token name **exactly** (case-sensitive per survey).
|
|
43
|
+
- Values are **display strings** for CRM/marketing — not survey answers.
|
|
44
|
+
- Omit keys not present in fetched text (do not copy example lists from docs blindly).
|
|
45
|
+
- **Answer tokens** `{{SURVEY_QUESTION-:-id}}` are **not** in `placeholders` — resolved at render via `resolveSurveyQuestionPlaceholders`.
|
|
46
|
+
|
|
47
|
+
Record discovered keys in `implementation_plan.md`:
|
|
48
|
+
|
|
49
|
+
```markdown
|
|
50
|
+
## Placeholder inventory (from fetch)
|
|
51
|
+
| Token | Key in SURVEY_PLACEHOLDERS | Example value | Found in question ids |
|
|
52
|
+
| {{FIRST_NAME}} | FIRST_NAME | … | q1, q3 |
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Step 2 — Wire placeholders (stable ref + hook)
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { useMemo } from 'react';
|
|
61
|
+
import { useSurveySDK } from '@explorer02/cfm-survey-sdk';
|
|
62
|
+
import { SURVEY_PLACEHOLDERS } from '@/lib/placeholders';
|
|
63
|
+
import { CUSTOM_FIELD_VALUES } from '@/lib/customFieldValues';
|
|
64
|
+
|
|
65
|
+
const surveyOptions = useMemo(
|
|
66
|
+
() => ({
|
|
67
|
+
instanceId: SURVEY_INSTANCE_ID,
|
|
68
|
+
language: selectedLanguage,
|
|
69
|
+
placeholders: SURVEY_PLACEHOLDERS,
|
|
70
|
+
customFieldValues: CUSTOM_FIELD_VALUES,
|
|
71
|
+
}),
|
|
72
|
+
[selectedLanguage],
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const { state, onAction, surveyQueryResults } = useSurveySDK({ options: surveyOptions });
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Failure modes:**
|
|
79
|
+
|
|
80
|
+
| Mistake | Symptom |
|
|
81
|
+
|---------|---------|
|
|
82
|
+
| Inline `placeholders={{ ... }}` in component | Infinite re-fetch |
|
|
83
|
+
| Key missing from map | Literal `{{FIRST_NAME}}` in UI |
|
|
84
|
+
| Mockup name instead of token key | Wrong or missing substitution |
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Step 3 — Discover custom field ids (after fetch)
|
|
89
|
+
|
|
90
|
+
Scan `survey.pages[].skipLogics`, `displayLogic`, `answerLogic`, and `endPages` for:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
"conditionEntity": { "entityType": "CUSTOM_FIELD", "id": "_c_67199096d294be011a2b4773", "fieldType": "TEXT" }
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Collect **every** `_c_…` id. Fill `implementation_plan.md` §3d.
|
|
97
|
+
|
|
98
|
+
Copy template → `src/lib/customFieldValues.ts`:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import type { CustomFieldValueMap } from '@explorer02/cfm-survey-sdk';
|
|
102
|
+
|
|
103
|
+
export const CUSTOM_FIELD_VALUES: CustomFieldValueMap = {
|
|
104
|
+
'_c_67199096d294be011a2b4773': 'abc', // TEXT — exact id from fetch
|
|
105
|
+
// '_c_…': 2, // NUMBER
|
|
106
|
+
// '_c_…': 'picklist-option-uuid', // PICKLIST
|
|
107
|
+
};
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Value shape by `fieldType` (must match SDK evaluator)
|
|
111
|
+
|
|
112
|
+
| fieldType | Pass |
|
|
113
|
+
|-----------|------|
|
|
114
|
+
| `TEXT`, `TEXT_MULTI`, `TEXTAREA` | `string` |
|
|
115
|
+
| `NUMBER` | `number` or numeric `string` |
|
|
116
|
+
| `PICKLIST` | option **id** string |
|
|
117
|
+
| `PICKLIST_MULTISELECT` | `string[]` of option ids |
|
|
118
|
+
| `DATETIME` | epoch ms (`number` or numeric string) |
|
|
119
|
+
|
|
120
|
+
Missing keys → treated as empty for logic. Wrong shape → rule may never match.
|
|
121
|
+
|
|
122
|
+
**Values come from CRM/transaction** — ask client or integration spec when not in prompt. Do **not** invent ids or values from mockup.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Step 4 — Wire custom fields (two places — same map)
|
|
127
|
+
|
|
128
|
+
### A. Hook
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
customFieldValues: CUSTOM_FIELD_VALUES, // inside useMemo surveyOptions
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### B. Question + visibility helpers
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
<Question
|
|
138
|
+
customFieldValues={CUSTOM_FIELD_VALUES}
|
|
139
|
+
allAnswers={state.answers}
|
|
140
|
+
allQuestions={allQuestions}
|
|
141
|
+
...
|
|
142
|
+
/>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Inside `Question.tsx` (from template):
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
getVisibleMcqOptionsForAnswers(question, allAnswers, allQuestions, customFieldValues);
|
|
149
|
+
getVisibleMatrixItemsForAnswers(question, allAnswers, allQuestions, customFieldValues);
|
|
150
|
+
getVisibleRankOrderOptionsForAnswers(question, allAnswers, allQuestions, customFieldValues);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Fourth argument must be the same map** as hook options whenever logic references `CUSTOM_FIELD`.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Step 5 — Wizard overrides (Phase 6c)
|
|
158
|
+
|
|
159
|
+
When client uses wizard, `survey-ui-config.json` may include:
|
|
160
|
+
|
|
161
|
+
| Config path | Code update |
|
|
162
|
+
|-------------|-------------|
|
|
163
|
+
| `placeholders.firstName` etc. | Merge into `SURVEY_PLACEHOLDERS` (wizard keys → SDK token keys per [`apply-ui-config.md`](apply-ui-config.md)) |
|
|
164
|
+
| `customFields._c_…` | Merge into `CUSTOM_FIELD_VALUES` |
|
|
165
|
+
|
|
166
|
+
Wizard **Testing & Tokens** step edits config only — you still wire stable refs in code after `confirm-ui-config`.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Verification checklist
|
|
171
|
+
|
|
172
|
+
- [ ] Placeholder keys discovered by **scanning fetched survey text**, not mockup
|
|
173
|
+
- [ ] `SURVEY_PLACEHOLDERS` at module scope; keys match `{{TOKEN}}` names
|
|
174
|
+
- [ ] Every `_c_…` id in logic appears in `CUSTOM_FIELD_VALUES`
|
|
175
|
+
- [ ] Value shapes match `fieldType` from fetch
|
|
176
|
+
- [ ] `useMemo` wraps hook `options`
|
|
177
|
+
- [ ] `customFieldValues` passed to hook **and** `Question`
|
|
178
|
+
- [ ] `getVisible*ForAnswers` receives 4th arg when CRM logic exists
|
|
179
|
+
- [ ] `resolveSurveyQuestionPlaceholders` used for answer tokens in question shell
|
|
180
|
+
- [ ] No placeholder or custom-field keys invented from mockup image
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Related
|
|
185
|
+
|
|
186
|
+
| Doc | Role |
|
|
187
|
+
|-----|------|
|
|
188
|
+
| [`mockup-ui-extraction.md`](mockup-ui-extraction.md) | UI-only vs fetch |
|
|
189
|
+
| [`placeholders-and-tokens.md`](placeholders-and-tokens.md) | Token resolution stages |
|
|
190
|
+
| [`custom-field-logic-and-navigation.md`](custom-field-logic-and-navigation.md) | Logic evaluation contract |
|
|
191
|
+
| [`client-lib-folder.md`](client-lib-folder.md) | File layout |
|
|
192
|
+
| [`templates/customFieldValues.ts`](../templates/customFieldValues.ts) | Copy template |
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Placeholders and Tokens
|
|
2
2
|
|
|
3
|
-
> Covers `sdkFeatures.placeholderResolution` — how CRM and dynamic answer tokens resolve in question text.
|
|
3
|
+
> Covers `sdkFeatures.placeholderResolution` — how CRM and dynamic answer tokens resolve in question text.
|
|
4
|
+
> **Agent wiring (discover keys from fetch):** [`placeholders-and-custom-fields-wiring.md`](placeholders-and-custom-fields-wiring.md)
|
|
4
5
|
|
|
5
6
|
---
|
|
6
7
|
|
|
@@ -52,10 +52,12 @@ Survey: 4 questions on active path (Q1–Q4 sequential).
|
|
|
52
52
|
|
|
53
53
|
## UI wiring
|
|
54
54
|
|
|
55
|
+
On the **content** phase, render progress inside sticky chrome so it stays visible when scrolling to the last question on a page:
|
|
56
|
+
|
|
55
57
|
```tsx
|
|
56
|
-
<
|
|
58
|
+
<SurveyStickyChrome progressPercentage={state.progressPercentage} />
|
|
57
59
|
```
|
|
58
60
|
|
|
59
|
-
See [`01-components/11-progress-bar.md`](../01-components/11-progress-bar.md) and [`03-ui-specs/12-survey-chrome.md`](../03-ui-specs/12-survey-chrome.md).
|
|
61
|
+
See [`01-components/19-survey-sticky-chrome.md`](../01-components/19-survey-sticky-chrome.md), [`01-components/11-progress-bar.md`](../01-components/11-progress-bar.md), and [`03-ui-specs/12-survey-chrome.md`](../03-ui-specs/12-survey-chrome.md).
|
|
60
62
|
|
|
61
63
|
See also: [`skip-logic-and-navigation.md`](skip-logic-and-navigation.md).
|
|
@@ -132,6 +132,18 @@ else → ask client which React setup to use
|
|
|
132
132
|
|
|
133
133
|
For **existing apps**, read `package.json` and project structure — do not scaffold from scratch unless the client asks.
|
|
134
134
|
|
|
135
|
+
### Recommended `src/lib/` scaffold
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
src/lib/
|
|
139
|
+
├── customFieldValues.ts ← templates/customFieldValues.ts (when CUSTOM_FIELD logic)
|
|
140
|
+
├── surveyUiScaleUtils.ts ← templates/surveyUiScaleUtils.ts
|
|
141
|
+
├── surveyUiIcons.tsx ← templates/surveyUiIcons.tsx (optional co-locate)
|
|
142
|
+
└── heatmapCoords.ts ← templates/heatmapCoords.ts (HEATMAP only)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
See [`client-lib-folder.md`](client-lib-folder.md).
|
|
146
|
+
|
|
135
147
|
---
|
|
136
148
|
|
|
137
149
|
## Survey-type conditional dependencies
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# UI Customization Wizard
|
|
2
|
+
|
|
3
|
+
> Optional **run** after Phase 6 verify. **Wizard-ready build** is mandatory in Phase 5 — see [`agent-execution-flow.md`](agent-execution-flow.md).
|
|
4
|
+
|
|
5
|
+
## Default: local wizard (`customize`)
|
|
6
|
+
|
|
7
|
+
When the client says **yes** to customization in agent chat, **always run:**
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx cfm-sdk customize
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This is the **recommended default** because it:
|
|
14
|
+
|
|
15
|
+
- Serves wizard + component previews from **one local server** (`localhost:4200`)
|
|
16
|
+
- Auto-exports all **11** question-type previews from agent components
|
|
17
|
+
- Writes `survey-ui-config.json` **directly** on save — no S3, no session polling
|
|
18
|
+
- Cleans up automatically when the CLI exits (no orphan S3 garbage)
|
|
19
|
+
- Updates live previews via the same iframe + preview bridge as production
|
|
20
|
+
|
|
21
|
+
**Agent script after client says yes:**
|
|
22
|
+
|
|
23
|
+
> *"I'll open the customization wizard in your browser. Complete all steps and click **Review & Build** when done — I'll apply your changes automatically."*
|
|
24
|
+
|
|
25
|
+
The CLI **blocks** until the client saves. Wait for:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
✅ UI configuration saved to survey-ui-config.json
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then apply per [`apply-ui-config.md`](apply-ui-config.md).
|
|
32
|
+
|
|
33
|
+
### Who can use it
|
|
34
|
+
|
|
35
|
+
| User | Can use `customize`? |
|
|
36
|
+
|------|---------------------|
|
|
37
|
+
| Client on **same machine** as agent (Cursor chat on dev laptop) | **Yes — default** |
|
|
38
|
+
| Client on **another device** | **No** — use EC2 fallback below |
|
|
39
|
+
|
|
40
|
+
`localhost:4200` is only reachable on the machine running the CLI.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## EC2 fallback (`customize-ui`) — remote clients only
|
|
45
|
+
|
|
46
|
+
Use **only** when the client must customize from another PC/tablet/network:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
export CFM_INSTANCE_ID="..." CFM_DEPLOY_API_BASE="http://43.204.26.213:3000"
|
|
50
|
+
npx cfm-sdk customize-ui
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- Uploads previews to EC2 disk (local-server model on remote host)
|
|
54
|
+
- Prints EC2 wizard link — agent sends link to client
|
|
55
|
+
- CLI **polls** until client submits → writes `.final.json` + `.diff.md`
|
|
56
|
+
- Requires deploy-api on EC2 + `CFM_INSTANCE_ID`
|
|
57
|
+
|
|
58
|
+
See [`wizard-api.md`](wizard-api.md) and [`wizard-config-handoff.md`](wizard-config-handoff.md).
|
|
59
|
+
|
|
60
|
+
**Do not** use `customize-ui` when client and agent share the same machine — `customize` is simpler and more reliable.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## When to ask (INPUT 3)
|
|
65
|
+
|
|
66
|
+
After Phase 6 verify + dev server:
|
|
67
|
+
|
|
68
|
+
> *"Your survey is running locally. Would you like to customize the UI through the web wizard?"*
|
|
69
|
+
|
|
70
|
+
- **Yes** → `npx cfm-sdk customize` (default)
|
|
71
|
+
- **Yes, but I'm on a different device** → `npx cfm-sdk customize-ui`
|
|
72
|
+
- **No** → Phase 7 deploy ask
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## How local wizard works
|
|
77
|
+
|
|
78
|
+
```mermaid
|
|
79
|
+
sequenceDiagram
|
|
80
|
+
participant Agent as Agent CLI
|
|
81
|
+
participant Srv as localhost:4200
|
|
82
|
+
participant Wizard as Wizard SPA
|
|
83
|
+
participant Prev as out/previews/
|
|
84
|
+
|
|
85
|
+
Agent->>Agent: export-previews (all 11 types)
|
|
86
|
+
Agent->>Srv: customize serves wizard + previews
|
|
87
|
+
Wizard->>Srv: GET /api/inventory
|
|
88
|
+
Wizard->>Prev: iframe /previews/MCQ_single/...
|
|
89
|
+
Wizard->>Srv: POST /api/save-config
|
|
90
|
+
Srv->>Agent: survey-ui-config.json written, CLI exits
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
| Route | Purpose |
|
|
94
|
+
|-------|---------|
|
|
95
|
+
| `/api/inventory` | Preview manifest + seed config |
|
|
96
|
+
| `/previews/{key}/index.html` | Component-wise live preview |
|
|
97
|
+
| `/api/save-config` | Client submit → JSON on disk |
|
|
98
|
+
| `/api/upload-logo` | Logo → `public/` |
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Seed config
|
|
103
|
+
|
|
104
|
+
| Priority | Source |
|
|
105
|
+
|----------|--------|
|
|
106
|
+
| 1 | `./survey-ui-config.json` (draft) |
|
|
107
|
+
| 2 | `src/styles/survey-theme.css` |
|
|
108
|
+
| 3 | `implementation_plan.md` |
|
|
109
|
+
| 4 | `Header.tsx` logo contract |
|
|
110
|
+
| 5 | SDK defaults |
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Agent checklist
|
|
115
|
+
|
|
116
|
+
- [ ] Phase 5: wizard-preview artifacts wired
|
|
117
|
+
- [ ] Client opted in (INPUT 3)
|
|
118
|
+
- [ ] Ran **`npx cfm-sdk customize`** (default) and waited for CLI exit 0
|
|
119
|
+
- [ ] Read `survey-ui-config.json` (or `.diff.md` if used EC2 fallback)
|
|
120
|
+
- [ ] Phase 6c: applied per [`apply-ui-config.md`](apply-ui-config.md)
|
|
121
|
+
- [ ] Re-ran verify + build
|
|
122
|
+
|
|
123
|
+
See [`wizard-troubleshooting.md`](wizard-troubleshooting.md) if previews show mock UI.
|
|
@@ -88,7 +88,41 @@ Missing ids in the map are treated as empty for logic evaluation.
|
|
|
88
88
|
|
|
89
89
|
When the survey uses custom-field logic, also pass the same map into `Question.tsx` visibility helpers — see [`custom-field-logic-and-navigation.md`](custom-field-logic-and-navigation.md).
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Custom field values (required when survey uses CRM logic)
|
|
94
|
+
|
|
95
|
+
Custom field values are **not** survey UI inputs — they come from CRM/transaction context (host app API, JWT claims, etc.) and enable SDK evaluation of rules where `entityType: 'CUSTOM_FIELD'`.
|
|
96
|
+
|
|
97
|
+
| Situation | Action |
|
|
98
|
+
|-----------|--------|
|
|
99
|
+
| No `_c_…` ids in fetched survey logic | `customFieldValues: {}` or omit — empty map is fine |
|
|
100
|
+
| Any skip/display/answer/end rule references `CUSTOM_FIELD` | **Required** — copy [`templates/customFieldValues.ts`](../templates/customFieldValues.ts) → `src/lib/customFieldValues.ts` |
|
|
101
|
+
|
|
102
|
+
### Import and wire (two places)
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { CUSTOM_FIELD_VALUES } from '@/lib/customFieldValues';
|
|
106
|
+
|
|
107
|
+
// 1. Hook options (skip, display, progress, validation, end-page logic)
|
|
108
|
+
const surveyOptions = useMemo(
|
|
109
|
+
() => ({
|
|
110
|
+
instanceId,
|
|
111
|
+
placeholders: SURVEY_PLACEHOLDERS,
|
|
112
|
+
customFieldValues: CUSTOM_FIELD_VALUES,
|
|
113
|
+
}),
|
|
114
|
+
[instanceId, selectedLanguage]
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// 2. Question prop (answer-logic UI — same map)
|
|
118
|
+
<Question customFieldValues={CUSTOM_FIELD_VALUES} ... />
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Both wiring points are mandatory** when custom-field logic exists. Hook-only wiring breaks answer-logic UI; Question-only wiring breaks skip/display/progress.
|
|
122
|
+
|
|
123
|
+
Discovery steps: [`custom-field-logic-and-navigation.md`](custom-field-logic-and-navigation.md) · lib layout: [`client-lib-folder.md`](client-lib-folder.md).
|
|
124
|
+
|
|
125
|
+
---
|
|
92
126
|
|
|
93
127
|
| Namespace | Field | Type | Purpose |
|
|
94
128
|
|-----------|-------|------|---------|
|