@explorer02/cfm-survey-sdk 0.2.4 → 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 +34 -33
- package/dist/cli/index.mjs +35 -34
- package/package.json +1 -6
- package/postinstall.js +2 -1
- package/templates/AGENT.md +3 -3
- package/templates/docs/00-integration/agent-execution-flow.md +39 -27
- package/templates/docs/00-integration/agent-operating-contract.md +13 -5
- package/templates/docs/00-integration/apply-ui-config.md +35 -10
- package/templates/docs/00-integration/aws-deploy.md +117 -3
- package/templates/docs/00-integration/component-checklist.md +4 -2
- package/templates/docs/00-integration/constraints.md +3 -2
- package/templates/docs/00-integration/custom-field-logic-and-navigation.md +1 -1
- 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/ui-customization-wizard.md +83 -104
- package/templates/docs/00-integration/wizard-api.md +74 -82
- package/templates/docs/00-integration/wizard-config-handoff.md +55 -9
- package/templates/docs/00-integration/wizard-preview-build-guide.md +12 -7
- package/templates/docs/00-integration/wizard-question-type-styling.md +4 -2
- package/templates/docs/00-integration/wizard-troubleshooting.md +80 -0
- package/templates/docs/01-components/10-header-footer.md +3 -3
- package/templates/docs/MANIFEST.json +30 -13
- package/templates/docs/index.md +7 -9
- package/templates/docs/templates/deploy-to-aws.sh +74 -0
- package/templates/docs/templates/implementation_plan.md +19 -12
- package/templates/wizard-dist/assets/{PreviewMock-DgHfrVeb.js → PreviewMock-AoZdAEPZ.js} +1 -1
- package/templates/wizard-dist/assets/{TypePanel-CFVC3Ptn.js → TypePanel-39FnbtvG.js} +1 -1
- package/templates/wizard-dist/assets/index-CWKdsJOp.js +34 -0
- package/templates/wizard-dist/index.html +1 -1
- package/templates/wizard-dist/assets/index-DYK3X1e5.js +0 -34
|
@@ -172,7 +172,9 @@ For production builds after wizard: syncing `survey-theme.css` is sufficient —
|
|
|
172
172
|
|
|
173
173
|
## Agent checklist (per survey type)
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
**Wizard customization** exposes all **11** question types regardless of fetched survey inventory. Wire styling for every scale template you copy — not only types in the client's mockup image.
|
|
176
|
+
|
|
177
|
+
For each type in **wizard export** (all 11):
|
|
176
178
|
|
|
177
179
|
- [ ] Scale component uses `var(--cfm-*)` for every wizard-exposed token (no hardcoded brand hex)
|
|
178
180
|
- [ ] Radio/scale selections use `selectionStyles.ts` pattern (focus ring + cell selected)
|
|
@@ -191,5 +193,5 @@ For each type in survey inventory:
|
|
|
191
193
|
| [`templates/selectionStyles.ts`](../templates/selectionStyles.ts) | Copy to client `src/lib/surveyUi/` |
|
|
192
194
|
| [`templates/labelStyles.ts`](../templates/labelStyles.ts) | Copy to client `src/lib/surveyUi/` |
|
|
193
195
|
| [`templates/survey-theme.css`](../../survey-theme.css) | Full `--cfm-*` defaults |
|
|
194
|
-
| [`wizard-
|
|
196
|
+
| [`wizard-troubleshooting.md`](wizard-troubleshooting.md) | Mock preview, local vs EC2, toggle/logo fixes |
|
|
195
197
|
| [`apply-ui-config.md`](apply-ui-config.md) | Post-wizard apply workflow |
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Wizard Troubleshooting — Agent Guide
|
|
2
|
+
|
|
3
|
+
> Companion: [`ui-customization-wizard.md`](ui-customization-wizard.md), [`wizard-preview-build-guide.md`](wizard-preview-build-guide.md).
|
|
4
|
+
|
|
5
|
+
## Default command
|
|
6
|
+
|
|
7
|
+
**When client says yes → run `npx cfm-sdk customize`** (not `customize-ui` unless client is on another device).
|
|
8
|
+
|
|
9
|
+
| | `customize` **(default)** | `customize-ui` **(fallback)** |
|
|
10
|
+
|--|---------------------------|--------------------------------|
|
|
11
|
+
| **When** | Client on same machine as agent | Client on different device |
|
|
12
|
+
| **URL** | `localhost:4200` | EC2 link with `session` + `secret` |
|
|
13
|
+
| **Previews** | `out/previews/` on agent disk | EC2 disk |
|
|
14
|
+
| **Save** | `survey-ui-config.json` immediately | Poll → `.final.json` + `.diff.md` |
|
|
15
|
+
| **GC** | CLI stops → no orphans | Session cleanup on EC2 |
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Mock preview instead of live components
|
|
20
|
+
|
|
21
|
+
### Symptom
|
|
22
|
+
|
|
23
|
+
Footer: **"Mock preview — run customize or customize-ui…"**
|
|
24
|
+
|
|
25
|
+
### Fix
|
|
26
|
+
|
|
27
|
+
1. Run `npx cfm-sdk customize` — auto-runs `export-previews` if needed
|
|
28
|
+
2. Ensure `src/components/Question.tsx` exists (Phase 5 build complete)
|
|
29
|
+
3. Re-run if you changed components after last export
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Client on another device opened localhost
|
|
34
|
+
|
|
35
|
+
### Symptom
|
|
36
|
+
|
|
37
|
+
Client cannot open `http://localhost:4200`
|
|
38
|
+
|
|
39
|
+
### Fix
|
|
40
|
+
|
|
41
|
+
Use EC2 fallback:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
export CFM_INSTANCE_ID="<JWT>"
|
|
45
|
+
export CFM_DEPLOY_API_BASE="http://43.204.26.213:3000"
|
|
46
|
+
npx cfm-sdk customize-ui
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Send **only the EC2 link** from CLI output.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Storage service unavailable (EC2 only)
|
|
54
|
+
|
|
55
|
+
Only applies to **`customize-ui`** on submit — S3 denied when saving final config/logo. Previews on EC2 disk do not need S3.
|
|
56
|
+
|
|
57
|
+
Fix: EC2 IAM + `HOSTING_BUCKET` on deploy-api.
|
|
58
|
+
|
|
59
|
+
For same-machine clients, use **`customize`** — no S3 during wizard at all.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Logo / toggles / layout not updating
|
|
64
|
+
|
|
65
|
+
Wire `data-cfm-*` hooks and `--cfm-*` CSS vars per [`wizard-preview-build-guide.md`](wizard-preview-build-guide.md).
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Only one question type showing
|
|
70
|
+
|
|
71
|
+
`customize` exports **all 11** types. Mockup may show NPS only — wizard still customizes all types.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Checklist
|
|
76
|
+
|
|
77
|
+
- [ ] Used **`customize`** as default when client said yes
|
|
78
|
+
- [ ] Waited for `✅ UI configuration saved`
|
|
79
|
+
- [ ] Phase 5 preview bridge + `data-cfm-*` wired
|
|
80
|
+
- [ ] EC2 only if client on remote device
|
|
@@ -25,12 +25,12 @@ Agents must implement **one** of these wizard-compatible patterns in `Header.tsx
|
|
|
25
25
|
|
|
26
26
|
| Mode | When | Required markup |
|
|
27
27
|
|------|------|-----------------|
|
|
28
|
-
| **Image** | Brand asset in `public/` | `<img data-cfm-logo src="
|
|
28
|
+
| **Image** | Brand asset in `public/` | `<img data-cfm-logo src="./exact-file.svg" />` for AWS deploy (`assetPrefix: './'`). Use `/exact-file.svg` only for local dev. Include hidden `<span data-cfm-logo-text>` fallback. |
|
|
29
29
|
| **Text** | CSS-only logo from prompt (no image file) | `<span data-cfm-logo-text>Company</span>` in logo slot — no `data-cfm-logo` img |
|
|
30
30
|
|
|
31
|
-
- **NO EXTERNAL URLS** for logos (`https
|
|
31
|
+
- **NO EXTERNAL URLS** for logos (`https://…`, wizard `/assets/` URLs, or `data:image/…`).
|
|
32
32
|
- **CSS-only logos** use `data-cfm-logo-text` (and optional CSS shapes) — wizard shows text until client uploads an image.
|
|
33
|
-
- After wizard upload,
|
|
33
|
+
- After wizard upload, set `src="./{global.logo.fileName}"` from saved config — see [`aws-deploy.md`](../00-integration/aws-deploy.md) § Logos & local assets.
|
|
34
34
|
|
|
35
35
|
## Theme Engineering
|
|
36
36
|
- Map the primary brand color to the accent and border colors across the entire survey.
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
"surveyUiConfig": {
|
|
20
20
|
"artifact": "survey-ui-config.json",
|
|
21
21
|
"schema": "templates/survey-ui-config.schema.json",
|
|
22
|
-
"cliCommand": "npx cfm-sdk customize
|
|
22
|
+
"cliCommand": "npx cfm-sdk customize",
|
|
23
23
|
"cliCommands": {
|
|
24
|
-
"
|
|
25
|
-
"
|
|
24
|
+
"default": "npx cfm-sdk customize",
|
|
25
|
+
"remoteClient": "npx cfm-sdk customize-ui",
|
|
26
26
|
"exportPreviews": "npx cfm-sdk export-previews"
|
|
27
27
|
},
|
|
28
28
|
"wizardApiDoc": "00-integration/wizard-api.md",
|
|
@@ -178,7 +178,19 @@
|
|
|
178
178
|
},
|
|
179
179
|
{
|
|
180
180
|
"path": "00-integration/wizard-api.md",
|
|
181
|
-
"purpose": "EC2 /wizard/* API
|
|
181
|
+
"purpose": "EC2 /wizard/* API — customize-ui remote-client fallback only"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"path": "00-integration/wizard-troubleshooting.md",
|
|
185
|
+
"purpose": "Fix mock preview, local vs EC2, layout toggles, all-11-types wizard export (Phase 6b)"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"path": "00-integration/mockup-ui-extraction.md",
|
|
189
|
+
"purpose": "UI-only extraction from client mockup — no logic/language/types from images (Phase 0–4)"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"path": "00-integration/placeholders-and-custom-fields-wiring.md",
|
|
193
|
+
"purpose": "Discover placeholder + _c_ keys from fetch; precise useSurveySDK wiring (Phase 4–5)"
|
|
182
194
|
}
|
|
183
195
|
],
|
|
184
196
|
"templateScaleFiles": [
|
|
@@ -203,7 +215,7 @@
|
|
|
203
215
|
"apiBaseEnv": "CFM_DEPLOY_API_BASE",
|
|
204
216
|
"apiBaseDefault": "http://43.204.26.213:3000",
|
|
205
217
|
"wizardClientUrlPattern": "{CFM_DEPLOY_API_BASE}/wizard-app/index.html?session={sessionId}&secret={sessionSecret}",
|
|
206
|
-
"wizardClientUrlNote": "
|
|
218
|
+
"wizardClientUrlNote": "customize-ui only (remote client): EC2 link after preview upload — default is npx cfm-sdk customize on localhost",
|
|
207
219
|
"instanceIdEnv": "CFM_INSTANCE_ID",
|
|
208
220
|
"outDirEnv": "OUT_DIR",
|
|
209
221
|
"healthPath": "/health",
|
|
@@ -263,11 +275,12 @@
|
|
|
263
275
|
"../AGENT.md",
|
|
264
276
|
"00-integration/agent-operating-contract.md",
|
|
265
277
|
"00-integration/agent-execution-flow.md",
|
|
278
|
+
"00-integration/mockup-ui-extraction.md",
|
|
266
279
|
"MANIFEST.json"
|
|
267
280
|
],
|
|
268
281
|
"actions": [
|
|
269
282
|
"detectFramework",
|
|
270
|
-
"
|
|
283
|
+
"extractUiOnlyFromMockup"
|
|
271
284
|
]
|
|
272
285
|
},
|
|
273
286
|
{
|
|
@@ -320,6 +333,8 @@
|
|
|
320
333
|
"readAlways": [
|
|
321
334
|
"00-integration/agent-operating-contract.md",
|
|
322
335
|
"00-integration/agent-execution-flow.md",
|
|
336
|
+
"00-integration/mockup-ui-extraction.md",
|
|
337
|
+
"00-integration/placeholders-and-custom-fields-wiring.md",
|
|
323
338
|
"00-integration/component-checklist.md",
|
|
324
339
|
"00-integration/canonical-survey-fixtures.md",
|
|
325
340
|
"00-integration/client-lib-folder.md",
|
|
@@ -409,21 +424,23 @@
|
|
|
409
424
|
"00-integration/ui-customization-wizard.md",
|
|
410
425
|
"00-integration/wizard-preview-build-guide.md",
|
|
411
426
|
"00-integration/wizard-question-type-styling.md",
|
|
412
|
-
"00-integration/wizard-api.md"
|
|
427
|
+
"00-integration/wizard-api.md",
|
|
428
|
+
"00-integration/wizard-troubleshooting.md"
|
|
413
429
|
],
|
|
414
|
-
"cliCommand": "npx cfm-sdk customize
|
|
415
|
-
"
|
|
430
|
+
"cliCommand": "npx cfm-sdk customize",
|
|
431
|
+
"cliCommandRemote": "npx cfm-sdk customize-ui",
|
|
416
432
|
"cliConfirmCommand": "npx cfm-sdk confirm-ui-config",
|
|
417
|
-
"output": "survey-ui-config.
|
|
418
|
-
"
|
|
433
|
+
"output": "survey-ui-config.json",
|
|
434
|
+
"outputArtifactsRemote": [
|
|
419
435
|
"survey-ui-config.seed.json",
|
|
420
436
|
"survey-ui-config.final.json",
|
|
421
437
|
"survey-ui-config.diff.json",
|
|
422
438
|
"survey-ui-config.diff.md"
|
|
423
439
|
],
|
|
424
440
|
"agentMustWait": true,
|
|
425
|
-
"waitUntil": "
|
|
426
|
-
"clientHandoff": "
|
|
441
|
+
"waitUntil": "cliExit0UiConfigurationSaved",
|
|
442
|
+
"clientHandoff": "openLocalhostWizardSameMachine",
|
|
443
|
+
"clientHandoffRemote": "shareDeployedWizardUrlAfterPreviewUpload",
|
|
427
444
|
"prerequisites": [
|
|
428
445
|
"phase6VerifyPassed",
|
|
429
446
|
"devServerRunning"
|
package/templates/docs/index.md
CHANGED
|
@@ -79,7 +79,7 @@ Full step-by-step: [`agent-execution-flow.md`](00-integration/agent-execution-fl
|
|
|
79
79
|
| **4** Plan | Inventory + copy dispatcher | `component-checklist.md`, per-type MANIFEST docs, `implementation_plan.md` |
|
|
80
80
|
| **5** Build | Wizard-ready UI | `constraints.md`, `wizard-preview-build-guide.md`, `wizard-question-type-styling.md`, `03-ui-specs/*` |
|
|
81
81
|
| **6** Verify | Build + dev server | `verify-agent-build.sh` — **ask wizard** |
|
|
82
|
-
| **6b** Wizard | Optional customize | `customize-ui`
|
|
82
|
+
| **6b** Wizard | Optional customize | **`npx cfm-sdk customize`** (default) — EC2 `customize-ui` only if client on another device |
|
|
83
83
|
| **6c** Apply | Sync final config | `apply-ui-config.md` |
|
|
84
84
|
| **7** Deploy | Production | **ask deploy** — `aws-deploy.md` or Vercel |
|
|
85
85
|
|
|
@@ -130,12 +130,10 @@ Run: `bash templates/verify-agent-build.sh`
|
|
|
130
130
|
Only after Phase 6 passes and client says **yes**:
|
|
131
131
|
|
|
132
132
|
```bash
|
|
133
|
-
|
|
134
|
-
export CFM_DEPLOY_API_BASE="http://43.204.26.213:3000"
|
|
135
|
-
npx cfm-sdk customize-ui # uploads previews → prints client link → WAITS until submit
|
|
133
|
+
npx cfm-sdk customize # DEFAULT — opens localhost:4200, WAITS until client saves
|
|
136
134
|
```
|
|
137
135
|
|
|
138
|
-
**Phase 6b:**
|
|
136
|
+
**Phase 6b:** Client on same machine → `customize` writes `survey-ui-config.json` directly. Remote client → `customize-ui` + EC2 link (see `wizard-troubleshooting.md`). Apply per `apply-ui-config.md`.
|
|
139
137
|
|
|
140
138
|
**Phase 6c:** Apply from `survey-ui-config.final.json` per [`wizard-config-handoff.md`](00-integration/wizard-config-handoff.md) + [`apply-ui-config.md`](00-integration/apply-ui-config.md) — **every** diff path. Then:
|
|
141
139
|
|
|
@@ -151,13 +149,13 @@ Re-run verify script + build.
|
|
|
151
149
|
|
|
152
150
|
| When | Read |
|
|
153
151
|
|------|------|
|
|
154
|
-
| **Always first** | `agent-operating-contract.md`, `agent-execution-flow.md`, `index.md`, `client-integration-guide.md`, `constraints.md` |
|
|
152
|
+
| **Always first** | `agent-operating-contract.md`, `agent-execution-flow.md`, `mockup-ui-extraction.md`, `index.md`, `client-integration-guide.md`, `constraints.md` |
|
|
155
153
|
| Phase 3 contract | `question-type-sdk-matrix.md`, `useSurveySDK.md`, logic/navigation docs |
|
|
156
|
-
|
|
|
154
|
+
| Phase 4 plan | `mockup-ui-extraction.md`, `placeholders-and-custom-fields-wiring.md`, `component-checklist.md`, per-type `03-ui-specs/*` |
|
|
157
155
|
| Wizard build | `wizard-preview-build-guide.md`, `wizard-question-type-styling.md` |
|
|
158
|
-
| Wizard run | `wizard-config-handoff.md`, `ui-customization-wizard.md`, `wizard-api.md` |
|
|
156
|
+
| Wizard run | `wizard-config-handoff.md`, `ui-customization-wizard.md`, `wizard-api.md`, `wizard-troubleshooting.md` |
|
|
159
157
|
| After wizard (apply all paths) | `apply-ui-config.md` |
|
|
160
|
-
| Deploy | `aws-deploy.md
|
|
158
|
+
| Deploy | `aws-deploy.md` (§ Logos & local assets), `setup.md#nextjs-aws-static-export` |
|
|
161
159
|
| Config audit | `02-reference/config-field-index.md` |
|
|
162
160
|
|
|
163
161
|
---
|
|
@@ -24,6 +24,55 @@ echo "API: $CFM_DEPLOY_API_BASE"
|
|
|
24
24
|
echo "OUT: $OUT_DIR ($FILE_COUNT files)"
|
|
25
25
|
echo
|
|
26
26
|
|
|
27
|
+
# Verify wizard logos and other public assets made it into the static build (not just browser memory).
|
|
28
|
+
python3 <<'PY' || exit 1
|
|
29
|
+
import json, os, re, sys
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
|
|
32
|
+
out = Path(os.environ["OUT_DIR"])
|
|
33
|
+
root = Path(os.environ.get("PROJECT_ROOT", os.getcwd()))
|
|
34
|
+
config_path = root / "survey-ui-config.json"
|
|
35
|
+
missing = []
|
|
36
|
+
|
|
37
|
+
if config_path.is_file():
|
|
38
|
+
cfg = json.load(open(config_path))
|
|
39
|
+
logo = (cfg.get("global") or {}).get("logo") or {}
|
|
40
|
+
fn = logo.get("fileName")
|
|
41
|
+
url = logo.get("url") or ""
|
|
42
|
+
if fn:
|
|
43
|
+
if url.startswith("data:"):
|
|
44
|
+
print(f"FAIL: global.logo.url is a data: URL — apply Phase 6c: Header src=./{fn}, file in public/")
|
|
45
|
+
sys.exit(1)
|
|
46
|
+
for base in (root / "public", out):
|
|
47
|
+
if not (base / fn).is_file():
|
|
48
|
+
missing.append(str(base / fn))
|
|
49
|
+
if missing:
|
|
50
|
+
print("FAIL: logo file missing from build output:")
|
|
51
|
+
for p in missing:
|
|
52
|
+
print(f" - {p}")
|
|
53
|
+
print("Fix: run confirm-ui-config (EC2 wizard) or re-upload in customize; update Header data-cfm-logo src")
|
|
54
|
+
sys.exit(1)
|
|
55
|
+
print(f"Logo OK: {fn} in out/")
|
|
56
|
+
else:
|
|
57
|
+
print("No global.logo.fileName in survey-ui-config.json — skipping logo check")
|
|
58
|
+
|
|
59
|
+
for header in sorted((root / "src").rglob("Header.tsx")):
|
|
60
|
+
text = header.read_text()
|
|
61
|
+
for m in re.finditer(r'data-cfm-logo[^>]*\ssrc=["\']([^"\']+)["\']', text):
|
|
62
|
+
src = m.group(1)
|
|
63
|
+
if src.startswith(("http://", "https://", "data:")):
|
|
64
|
+
print(f"FAIL: {header} uses external/data logo src: {src[:60]}")
|
|
65
|
+
sys.exit(1)
|
|
66
|
+
rel = src.lstrip("./").lstrip("/")
|
|
67
|
+
if rel and not (out / rel).is_file():
|
|
68
|
+
missing.append(str(out / rel))
|
|
69
|
+
print(f"FAIL: Header references {src} but {out / rel} not in build")
|
|
70
|
+
sys.exit(1)
|
|
71
|
+
|
|
72
|
+
if not missing:
|
|
73
|
+
print("Static asset preflight OK")
|
|
74
|
+
PY
|
|
75
|
+
|
|
27
76
|
HEALTH=$(curl -s "$CFM_DEPLOY_API_BASE/health")
|
|
28
77
|
echo "Health: $HEALTH"
|
|
29
78
|
echo
|
|
@@ -111,4 +160,29 @@ if [ "$HTTP" != "200" ]; then
|
|
|
111
160
|
exit 1
|
|
112
161
|
fi
|
|
113
162
|
|
|
163
|
+
# Optional: verify logo asset under same deploy prefix (broken img = missing from out/ or wrong Header src)
|
|
164
|
+
python3 <<'PY' || true
|
|
165
|
+
import json, os, re, subprocess
|
|
166
|
+
from pathlib import Path
|
|
167
|
+
from urllib.parse import urljoin
|
|
168
|
+
|
|
169
|
+
root = Path(os.environ.get("PROJECT_ROOT", os.getcwd()))
|
|
170
|
+
cfg_path = root / "survey-ui-config.json"
|
|
171
|
+
live = json.load(open("/tmp/deploy-complete.json"))["url"]
|
|
172
|
+
if not cfg_path.is_file():
|
|
173
|
+
raise SystemExit(0)
|
|
174
|
+
fn = ((json.load(open(cfg_path)).get("global") or {}).get("logo") or {}).get("fileName")
|
|
175
|
+
if not fn:
|
|
176
|
+
raise SystemExit(0)
|
|
177
|
+
base = live.rsplit("/", 1)[0] + "/"
|
|
178
|
+
logo_url = urljoin(base, fn)
|
|
179
|
+
code = subprocess.check_output(
|
|
180
|
+
["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", logo_url],
|
|
181
|
+
text=True,
|
|
182
|
+
).strip()
|
|
183
|
+
print(f"Logo asset: {logo_url} → HTTP {code}")
|
|
184
|
+
if code != "200":
|
|
185
|
+
print("WARN: logo missing on CloudFront — rebuild after Phase 6c logo apply (see aws-deploy.md § Static assets)")
|
|
186
|
+
PY
|
|
187
|
+
|
|
114
188
|
echo "=== Deploy complete ==="
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
> Copy this file to `./implementation_plan.md` in the project root. Fill every section before writing React code.
|
|
4
4
|
>
|
|
5
|
-
> Pipeline: [`agent-operating-contract.md`](../00-integration/agent-operating-contract.md) → [`agent-execution-flow.md`](../00-integration/agent-execution-flow.md)
|
|
5
|
+
> Pipeline: [`agent-operating-contract.md`](../00-integration/agent-operating-contract.md) → [`agent-execution-flow.md`](../00-integration/agent-execution-flow.md)
|
|
6
|
+
> Mockup rules: [`mockup-ui-extraction.md`](../00-integration/mockup-ui-extraction.md)
|
|
6
7
|
|
|
7
8
|
## 0. Project Context
|
|
8
9
|
|
|
9
10
|
- **Framework:** [ ] Next.js App Router [ ] Vite [ ] CRA [ ] Existing app
|
|
10
11
|
- **Package import name:** (from `package.json` — `@explorer02/cfm-survey-sdk` or `@repo/sdk`)
|
|
11
12
|
- **instanceId:** (JWT — wired in SurveyPage)
|
|
12
|
-
- **Branding source:** (client prompt / mockup
|
|
13
|
+
- **Branding source:** (client prompt / mockup — **UI only** per [`mockup-ui-extraction.md`](../00-integration/mockup-ui-extraction.md); optional wizard override via `survey-ui-config.json`)
|
|
13
14
|
|
|
14
15
|
## 1. Data Fetching & State
|
|
15
16
|
|
|
@@ -109,7 +110,8 @@ Read `00-integration/canonical-survey-fixtures.md`. For each matrix question not
|
|
|
109
110
|
|
|
110
111
|
## 3d. Custom field inventory (mandatory when `_c_…` ids found)
|
|
111
112
|
|
|
112
|
-
After fetch, scan `skipLogics`, `displayLogic`, `answerLogic`, and `endPages` for `entityType: 'CUSTOM_FIELD'`.
|
|
113
|
+
After fetch, scan `skipLogics`, `displayLogic`, `answerLogic`, and `endPages` for `entityType: 'CUSTOM_FIELD'`.
|
|
114
|
+
**Do not** infer ids from mockup — see [`placeholders-and-custom-fields-wiring.md`](../00-integration/placeholders-and-custom-fields-wiring.md).
|
|
113
115
|
|
|
114
116
|
| `_c_` id | fieldType | used in (skip/display/answer/end) | logic field (e.g. CASE_SENSITIVE_TEXT) | CRM value | populated in `lib/customFieldValues.ts`? |
|
|
115
117
|
|----------|-----------|-----------------------------------|----------------------------------------|-----------|---------------------------------------------|
|
|
@@ -121,9 +123,17 @@ Wire map in **both** places: `useSurveySDK({ options: { customFieldValues } })`
|
|
|
121
123
|
|
|
122
124
|
See `00-integration/custom-field-logic-and-navigation.md` and `00-integration/client-lib-folder.md`.
|
|
123
125
|
|
|
126
|
+
## 3d-b. Placeholder inventory (from fetched question text)
|
|
127
|
+
|
|
128
|
+
Scan fetched survey for `{{TOKEN}}` and `{{SURVEY_QUESTION-:-id}}` — **not** from mockup. See [`placeholders-and-custom-fields-wiring.md`](../00-integration/placeholders-and-custom-fields-wiring.md).
|
|
129
|
+
|
|
130
|
+
| Token in fetch | Key in `SURVEY_PLACEHOLDERS` | Example value | Question ids |
|
|
131
|
+
|----------------|------------------------------|---------------|--------------|
|
|
132
|
+
| | | | |
|
|
133
|
+
|
|
124
134
|
## 3e. Logic inventory (from fetched survey)
|
|
125
135
|
|
|
126
|
-
Scan `survey.pages` for logic flags. Fill after fetch:
|
|
136
|
+
Scan `survey.pages` for logic flags. Fill after fetch — **not** from mockup:
|
|
127
137
|
|
|
128
138
|
| questionId | skipLogics | displayLogic | answerLogic (options/rows/cols) | customField refs (`_c_…`) |
|
|
129
139
|
|------------|------------|--------------|----------------------------------|---------------------------|
|
|
@@ -182,7 +192,7 @@ Inventory required config fields per type:
|
|
|
182
192
|
- [ ] `src/styles/survey-theme.css` with `--cfm-*` CSS variables (full template set)
|
|
183
193
|
- [ ] **Wizard preview contract:** `var(--cfm-*)` in chrome/scales + `data-cfm-*` on editable text/logo — see `00-integration/wizard-preview-build-guide.md`
|
|
184
194
|
- [ ] **Wizard per-type styling:** `selectionStyles.ts`, `labelStyles.ts`, per-type tokens — see `00-integration/wizard-question-type-styling.md`
|
|
185
|
-
- [ ] **
|
|
195
|
+
- [ ] **Wizard `surveyTypes`:** all 11 literals in seed (mockup may show NPS only — wizard still customizes all types)
|
|
186
196
|
- [ ] `previewBridge.ts` wired for wizard live preview (see `ui-customization-wizard.md`)
|
|
187
197
|
- [ ] If `survey-ui-config.json` exists: apply per `apply-ui-config.md` (Phase 5 draft or Phase 6c final)
|
|
188
198
|
|
|
@@ -190,13 +200,10 @@ Inventory required config fields per type:
|
|
|
190
200
|
|
|
191
201
|
See `wizard-config-handoff.md`.
|
|
192
202
|
|
|
193
|
-
- [ ] `customize
|
|
194
|
-
- [ ]
|
|
195
|
-
- [ ]
|
|
196
|
-
- [ ]
|
|
197
|
-
- [ ] Applied from `survey-ui-config.final.json` (AWS) or `survey-ui-config.json` (local)
|
|
198
|
-
- [ ] Every diff path applied (count matches)
|
|
199
|
-
- [ ] `confirm-ui-config` run (AWS)
|
|
203
|
+
- [ ] `npx cfm-sdk customize` ran (default) and exited 0 — client saved on same machine
|
|
204
|
+
- [ ] OR `customize-ui` + EC2 link if client on remote device
|
|
205
|
+
- [ ] `survey-ui-config.json` written (or `.final.json` + `.diff.md` for EC2)
|
|
206
|
+
- [ ] Applied per `apply-ui-config.md`
|
|
200
207
|
- [ ] Verify + build re-run after apply
|
|
201
208
|
|
|
202
209
|
## 6. Submit & Thank You
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as x,j as e}from"./index-
|
|
1
|
+
import{u as x,j as e}from"./index-CWKdsJOp.js";import{b as t}from"./vendor-BwkXDkd3.js";function p(d=150){const l=x(r=>r.config),[a,s]=t.useState(l);return t.useEffect(()=>{const r=window.setTimeout(()=>s(l),d);return()=>window.clearTimeout(r)},[l,d]),a}const h=t.memo(function(){const l=p(150),a=x(n=>n.logoPreviewDataUrl),{global:s}=l,{layout:r,colorScheme:o,buttons:c}=s,m=t.useMemo(()=>r.borderStyle==="sharp"?"rounded-none":r.borderStyle==="pill"?"rounded-[32px]":"rounded-2xl",[r.borderStyle]),i=t.useMemo(()=>r.fontStyle==="serif"?"Georgia, serif":r.fontStyle==="system"?"system-ui, sans-serif":"Inter, sans-serif",[r.fontStyle]),u=a??s.logo.url,f=t.useMemo(()=>({backgroundColor:o.background,color:o.text,borderColor:o.secondary,fontFamily:i}),[o,i]);return e.jsxs("div",{className:`overflow-hidden border shadow-md ${m}`,style:f,children:[r.showHeader&&e.jsxs("div",{className:"flex items-center gap-3 border-b px-5 py-4",style:{borderColor:o.secondary},children:[u&&e.jsx("img",{src:u,alt:"Logo",className:"max-h-6 w-auto object-contain",loading:"lazy"}),e.jsx("span",{className:"text-xs font-semibold tracking-wider",children:s.companyName})]}),e.jsxs("div",{className:"space-y-6 p-6",children:[r.showProgressBar&&e.jsxs("div",{className:"space-y-1.5",children:[e.jsxs("div",{className:"flex justify-between text-[10px] font-semibold text-slate-400",children:[e.jsx("span",{children:"Progress"}),e.jsx("span",{children:"35%"})]}),e.jsx("div",{className:"h-1.5 w-full overflow-hidden rounded-full bg-slate-100",children:e.jsx("div",{className:"h-full w-[35%] rounded-full",style:{backgroundColor:o.accent}})})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("h4",{className:"flex items-start gap-1.5 text-sm font-bold leading-snug",children:[r.showQuestionNumbers&&e.jsx("span",{className:"font-medium text-slate-400",children:"Q1."}),e.jsx("span",{children:s.surveyTitle}),r.showRequiredAsterisk&&e.jsx("span",{className:"text-red-500",children:"*"})]}),e.jsx("p",{className:"text-[11px] text-slate-400",children:"How would you rate your overall experience?"}),e.jsx("div",{className:"grid grid-cols-5 gap-2",children:[1,2,3,4,5].map(n=>e.jsx("div",{className:`flex h-9 items-center justify-center border text-xs font-semibold ${r.borderStyle==="pill"?"rounded-full":r.borderStyle==="sharp"?"rounded-none":"rounded-lg"}`,style:n===1?{backgroundColor:o.secondary,borderColor:o.primary,color:o.primary}:{backgroundColor:o.background,borderColor:o.secondary,color:o.text},children:n},n))})]})]}),e.jsxs("div",{className:"flex items-center justify-between border-t bg-slate-50/50 px-6 py-4",children:[r.showBackButton&&e.jsx("span",{className:`border px-3 py-1.5 text-[10px] font-semibold ${r.borderStyle==="pill"?"rounded-full":r.borderStyle==="sharp"?"rounded-none":"rounded-lg"}`,style:{borderColor:o.secondary,color:o.text},children:c.back}),e.jsx("div",{className:"flex-1"}),r.showNextButton&&e.jsx("span",{className:`px-4 py-1.5 text-[10px] font-bold ${r.borderStyle==="pill"?"rounded-full":r.borderStyle==="sharp"?"rounded-none":"rounded-lg"}`,style:{backgroundColor:o.primary,color:o.buttonText},children:c.next})]})]})});export{h as PreviewMock};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as g,j as e,T as f,S as j,R as u,N as t,C as i,a as M,M as L}from"./index-DYK3X1e5.js";import"./vendor-BwkXDkd3.js";function b({values:o,onPatch:r}){return e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(i,{label:"Label text color",value:o.columnLabelColor,onChange:a=>r({columnLabelColor:a})}),e.jsx(i,{label:"Label background",value:o.columnLabelBgColor,onChange:a=>r({columnLabelBgColor:a})})]})}function P({values:o,onPatch:r}){return e.jsxs("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsxs("label",{className:"space-y-1 sm:col-span-2",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-slate-500",children:"Min hint label"}),e.jsx("input",{className:"w-full rounded-lg border border-white/10 bg-slate-950/50 px-3 py-2 text-sm text-white",value:o.hintMinText,onChange:a=>r({hintMinText:a.target.value})})]}),e.jsxs("label",{className:"space-y-1 sm:col-span-2",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-slate-500",children:"Max hint label"}),e.jsx("input",{className:"w-full rounded-lg border border-white/10 bg-slate-950/50 px-3 py-2 text-sm text-white",value:o.hintMaxText,onChange:a=>r({hintMaxText:a.target.value})})]}),e.jsx(i,{label:"Hint text color",value:o.hintLabelColor,onChange:a=>r({hintLabelColor:a})}),e.jsx(i,{label:"Hint label background",value:o.hintLabelBgColor,onChange:a=>r({hintLabelBgColor:a})})]})}function p({values:o,onPatch:r,count:a=11}){return e.jsxs("div",{className:"space-y-3",children:[e.jsx(j,{label:"Number label style",value:o.numberLabelMode,onChange:d=>r({numberLabelMode:d}),options:[{value:"traffic",label:"Traffic light (default)"},{value:"monochrome",label:"Monochrome (one color)"},{value:"individual",label:"Individual per number"}]}),o.numberLabelMode==="monochrome"&&e.jsx(i,{label:"Monochrome color",value:o.monochromeNumberColor,onChange:d=>r({monochromeNumberColor:d})}),o.numberLabelMode==="individual"&&e.jsx("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-3",children:Array.from({length:a},(d,c)=>e.jsx(i,{label:`#${c}`,value:o.individualNumberColors[c]??"#9CA3AF",onChange:C=>{const x=[...o.individualNumberColors];x[c]=C,r({individualNumberColors:x})}},c))})]})}function s({title:o,children:r}){return e.jsxs("div",{className:"space-y-3 rounded-xl border border-white/5 bg-slate-950/20 p-4",children:[e.jsx("h4",{className:"text-xs font-semibold uppercase tracking-wider text-slate-400",children:o}),r]})}function B({type:o,activeFormat:r}){const a=g(l=>l.config.questionTypes[o]),d=g(l=>l.updateQuestionType),c=g(l=>l.previewMultiStatement),C=g(l=>l.setPreviewMultiStatement),x=g(l=>l.heatmapPreviewPin);if(!a)return e.jsx("p",{className:"text-sm text-slate-500",children:"No configuration available for this type."});const n=l=>d(o,l),S=L.includes(o),T=r.includes("star"),h=r.includes("emoji"),v=r.includes("numbered"),N=r.includes("drag"),w=r.includes("dropdown"),k=r.includes("radio"),m=h||T||v||k;return e.jsxs("div",{className:"space-y-4",children:[S&&e.jsx(f,{label:"Preview multiple statements",checked:c,onChange:C}),o==="MCQ"&&"optionGap"in a&&e.jsx(s,{title:"Option style",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(j,{label:"Option style",value:a.optionStyle??a.cardStyle??"outlined",onChange:l=>n({optionStyle:l}),options:[{value:"outlined",label:"Outlined"},{value:"filled",label:"Filled"},{value:"minimal",label:"Minimal"}]}),e.jsx(u,{label:"Option gap",value:a.optionGap,onChange:l=>n({optionGap:l}),min:0,max:32}),e.jsx(u,{label:"Border radius",value:a.borderRadius,onChange:l=>n({borderRadius:l}),min:0,max:24}),e.jsx(u,{label:"Option padding",value:a.optionPadding??12,onChange:l=>n({optionPadding:l}),min:4,max:24})]})}),o==="TEXTFIELD"&&"defaultPlaceholder"in a&&e.jsx(s,{title:"Text input",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("label",{className:"space-y-1 sm:col-span-2",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-slate-500",children:"Default placeholder"}),e.jsx("input",{className:"w-full rounded-lg border border-white/10 bg-slate-950/50 px-3 py-2 text-sm text-white",value:a.defaultPlaceholder,onChange:l=>n({defaultPlaceholder:l.target.value})})]}),e.jsx(t,{label:"Input radius (px)",value:a.inputRadius,onChange:l=>n({inputRadius:l}),min:0,max:24}),e.jsx(i,{label:"Border color",value:a.borderColor,onChange:l=>n({borderColor:l})}),e.jsx(i,{label:"Placeholder color",value:a.placeholderColor,onChange:l=>n({placeholderColor:l})})]})}),o==="NPS_SCALE"&&"buttonStyle"in a&&e.jsxs(e.Fragment,{children:[e.jsx(s,{title:"NPS buttons",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(j,{label:"Button style",value:a.buttonStyle,onChange:l=>n({buttonStyle:l}),options:[{value:"standard",label:"Radio"},{value:"numbered",label:"Numbered badges"},{value:"pill",label:"Pill"}]}),e.jsx(i,{label:"Selected fill",value:a.selectedFill,onChange:l=>n({selectedFill:l})}),e.jsx(i,{label:"Track bar",value:a.trackBarColor,onChange:l=>n({trackBarColor:l})}),e.jsx(i,{label:"Track highlight",value:a.trackHighlightColor,onChange:l=>n({trackHighlightColor:l})})]})}),e.jsx(s,{title:"Hint labels",children:e.jsx(P,{values:a,onPatch:n})}),e.jsx(s,{title:"Number labels",children:e.jsx(p,{values:a,onPatch:n})})]}),o==="CFM_MATRIX"&&"rowLabelWidth"in a&&e.jsxs(e.Fragment,{children:[e.jsx(s,{title:"Matrix layout",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(t,{label:"Row label width (px)",value:a.rowLabelWidth,onChange:l=>n({rowLabelWidth:l}),min:120,max:280}),e.jsx(t,{label:"Bipolar column width (%)",value:a.bipolarColumnWidthPercent,onChange:l=>n({bipolarColumnWidthPercent:l}),min:15,max:40})]})}),e.jsx(s,{title:"Label items",children:e.jsx(b,{values:a,onPatch:n})})]}),o==="CSAT_MATRIX"&&"emojiSize"in a&&e.jsxs(e.Fragment,{children:[(h||m)&&e.jsxs(s,{title:`${M.CSAT_MATRIX} — ${r.replace("CSAT_","")}`,children:[e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[h&&e.jsx(t,{label:"Emoji size (px)",value:a.emojiSize,onChange:l=>n({emojiSize:l}),min:16,max:40}),m&&e.jsx(u,{label:"Unselected opacity",value:Math.round(a.unselectedOpacity*100),onChange:l=>n({unselectedOpacity:l/100}),min:10,max:100})]}),e.jsx("p",{className:"text-xs text-slate-500",children:"Selected cell color and focus ring come from Theme → Question card."})]}),e.jsx(s,{title:"Label items",children:e.jsx(b,{values:a,onPatch:n})}),v&&e.jsx(s,{title:"Number labels",children:e.jsx(p,{values:a,onPatch:n,count:10})})]}),o==="RATING_MATRIX"&&"unselectedStarOpacity"in a&&e.jsxs(e.Fragment,{children:[(h||m)&&e.jsxs(s,{title:`Rating — ${r.replace("RATING_","")}`,children:[e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[h&&e.jsx(t,{label:"Emoji size (px)",value:a.emojiSize,onChange:l=>n({emojiSize:l}),min:16,max:40}),m&&e.jsx(u,{label:"Unselected opacity",value:Math.round(a.unselectedStarOpacity*100),onChange:l=>n({unselectedStarOpacity:l/100}),min:10,max:100})]}),e.jsx("p",{className:"text-xs text-slate-500",children:"Selected cell color and focus ring come from Theme → Question card."})]}),e.jsx(s,{title:"Label items",children:e.jsx(b,{values:a,onPatch:n})}),v&&e.jsx(s,{title:"Number labels",children:e.jsx(p,{values:a,onPatch:n,count:10})})]}),o==="SLIDER_MATRIX"&&"trackColor"in a&&e.jsxs(e.Fragment,{children:[e.jsx(s,{title:"Slider track",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(i,{label:"Track",value:a.trackColor,onChange:l=>n({trackColor:l})}),e.jsx(i,{label:"Thumb",value:a.thumbColor,onChange:l=>n({thumbColor:l})}),e.jsx(i,{label:"Tick",value:a.tickColor,onChange:l=>n({tickColor:l})}),e.jsx(t,{label:"Row label width (px)",value:a.rowLabelWidth,onChange:l=>n({rowLabelWidth:l}),min:120,max:280})]})}),e.jsx(s,{title:"Tick label items",children:e.jsx(b,{values:a,onPatch:n})}),e.jsx(s,{title:"Tick number labels",children:e.jsx(p,{values:a,onPatch:n,count:11})})]}),o==="FILE_UPLOAD"&&"dropzoneStyle"in a&&e.jsx(s,{title:"Dropzone",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(j,{label:"Dropzone border",value:a.dropzoneStyle,onChange:l=>n({dropzoneStyle:l}),options:[{value:"dashed",label:"Dashed"},{value:"solid",label:"Solid"}]}),e.jsx(i,{label:"Border color",value:a.borderColor??a.accentColor,onChange:l=>n({borderColor:l})}),e.jsx(i,{label:"Fill color",value:a.dropzoneFillColor,onChange:l=>n({dropzoneFillColor:l})}),e.jsx(t,{label:"Padding (px)",value:a.dropzonePadding,onChange:l=>n({dropzonePadding:l}),min:12,max:48})]})}),o==="HEATMAP"&&"pinColor"in a&&e.jsx(s,{title:"Heatmap pin",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(i,{label:"Pin color",value:a.pinColor,onChange:l=>n({pinColor:l})}),e.jsx(i,{label:"Pin border",value:a.pinBorderColor,onChange:l=>n({pinBorderColor:l})}),e.jsx(u,{label:"Pin size",value:a.pinSize,onChange:l=>n({pinSize:l}),min:8,max:32}),e.jsxs("p",{className:"text-xs text-slate-500 sm:col-span-2",children:["Click the heatmap image in the preview to place a pin and see styling update live. Pin preview position: ",Math.round(x.x*100),"%, ",Math.round(x.y*100),"%"]})]})}),o==="RANK_ORDER"&&"drag"in a&&e.jsx(s,{title:N?"Drag & drop":w?"Dropdown rank":"Rank order",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[N&&e.jsxs(e.Fragment,{children:[e.jsx(i,{label:"Item background",value:a.drag.itemBg,onChange:l=>n({drag:{...a.drag,itemBg:l}})}),e.jsx(i,{label:"Drag handle",value:a.drag.dragHandleColor,onChange:l=>n({drag:{...a.drag,dragHandleColor:l}})}),e.jsx(i,{label:"Rank badge",value:a.drag.rankBadgeColor,onChange:l=>n({drag:{...a.drag,rankBadgeColor:l}})})]}),w&&e.jsxs(e.Fragment,{children:[e.jsx(i,{label:"Item background",value:a.dropdown.itemBg,onChange:l=>n({dropdown:{...a.dropdown,itemBg:l}})}),e.jsx(i,{label:"Select border",value:a.dropdown.selectBorderColor,onChange:l=>n({dropdown:{...a.dropdown,selectBorderColor:l}})}),e.jsx(i,{label:"Rank badge",value:a.dropdown.rankBadgeColor,onChange:l=>n({dropdown:{...a.dropdown,rankBadgeColor:l}})})]})]})})]})}export{B as TypePanel};
|
|
1
|
+
import{u as g,j as e,T as f,S as j,R as u,N as t,C as i,a as M,M as L}from"./index-CWKdsJOp.js";import"./vendor-BwkXDkd3.js";function b({values:o,onPatch:r}){return e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(i,{label:"Label text color",value:o.columnLabelColor,onChange:a=>r({columnLabelColor:a})}),e.jsx(i,{label:"Label background",value:o.columnLabelBgColor,onChange:a=>r({columnLabelBgColor:a})})]})}function P({values:o,onPatch:r}){return e.jsxs("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsxs("label",{className:"space-y-1 sm:col-span-2",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-slate-500",children:"Min hint label"}),e.jsx("input",{className:"w-full rounded-lg border border-white/10 bg-slate-950/50 px-3 py-2 text-sm text-white",value:o.hintMinText,onChange:a=>r({hintMinText:a.target.value})})]}),e.jsxs("label",{className:"space-y-1 sm:col-span-2",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-slate-500",children:"Max hint label"}),e.jsx("input",{className:"w-full rounded-lg border border-white/10 bg-slate-950/50 px-3 py-2 text-sm text-white",value:o.hintMaxText,onChange:a=>r({hintMaxText:a.target.value})})]}),e.jsx(i,{label:"Hint text color",value:o.hintLabelColor,onChange:a=>r({hintLabelColor:a})}),e.jsx(i,{label:"Hint label background",value:o.hintLabelBgColor,onChange:a=>r({hintLabelBgColor:a})})]})}function p({values:o,onPatch:r,count:a=11}){return e.jsxs("div",{className:"space-y-3",children:[e.jsx(j,{label:"Number label style",value:o.numberLabelMode,onChange:d=>r({numberLabelMode:d}),options:[{value:"traffic",label:"Traffic light (default)"},{value:"monochrome",label:"Monochrome (one color)"},{value:"individual",label:"Individual per number"}]}),o.numberLabelMode==="monochrome"&&e.jsx(i,{label:"Monochrome color",value:o.monochromeNumberColor,onChange:d=>r({monochromeNumberColor:d})}),o.numberLabelMode==="individual"&&e.jsx("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-3",children:Array.from({length:a},(d,c)=>e.jsx(i,{label:`#${c}`,value:o.individualNumberColors[c]??"#9CA3AF",onChange:C=>{const x=[...o.individualNumberColors];x[c]=C,r({individualNumberColors:x})}},c))})]})}function s({title:o,children:r}){return e.jsxs("div",{className:"space-y-3 rounded-xl border border-white/5 bg-slate-950/20 p-4",children:[e.jsx("h4",{className:"text-xs font-semibold uppercase tracking-wider text-slate-400",children:o}),r]})}function B({type:o,activeFormat:r}){const a=g(l=>l.config.questionTypes[o]),d=g(l=>l.updateQuestionType),c=g(l=>l.previewMultiStatement),C=g(l=>l.setPreviewMultiStatement),x=g(l=>l.heatmapPreviewPin);if(!a)return e.jsx("p",{className:"text-sm text-slate-500",children:"No configuration available for this type."});const n=l=>d(o,l),S=L.includes(o),T=r.includes("star"),h=r.includes("emoji"),v=r.includes("numbered"),N=r.includes("drag"),w=r.includes("dropdown"),k=r.includes("radio"),m=h||T||v||k;return e.jsxs("div",{className:"space-y-4",children:[S&&e.jsx(f,{label:"Preview multiple statements",checked:c,onChange:C}),o==="MCQ"&&"optionGap"in a&&e.jsx(s,{title:"Option style",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(j,{label:"Option style",value:a.optionStyle??a.cardStyle??"outlined",onChange:l=>n({optionStyle:l}),options:[{value:"outlined",label:"Outlined"},{value:"filled",label:"Filled"},{value:"minimal",label:"Minimal"}]}),e.jsx(u,{label:"Option gap",value:a.optionGap,onChange:l=>n({optionGap:l}),min:0,max:32}),e.jsx(u,{label:"Border radius",value:a.borderRadius,onChange:l=>n({borderRadius:l}),min:0,max:24}),e.jsx(u,{label:"Option padding",value:a.optionPadding??12,onChange:l=>n({optionPadding:l}),min:4,max:24})]})}),o==="TEXTFIELD"&&"defaultPlaceholder"in a&&e.jsx(s,{title:"Text input",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("label",{className:"space-y-1 sm:col-span-2",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-slate-500",children:"Default placeholder"}),e.jsx("input",{className:"w-full rounded-lg border border-white/10 bg-slate-950/50 px-3 py-2 text-sm text-white",value:a.defaultPlaceholder,onChange:l=>n({defaultPlaceholder:l.target.value})})]}),e.jsx(t,{label:"Input radius (px)",value:a.inputRadius,onChange:l=>n({inputRadius:l}),min:0,max:24}),e.jsx(i,{label:"Border color",value:a.borderColor,onChange:l=>n({borderColor:l})}),e.jsx(i,{label:"Placeholder color",value:a.placeholderColor,onChange:l=>n({placeholderColor:l})})]})}),o==="NPS_SCALE"&&"buttonStyle"in a&&e.jsxs(e.Fragment,{children:[e.jsx(s,{title:"NPS buttons",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(j,{label:"Button style",value:a.buttonStyle,onChange:l=>n({buttonStyle:l}),options:[{value:"standard",label:"Radio"},{value:"numbered",label:"Numbered badges"},{value:"pill",label:"Pill"}]}),e.jsx(i,{label:"Selected fill",value:a.selectedFill,onChange:l=>n({selectedFill:l})}),e.jsx(i,{label:"Track bar",value:a.trackBarColor,onChange:l=>n({trackBarColor:l})}),e.jsx(i,{label:"Track highlight",value:a.trackHighlightColor,onChange:l=>n({trackHighlightColor:l})})]})}),e.jsx(s,{title:"Hint labels",children:e.jsx(P,{values:a,onPatch:n})}),e.jsx(s,{title:"Number labels",children:e.jsx(p,{values:a,onPatch:n})})]}),o==="CFM_MATRIX"&&"rowLabelWidth"in a&&e.jsxs(e.Fragment,{children:[e.jsx(s,{title:"Matrix layout",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(t,{label:"Row label width (px)",value:a.rowLabelWidth,onChange:l=>n({rowLabelWidth:l}),min:120,max:280}),e.jsx(t,{label:"Bipolar column width (%)",value:a.bipolarColumnWidthPercent,onChange:l=>n({bipolarColumnWidthPercent:l}),min:15,max:40})]})}),e.jsx(s,{title:"Label items",children:e.jsx(b,{values:a,onPatch:n})})]}),o==="CSAT_MATRIX"&&"emojiSize"in a&&e.jsxs(e.Fragment,{children:[(h||m)&&e.jsxs(s,{title:`${M.CSAT_MATRIX} — ${r.replace("CSAT_","")}`,children:[e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[h&&e.jsx(t,{label:"Emoji size (px)",value:a.emojiSize,onChange:l=>n({emojiSize:l}),min:16,max:40}),m&&e.jsx(u,{label:"Unselected opacity",value:Math.round(a.unselectedOpacity*100),onChange:l=>n({unselectedOpacity:l/100}),min:10,max:100})]}),e.jsx("p",{className:"text-xs text-slate-500",children:"Selected cell color and focus ring come from Theme → Question card."})]}),e.jsx(s,{title:"Label items",children:e.jsx(b,{values:a,onPatch:n})}),v&&e.jsx(s,{title:"Number labels",children:e.jsx(p,{values:a,onPatch:n,count:10})})]}),o==="RATING_MATRIX"&&"unselectedStarOpacity"in a&&e.jsxs(e.Fragment,{children:[(h||m)&&e.jsxs(s,{title:`Rating — ${r.replace("RATING_","")}`,children:[e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[h&&e.jsx(t,{label:"Emoji size (px)",value:a.emojiSize,onChange:l=>n({emojiSize:l}),min:16,max:40}),m&&e.jsx(u,{label:"Unselected opacity",value:Math.round(a.unselectedStarOpacity*100),onChange:l=>n({unselectedStarOpacity:l/100}),min:10,max:100})]}),e.jsx("p",{className:"text-xs text-slate-500",children:"Selected cell color and focus ring come from Theme → Question card."})]}),e.jsx(s,{title:"Label items",children:e.jsx(b,{values:a,onPatch:n})}),v&&e.jsx(s,{title:"Number labels",children:e.jsx(p,{values:a,onPatch:n,count:10})})]}),o==="SLIDER_MATRIX"&&"trackColor"in a&&e.jsxs(e.Fragment,{children:[e.jsx(s,{title:"Slider track",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(i,{label:"Track",value:a.trackColor,onChange:l=>n({trackColor:l})}),e.jsx(i,{label:"Thumb",value:a.thumbColor,onChange:l=>n({thumbColor:l})}),e.jsx(i,{label:"Tick",value:a.tickColor,onChange:l=>n({tickColor:l})}),e.jsx(t,{label:"Row label width (px)",value:a.rowLabelWidth,onChange:l=>n({rowLabelWidth:l}),min:120,max:280})]})}),e.jsx(s,{title:"Tick label items",children:e.jsx(b,{values:a,onPatch:n})}),e.jsx(s,{title:"Tick number labels",children:e.jsx(p,{values:a,onPatch:n,count:11})})]}),o==="FILE_UPLOAD"&&"dropzoneStyle"in a&&e.jsx(s,{title:"Dropzone",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(j,{label:"Dropzone border",value:a.dropzoneStyle,onChange:l=>n({dropzoneStyle:l}),options:[{value:"dashed",label:"Dashed"},{value:"solid",label:"Solid"}]}),e.jsx(i,{label:"Border color",value:a.borderColor??a.accentColor,onChange:l=>n({borderColor:l})}),e.jsx(i,{label:"Fill color",value:a.dropzoneFillColor,onChange:l=>n({dropzoneFillColor:l})}),e.jsx(t,{label:"Padding (px)",value:a.dropzonePadding,onChange:l=>n({dropzonePadding:l}),min:12,max:48})]})}),o==="HEATMAP"&&"pinColor"in a&&e.jsx(s,{title:"Heatmap pin",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(i,{label:"Pin color",value:a.pinColor,onChange:l=>n({pinColor:l})}),e.jsx(i,{label:"Pin border",value:a.pinBorderColor,onChange:l=>n({pinBorderColor:l})}),e.jsx(u,{label:"Pin size",value:a.pinSize,onChange:l=>n({pinSize:l}),min:8,max:32}),e.jsxs("p",{className:"text-xs text-slate-500 sm:col-span-2",children:["Click the heatmap image in the preview to place a pin and see styling update live. Pin preview position: ",Math.round(x.x*100),"%, ",Math.round(x.y*100),"%"]})]})}),o==="RANK_ORDER"&&"drag"in a&&e.jsx(s,{title:N?"Drag & drop":w?"Dropdown rank":"Rank order",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[N&&e.jsxs(e.Fragment,{children:[e.jsx(i,{label:"Item background",value:a.drag.itemBg,onChange:l=>n({drag:{...a.drag,itemBg:l}})}),e.jsx(i,{label:"Drag handle",value:a.drag.dragHandleColor,onChange:l=>n({drag:{...a.drag,dragHandleColor:l}})}),e.jsx(i,{label:"Rank badge",value:a.drag.rankBadgeColor,onChange:l=>n({drag:{...a.drag,rankBadgeColor:l}})})]}),w&&e.jsxs(e.Fragment,{children:[e.jsx(i,{label:"Item background",value:a.dropdown.itemBg,onChange:l=>n({dropdown:{...a.dropdown,itemBg:l}})}),e.jsx(i,{label:"Select border",value:a.dropdown.selectBorderColor,onChange:l=>n({dropdown:{...a.dropdown,selectBorderColor:l}})}),e.jsx(i,{label:"Rank badge",value:a.dropdown.rankBadgeColor,onChange:l=>n({dropdown:{...a.dropdown,rankBadgeColor:l}})})]})]})})]})}export{B as TypePanel};
|