@explorer02/cfm-survey-sdk 0.1.7 → 0.1.9
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/index.d.mts +24 -26
- package/dist/index.d.ts +24 -26
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
- package/postinstall.js +21 -26
- package/templates/AGENT.md +24 -10
- package/templates/docs/00-integration/constraints.md +54 -0
- package/templates/docs/00-integration/setup.md +80 -0
- package/templates/docs/00-integration/useSurveySDK.md +107 -0
- package/templates/docs/01-components/01-survey-page.md +91 -0
- package/templates/docs/01-components/02-question.md +105 -0
- package/templates/docs/01-components/08-file-upload-scale.md +56 -0
- package/templates/docs/{03-client-components → 01-components}/README.md +1 -1
- package/templates/docs/02-question-types/01-rating.md +0 -8
- package/templates/docs/02-reference/question-types/01-rating.md +52 -0
- package/templates/docs/02-reference/question-types/README.md +71 -0
- package/templates/docs/02-reference/routing-table.md +37 -0
- package/templates/docs/MANIFEST.json +129 -0
- package/templates/docs/index.md +100 -140
- package/templates/docs/templates/implementation_plan.md +78 -0
- package/templates/docs/01-sdk-core/01-fetch-survey.md +0 -68
- package/templates/docs/01-sdk-core/02-survey-mapper.md +0 -85
- package/templates/docs/01-sdk-core/03-question-mappers.md +0 -114
- package/templates/docs/01-sdk-core/04-pagination.md +0 -72
- package/templates/docs/01-sdk-core/05-validation.md +0 -66
- package/templates/docs/01-sdk-core/06-submit-survey.md +0 -90
- package/templates/docs/01-sdk-core/07-language-handling.md +0 -111
- package/templates/docs/01-sdk-core/08-icons-and-emojis.md +0 -56
- package/templates/docs/01-sdk-core/README.md +0 -53
- package/templates/docs/02-question-types/02-radio.md +0 -26
- package/templates/docs/02-question-types/03-text.md +0 -26
- package/templates/docs/02-question-types/12-text-and-media.md +0 -35
- package/templates/docs/02-question-types/README.md +0 -74
- package/templates/docs/03-client-components/01-survey-page.md +0 -113
- package/templates/docs/03-client-components/02-question.md +0 -74
- package/templates/docs/03-client-components/08-file-upload-scale.md +0 -37
- package/templates/docs/04-critical-rules/01-import-rules.md +0 -51
- package/templates/docs/04-critical-rules/02-action-dispatching.md +0 -56
- package/templates/docs/04-critical-rules/03-scroll-navigation.md +0 -37
- package/templates/docs/04-critical-rules/04-logo-branding.md +0 -42
- package/templates/docs/04-critical-rules/05-troubleshooting.md +0 -46
- package/templates/docs/04-critical-rules/README.md +0 -29
- /package/templates/docs/{03-client-components → 01-components}/03-rating-scale.md +0 -0
- /package/templates/docs/{03-client-components → 01-components}/04-csat-scale.md +0 -0
- /package/templates/docs/{03-client-components → 01-components}/05-csat-matrix-scale.md +0 -0
- /package/templates/docs/{03-client-components → 01-components}/06-likert-matrix-scale.md +0 -0
- /package/templates/docs/{03-client-components → 01-components}/07-slider-matrix-scale.md +0 -0
- /package/templates/docs/{03-client-components → 01-components}/09-custom-slider-track.md +0 -0
- /package/templates/docs/{03-client-components → 01-components}/10-header-footer.md +0 -0
- /package/templates/docs/{03-client-components → 01-components}/11-progress-bar.md +0 -0
- /package/templates/docs/{03-client-components → 01-components}/12-language-selector.md +0 -0
- /package/templates/docs/{03-client-components → 01-components}/13-matrix-dropdown.md +0 -0
- /package/templates/docs/{02-question-types → 02-reference/question-types}/04-csat.md +0 -0
- /package/templates/docs/{02-question-types → 02-reference/question-types}/05-rating-scale.md +0 -0
- /package/templates/docs/{02-question-types → 02-reference/question-types}/06-slider.md +0 -0
- /package/templates/docs/{02-question-types → 02-reference/question-types}/07-matrix-cfm.md +0 -0
- /package/templates/docs/{02-question-types → 02-reference/question-types}/08-matrix-csat.md +0 -0
- /package/templates/docs/{02-question-types → 02-reference/question-types}/09-matrix-rating.md +0 -0
- /package/templates/docs/{02-question-types → 02-reference/question-types}/10-slider-matrix.md +0 -0
- /package/templates/docs/{02-question-types → 02-reference/question-types}/11-file-upload.md +0 -0
package/templates/docs/index.md
CHANGED
|
@@ -1,149 +1,109 @@
|
|
|
1
1
|
# CFM SURVEY SDK — AGENT DOCUMENTATION INDEX
|
|
2
2
|
|
|
3
|
-
**@explorer02/cfm-survey-sdk**
|
|
3
|
+
**@explorer02/cfm-survey-sdk** (npm) · **@repo/sdk** (monorepo)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
It is a structured roadmap that tells the agent exactly which documentation files to read and in what order.
|
|
5
|
+
Master guide for AI coding agents. Machine-readable index: `MANIFEST.json`.
|
|
7
6
|
|
|
8
|
-
##
|
|
9
|
-
|
|
10
|
-
The `docs/` folder mirrors the SDK's internal architecture:
|
|
7
|
+
## Documentation Layout
|
|
11
8
|
|
|
12
9
|
```
|
|
13
10
|
docs/
|
|
14
|
-
├── index.md
|
|
15
|
-
├──
|
|
16
|
-
├──
|
|
17
|
-
├──
|
|
18
|
-
|
|
11
|
+
├── index.md ← YOU ARE HERE
|
|
12
|
+
├── MANIFEST.json ← Phase + question-type routing (for tooling)
|
|
13
|
+
├── 00-integration/ ← Setup, hook contract, constraints
|
|
14
|
+
├── 01-components/ ← UI blueprints (read ALL before coding)
|
|
15
|
+
├── 02-reference/ ← Routing table + question-type data (on demand)
|
|
16
|
+
└── templates/
|
|
17
|
+
└── implementation_plan.md
|
|
19
18
|
```
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
| `question.type` | Question Doc | Component Doc |
|
|
112
|
-
|---|---|---|
|
|
113
|
-
| `'rating'` | `02-question-types/01-rating` | `03-components/03-rating` |
|
|
114
|
-
| `'radio'` | `02-question-types/02-radio` | (inline in Question) |
|
|
115
|
-
| `'text'` | `02-question-types/03-text` | (inline in Question) |
|
|
116
|
-
| `'csat'` | `02-question-types/04-csat` | `03-components/04-csat` |
|
|
117
|
-
| `'rating_scale'` | `02-question-types/05-rating-s` | `03-components/03-rating` |
|
|
118
|
-
| `'slider'` | `02-question-types/06-slider` | `03-components/09-slider` |
|
|
119
|
-
| `'matrix'` CFM | `02-question-types/07-matrix-c` | `03-components/06-likert` |
|
|
120
|
-
| `'matrix'` CSAT | `02-question-types/08-matrix-c` | `03-components/05-csat-m` |
|
|
121
|
-
| `'matrix'` RATING| `02-question-types/09-matrix-r` | `03-components/05-csat-m` |
|
|
122
|
-
| `'slider_matrix'`| `02-question-types/10-slider-m` | `03-components/07-slider` |
|
|
123
|
-
| `'file_upload'` | `02-question-types/11-file-up` | `03-components/08-file` |
|
|
124
|
-
| `'text_and_media'`| `02-question-types/12-text-med` | (inline in Question) |
|
|
125
|
-
|
|
126
|
-
Also read these shared component docs:
|
|
127
|
-
- `03-client-components/09-custom-slider-track.md` (used by CSAT matrix, slider matrix when sliderType='graphics')
|
|
128
|
-
- `03-client-components/13-matrix-dropdown.md` (used by matrix dropdown fmt)
|
|
129
|
-
|
|
130
|
-
### PHASE 5: APPLY CRITICAL RULES
|
|
131
|
-
Read ALL files in `04-critical-rules/`:
|
|
132
|
-
1. `01-import-rules.md` — Package imports, 'use client', Suspense
|
|
133
|
-
2. `02-action-dispatching.md` — onAction pattern, placeholder constants
|
|
134
|
-
3. `03-scroll-navigation.md` — id={question.id} requirement
|
|
135
|
-
4. `04-logo-branding.md` — CSS-only logo, no external image needed
|
|
136
|
-
5. `05-troubleshooting.md` — Common build errors and fixes
|
|
137
|
-
|
|
138
|
-
Verify your implementation against every rule before proceeding.
|
|
139
|
-
|
|
140
|
-
### PHASE 6: BUILD VERIFICATION
|
|
141
|
-
1. Run: `npm run build`
|
|
142
|
-
2. If errors → fix automatically → re-run until clean
|
|
143
|
-
3. Run: `npm run dev`
|
|
144
|
-
4. Verify: survey loads, navigation works, validation fires, submit works
|
|
145
|
-
|
|
146
|
-
### PHASE 7: DEPLOYMENT (INPUT 3)
|
|
147
|
-
Ask the client: "Your survey is built and verified. Ready to deploy to Vercel?"
|
|
148
|
-
If yes → run: `npx vercel --prod --yes`
|
|
149
|
-
Report the final deployment URL to the client.
|
|
20
|
+
**Import rule:** Use whatever package name appears in the project's `package.json` (`@explorer02/cfm-survey-sdk` or `@repo/sdk`).
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Client Inputs (3 only)
|
|
25
|
+
|
|
26
|
+
1. **Initial prompt** — mockup, brand colors, layout preferences
|
|
27
|
+
2. **Instance ID** — JWT token (agent asks in chat)
|
|
28
|
+
3. **Deploy confirmation** — yes/no for production deploy
|
|
29
|
+
|
|
30
|
+
**Branding comes from INPUT 1 only.** No setup wizard. No `survey-config.json`.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Execution Pipeline
|
|
35
|
+
|
|
36
|
+
### PHASE 0: ORIENT
|
|
37
|
+
|
|
38
|
+
- Read this file and `AGENT.md`
|
|
39
|
+
- Detect framework: read `package.json` — Next.js / Vite / CRA (see `00-integration/setup.md`)
|
|
40
|
+
- Extract branding and layout from client prompt
|
|
41
|
+
- For existing apps: read project structure; do not blindly scaffold
|
|
42
|
+
|
|
43
|
+
### PHASE 1: SCAFFOLD
|
|
44
|
+
|
|
45
|
+
Read: `00-integration/setup.md` (matching framework section)
|
|
46
|
+
|
|
47
|
+
Install SDK + `@tanstack/react-query` + `react-icons`. Apply framework-specific config.
|
|
48
|
+
|
|
49
|
+
### PHASE 2: INSTANCE ID (INPUT 2)
|
|
50
|
+
|
|
51
|
+
Read: `00-integration/useSurveySDK.md`
|
|
52
|
+
|
|
53
|
+
Ask: *"Please provide your survey instance ID (JWT token)."*
|
|
54
|
+
|
|
55
|
+
### PHASE 3: SDK CONTRACT
|
|
56
|
+
|
|
57
|
+
Read: `00-integration/useSurveySDK.md`
|
|
58
|
+
|
|
59
|
+
Understand `useSurveySDK`, `onAction`, states. Do **not** read internal mapper/source paths.
|
|
60
|
+
|
|
61
|
+
Optional: read `02-reference/routing-table.md` for type overview.
|
|
62
|
+
|
|
63
|
+
### PHASE 4: PLAN + INGEST (CRITICAL)
|
|
64
|
+
|
|
65
|
+
1. Read **every** file in `01-components/` (all 14 blueprints)
|
|
66
|
+
2. Copy `docs/templates/implementation_plan.md` → `./implementation_plan.md`
|
|
67
|
+
3. Fill every section — do **not** invent a different structure
|
|
68
|
+
4. **Auto-proceed to Phase 5** — do not wait for approval
|
|
69
|
+
|
|
70
|
+
For each question type in the fetched survey, also read matching docs from `02-reference/question-types/` (see `MANIFEST.json` or `02-reference/routing-table.md`).
|
|
71
|
+
|
|
72
|
+
### PHASE 5: BUILD
|
|
73
|
+
|
|
74
|
+
Read: `00-integration/constraints.md`
|
|
75
|
+
|
|
76
|
+
Implement components per blueprints. Use exported types:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { useSurveySDK, ACTIONS, type SurveyAction } from '@explorer02/cfm-survey-sdk';
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### PHASE 6: VERIFY
|
|
83
|
+
|
|
84
|
+
Read: `00-integration/constraints.md` (troubleshooting)
|
|
85
|
+
|
|
86
|
+
Checklist:
|
|
87
|
+
|
|
88
|
+
- [ ] `Question.tsx` switch covers all 12 `question.type` values
|
|
89
|
+
- [ ] Every question wrapper has `id={question.id}`
|
|
90
|
+
- [ ] No imports from `@explorer02/cfm-survey-sdk/src/...`
|
|
91
|
+
- [ ] `SurveyPage` handles loading / error / empty / submitted / active
|
|
92
|
+
- [ ] `npm run build` exits 0
|
|
93
|
+
|
|
94
|
+
### PHASE 7: DEPLOY (INPUT 3)
|
|
95
|
+
|
|
96
|
+
Ask: *"Your survey is built and verified. Ready to deploy?"*
|
|
97
|
+
|
|
98
|
+
If yes: `npx cfm-sdk deploy` (preferred) or `npx vercel --prod --yes`
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Progressive Reading Guide
|
|
103
|
+
|
|
104
|
+
| When | Read |
|
|
105
|
+
|------|------|
|
|
106
|
+
| Always first | `index.md`, `00-integration/setup.md`, `00-integration/useSurveySDK.md`, `00-integration/constraints.md` |
|
|
107
|
+
| Before any React code | All `01-components/*.md` |
|
|
108
|
+
| On demand | `02-reference/question-types/<type>.md` for types in survey |
|
|
109
|
+
| Tooling | `MANIFEST.json`, `templates/implementation_plan.md` |
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Survey UI Implementation Plan
|
|
2
|
+
|
|
3
|
+
> Copy this file to `./implementation_plan.md` in the project root. Fill every section before writing React code.
|
|
4
|
+
|
|
5
|
+
## 0. Project Context
|
|
6
|
+
|
|
7
|
+
- **Framework:** [ ] Next.js App Router [ ] Vite [ ] CRA [ ] Existing app
|
|
8
|
+
- **Package import name:** (from `package.json` — `@explorer02/cfm-survey-sdk` or `@repo/sdk`)
|
|
9
|
+
- **instanceId:** (JWT — wired in SurveyPage)
|
|
10
|
+
- **Branding source:** (client prompt / mockup description — no wizard)
|
|
11
|
+
|
|
12
|
+
## 1. Data Fetching & State
|
|
13
|
+
|
|
14
|
+
- [ ] `useSurveySDK` options: instanceId, language, placeholders, debug
|
|
15
|
+
- [ ] `SurveyPage` 5-state machine: loading / error / empty / submitted / active
|
|
16
|
+
- [ ] `surveyQueryResults.isLoading`, `.error`, `.data` handling
|
|
17
|
+
- [ ] `submitSurveyResults.isLoading`, `.error`, `.data` handling
|
|
18
|
+
|
|
19
|
+
## 2. Pagination, Actions & Flow
|
|
20
|
+
|
|
21
|
+
- [ ] `onAction` NEXT / PREVIOUS / SUBMIT wiring
|
|
22
|
+
- [ ] `ProgressBar` bound to `state.progressPercentage`
|
|
23
|
+
- [ ] Back/Next button visibility per layout config
|
|
24
|
+
- [ ] Last-page NEXT → auto SUBMIT behavior
|
|
25
|
+
|
|
26
|
+
## 3. Question Dispatching (`Question.tsx`)
|
|
27
|
+
|
|
28
|
+
Exhaustive switch — check each:
|
|
29
|
+
|
|
30
|
+
- [ ] `rating` → `RatingScale`
|
|
31
|
+
- [ ] `csat` → `CsatScale`
|
|
32
|
+
- [ ] `radio` → inline MCQ
|
|
33
|
+
- [ ] `text` → inline textarea/input
|
|
34
|
+
- [ ] `rating_scale` → `RatingScale` (star/emoji)
|
|
35
|
+
- [ ] `slider` → `CustomSliderTrack`
|
|
36
|
+
- [ ] `matrix` + `CFM_MATRIX` → `LikertMatrixScale`
|
|
37
|
+
- [ ] `matrix` + `CSAT_MATRIX` / `RATING_MATRIX` → `CsatMatrixScale`
|
|
38
|
+
- [ ] `rating_matrix` → `CsatMatrixScale`
|
|
39
|
+
- [ ] `slider_matrix` → `SliderMatrixScale`
|
|
40
|
+
- [ ] `file_upload` → `FileUploadScale`
|
|
41
|
+
- [ ] `text_and_media` → inline media (no scale)
|
|
42
|
+
- [ ] `dangerouslySetInnerHTML` for `question.text` / `description`
|
|
43
|
+
- [ ] `validationError` banner per question
|
|
44
|
+
- [ ] `id={question.id}` on every question wrapper
|
|
45
|
+
|
|
46
|
+
## 4. Component Architecture Checklist
|
|
47
|
+
|
|
48
|
+
| Component | In survey? | Blueprint doc | Key constraints verified |
|
|
49
|
+
|-----------|------------|---------------|--------------------------|
|
|
50
|
+
| RatingScale | | `01-components/03-rating-scale.md` | |
|
|
51
|
+
| CsatScale | | `01-components/04-csat-scale.md` | |
|
|
52
|
+
| CsatMatrixScale | | `01-components/05-csat-matrix-scale.md` | |
|
|
53
|
+
| LikertMatrixScale | | `01-components/06-likert-matrix-scale.md` | |
|
|
54
|
+
| SliderMatrixScale | | `01-components/07-slider-matrix-scale.md` | |
|
|
55
|
+
| FileUploadScale | | `01-components/08-file-upload-scale.md` | |
|
|
56
|
+
| CustomSliderTrack | | `01-components/09-custom-slider-track.md` | |
|
|
57
|
+
| Header / Footer | | `01-components/10-header-footer.md` | |
|
|
58
|
+
| ProgressBar | | `01-components/11-progress-bar.md` | |
|
|
59
|
+
| LanguageSelector | | `01-components/12-language-selector.md` | |
|
|
60
|
+
| MatrixDropdown | | `01-components/13-matrix-dropdown.md` | |
|
|
61
|
+
|
|
62
|
+
## 5. Theme, Brand & Logo
|
|
63
|
+
|
|
64
|
+
- [ ] CSS-only logo (no `<img>`, no `public/` uploads)
|
|
65
|
+
- [ ] Primary / hover colors from client prompt
|
|
66
|
+
- [ ] Header / Footer / ProgressBar / LanguageSelector per layout
|
|
67
|
+
|
|
68
|
+
## 6. Submit & Thank You
|
|
69
|
+
|
|
70
|
+
- [ ] `onAction({ type: 'SUBMIT' })` on final page
|
|
71
|
+
- [ ] Thank-you screen when `submitSurveyResults.data` is set
|
|
72
|
+
- [ ] Custom thank-you message from client prompt if provided
|
|
73
|
+
|
|
74
|
+
## 7. Pre-Build Verification
|
|
75
|
+
|
|
76
|
+
- [ ] No imports from `.../src/` internal paths
|
|
77
|
+
- [ ] All mutations via `onAction` — no direct state mutation
|
|
78
|
+
- [ ] `npm run build` passes
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# Fetch Survey — `useFetchSurvey`
|
|
2
|
-
|
|
3
|
-
> **Source**: `packages/sdk/src/fetchSurvey/useFetchSurvey.ts`
|
|
4
|
-
> **Called by**: `useSurveySDK()` internally — the client never calls this directly.
|
|
5
|
-
|
|
6
|
-
## What It Does
|
|
7
|
-
|
|
8
|
-
1. Builds the API URL from the client's `instanceId` (JWT token)
|
|
9
|
-
2. Makes a `GET` request to the Sprinklr CFM API endpoint
|
|
10
|
-
3. Caches the raw response using `@tanstack/react-query` (singleton QueryClient — no provider needed)
|
|
11
|
-
4. Re-maps the cached response whenever the target language changes (client-side, no re-fetch)
|
|
12
|
-
|
|
13
|
-
## API Endpoint
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
https://custom-p0.feedbook.me/api/feedback/survey/cfm?instanceId={JWT_TOKEN}
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
The URL is constructed by `buildSurveyUrl()` in `fetchSurvey/utils/url.ts`.
|
|
20
|
-
|
|
21
|
-
## Instance ID
|
|
22
|
-
|
|
23
|
-
The `instanceId` is a **JWT token** string that encodes:
|
|
24
|
-
- `surveyId` — Which survey to load
|
|
25
|
-
- `distributionEntityId` — Which distribution channel
|
|
26
|
-
- `surveyLanguage` — Default language (e.g. `'de'`)
|
|
27
|
-
- `partnerId` — Tenant identifier
|
|
28
|
-
|
|
29
|
-
**⚠️ CRITICAL**: The instanceId comes from the **client's chat prompt**. The agent must ask the client for it before building the survey. Without it, `useFetchSurvey` returns `null` and the survey cannot load.
|
|
30
|
-
|
|
31
|
-
## Return Shape
|
|
32
|
-
|
|
33
|
-
```typescript
|
|
34
|
-
{
|
|
35
|
-
survey: Survey | null, // Fully mapped survey object (see 02-survey-mapper.md)
|
|
36
|
-
session: SurveySession | null, // { instanceId, language } — passed to submit hook
|
|
37
|
-
fetching: boolean, // True while network request is in flight
|
|
38
|
-
fetchError: Error | null, // Network/API error
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Caching Behaviour
|
|
43
|
-
|
|
44
|
-
- Keyed by `['survey', url]` — fetched **once** per instanceId
|
|
45
|
-
- Language changes do NOT re-fetch — they re-map the cached raw response via `useMemo`
|
|
46
|
-
- Uses `cache: 'force-cache'` on the fetch request for browser-level HTTP caching
|
|
47
|
-
|
|
48
|
-
## QueryClient
|
|
49
|
-
|
|
50
|
-
The SDK creates its own internal singleton `QueryClient` in `src/queryClient.ts`.
|
|
51
|
-
The client app does **NOT** need to wrap anything in `<QueryClientProvider>`.
|
|
52
|
-
|
|
53
|
-
## Logging & Telemetry
|
|
54
|
-
|
|
55
|
-
The fetch lifecycle emits structured logs (when `debug: true`):
|
|
56
|
-
- `logFetchStart(url)` — before the request
|
|
57
|
-
- `logFetchPerfSuccess(durationMs, status, url, payloadSize)` — on success
|
|
58
|
-
- `logFetchPerfFailure(durationMs, status, url)` — on failure
|
|
59
|
-
- `trackFetchLatency(...)` — performance telemetry
|
|
60
|
-
|
|
61
|
-
## Error Handling
|
|
62
|
-
|
|
63
|
-
| Scenario | Behaviour |
|
|
64
|
-
|----------|-----------|
|
|
65
|
-
| Network offline | `fetchError` populated, `survey` is `null` |
|
|
66
|
-
| HTTP 4xx/5xx | `fetchError` populated with status message |
|
|
67
|
-
| Invalid instanceId | API returns empty/malformed → `survey` maps to `null` |
|
|
68
|
-
| Successful but empty | `survey` is `null`, no error |
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# Survey Mapper — `mapSurvey`
|
|
2
|
-
|
|
3
|
-
> **Source**: `packages/sdk/src/fetchSurvey/utils/mappers/surveyMapper.ts`
|
|
4
|
-
> **Called by**: `useFetchSurvey()` inside `useMemo` — re-runs when language changes.
|
|
5
|
-
|
|
6
|
-
## What It Does
|
|
7
|
-
|
|
8
|
-
Transforms the raw API response (`ApiResponse`) into a clean, typed `Survey` object:
|
|
9
|
-
|
|
10
|
-
```
|
|
11
|
-
ApiResponse (raw network JSON)
|
|
12
|
-
│
|
|
13
|
-
├── extractQuestions() → Flat list of ApiQuestion[]
|
|
14
|
-
├── resolveSurveyLanguage() → Determine active language code
|
|
15
|
-
├── extractSurveyLanguages()→ Build SurveyLanguage[] for language switcher
|
|
16
|
-
└── mapSurveyPages() → Pages → Questions → per-type mappers
|
|
17
|
-
│
|
|
18
|
-
└── mapQuestion() per question (see 03-question-mappers.md)
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Output: `Survey` Type
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
type Survey = {
|
|
25
|
-
id: string; // Survey identifier
|
|
26
|
-
language: string; // Active language code (e.g. 'en', 'de')
|
|
27
|
-
languages: SurveyLanguage[]; // All available languages for the switcher
|
|
28
|
-
pages: SurveyPageData[]; // Ordered list of pages
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
type SurveyPageData = {
|
|
32
|
-
id: string; // Page identifier
|
|
33
|
-
title?: string; // Optional page heading
|
|
34
|
-
questions: SurveyQuestion[]; // Questions on this page
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
type SurveyLanguage = {
|
|
38
|
-
code: string; // BCP-47 code (e.g. 'de')
|
|
39
|
-
name: string; // Display name (e.g. 'Deutsch')
|
|
40
|
-
};
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Key Functions
|
|
44
|
-
|
|
45
|
-
### `extractQuestions(api)`
|
|
46
|
-
Traverses `api.cfmSurveyDTO.surveyPages[].questionHolders[].question` to produce a flat array of raw API questions.
|
|
47
|
-
|
|
48
|
-
### `resolveSurveyLanguage(api, language?)`
|
|
49
|
-
Priority: `language` parameter → `api.surveyLanguage` → `api.cfmSurveyDTO.baseLanguage` → `'en'`
|
|
50
|
-
|
|
51
|
-
### `extractSession(api)`
|
|
52
|
-
Returns `{ instanceId, language }` or `null` if no valid instanceId exists. This session object is passed to the submit hook.
|
|
53
|
-
|
|
54
|
-
### `mapSurveyPages(api, language, placeholders)`
|
|
55
|
-
Iterates over `api.cfmSurveyDTO.surveyPages`, calling `mapQuestion()` for each question within each page's `questionHolders`. Returns `SurveyPageData[]`.
|
|
56
|
-
|
|
57
|
-
## API Response Structure (Simplified)
|
|
58
|
-
|
|
59
|
-
```typescript
|
|
60
|
-
type ApiResponse = {
|
|
61
|
-
instanceId: string;
|
|
62
|
-
surveyLanguage: string;
|
|
63
|
-
cfmSurveyDTO: {
|
|
64
|
-
id: string;
|
|
65
|
-
baseLanguage: string;
|
|
66
|
-
surveyPages: Array<{
|
|
67
|
-
id: string;
|
|
68
|
-
pageTitle?: string;
|
|
69
|
-
questionHolders: Array<{
|
|
70
|
-
question: ApiQuestion;
|
|
71
|
-
}>;
|
|
72
|
-
}>;
|
|
73
|
-
};
|
|
74
|
-
};
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## Language Re-mapping
|
|
78
|
-
|
|
79
|
-
When the user switches language via the `LanguageSelector`:
|
|
80
|
-
1. `selectedLanguage` state changes in `SurveyPage.tsx`
|
|
81
|
-
2. This flows into `useSurveySDK({ options: { language: selectedLanguage } })`
|
|
82
|
-
3. `useFetchSurvey` does **NOT re-fetch** — the raw `ApiResponse` is cached
|
|
83
|
-
4. `useMemo` re-runs `mapSurvey(apiResponse, newLanguage, placeholders)`
|
|
84
|
-
5. Each question's text, options, and labels are resolved from `translations[language]`
|
|
85
|
-
6. The entire UI re-renders with translated content
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
# Question Mappers — `mapQuestion`
|
|
2
|
-
|
|
3
|
-
> **Source**: `packages/sdk/src/fetchSurvey/utils/mappers/questionMappers/index.ts`
|
|
4
|
-
> **Called by**: `mapSurveyPages()` for each question in each page.
|
|
5
|
-
|
|
6
|
-
## What It Does
|
|
7
|
-
|
|
8
|
-
Takes a raw `ApiQuestion` and produces a fully typed `SurveyQuestion` variant. This is the core routing logic that determines what question type the client component will render.
|
|
9
|
-
|
|
10
|
-
## Dispatch Pipeline
|
|
11
|
-
|
|
12
|
-
```
|
|
13
|
-
ApiQuestion
|
|
14
|
-
│
|
|
15
|
-
├── resolveBase(raw, configs, language, placeholders)
|
|
16
|
-
│ → { id, text, description, required, requiredErrorMessage, containerMedia* }
|
|
17
|
-
│
|
|
18
|
-
├── normalizeType(raw.answerType)
|
|
19
|
-
│ → 'rating' | 'text' | 'matrix' | 'rating_matrix' | 'slider_matrix'
|
|
20
|
-
│ | 'text_and_media' | 'file_upload' | 'radio' (default)
|
|
21
|
-
│
|
|
22
|
-
└── switch(type) → per-type mapper
|
|
23
|
-
├── 'rating' → mapRatingQuestion() [handles NPS, CSAT, Slider, RatingScale]
|
|
24
|
-
├── 'text' → mapTextQuestion()
|
|
25
|
-
├── 'matrix' → mapMatrixQuestion() [handles CFM, CSAT, RATING matrix]
|
|
26
|
-
├── 'rating_matrix' → mapMatrixQuestion() [same handler, different subType]
|
|
27
|
-
├── 'slider_matrix' → mapSliderMatrixQuestion()
|
|
28
|
-
├── 'text_and_media' → mapTextAndMediaQuestion()
|
|
29
|
-
├── 'file_upload' → mapFileUploadQuestion()
|
|
30
|
-
└── default → mapRadioQuestion() [MCQ and any unrecognised type]
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## `normalizeType(answerType)` — Type Resolution
|
|
34
|
-
|
|
35
|
-
| API `answerType` | Normalized Type | Notes |
|
|
36
|
-
|-----------------|----------------|-------|
|
|
37
|
-
| `'SCALE'` | `'rating'` | Further sub-typed inside ratingMapper |
|
|
38
|
-
| `'RATING'` | `'rating'` | Legacy alias |
|
|
39
|
-
| `'RATING_MATRIX'` | `'rating_matrix'` | Grid with NPS-style columns |
|
|
40
|
-
| `'TEXTFIELD'` | `'text'` | Short or long text input |
|
|
41
|
-
| `'MCQ'` | `'radio'` | Multiple choice (single select) |
|
|
42
|
-
| `'CFM_MATRIX'` | `'matrix'` | Likert-style grid |
|
|
43
|
-
| `'CSAT_MATRIX'` | `'matrix'` | Satisfaction grid with emoji/star |
|
|
44
|
-
| `'SLIDER_MATRIX'` | `'slider_matrix'` | Grid of range sliders |
|
|
45
|
-
| `'TEXT_AND_MEDIA'` | `'text_and_media'` | Display-only media card |
|
|
46
|
-
| `'FILE_UPLOAD'` | `'file_upload'` | File attachment question |
|
|
47
|
-
| Any other | `'radio'` | Safe fallback |
|
|
48
|
-
|
|
49
|
-
## `resolveBase()` — Shared Fields
|
|
50
|
-
|
|
51
|
-
Every question variant inherits these base fields:
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
type QuestionBase = {
|
|
55
|
-
id: string; // ⚠️ MUST be used as DOM element id
|
|
56
|
-
text: string; // May contain HTML — use dangerouslySetInnerHTML
|
|
57
|
-
description?: string; // Supplementary instruction text (HTML)
|
|
58
|
-
required?: boolean; // Whether answer is mandatory
|
|
59
|
-
requiredErrorMessage?: string; // Custom validation error text
|
|
60
|
-
questionNumber?: number; // 1-indexed ordinal position
|
|
61
|
-
containerMediaUrl?: string; // Image/video shown alongside question
|
|
62
|
-
containerMediaMimeType?: string; // MIME type for container media
|
|
63
|
-
containerMediaAlignment?: string;// Layout position of container media
|
|
64
|
-
containerMediaSize?: number; // Width percentage of container media
|
|
65
|
-
};
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### Text Resolution Priority
|
|
69
|
-
```
|
|
70
|
-
language translation (richText) → language translation (plainText)
|
|
71
|
-
→ default richText → default plainText → ''
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### Placeholder Replacement
|
|
75
|
-
The `resolveBase` function replaces `{{TOKEN}}` patterns in question text and description:
|
|
76
|
-
```typescript
|
|
77
|
-
text.replace(/\{\{(\w+)\}\}/g, (match, key) =>
|
|
78
|
-
placeholders[key] !== undefined ? placeholders[key] : match
|
|
79
|
-
);
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Rating Mapper Sub-Dispatch
|
|
83
|
-
|
|
84
|
-
The `mapRatingQuestion()` handler further sub-types based on `questionConfigs`:
|
|
85
|
-
|
|
86
|
-
```
|
|
87
|
-
SCALE answerType
|
|
88
|
-
│
|
|
89
|
-
├── SCALE_TYPE=CSAT (or ≤5 options) → type: 'csat'
|
|
90
|
-
├── SCALE_TYPE=STAR/EMOJI/FIVE_POINT → type: 'rating_scale'
|
|
91
|
-
├── INPUT_TYPE=SLIDER → type: 'slider'
|
|
92
|
-
└── default (NPS/TEN_POINT) → type: 'rating'
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
This means the client component's `Question.tsx` needs to handle **all these refined types**, not just the raw `'rating'` type.
|
|
96
|
-
|
|
97
|
-
## Final Output: `SurveyQuestion` Union
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
type SurveyQuestion =
|
|
101
|
-
| RatingQuestion // type: 'rating'
|
|
102
|
-
| RadioQuestion // type: 'radio'
|
|
103
|
-
| TextQuestion // type: 'text'
|
|
104
|
-
| MatrixQuestion // type: 'matrix'
|
|
105
|
-
| RatingMatrixQuestion // type: 'rating_matrix'
|
|
106
|
-
| SliderMatrixQuestion // type: 'slider_matrix'
|
|
107
|
-
| TextAndMediaQuestion // type: 'text_and_media'
|
|
108
|
-
| CsatQuestion // type: 'csat'
|
|
109
|
-
| SliderQuestion // type: 'slider'
|
|
110
|
-
| RatingScaleQuestion // type: 'rating_scale'
|
|
111
|
-
| FileUploadQuestion; // type: 'file_upload'
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Each type is documented in detail in `02-question-types/`.
|