@explorer02/cfm-survey-sdk 0.2.3 → 0.2.4
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 +140 -33
- package/dist/cli/index.mjs +140 -33
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +8 -1
- package/postinstall.js +8 -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 +281 -0
- package/templates/docs/00-integration/agent-operating-contract.md +260 -0
- package/templates/docs/00-integration/apply-ui-config.md +365 -0
- 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 +88 -62
- package/templates/docs/00-integration/constraints.md +13 -5
- package/templates/docs/00-integration/custom-field-logic-and-navigation.md +56 -0
- 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 +144 -0
- package/templates/docs/00-integration/useSurveySDK.md +35 -1
- package/templates/docs/00-integration/wizard-api.md +134 -0
- package/templates/docs/00-integration/wizard-config-handoff.md +246 -0
- package/templates/docs/00-integration/wizard-preview-build-guide.md +400 -0
- package/templates/docs/00-integration/wizard-question-type-styling.md +195 -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 +162 -6
- package/templates/docs/index.md +116 -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/implementation_plan.md +56 -9
- 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-DgHfrVeb.js +1 -0
- package/templates/wizard-dist/assets/TypePanel-CFVC3Ptn.js +1 -0
- package/templates/wizard-dist/assets/index-BhWM50Yu.css +1 -0
- package/templates/wizard-dist/assets/index-DYK3X1e5.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
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
# Wizard Live Preview — Client Build Guide
|
|
2
|
+
|
|
3
|
+
> **Read during Phase 5 (BUILD) — mandatory.** Wizard **run** (Phase 6b) is optional; this contract is required for every agent build.
|
|
4
|
+
> Pipeline: [`agent-execution-flow.md`](agent-execution-flow.md).
|
|
5
|
+
|
|
6
|
+
Related docs:
|
|
7
|
+
|
|
8
|
+
- [`ui-customization-wizard.md`](ui-customization-wizard.md) — wizard flow and CLI
|
|
9
|
+
- [`apply-ui-config.md`](apply-ui-config.md) — applying final `survey-ui-config.json` after wizard
|
|
10
|
+
- [`wizard-api.md`](wizard-api.md) — EC2 `/wizard/*` API
|
|
11
|
+
- [`03-ui-specs/12-survey-chrome.md`](../03-ui-specs/12-survey-chrome.md) — chrome layout spec
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Why client code matters for live preview
|
|
16
|
+
|
|
17
|
+
The wizard does **not** re-render your React app. It loads **static preview pages** built from your real `src/components/` (`npx cfm-sdk export-previews`), then sends token updates into each preview iframe via `postMessage`.
|
|
18
|
+
|
|
19
|
+
```mermaid
|
|
20
|
+
sequenceDiagram
|
|
21
|
+
participant Agent as Agent_build
|
|
22
|
+
participant CLI as export_previews
|
|
23
|
+
participant S3 as S3_previews
|
|
24
|
+
participant Wizard as Wizard_SPA
|
|
25
|
+
participant Iframe as Preview_iframe
|
|
26
|
+
|
|
27
|
+
Agent->>Agent: Build components with token contract
|
|
28
|
+
Agent->>CLI: customize-ui / export-previews
|
|
29
|
+
CLI->>S3: Upload HTML + JS + CSS
|
|
30
|
+
Wizard->>Iframe: Load chrome / MCQ_single / etc.
|
|
31
|
+
Wizard->>Iframe: postMessage SNAPSHOT + DELTA
|
|
32
|
+
Iframe->>Iframe: Apply --cfm-* vars + content patches
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If components use **hardcoded** colors (`bg-[#e20074]`) with no `var(--cfm-*)` hooks, the preview **looks correct initially** but **does not change** when the client drags color pickers or edits identity fields (unless a harness override happens to match your class names).
|
|
36
|
+
|
|
37
|
+
**The same token contract is used after the wizard** when you apply `survey-ui-config.json` to production (Phase 6c). Building for live preview = building for accurate customization end-to-end.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Two preview modes (know which you get)
|
|
42
|
+
|
|
43
|
+
| Mode | CLI | Preview source | Live updates | Fidelity |
|
|
44
|
+
|------|-----|----------------|--------------|----------|
|
|
45
|
+
| **Agent components** (default) | `export-previews` | Copies your `src/components/` + Vite build | Full **only if** token contract below is followed | Matches real survey UI |
|
|
46
|
+
| **Template harness only** | `export-previews --use-templates-only` | SDK static HTML harness | Always live | Generic SDK chrome — not your implementation |
|
|
47
|
+
|
|
48
|
+
**Default for production wizard:** agent components. Use templates-only for SDK smoke tests, not client delivery.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Required project artifacts (Phase 5)
|
|
53
|
+
|
|
54
|
+
Create these **before** the client opens the wizard:
|
|
55
|
+
|
|
56
|
+
| File | Purpose |
|
|
57
|
+
|------|---------|
|
|
58
|
+
| `src/styles/survey-theme.css` | All `--cfm-*` CSS custom properties (defaults from mockup) |
|
|
59
|
+
| `survey-ui-config.json` (draft) | Seeds wizard form fields from agent branding |
|
|
60
|
+
| `src/lib/previewBridge.ts` | Live bridge in **local dev** (`npx cfm-sdk customize`) — copy from `templates/previewBridge.ts` |
|
|
61
|
+
| `src/components/PreviewBridgeInit.tsx` | Mount bridge once in `layout.tsx` (local dev only) |
|
|
62
|
+
|
|
63
|
+
Import theme in `globals.css`:
|
|
64
|
+
|
|
65
|
+
```css
|
|
66
|
+
@import "tailwindcss";
|
|
67
|
+
@import "../styles/survey-theme.css";
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Wire bridge in root layout (client app only — not uploaded to wizard):
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { PreviewBridgeInit } from '@/components/PreviewBridgeInit';
|
|
74
|
+
|
|
75
|
+
export default function RootLayout({ children }) {
|
|
76
|
+
return (
|
|
77
|
+
<html lang="en">
|
|
78
|
+
<body>
|
|
79
|
+
<PreviewBridgeInit />
|
|
80
|
+
{children}
|
|
81
|
+
</body>
|
|
82
|
+
</html>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Wizard iframes** embed `preview-bridge.inline.js` at export time — you do not ship `previewBridge.ts` inside preview HTML.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## The token contract (two layers)
|
|
92
|
+
|
|
93
|
+
### Layer 1 — CSS variables (`--cfm-*`)
|
|
94
|
+
|
|
95
|
+
Wizard sends CSS custom properties on `:root` (SNAPSHOT on tab load, DELTA during drag).
|
|
96
|
+
|
|
97
|
+
**Rule:** Any brand color, radius, spacing, or chrome dimension the client can edit in the wizard must be consumed via `var(--cfm-…)` in components or shared CSS — **not** hardcoded hex in Tailwind arbitrary values.
|
|
98
|
+
|
|
99
|
+
Copy the full default set from [`templates/survey-theme.css`](../../survey-theme.css) and extend with per-type vars your survey uses.
|
|
100
|
+
|
|
101
|
+
**Good — responds to wizard color changes:**
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
<div
|
|
105
|
+
className="h-3 rounded-full transition-all"
|
|
106
|
+
style={{
|
|
107
|
+
width: `${progress}%`,
|
|
108
|
+
backgroundColor: 'var(--cfm-progress-fill, var(--cfm-primary))',
|
|
109
|
+
}}
|
|
110
|
+
/>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Avoid for wizard-controlled colors:**
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
<div className="bg-[#e20074] h-3 rounded-full" />
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Tailwind + tokens pattern** (when you prefer classes):
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
<button
|
|
123
|
+
className="rounded-md px-6 py-2 text-sm font-semibold hover:opacity-90"
|
|
124
|
+
style={{
|
|
125
|
+
backgroundColor: 'var(--cfm-primary)',
|
|
126
|
+
color: 'var(--cfm-button-text)',
|
|
127
|
+
borderRadius: 'var(--cfm-border-radius)',
|
|
128
|
+
}}
|
|
129
|
+
>
|
|
130
|
+
{nextLabel}
|
|
131
|
+
</button>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Or define utilities in `survey-theme.css`:
|
|
135
|
+
|
|
136
|
+
```css
|
|
137
|
+
.cfm-btn-primary {
|
|
138
|
+
background-color: var(--cfm-primary);
|
|
139
|
+
color: var(--cfm-button-text);
|
|
140
|
+
border-radius: var(--cfm-border-radius);
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Layer 2 — Content hooks (`data-cfm-*`)
|
|
145
|
+
|
|
146
|
+
Wizard sends a **content patch** for text, logo URL, layout toggles, and footer links. The preview bridge updates DOM nodes matching these attributes.
|
|
147
|
+
|
|
148
|
+
| Attribute | Wizard source | Apply to |
|
|
149
|
+
|-----------|---------------|----------|
|
|
150
|
+
| `data-cfm-logo` | Logo step / `global.logo` | `<img>` in Header, Footer — **image logo mode** |
|
|
151
|
+
| `data-cfm-logo-text` | Identity → company name (when no image) | Text fallback inside logo slot — **text logo mode** |
|
|
152
|
+
| `data-cfm-company` | Identity → company name | Header company text (separate from logo slot) |
|
|
153
|
+
| `data-cfm-survey-title` | Identity → survey title | Main heading, chrome preview |
|
|
154
|
+
| `data-cfm-thank-you` | Identity → thank-you message | End page message |
|
|
155
|
+
| `data-cfm-copyright` | Footer step | Footer copyright line |
|
|
156
|
+
| `data-cfm-footer-links` | Footer step | Footer `<nav>` container (links injected) |
|
|
157
|
+
| `data-cfm-btn-next` | Layout → button labels | Next / Submit button |
|
|
158
|
+
| `data-cfm-btn-back` | Layout → button labels | Back button |
|
|
159
|
+
| `data-cfm-progress` | Layout → show progress bar | Wrapper around `ProgressBar` |
|
|
160
|
+
|
|
161
|
+
**Image logo (file in `public/`):**
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
<div className="cfm-header-logo-slot flex shrink-0 items-center justify-center">
|
|
165
|
+
<img
|
|
166
|
+
data-cfm-logo
|
|
167
|
+
src="/telekom-logo.svg"
|
|
168
|
+
alt="Company"
|
|
169
|
+
className="object-contain"
|
|
170
|
+
style={{
|
|
171
|
+
padding: 'var(--cfm-header-logo-padding)',
|
|
172
|
+
width: '100%',
|
|
173
|
+
height: '100%',
|
|
174
|
+
}}
|
|
175
|
+
/>
|
|
176
|
+
{/* Hidden until wizard has no uploaded image — bridge toggles visibility */}
|
|
177
|
+
<span data-cfm-logo-text className="hidden font-semibold">
|
|
178
|
+
Company Name
|
|
179
|
+
</span>
|
|
180
|
+
</div>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Text-only logo (CSS-built brand, no `public/` image):**
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
<div className="cfm-header-logo-slot flex shrink-0 items-center justify-center">
|
|
187
|
+
<span
|
|
188
|
+
data-cfm-logo-text
|
|
189
|
+
className="font-semibold"
|
|
190
|
+
style={{
|
|
191
|
+
color: 'var(--cfm-header-company-color)',
|
|
192
|
+
fontSize: 'var(--cfm-header-company-size)',
|
|
193
|
+
fontWeight: 'var(--cfm-header-company-weight)',
|
|
194
|
+
}}
|
|
195
|
+
>
|
|
196
|
+
Company Name
|
|
197
|
+
</span>
|
|
198
|
+
</div>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Do **not** add unrelated `public/logo_*` files during agent build — the CLI seeds the wizard from `Header.tsx` (`data-cfm-logo` src) or `data-cfm-logo-text`, not the newest file in `public/`. After the client uploads a logo in the wizard, `survey-ui-config.json` stores `global.logo.fileName`; the next wizard session uses **only that saved file**.
|
|
202
|
+
|
|
203
|
+
**Example SurveyPage nav buttons:**
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
<button data-cfm-btn-back type="button" onClick={onBack}>
|
|
207
|
+
Back
|
|
208
|
+
</button>
|
|
209
|
+
<button
|
|
210
|
+
data-cfm-btn-next
|
|
211
|
+
type="button"
|
|
212
|
+
style={{ backgroundColor: 'var(--cfm-primary)', color: 'var(--cfm-button-text)' }}
|
|
213
|
+
onClick={onNext}
|
|
214
|
+
>
|
|
215
|
+
Next
|
|
216
|
+
</button>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Per-component checklist
|
|
222
|
+
|
|
223
|
+
### Chrome (always)
|
|
224
|
+
|
|
225
|
+
| Component | CSS vars | data-cfm-* |
|
|
226
|
+
|-----------|----------|------------|
|
|
227
|
+
| `Header.tsx` | `--cfm-header-*`, `--cfm-primary` (logo box) | `data-cfm-logo`, `data-cfm-company` |
|
|
228
|
+
| `Footer.tsx` | `--cfm-footer-*` | `data-cfm-logo`, `data-cfm-copyright`, `data-cfm-footer-links` |
|
|
229
|
+
| `ProgressBar.tsx` | `--cfm-progress-*` | wrap parent with `data-cfm-progress` |
|
|
230
|
+
| `SurveyStickyChrome.tsx` | header + progress vars | same as Header / progress |
|
|
231
|
+
| `IntroPage.tsx` | page bg, card, primary button | `data-cfm-survey-title` on main heading |
|
|
232
|
+
| `EndPage.tsx` | same | `data-cfm-thank-you` on thank-you copy |
|
|
233
|
+
| `SurveyPage.tsx` | `--cfm-max-width`, layout toggles | `data-cfm-btn-next`, `data-cfm-btn-back`; conditional render for `showHeader`, `showFooter`, `showProgressBar` from config at apply time |
|
|
234
|
+
|
|
235
|
+
### Question scales (per type in survey)
|
|
236
|
+
|
|
237
|
+
Full per-type wizard control mapping: [`wizard-question-type-styling.md`](wizard-question-type-styling.md).
|
|
238
|
+
|
|
239
|
+
Use vars from `survey-theme.css` for cosmetic tokens the wizard exposes per type. See [`apply-ui-config.md`](apply-ui-config.md) token → file mapping.
|
|
240
|
+
|
|
241
|
+
| Type | Key vars | Component |
|
|
242
|
+
|------|----------|-----------|
|
|
243
|
+
| MCQ | `--cfm-mcq-*` | `Question.tsx` MCQ branch / `OptionItem` |
|
|
244
|
+
| NPS_SCALE | `--cfm-nps-*` | `RatingScale.tsx` |
|
|
245
|
+
| CFM_MATRIX | `--cfm-matrix-*` | `LikertMatrixScale.tsx` |
|
|
246
|
+
| CSAT_MATRIX | `--cfm-csat-*` | `CsatMatrixScale.tsx` |
|
|
247
|
+
| RATING_MATRIX | `--cfm-star-*`, `--cfm-badge-*` | `RatingScale.tsx` / `CsatMatrixScale.tsx` |
|
|
248
|
+
| SLIDER_MATRIX | `--cfm-slider-*` | `SliderMatrixScale.tsx`, `CustomSliderTrack.tsx` |
|
|
249
|
+
| FILE_UPLOAD | `--cfm-upload-*` | `FileUploadScale.tsx` |
|
|
250
|
+
| HEATMAP | `--cfm-heatmap-*` | `HeatmapScale.tsx` |
|
|
251
|
+
| RANK_ORDER | `--cfm-rank-*` | `RankOrderScale.tsx` |
|
|
252
|
+
|
|
253
|
+
**Do not change** dispatch logic, answer shapes, or SDK visibility helpers for wizard compatibility.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Draft `survey-ui-config.json` (wizard seed)
|
|
258
|
+
|
|
259
|
+
After branding from the client prompt, write a **draft** `survey-ui-config.json` at project root so `customize-ui` seeds the wizard with your build — not generic Sprinklr defaults.
|
|
260
|
+
|
|
261
|
+
CLI resolution order:
|
|
262
|
+
|
|
263
|
+
1. `./survey-ui-config.json` — including wizard-saved `global.logo.fileName` (re-open uses uploaded logo only)
|
|
264
|
+
2. Parsed `src/styles/survey-theme.css`
|
|
265
|
+
3. `implementation_plan.md` branding hints
|
|
266
|
+
4. `Header.tsx` — `data-cfm-logo` image `src` (e.g. `/telekom-logo.svg`) or `data-cfm-logo-text` for text-only builds
|
|
267
|
+
5. SDK defaults
|
|
268
|
+
|
|
269
|
+
**Logo seed rules for agents:**
|
|
270
|
+
|
|
271
|
+
- **Image logo:** put file in `public/`, reference exact path on `<img data-cfm-logo src="/your-logo.svg" />`. CLI base64-encodes that file for the wizard preview.
|
|
272
|
+
- **Text logo:** use `<span data-cfm-logo-text>` in the logo slot (CSS shapes optional). Omit `data-cfm-logo` img. Wizard shows company text until client uploads an image.
|
|
273
|
+
- **After wizard upload:** `global.logo.fileName` in saved config takes precedence — do not fall back to `Header.tsx` or scan `public/logo_*`.
|
|
274
|
+
|
|
275
|
+
Debug without opening wizard:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
npx cfm-sdk resolve-ui-config --write
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Keep draft JSON and `survey-theme.css` **in sync** (same primary color, title, company name).
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## How `export-previews` uses your code
|
|
286
|
+
|
|
287
|
+
When the client opts in, `customize-ui` runs `export-previews`:
|
|
288
|
+
|
|
289
|
+
1. Copies `src/components/`, `src/lib/`, `public/`, `survey-theme.css` into a temp Vite harness
|
|
290
|
+
2. Stubs `next/image` and `next/dynamic` for static build
|
|
291
|
+
3. Builds one HTML page per preview key (`header`, `chrome`, `MCQ_single`, …) with canonical fixtures
|
|
292
|
+
4. Injects `preview-bridge.inline.js` into each `index.html`
|
|
293
|
+
5. Uploads each preview page to S3 via EC2 presigned PUTs
|
|
294
|
+
6. Prints the **deployed wizard link** for the client:
|
|
295
|
+
|
|
296
|
+
```
|
|
297
|
+
http://43.204.26.213:3000/wizard-app/index.html?session=<uuid>&secret=<hex>
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
7. Wizard iframes load previews via EC2 proxy (`GET /wizard/preview/:sessionId/:component/...`)
|
|
301
|
+
|
|
302
|
+
**Agent handoff:** after step 5–6, copy the printed link and send it to the client. The client customizes on EC2 only — not localhost.
|
|
303
|
+
|
|
304
|
+
Preview keys match wizard steps — see [`ui-customization-wizard.md`](ui-customization-wizard.md) step table.
|
|
305
|
+
|
|
306
|
+
**Implication:** Wizard previews are a **snapshot of your component source at export time**. Re-run `customize-ui` (or `export-previews` + re-upload) after you change component structure.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Live update protocol (wizard ↔ iframe)
|
|
311
|
+
|
|
312
|
+
| Message | When | Payload |
|
|
313
|
+
|---------|------|---------|
|
|
314
|
+
| `CFM_UI_CONFIG_SNAPSHOT` | Iframe load, tab change, text debounce | Full `cssVars` + `contentPatch` |
|
|
315
|
+
| `CFM_UI_CONFIG_DELTA` | Color sliders, drag (~60fps) | Partial `cssVars` only |
|
|
316
|
+
|
|
317
|
+
Content patches apply to `[data-cfm-*]` nodes. CSS vars apply to `:root`. Components must **read** those vars (Layer 1) for visual updates.
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Agent build checklist (blocking for full live preview)
|
|
322
|
+
|
|
323
|
+
Add to `implementation_plan.md` §5 and verify before Phase 6b:
|
|
324
|
+
|
|
325
|
+
- [ ] `src/styles/survey-theme.css` exists with full `--cfm-*` set for types in survey
|
|
326
|
+
- [ ] Draft `survey-ui-config.json` matches theme + identity from mockup
|
|
327
|
+
- [ ] `previewBridge.ts` + `PreviewBridgeInit` wired for local `customize` dev
|
|
328
|
+
- [ ] **No hardcoded brand hex** in chrome or scale components for wizard-controlled tokens
|
|
329
|
+
- [ ] Header: `data-cfm-logo`, `data-cfm-company` + header CSS vars
|
|
330
|
+
- [ ] Footer: `data-cfm-copyright`, `data-cfm-footer-links`, footer CSS vars
|
|
331
|
+
- [ ] ProgressBar: `--cfm-progress-fill` / `--cfm-progress-track`; parent `data-cfm-progress`
|
|
332
|
+
- [ ] SurveyPage buttons: `data-cfm-btn-next`, `data-cfm-btn-back`
|
|
333
|
+
- [ ] Intro/End: `data-cfm-survey-title`, `data-cfm-thank-you` where applicable
|
|
334
|
+
- [ ] Per-type scale vars wired per `apply-ui-config.md` mapping
|
|
335
|
+
- [ ] `npx cfm-sdk export-previews` succeeds from project root
|
|
336
|
+
- [ ] Grep: no `not yet implemented` stubs
|
|
337
|
+
|
|
338
|
+
Quick self-test (local):
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
npx cfm-sdk export-previews
|
|
342
|
+
# Open out/previews/chrome/index.html in browser; in devtools console:
|
|
343
|
+
# postMessage({ type: 'CFM_UI_CONFIG_SNAPSHOT', cssVars: { '--cfm-primary': '#0066cc' }, contentPatch: { surveyTitle: 'Test Title' }}, '*')
|
|
344
|
+
# Title and primary-colored surfaces should update
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Common mistakes
|
|
350
|
+
|
|
351
|
+
| Mistake | Symptom in wizard | Fix |
|
|
352
|
+
|---------|-------------------|-----|
|
|
353
|
+
| Hardcoded `bg-[#brand]` everywhere | Preview frozen on theme step | Use `var(--cfm-primary)` or `.cfm-btn-primary` |
|
|
354
|
+
| `survey-theme.css` missing or minimal | Seed config wrong; few vars update | Copy full template `survey-theme.css` |
|
|
355
|
+
| No `data-cfm-survey-title` | Identity edits don't change preview text | Add attribute to visible headings |
|
|
356
|
+
| Logo `<Image>` without `data-cfm-logo` | Logo step doesn't update preview | Add `data-cfm-logo` to img |
|
|
357
|
+
| Only Phase 6c tokenization | Worked after wizard, not during | Tokenize in Phase 5 (this guide) |
|
|
358
|
+
| Skipped `export-previews` after component edits | Wizard shows old UI | Re-run `customize-ui` |
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## Phase flow summary
|
|
363
|
+
|
|
364
|
+
| Phase | Agent action |
|
|
365
|
+
|-------|----------------|
|
|
366
|
+
| **5 BUILD** | Implement components per this guide + UI specs; draft config + theme |
|
|
367
|
+
| **6 VERIFY** | `npm run build`, verify script, localhost preview |
|
|
368
|
+
| **6b WIZARD** (optional) | Client says yes → `customize-ui` → **wait** for submit → read `.diff.md` |
|
|
369
|
+
| **6c APPLY** | Apply **all** paths from `survey-ui-config.final.json` per [`wizard-config-handoff.md`](wizard-config-handoff.md) + [`apply-ui-config.md`](apply-ui-config.md) → `confirm-ui-config` |
|
|
370
|
+
| **7 DEPLOY** | Full static build upload (separate from wizard preview files) |
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
## Copy-from-template shortcut
|
|
375
|
+
|
|
376
|
+
Fastest path to full live preview: start from SDK portable templates in `templates/docs/templates/`, then customize branding using **tokens from day one** rather than hardcoded mockup hex. Extend tokens as you deviate from defaults.
|
|
377
|
+
|
|
378
|
+
Templates to prioritize for token wiring:
|
|
379
|
+
|
|
380
|
+
- `Header.tsx`, `Footer.tsx`, `ProgressBar.tsx`, `SurveyStickyChrome.tsx`
|
|
381
|
+
- Scale components listed in [`component-checklist.md`](component-checklist.md)
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## CLI reference
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
# Build preview pages only (from project root)
|
|
389
|
+
npx cfm-sdk export-previews
|
|
390
|
+
|
|
391
|
+
# Template harness smoke test (not client UI)
|
|
392
|
+
npx cfm-sdk export-previews --use-templates-only
|
|
393
|
+
|
|
394
|
+
# Full AWS wizard session
|
|
395
|
+
export CFM_INSTANCE_ID="..." CFM_DEPLOY_API_BASE="http://your-ec2:3000"
|
|
396
|
+
npx cfm-sdk customize-ui
|
|
397
|
+
|
|
398
|
+
# Inspect seed config
|
|
399
|
+
npx cfm-sdk resolve-ui-config --write
|
|
400
|
+
```
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Wizard Question-Type Styling
|
|
2
|
+
|
|
3
|
+
> **Read during Phase 5 (BUILD) — mandatory.** Alongside [`wizard-preview-build-guide.md`](wizard-preview-build-guide.md) and [`apply-ui-config.md`](apply-ui-config.md).
|
|
4
|
+
> Pipeline: [`agent-execution-flow.md`](agent-execution-flow.md).
|
|
5
|
+
|
|
6
|
+
**Do not change** `Question.tsx` dispatch logic, answer shapes, SDK visibility helpers, or matrix routing algorithms — styling only.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Shared selection pattern (Question card theme)
|
|
11
|
+
|
|
12
|
+
Wizard **Theme & Colors → Question card** exposes two tokens used across radio/scale selections:
|
|
13
|
+
|
|
14
|
+
| Wizard field | CSS variable | Visual role |
|
|
15
|
+
|--------------|--------------|-------------|
|
|
16
|
+
| **Cell selected color** | `--cfm-matrix-selected` | Fill **between** outer ring and inner dot (annulus); also solid numbered/star cell background when selected |
|
|
17
|
+
| **Focus ring** | `--cfm-input-focus-ring` | Outer circle **border** + inner **dot** color |
|
|
18
|
+
|
|
19
|
+
Also mapped (for MCQ compatibility): `--cfm-mcq-selected-accent` ← cell selected color.
|
|
20
|
+
|
|
21
|
+
Copy [`templates/selectionStyles.ts`](../templates/selectionStyles.ts) → `src/lib/surveyUi/selectionStyles.ts` and use in scale components:
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import {
|
|
25
|
+
scaleRadioRingStyle,
|
|
26
|
+
scaleRadioDotStyle,
|
|
27
|
+
matrixRadioRingStyle,
|
|
28
|
+
matrixRadioDotStyle,
|
|
29
|
+
cellSelectedVar,
|
|
30
|
+
focusRingVar,
|
|
31
|
+
} from '@/lib/surveyUi/selectionStyles';
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Selected radio cell structure:**
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
┌─ focus ring (border) ─────────┐
|
|
38
|
+
│ cell selected (annulus) │
|
|
39
|
+
│ ● focus ring (dot) │
|
|
40
|
+
└─────────────────────────────┘
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Numbered badge when selected:** border = focus ring, background = cell selected, text = white.
|
|
44
|
+
**Unselected numbered badges:** keep traffic-light / per-number colors from `--cfm-number-*` vars (do not override with theme tokens).
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Shared label helpers
|
|
49
|
+
|
|
50
|
+
Copy [`templates/labelStyles.ts`](../templates/labelStyles.ts) → `src/lib/surveyUi/labelStyles.ts`.
|
|
51
|
+
|
|
52
|
+
| Helper | CSS vars | Wizard control |
|
|
53
|
+
|--------|----------|----------------|
|
|
54
|
+
| `hintLabelStyle()` | `--cfm-hint-label-color`, `--cfm-hint-label-bg` | Hint labels (min/max anchors) |
|
|
55
|
+
| `matrixColumnLabelStyle()` | `--cfm-matrix-column-label-*` | CFM matrix column header items |
|
|
56
|
+
| `csatColumnLabelStyle()` | `--cfm-csat-column-label-*` | CSAT/Rating column header items |
|
|
57
|
+
| `sliderTickLabelStyle()` | `--cfm-slider-tick-label-*` | Slider matrix tick label items |
|
|
58
|
+
|
|
59
|
+
**CFM matrix:** column headers are **label items** only — not hint labels, not number labels.
|
|
60
|
+
**CSAT/Rating:** per-format controls differ — see per-type table below.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Per-type wizard controls → CSS vars → components
|
|
65
|
+
|
|
66
|
+
### MCQ (`MCQ_single`, `MCQ_multiple`)
|
|
67
|
+
|
|
68
|
+
| Wizard section | Config path | CSS vars | Apply in |
|
|
69
|
+
|----------------|-------------|----------|----------|
|
|
70
|
+
| Option style | `questionTypes.MCQ.optionStyle` | `data-cfm-mcq-style` on `:root` | `Question.tsx` MCQ branch |
|
|
71
|
+
| Option gap / radius / padding | `questionTypes.MCQ.*` | `--cfm-mcq-option-gap`, `--cfm-mcq-border-radius`, `--cfm-mcq-card-padding` | MCQ option cards |
|
|
72
|
+
| Selection | Theme → Question card | `--cfm-input-focus-ring`, `--cfm-matrix-selected`, `--cfm-mcq-selected-bg` | Radio: ring border + annulus + dot; checkbox: ring border + fill |
|
|
73
|
+
|
|
74
|
+
Single-select radio: outer border = focus ring, annulus = cell selected, inner dot = focus ring.
|
|
75
|
+
|
|
76
|
+
### TEXTFIELD (`TEXTFIELD_short`, `TEXTFIELD_long`)
|
|
77
|
+
|
|
78
|
+
| Wizard section | CSS vars |
|
|
79
|
+
|----------------|----------|
|
|
80
|
+
| Input radius, border, placeholder | `--cfm-input-radius`, `--cfm-input-border`, `--cfm-input-placeholder` |
|
|
81
|
+
| Focus | `--cfm-input-focus-ring` on focus outline |
|
|
82
|
+
|
|
83
|
+
### NPS_SCALE (`NPS_SCALE`)
|
|
84
|
+
|
|
85
|
+
| Wizard section | Config path | CSS vars | Apply in |
|
|
86
|
+
|----------------|-------------|----------|----------|
|
|
87
|
+
| Button style | `questionTypes.NPS_SCALE.buttonStyle` | `data-cfm-nps-button-style` | `RatingScale.tsx` |
|
|
88
|
+
| Track | `selectedFill`, `trackBar`, `trackHighlight` | `--cfm-nps-selected-fill`, `--cfm-nps-track-bar`, `--cfm-nps-track-highlight` | Track bar background |
|
|
89
|
+
| Hint labels | `hintMinText`, `hintMaxText` + hint colors | `--cfm-hint-label-*` | Min/max anchor row |
|
|
90
|
+
| Number labels | `numberLabelMode`, per-index colors | `--cfm-number-label-mode`, `--cfm-number-mono-color`, `--cfm-number-color-{n}` | Badge row above radios |
|
|
91
|
+
| Selection | Theme → Question card | `--cfm-matrix-selected`, `--cfm-input-focus-ring` | `scaleRadioRingStyle` + `scaleRadioDotStyle` |
|
|
92
|
+
|
|
93
|
+
### CFM_MATRIX (`CFM_matrix`, `CFM_dropdown`, `CFM_transpose`, `CFM_likert`, `CFM_bipolar`)
|
|
94
|
+
|
|
95
|
+
| Wizard section | CSS vars | Apply in |
|
|
96
|
+
|----------------|----------|----------|
|
|
97
|
+
| Row label width | `--cfm-matrix-row-width` | `LikertMatrixScale.tsx` |
|
|
98
|
+
| Bipolar column width | `--cfm-matrix-bipolar-width` | Bipolar anchor column |
|
|
99
|
+
| Label items | `--cfm-matrix-column-label-color`, `--cfm-matrix-column-label-bg` | Column header row only |
|
|
100
|
+
| Selection | `--cfm-matrix-selected`, `--cfm-input-focus-ring` | `matrixRadioRingStyle` / custom cells; dropdown option ring |
|
|
101
|
+
|
|
102
|
+
**No** per-type accent/ring overrides in CFM — use Question card tokens only.
|
|
103
|
+
|
|
104
|
+
### CSAT_MATRIX (`CSAT_carousel`, `CSAT_dropdown`, `CSAT_emoji`, `CSAT_graphics`, `CSAT_numbered`, `CSAT_star`)
|
|
105
|
+
|
|
106
|
+
| Format | Wizard sections | Key styling |
|
|
107
|
+
|--------|-----------------|-------------|
|
|
108
|
+
| **emoji** | Emoji size, unselected opacity, label items | `emojiSizeStyle()`, `unselectedOpacityStyle()`, emoji ring = focus ring on select |
|
|
109
|
+
| **star** | Emoji size, unselected opacity, label items | Stars: selected color = `cellSelectedVar` |
|
|
110
|
+
| **numbered** | Number labels, label items | Selected cell: border focus ring, fill cell selected |
|
|
111
|
+
| **radio** (grid) | Label items | Horizontal radio grid; `matrixRadioRingStyle` |
|
|
112
|
+
| **graphics** (slider) | Label items, tick labels | `CustomSliderTrack` thumb: ring + annulus + dot pattern |
|
|
113
|
+
| **carousel** | Label items | Dot indicators: cell selected when active |
|
|
114
|
+
| **dropdown / selectbox** | Label items | `MatrixDropdown` + list radio pattern |
|
|
115
|
+
|
|
116
|
+
**Removed from wizard UI (do not wire):** per-type accent, selected ring, badge color, hint labels section on CSAT formats that use label items only.
|
|
117
|
+
|
|
118
|
+
### RATING_MATRIX (`RATING_radio`, `RATING_emoji`, `RATING_graphics`, `RATING_slider`, `RATING_star`, `RATING_numbered`)
|
|
119
|
+
|
|
120
|
+
Same CSAT patterns where formats overlap. **Radio format:** horizontal grid (not vertical list). Use CSAT matrix component paths with star/numbered/emoji/graphics variants.
|
|
121
|
+
|
|
122
|
+
### SLIDER_MATRIX (`SLIDER_matrix`)
|
|
123
|
+
|
|
124
|
+
| Wizard section | CSS vars | Apply in |
|
|
125
|
+
|----------------|----------|----------|
|
|
126
|
+
| Track / thumb / tick | `--cfm-slider-track`, `--cfm-slider-thumb`, `--cfm-slider-tick` | `SliderMatrixScale`, `CustomSliderTrack` |
|
|
127
|
+
| Row band | `--cfm-slider-row-band` | Statement row background |
|
|
128
|
+
| Tick label items | `--cfm-slider-tick-label-*` | Header tick labels |
|
|
129
|
+
| Tick number labels | `--cfm-number-*` | Colored number badges |
|
|
130
|
+
| Thumb selection | `--cfm-matrix-selected`, `--cfm-input-focus-ring` | Knob: border + annulus + center dot |
|
|
131
|
+
|
|
132
|
+
**No** hint labels section in wizard for slider matrix — use tick label items.
|
|
133
|
+
|
|
134
|
+
### FILE_UPLOAD (`FILE_UPLOAD`)
|
|
135
|
+
|
|
136
|
+
| Wizard section | CSS vars | Apply in |
|
|
137
|
+
|----------------|----------|----------|
|
|
138
|
+
| Dropzone border style | `--cfm-upload-border-style`, `data-cfm-dropzone-style` | `FileUploadScale.tsx` |
|
|
139
|
+
| Border color | `--cfm-upload-border-color` | Dropzone border (not hardcoded `#d1d5db`) |
|
|
140
|
+
| Fill / padding | `--cfm-upload-fill`, `--cfm-upload-padding` | Dropzone background |
|
|
141
|
+
| Focus/hover | `--cfm-input-focus-ring`, `--cfm-mcq-selected-bg` | Focus border + drag-active bg |
|
|
142
|
+
|
|
143
|
+
### HEATMAP (`HEATMAP`)
|
|
144
|
+
|
|
145
|
+
| Wizard section | CSS vars |
|
|
146
|
+
|----------------|----------|
|
|
147
|
+
| Pin color / border / size | `--cfm-heatmap-pin`, pin border config, `--cfm-heatmap-pin-size` |
|
|
148
|
+
|
|
149
|
+
### RANK_ORDER (`RANK_drag`, `RANK_dropdown`)
|
|
150
|
+
|
|
151
|
+
| Variant | Wizard controls | CSS vars |
|
|
152
|
+
|---------|-----------------|----------|
|
|
153
|
+
| Drag | Item bg, handle, badge, gap, padding | `--cfm-rank-item-bg`, `--cfm-rank-handle`, `--cfm-rank-badge`, `--cfm-rank-item-gap`, `--cfm-rank-item-padding` |
|
|
154
|
+
| Dropdown | Item bg, select border, badge | `--cfm-rank-select-border`, etc. |
|
|
155
|
+
| Focus on inputs | Theme focus ring | `--cfm-input-focus-ring` on focus |
|
|
156
|
+
|
|
157
|
+
**Rank drag:** ensure `interactionMode: 'dragAndDrop'` in fixture/survey — do not change dispatch.
|
|
158
|
+
|
|
159
|
+
### TEXT_AND_MEDIA
|
|
160
|
+
|
|
161
|
+
Use `--cfm-media-max-width`, `--cfm-media-radius` from theme.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Live preview re-render (export-previews harness)
|
|
166
|
+
|
|
167
|
+
Components that read CSS vars at render time should import `useLiveThemeTick` from preview harness or bump state when wizard sends `CFM_UI_CONFIG_SNAPSHOT` / `DELTA`. The **export-previews** Vite harness includes this; production client apps only need it if running local `npx cfm-sdk customize`.
|
|
168
|
+
|
|
169
|
+
For production builds after wizard: syncing `survey-theme.css` is sufficient — no `previewLiveTick` required.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Agent checklist (per survey type)
|
|
174
|
+
|
|
175
|
+
For each type in survey inventory:
|
|
176
|
+
|
|
177
|
+
- [ ] Scale component uses `var(--cfm-*)` for every wizard-exposed token (no hardcoded brand hex)
|
|
178
|
+
- [ ] Radio/scale selections use `selectionStyles.ts` pattern (focus ring + cell selected)
|
|
179
|
+
- [ ] Matrix column headers use `labelStyles.ts` (label items — not conflated with hint/number labels)
|
|
180
|
+
- [ ] NPS/numbered formats use `resolveNumberLabelColor` from `surveyUiScaleUtils.ts` for **unselected** badges only
|
|
181
|
+
- [ ] File upload dropzone uses `--cfm-upload-border-color`
|
|
182
|
+
- [ ] `Question.tsx` dispatch unchanged; cosmetic inline styles only
|
|
183
|
+
- [ ] `npx cfm-sdk export-previews` succeeds after styling wiring
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Related files
|
|
188
|
+
|
|
189
|
+
| File | Purpose |
|
|
190
|
+
|------|---------|
|
|
191
|
+
| [`templates/selectionStyles.ts`](../templates/selectionStyles.ts) | Copy to client `src/lib/surveyUi/` |
|
|
192
|
+
| [`templates/labelStyles.ts`](../templates/labelStyles.ts) | Copy to client `src/lib/surveyUi/` |
|
|
193
|
+
| [`templates/survey-theme.css`](../../survey-theme.css) | Full `--cfm-*` defaults |
|
|
194
|
+
| [`wizard-preview-build-guide.md`](wizard-preview-build-guide.md) | Chrome + bridge contract |
|
|
195
|
+
| [`apply-ui-config.md`](apply-ui-config.md) | Post-wizard apply workflow |
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Survey Page Orchestrator Architectural Blueprint
|
|
2
2
|
|
|
3
3
|
> **UI spec (authoritative):** `03-ui-specs/12-survey-chrome.md`
|
|
4
|
-
> **
|
|
4
|
+
> **Portable template:** implement from `docs/templates/` + [`agent-execution-flow.md`](../00-integration/agent-execution-flow.md) Phase 5
|
|
5
|
+
> **Monorepo snapshot (do not copy):** `apps/client/src/components/SurveyPage.tsx`
|
|
5
6
|
> **Target Component**: `SurveyPage`
|
|
6
7
|
> **Role**: Wires `useSurveySDK` to the UI — loading/error states, phase routing, pagination, submission.
|
|
7
8
|
|
|
@@ -13,9 +14,9 @@ Act as the **phase state machine** for the survey. Never render questions direct
|
|
|
13
14
|
|
|
14
15
|
```tsx
|
|
15
16
|
import type { CustomFieldValueMap } from '@explorer02/cfm-survey-sdk';
|
|
17
|
+
import { CUSTOM_FIELD_VALUES } from '@/lib/customFieldValues';
|
|
16
18
|
|
|
17
19
|
const SURVEY_PLACEHOLDERS = { FIRST_NAME: 'Customer' }; // Must be outside component!
|
|
18
|
-
const CUSTOM_FIELD_VALUES: CustomFieldValueMap = {}; // Populate when survey uses custom-field logic
|
|
19
20
|
|
|
20
21
|
export default function SurveyPage() {
|
|
21
22
|
const [selectedLanguage, setSelectedLanguage] = useState<string | undefined>();
|
|
@@ -46,6 +47,14 @@ export default function SurveyPage() {
|
|
|
46
47
|
|
|
47
48
|
See [`client-integration-guide.md`](../00-integration/client-integration-guide.md) for lifecycle effects (`SCROLL`, `RECORD_QUESTION_VIEW`).
|
|
48
49
|
|
|
50
|
+
When fetched survey contains any `_c_…` custom field id in logic rules:
|
|
51
|
+
|
|
52
|
+
- [ ] Copy [`templates/customFieldValues.ts`](../templates/customFieldValues.ts) → `src/lib/customFieldValues.ts`
|
|
53
|
+
- [ ] Populate map from CRM/transaction payload
|
|
54
|
+
- [ ] Import `CUSTOM_FIELD_VALUES` in `SurveyPage` (do not define inline empty `{}`)
|
|
55
|
+
|
|
56
|
+
See [`client-lib-folder.md`](../00-integration/client-lib-folder.md) and [`custom-field-logic-and-navigation.md`](../00-integration/custom-field-logic-and-navigation.md).
|
|
57
|
+
|
|
49
58
|
## Render Order (MANDATORY)
|
|
50
59
|
|
|
51
60
|
Handle in this order:
|
|
@@ -73,12 +82,13 @@ See `14-intro-page.md`, `15-end-page.md`, `16-paused-page.md`.
|
|
|
73
82
|
|
|
74
83
|
### 3. Active content (`phase.kind === 'content'`)
|
|
75
84
|
|
|
76
|
-
1. `Header`
|
|
77
|
-
2. `
|
|
78
|
-
3.
|
|
79
|
-
4.
|
|
80
|
-
5.
|
|
81
|
-
|
|
85
|
+
1. `SurveyStickyChrome` — sticky `Header` + `ProgressBar` (`state.progressPercentage`); see `19-survey-sticky-chrome.md` and `00-integration/progress.md`
|
|
86
|
+
2. `main`: `LanguageSelector`
|
|
87
|
+
3. Question map (below)
|
|
88
|
+
4. Navigation buttons (below)
|
|
89
|
+
5. `Footer`
|
|
90
|
+
|
|
91
|
+
Use standalone `Header` (no sticky chrome) on intro, end, paused, loading, and terminal phases.
|
|
82
92
|
|
|
83
93
|
## The Question Map
|
|
84
94
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **UI spec (authoritative):** `03-ui-specs/00-question-shell.md`
|
|
4
4
|
> **Canonical template:** [`templates/Question.tsx`](../templates/Question.tsx) — copy verbatim, then create imported components
|
|
5
|
-
> **Monorepo
|
|
5
|
+
> **Monorepo snapshot (illustrative only):** `apps/client/src/components/Question.tsx`
|
|
6
6
|
> **Target Component**: `Question`
|
|
7
7
|
|
|
8
8
|
## Start Here (CRITICAL)
|
|
@@ -77,7 +77,7 @@ Store matrix cell values as column **`id`** via `matrixColumnStoredValue(col)`
|
|
|
77
77
|
### MCQ (`QUESTION_TYPE.MCQ`)
|
|
78
78
|
|
|
79
79
|
- [ ] Filter options with `getVisibleMcqOptionsForAnswers` before render
|
|
80
|
-
- [ ] Store `option.id`;
|
|
80
|
+
- [ ] Store `option.id`; use `selectionMode` (`single` | `multiple`) — not `isMultiSelect`
|
|
81
81
|
- [ ] onAction CHANGE: `{ questionId, answerValue: optionId | optionId[] }`
|
|
82
82
|
|
|
83
83
|
### TEXTFIELD (`QUESTION_TYPE.TEXTFIELD`)
|