@explorer02/cfm-survey-sdk 0.1.8 → 0.2.0
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 -30
- 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/{03-client-components → 01-components}/01-survey-page.md +2 -0
- package/templates/docs/{03-client-components → 01-components}/02-question.md +2 -0
- package/templates/docs/{03-client-components → 01-components}/03-rating-scale.md +2 -0
- package/templates/docs/{03-client-components → 01-components}/04-csat-scale.md +3 -1
- package/templates/docs/{03-client-components → 01-components}/05-csat-matrix-scale.md +2 -0
- package/templates/docs/{03-client-components → 01-components}/06-likert-matrix-scale.md +2 -0
- package/templates/docs/{03-client-components → 01-components}/07-slider-matrix-scale.md +2 -0
- package/templates/docs/{03-client-components → 01-components}/08-file-upload-scale.md +2 -0
- package/templates/docs/{03-client-components → 01-components}/09-custom-slider-track.md +2 -0
- package/templates/docs/{03-client-components → 01-components}/10-header-footer.md +3 -1
- package/templates/docs/{03-client-components → 01-components}/11-progress-bar.md +2 -0
- package/templates/docs/{03-client-components → 01-components}/12-language-selector.md +2 -0
- package/templates/docs/{03-client-components → 01-components}/13-matrix-dropdown.md +2 -0
- package/templates/docs/{03-client-components → 01-components}/README.md +3 -3
- package/templates/docs/02-question-types/01-rating.md +0 -8
- package/templates/docs/02-reference/config-field-index.md +158 -0
- 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/03-ui-specs/00-question-shell.md +89 -0
- package/templates/docs/03-ui-specs/01-rating.md +80 -0
- package/templates/docs/03-ui-specs/02-radio.md +57 -0
- package/templates/docs/03-ui-specs/03-text.md +51 -0
- package/templates/docs/03-ui-specs/04-csat.md +57 -0
- package/templates/docs/03-ui-specs/05-rating-scale.md +49 -0
- package/templates/docs/03-ui-specs/06-slider.md +42 -0
- package/templates/docs/03-ui-specs/07-matrix-cfm.md +66 -0
- package/templates/docs/03-ui-specs/08-matrix-csat-rating.md +65 -0
- package/templates/docs/03-ui-specs/09-slider-matrix.md +61 -0
- package/templates/docs/03-ui-specs/10-file-upload.md +54 -0
- package/templates/docs/03-ui-specs/11-text-and-media.md +49 -0
- package/templates/docs/03-ui-specs/12-survey-chrome.md +60 -0
- package/templates/docs/03-ui-specs/README.md +79 -0
- package/templates/docs/03-ui-specs/shared/custom-slider-track.md +52 -0
- package/templates/docs/03-ui-specs/shared/matrix-dropdown.md +38 -0
- package/templates/docs/MANIFEST.json +150 -0
- package/templates/docs/index.md +111 -142
- package/templates/docs/templates/implementation_plan.md +91 -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/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/{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
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
# Language Handling — Translations & Placeholders
|
|
2
|
-
|
|
3
|
-
> **Source**: `packages/sdk/src/fetchSurvey/utils/extractSurveyLanguages.ts`
|
|
4
|
-
|
|
5
|
-
## How Multi-Language Works
|
|
6
|
-
|
|
7
|
-
1. The raw API response contains `translations` objects on each question and answer detail
|
|
8
|
-
2. `extractSurveyLanguages()` scans all questions to discover available language codes
|
|
9
|
-
3. `mapSurvey()` resolves text fields using the active language's translations
|
|
10
|
-
4. Language switching is **client-side only** — no API re-fetch
|
|
11
|
-
|
|
12
|
-
## Language Discovery
|
|
13
|
-
|
|
14
|
-
The SDK traverses all questions in the survey and collects unique language codes from `question.translations` keys:
|
|
15
|
-
|
|
16
|
-
```typescript
|
|
17
|
-
// Pseudocode
|
|
18
|
-
languagesSet.add(baseLanguage); // e.g. 'de'
|
|
19
|
-
for each question:
|
|
20
|
-
for each key in question.translations:
|
|
21
|
-
languagesSet.add(key); // e.g. 'en', 'fr'
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Display Names
|
|
25
|
-
|
|
26
|
-
Built-in language code → display name mapping:
|
|
27
|
-
|
|
28
|
-
| Code | Display Name |
|
|
29
|
-
|------|-------------|
|
|
30
|
-
| `en` | English |
|
|
31
|
-
| `de` | Deutsch |
|
|
32
|
-
| `hi` | Hindi |
|
|
33
|
-
| `es` | Español |
|
|
34
|
-
| `fr` | Français |
|
|
35
|
-
| `it` | Italiano |
|
|
36
|
-
| `ja` | 日本語 |
|
|
37
|
-
| `ko` | 한국어 |
|
|
38
|
-
| `zh` | 中文 |
|
|
39
|
-
| `bn` | Bengali |
|
|
40
|
-
| `gu` | Gujarati |
|
|
41
|
-
| `mr` | Marathi |
|
|
42
|
-
| `pa` | Punjabi |
|
|
43
|
-
| `ta` | Tamil |
|
|
44
|
-
| `te` | Telugu |
|
|
45
|
-
| `ur` | Urdu |
|
|
46
|
-
|
|
47
|
-
Unknown codes fall back to `code.toUpperCase()`.
|
|
48
|
-
|
|
49
|
-
## Translation Resolution Priority
|
|
50
|
-
|
|
51
|
-
For question text:
|
|
52
|
-
```
|
|
53
|
-
translations[language].questionRichText
|
|
54
|
-
→ translations[language].questionText
|
|
55
|
-
→ raw.questionRichText
|
|
56
|
-
→ raw.questionText
|
|
57
|
-
→ ''
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
For answer option labels:
|
|
61
|
-
```
|
|
62
|
-
translations[language].answerText → raw.answerText → ''
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
For validation error messages:
|
|
66
|
-
```
|
|
67
|
-
config.translations[language].value[0] → config.value[0] → default message
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Placeholders
|
|
71
|
-
|
|
72
|
-
Tokens like `{{FIRST_NAME}}` in question text are replaced at map time:
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
const SURVEY_PLACEHOLDERS = {
|
|
76
|
-
FIRST_NAME: 'Customer',
|
|
77
|
-
LAST_NAME: 'Smith',
|
|
78
|
-
EMAIL_ADDRESS: 'customer@example.com',
|
|
79
|
-
};
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
**⚠️ CRITICAL**: Define `SURVEY_PLACEHOLDERS` as a **constant outside the component** to prevent infinite re-render loops:
|
|
83
|
-
|
|
84
|
-
```tsx
|
|
85
|
-
// ✅ CORRECT — stable reference
|
|
86
|
-
const SURVEY_PLACEHOLDERS = { FIRST_NAME: 'John' };
|
|
87
|
-
export default function SurveyPage() { ... }
|
|
88
|
-
|
|
89
|
-
// ❌ WRONG — new object every render → infinite re-fetch
|
|
90
|
-
export default function SurveyPage() {
|
|
91
|
-
useSurveySDK({ options: { placeholders: { FIRST_NAME: 'John' } } });
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## Language Switching in UI
|
|
96
|
-
|
|
97
|
-
```tsx
|
|
98
|
-
const [selectedLanguage, setSelectedLanguage] = useState<string | undefined>("");
|
|
99
|
-
|
|
100
|
-
// Pass to SDK
|
|
101
|
-
const { ... } = useSurveySDK({ options: { language: selectedLanguage } });
|
|
102
|
-
|
|
103
|
-
// Render selector
|
|
104
|
-
<LanguageSelector
|
|
105
|
-
languages={survey.languages}
|
|
106
|
-
selectedLanguage={survey.language}
|
|
107
|
-
onChange={setSelectedLanguage}
|
|
108
|
-
/>
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
When `setSelectedLanguage` fires, the SDK re-maps the cached survey data to the new language — no network request.
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# Icons & Emojis Architecture
|
|
2
|
-
|
|
3
|
-
> **Source**: `apps/client/src/components/icons.tsx` (to be created by the agent)
|
|
4
|
-
|
|
5
|
-
## The CSAT Emoji System
|
|
6
|
-
|
|
7
|
-
The SDK relies on a specific sequence of sentiment faces for CSAT scales. You MUST implement this mapping in your client application using a library like `react-icons/fa` or raw SVGs.
|
|
8
|
-
|
|
9
|
-
### Default 5-Point Mapping
|
|
10
|
-
|
|
11
|
-
```tsx
|
|
12
|
-
import { FaRegSmile, FaRegMeh, FaRegFrown, FaRegSmileBeam, FaRegTired } from 'react-icons/fa';
|
|
13
|
-
|
|
14
|
-
export const CsatEmojiMapping: Record<number | string, JSX.Element> = {
|
|
15
|
-
1: <FaRegTired className="text-red-500 w-full h-full" />,
|
|
16
|
-
2: <FaRegFrown className="text-orange-500 w-full h-full" />,
|
|
17
|
-
3: <FaRegMeh className="text-yellow-500 w-full h-full" />,
|
|
18
|
-
4: <FaRegSmile className="text-green-500 w-full h-full" />,
|
|
19
|
-
5: <FaRegSmileBeam className="text-green-600 w-full h-full" />,
|
|
20
|
-
};
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### The `getEmojiForIndex` Helper
|
|
24
|
-
|
|
25
|
-
Because some surveys use 3-point, 7-point, or 10-point scales instead of 5, you MUST use a helper function to proportionally map any scale length to the 5 core sentiment faces.
|
|
26
|
-
|
|
27
|
-
```tsx
|
|
28
|
-
export function getEmojiForIndex(index: number, totalOptions: number): JSX.Element {
|
|
29
|
-
const percentage = index / (totalOptions - 1);
|
|
30
|
-
|
|
31
|
-
if (percentage < 0.2) return CsatEmojiMapping[1];
|
|
32
|
-
if (percentage < 0.4) return CsatEmojiMapping[2];
|
|
33
|
-
if (percentage < 0.6) return CsatEmojiMapping[3];
|
|
34
|
-
if (percentage < 0.8) return CsatEmojiMapping[4];
|
|
35
|
-
return CsatEmojiMapping[5];
|
|
36
|
-
}
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## The Star Icon System
|
|
40
|
-
|
|
41
|
-
For star ratings, you need filled and empty variants:
|
|
42
|
-
|
|
43
|
-
```tsx
|
|
44
|
-
import { FaStar, FaRegStar } from 'react-icons/fa';
|
|
45
|
-
|
|
46
|
-
export const CsatStarIcons = {
|
|
47
|
-
filled: <FaStar className="text-yellow-400 w-full h-full" />,
|
|
48
|
-
empty: <FaRegStar className="text-gray-300 w-full h-full" />
|
|
49
|
-
};
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## Color Mapping System
|
|
53
|
-
For rating matrices and numbered NPS grids, colors are usually provided by the SDK in `option.color`. If not, use standard NPS coloring:
|
|
54
|
-
- **0-6 (Detractors)**: Red/Orange
|
|
55
|
-
- **7-8 (Passives)**: Yellow
|
|
56
|
-
- **9-10 (Promoters)**: Green
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# SDK Core Architecture
|
|
2
|
-
|
|
3
|
-
> This folder documents the internal architecture of `@explorer02/cfm-survey-sdk`.
|
|
4
|
-
> Read these files **in order** to understand how the SDK processes a survey from network fetch to user submission.
|
|
5
|
-
|
|
6
|
-
## Pipeline Overview
|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
┌─────────────┐ ┌──────────────┐ ┌──────────────────┐ ┌─────────────┐
|
|
10
|
-
│ Fetch API │ ──→ │ Map Survey │ ──→ │ Map Questions │ ──→ │ Paginate │
|
|
11
|
-
│ (network) │ │ (language) │ │ (per-type) │ │ (pages) │
|
|
12
|
-
└─────────────┘ └──────────────┘ └──────────────────┘ └─────────────┘
|
|
13
|
-
│
|
|
14
|
-
▼
|
|
15
|
-
┌─────────────┐ ┌──────────────┐ ┌──────────────────┐ ┌─────────────┐
|
|
16
|
-
│ Submit │ ←── │ Format Body │ ←── │ Validate │ ←── │ Render UI │
|
|
17
|
-
│ (network) │ │ (payload) │ │ (required) │ │ (React) │
|
|
18
|
-
└─────────────┘ └──────────────┘ └──────────────────┘ └─────────────┘
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Files in This Folder
|
|
22
|
-
|
|
23
|
-
| File | Topic | When to Read |
|
|
24
|
-
|------|-------|-------------|
|
|
25
|
-
| `01-fetch-survey.md` | Network fetching, API endpoint, instanceId | **Always** — first step |
|
|
26
|
-
| `02-survey-mapper.md` | Raw API → Survey object transformation | **Always** — understand data shape |
|
|
27
|
-
| `03-question-mappers.md` | Question type dispatch, normalizeType | **Always** — core routing logic |
|
|
28
|
-
| `04-pagination.md` | Page navigation, currentPageIndex | **Always** — state management |
|
|
29
|
-
| `05-validation.md` | Required field validation, scroll-to-error | **Always** — UX critical |
|
|
30
|
-
| `06-submit-survey.md` | Response submission, payload formatting | **Always** — submission pipeline |
|
|
31
|
-
| `07-language-handling.md` | Translations, placeholders, language switching | When survey is multi-language |
|
|
32
|
-
| `08-icons-and-emojis.md` | CSAT emoji faces, star icons | When CSAT/rating_scale types present |
|
|
33
|
-
|
|
34
|
-
## The Single Hook: `useSurveySDK()`
|
|
35
|
-
|
|
36
|
-
The entire SDK is consumed through **one hook**:
|
|
37
|
-
|
|
38
|
-
```typescript
|
|
39
|
-
import { useSurveySDK } from '@explorer02/cfm-survey-sdk';
|
|
40
|
-
|
|
41
|
-
const { surveyQueryResults, submitSurveyResults, state, onAction } = useSurveySDK({
|
|
42
|
-
options: {
|
|
43
|
-
instanceId: string, // JWT token from client
|
|
44
|
-
language: string | undefined, // Active language code
|
|
45
|
-
placeholders: Record<string, string>, // Token replacements
|
|
46
|
-
debug: boolean, // Console logging
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
This hook internally composes: `useFetchSurvey` → `useSurveyPagination` → `useSubmitResponse` → `useSurveyProgress`.
|
|
52
|
-
|
|
53
|
-
The client component **never** needs to import or call these internal hooks directly.
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# Radio Question (MCQ)
|
|
2
|
-
|
|
3
|
-
> **Type**: `'radio'` | **API Source**: `MCQ` (and any unrecognised answerType)
|
|
4
|
-
> **Mapper**: `radioMapper.ts` | **Component**: Inline in `Question.tsx`
|
|
5
|
-
|
|
6
|
-
## TypeScript Type
|
|
7
|
-
|
|
8
|
-
```typescript
|
|
9
|
-
type RadioQuestion = QuestionBase & {
|
|
10
|
-
type: 'radio';
|
|
11
|
-
options: SurveyOption[]; // Answer choices
|
|
12
|
-
isMultiSelect?: boolean; // If true, answer is (string|number)[]
|
|
13
|
-
};
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
## Answer Shape: `string | number`
|
|
17
|
-
Example: `"option_1"` or `3`
|
|
18
|
-
If `isMultiSelect: true` → `(string | number)[]`
|
|
19
|
-
|
|
20
|
-
## Rendering Guidance
|
|
21
|
-
- Render as card-style option list with radio circles
|
|
22
|
-
- Each option: border card with custom radio indicator + label
|
|
23
|
-
- Selected state: brand-color border + light tint background + filled dot
|
|
24
|
-
- Use `<input type="radio" className="sr-only">` for accessibility
|
|
25
|
-
- Labels use `dangerouslySetInnerHTML` (may contain HTML)
|
|
26
|
-
- `onChange={() => onSelect(option.value)}`
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# Text Question (Free Text)
|
|
2
|
-
|
|
3
|
-
> **Type**: `'text'` | **API Source**: `TEXTFIELD`
|
|
4
|
-
> **Mapper**: `textMapper.ts` | **Component**: Inline in `Question.tsx`
|
|
5
|
-
|
|
6
|
-
## TypeScript Type
|
|
7
|
-
|
|
8
|
-
```typescript
|
|
9
|
-
type TextQuestion = QuestionBase & {
|
|
10
|
-
type: 'text';
|
|
11
|
-
maxCharacterCount?: number; // Character limit
|
|
12
|
-
placeholder?: string; // Input placeholder text
|
|
13
|
-
inputVariant?: 'short' | 'long'; // Single-line vs textarea
|
|
14
|
-
};
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Answer Shape: `string`
|
|
18
|
-
Example: `"Great customer service, very satisfied"`
|
|
19
|
-
|
|
20
|
-
## Rendering Guidance
|
|
21
|
-
- `inputVariant === 'short'` → `<input type="text">`, `inputVariant === 'long'` → `<textarea rows={4}>`
|
|
22
|
-
- Default to `<textarea>` if `inputVariant` is not specified
|
|
23
|
-
- Show character counter: `maxCharacterCount - currentLength` remaining
|
|
24
|
-
- `onChange={e => onSelect(e.target.value)}`
|
|
25
|
-
- Use `question.placeholder` or fallback: `"Type your response here..."`
|
|
26
|
-
- Focus state: brand-color border + ring
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# Text and Media Question (Display-Only)
|
|
2
|
-
|
|
3
|
-
> **Type**: `'text_and_media'` | **API Source**: `TEXT_AND_MEDIA`
|
|
4
|
-
> **Mapper**: `textAndMediaMapper.ts` | **Component**: Inline in `Question.tsx`
|
|
5
|
-
|
|
6
|
-
## TypeScript Type
|
|
7
|
-
|
|
8
|
-
```typescript
|
|
9
|
-
type TextAndMediaQuestion = QuestionBase & {
|
|
10
|
-
type: 'text_and_media';
|
|
11
|
-
mediaUrl?: string; // Image or video URL
|
|
12
|
-
mediaMimeType?: string; // 'image/*' or 'video/*'
|
|
13
|
-
mediaTitle?: string; // Caption/alt text
|
|
14
|
-
mediaAlignment?: string; // Layout position
|
|
15
|
-
mediaSize?: number; // Width percentage
|
|
16
|
-
};
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Answer Shape: NONE
|
|
20
|
-
This is **display-only** — no answer is collected.
|
|
21
|
-
|
|
22
|
-
## ⚠️ Critical Rules
|
|
23
|
-
- **DO NOT** dispatch a `CHANGE` action for this question type
|
|
24
|
-
- **Excluded** from validation (always passes)
|
|
25
|
-
- **Excluded** from progress percentage counting
|
|
26
|
-
- **Skipped** in `buildSubmitRequestBody()` — nothing is submitted
|
|
27
|
-
|
|
28
|
-
## Rendering Guidance
|
|
29
|
-
- Show `question.text` as the heading
|
|
30
|
-
- If `mediaUrl` exists:
|
|
31
|
-
- `mediaMimeType` starts with `'video/'` → `<video controls src={mediaUrl}>`
|
|
32
|
-
- Otherwise → `<img src={mediaUrl} alt={mediaTitle}>`
|
|
33
|
-
- Position media according to `mediaAlignment`
|
|
34
|
-
- Size media according to `mediaSize` percentage
|
|
35
|
-
- Show `mediaTitle` as caption below media
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# Question Types Overview
|
|
2
|
-
|
|
3
|
-
> This folder contains one detailed doc per question type. Each doc covers: TypeScript type, mapper logic, answer shape, properties, and rendering guidance.
|
|
4
|
-
|
|
5
|
-
## The `SurveyQuestion` Discriminated Union
|
|
6
|
-
|
|
7
|
-
The SDK maps API questions into a **discriminated union** using the `type` field:
|
|
8
|
-
|
|
9
|
-
```typescript
|
|
10
|
-
type SurveyQuestion =
|
|
11
|
-
| RatingQuestion // type: 'rating' — NPS 0-10 numeric scale
|
|
12
|
-
| RadioQuestion // type: 'radio' — MCQ single/multi select
|
|
13
|
-
| TextQuestion // type: 'text' — Free text input
|
|
14
|
-
| CsatQuestion // type: 'csat' — 1-5 satisfaction (emoji/star)
|
|
15
|
-
| RatingScaleQuestion // type: 'rating_scale' — Star/emoji rating (1-5/1-10)
|
|
16
|
-
| SliderQuestion // type: 'slider' — Single range slider
|
|
17
|
-
| MatrixQuestion // type: 'matrix' — Grid (CFM/CSAT/RATING subTypes)
|
|
18
|
-
| RatingMatrixQuestion // type: 'rating_matrix' — NPS-style rating grid
|
|
19
|
-
| SliderMatrixQuestion // type: 'slider_matrix' — Grid of range sliders
|
|
20
|
-
| FileUploadQuestion // type: 'file_upload' — File attachment
|
|
21
|
-
| TextAndMediaQuestion; // type: 'text_and_media' — Display-only media card
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Question → Component Routing Table
|
|
25
|
-
|
|
26
|
-
| `question.type` | `question.subType` | Client Component | Answer Shape |
|
|
27
|
-
|-----------------|-------------------|-----------------|-------------|
|
|
28
|
-
| `'rating'` | — | `RatingScale` | `number` |
|
|
29
|
-
| `'radio'` | — | Inline radio cards | `string \| number` |
|
|
30
|
-
| `'text'` | — | Inline textarea | `string` |
|
|
31
|
-
| `'csat'` | — | `CsatScale` | `number \| null` |
|
|
32
|
-
| `'rating_scale'` | — | `RatingScale` (star/emoji variant) | `number` |
|
|
33
|
-
| `'slider'` | — | `CustomSliderTrack` | `number` |
|
|
34
|
-
| `'matrix'` | `'CFM_MATRIX'` | `LikertMatrixScale` | `MatrixAnswerMap` |
|
|
35
|
-
| `'matrix'` | `'CSAT_MATRIX'` | `CsatMatrixScale` | `MatrixAnswerMap` |
|
|
36
|
-
| `'matrix'` | `'RATING_MATRIX'` | `CsatMatrixScale` | `MatrixAnswerMap` |
|
|
37
|
-
| `'rating_matrix'` | — | `CsatMatrixScale` | `MatrixAnswerMap` |
|
|
38
|
-
| `'slider_matrix'` | — | `SliderMatrixScale` | `MatrixAnswerMap` |
|
|
39
|
-
| `'file_upload'` | — | `FileUploadScale` | `UploadedFile[]` |
|
|
40
|
-
| `'text_and_media'` | — | Inline media card | (no answer) |
|
|
41
|
-
|
|
42
|
-
## Shared Base Properties
|
|
43
|
-
|
|
44
|
-
All question types extend `QuestionBase`:
|
|
45
|
-
|
|
46
|
-
| Property | Type | Description |
|
|
47
|
-
|----------|------|-------------|
|
|
48
|
-
| `id` | `string` | ⚠️ MUST be DOM element id |
|
|
49
|
-
| `text` | `string` | Question text (may contain HTML) |
|
|
50
|
-
| `description` | `string?` | Supplementary instruction (HTML) |
|
|
51
|
-
| `required` | `boolean?` | Mandatory answer flag |
|
|
52
|
-
| `requiredErrorMessage` | `string?` | Custom validation error |
|
|
53
|
-
| `questionNumber` | `number?` | 1-indexed ordinal |
|
|
54
|
-
| `containerMediaUrl` | `string?` | Image/video alongside question |
|
|
55
|
-
| `containerMediaMimeType` | `string?` | MIME type for container media |
|
|
56
|
-
| `containerMediaAlignment` | `string?` | Media layout position |
|
|
57
|
-
| `containerMediaSize` | `number?` | Media width percentage |
|
|
58
|
-
|
|
59
|
-
## Files in This Folder
|
|
60
|
-
|
|
61
|
-
| File | Question Type | API Source |
|
|
62
|
-
|------|-------------|-----------|
|
|
63
|
-
| `01-rating.md` | `RatingQuestion` | `SCALE` (NPS/TEN_POINT) |
|
|
64
|
-
| `02-radio.md` | `RadioQuestion` | `MCQ` |
|
|
65
|
-
| `03-text.md` | `TextQuestion` | `TEXTFIELD` |
|
|
66
|
-
| `04-csat.md` | `CsatQuestion` | `SCALE` (CSAT, ≤5 options) |
|
|
67
|
-
| `05-rating-scale.md` | `RatingScaleQuestion` | `SCALE` (STAR/EMOJI) |
|
|
68
|
-
| `06-slider.md` | `SliderQuestion` | `SCALE` (INPUT_TYPE=SLIDER) |
|
|
69
|
-
| `07-matrix-cfm.md` | `MatrixQuestion` CFM | `CFM_MATRIX` |
|
|
70
|
-
| `08-matrix-csat.md` | `MatrixQuestion` CSAT | `CSAT_MATRIX` |
|
|
71
|
-
| `09-matrix-rating.md` | `RatingMatrixQuestion` | `RATING_MATRIX` |
|
|
72
|
-
| `10-slider-matrix.md` | `SliderMatrixQuestion` | `SLIDER_MATRIX` |
|
|
73
|
-
| `11-file-upload.md` | `FileUploadQuestion` | `FILE_UPLOAD` |
|
|
74
|
-
| `12-text-and-media.md` | `TextAndMediaQuestion` | `TEXT_AND_MEDIA` |
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Import Rules & Setup
|
|
2
|
-
|
|
3
|
-
> Non-negotiable constraints for setting up Next.js with `@explorer02/cfm-survey-sdk`.
|
|
4
|
-
|
|
5
|
-
## 1. Top-Level Imports ONLY
|
|
6
|
-
|
|
7
|
-
You must import from the root package name.
|
|
8
|
-
|
|
9
|
-
```tsx
|
|
10
|
-
// ✅ REQUIRED
|
|
11
|
-
import { useSurveySDK, getEmojiForIndex } from '@explorer02/cfm-survey-sdk';
|
|
12
|
-
|
|
13
|
-
// ❌ FORBIDDEN (Will fail Next.js build)
|
|
14
|
-
import { useSurveySDK } from '@explorer02/cfm-survey-sdk/src/fetchSurvey/useFetchSurvey';
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## 2. Peer Dependencies
|
|
18
|
-
|
|
19
|
-
The SDK requires `@tanstack/react-query` to be installed in the client project:
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm install @explorer02/cfm-survey-sdk @tanstack/react-query
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## 3. Client Components Only
|
|
26
|
-
|
|
27
|
-
Because the SDK uses React state, `useQuery`, and DOM interactions, the `SurveyPage` must be a client component.
|
|
28
|
-
|
|
29
|
-
```tsx
|
|
30
|
-
'use client';
|
|
31
|
-
|
|
32
|
-
import { useSurveySDK } from '@explorer02/cfm-survey-sdk';
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## 4. Next.js Configuration
|
|
36
|
-
|
|
37
|
-
**CRITICAL**: You must configure `next.config.js` to transpile the SDK, because the SDK exports modern ES modules and uses CSS that Next.js needs to process.
|
|
38
|
-
|
|
39
|
-
```javascript
|
|
40
|
-
/** @type {import('next').NextConfig} */
|
|
41
|
-
const nextConfig = {
|
|
42
|
-
transpilePackages: ['@explorer02/cfm-survey-sdk'],
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
module.exports = nextConfig;
|
|
46
|
-
```
|
|
47
|
-
If you forget this, you will get `"SyntaxError: Cannot use import statement outside a module"`.
|
|
48
|
-
|
|
49
|
-
## 5. React 18 / StrictMode
|
|
50
|
-
|
|
51
|
-
Next.js `reactStrictMode: true` causes effects to fire twice in development. The SDK is built to handle this safely (e.g., query caching), but be aware of double-logging if `debug: true` is enabled.
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# Action Dispatching Rule
|
|
2
|
-
|
|
3
|
-
> The single flow of data mutation in the SDK.
|
|
4
|
-
|
|
5
|
-
## The Rule
|
|
6
|
-
|
|
7
|
-
You must NEVER try to update the `state` object directly. The `state` returned by `useSurveySDK` is deeply immutable.
|
|
8
|
-
|
|
9
|
-
All state mutations (answering a question, navigating pages, submitting) must be done through the `onAction` dispatcher function provided by the hook.
|
|
10
|
-
|
|
11
|
-
## The `onAction` Function
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
const { onAction } = useSurveySDK({ ... });
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
### Action Types
|
|
18
|
-
|
|
19
|
-
#### 1. Answering a Question
|
|
20
|
-
```tsx
|
|
21
|
-
// Standard (number/string)
|
|
22
|
-
onAction({
|
|
23
|
-
type: 'CHANGE',
|
|
24
|
-
payload: { questionId: 'q123', value: 4 }
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// Matrix (MatrixAnswerMap)
|
|
28
|
-
onAction({
|
|
29
|
-
type: 'CHANGE',
|
|
30
|
-
payload: { questionId: 'q456', value: { row1: 5, row2: 2 } }
|
|
31
|
-
});
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
#### 2. Next Page
|
|
35
|
-
```tsx
|
|
36
|
-
// Automatically triggers validation. If on the last page, auto-converts to SUBMIT.
|
|
37
|
-
onAction({ type: 'NEXT' });
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
#### 3. Previous Page
|
|
41
|
-
```tsx
|
|
42
|
-
onAction({ type: 'PREVIOUS' });
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
#### 4. Force Submit
|
|
46
|
-
```tsx
|
|
47
|
-
// Validates ALL pages, then triggers API request.
|
|
48
|
-
onAction({ type: 'SUBMIT' });
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Why This Matters
|
|
52
|
-
The `onAction` dispatcher internally handles:
|
|
53
|
-
- Clearing validation errors the moment a user answers
|
|
54
|
-
- Tracking analytics (timestamps, backtrack counts)
|
|
55
|
-
- Preserving scroll position
|
|
56
|
-
- Triggering cross-question logic
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# Scroll Navigation Rule
|
|
2
|
-
|
|
3
|
-
> The DOM requirement for validation error scrolling to function.
|
|
4
|
-
|
|
5
|
-
## The Rule
|
|
6
|
-
|
|
7
|
-
When rendering the wrapper for ANY question, the outermost DOM element (usually a `<section>` or `<div>`) **MUST** have its `id` attribute set to `question.id`.
|
|
8
|
-
|
|
9
|
-
```tsx
|
|
10
|
-
// ✅ REQUIRED
|
|
11
|
-
export default function Question({ question, ... }) {
|
|
12
|
-
return (
|
|
13
|
-
<section id={question.id} className="p-6 bg-white rounded-xl">
|
|
14
|
-
<h2>{question.text}</h2>
|
|
15
|
-
{/* ... */}
|
|
16
|
-
</section>
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// ❌ FORBIDDEN
|
|
21
|
-
export default function Question({ question, ... }) {
|
|
22
|
-
return (
|
|
23
|
-
<section className="p-6 bg-white rounded-xl">
|
|
24
|
-
<h2 id={question.id}>{question.text}</h2> {/* Wrong element */}
|
|
25
|
-
{/* ... */}
|
|
26
|
-
</section>
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Why This Matters
|
|
32
|
-
|
|
33
|
-
When the user clicks "Next" or "Submit", the SDK validates the fields. If it finds a required field is empty, it does two things:
|
|
34
|
-
1. Sets `validationErrors[questionId]`
|
|
35
|
-
2. Calls `document.getElementById(questionId).scrollIntoView()`
|
|
36
|
-
|
|
37
|
-
If the ID is missing from the DOM, the error message will appear, but the page will not scroll to the error, resulting in a broken User Experience (especially on long pages).
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Logo and Branding Rule
|
|
2
|
-
|
|
3
|
-
> How to handle logos and branding without breaking the build or deployment.
|
|
4
|
-
|
|
5
|
-
## The Rule
|
|
6
|
-
|
|
7
|
-
You must **NEVER** use `<img>` tags pointing to external URLs (e.g., Telekom or Sprinklr servers) for the main brand logo.
|
|
8
|
-
|
|
9
|
-
You must **NEVER** attempt to download image files, save them to the `public/` folder, and reference them.
|
|
10
|
-
|
|
11
|
-
You MUST construct the logo purely using **Tailwind CSS**.
|
|
12
|
-
|
|
13
|
-
## Example: Telekom "T" Logo (Abstracted)
|
|
14
|
-
|
|
15
|
-
Instead of finding the exact Telekom logo, build a clean, recognizable abstract representation using geometric divs:
|
|
16
|
-
|
|
17
|
-
```tsx
|
|
18
|
-
{/* Abstract Magenta "T" equivalent */}
|
|
19
|
-
<div className="flex items-center gap-2">
|
|
20
|
-
<div className="flex h-8 w-8 items-center justify-center rounded-sm bg-[#e20074]">
|
|
21
|
-
<div className="flex flex-col items-center">
|
|
22
|
-
<div className="h-1 w-4 bg-white" />
|
|
23
|
-
<div className="h-3 w-1 bg-white" />
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
<span className="font-bold text-gray-900 tracking-tight">Telekom</span>
|
|
27
|
-
</div>
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Example: Generic Circular Logo
|
|
31
|
-
|
|
32
|
-
```tsx
|
|
33
|
-
<div className="flex items-center gap-3">
|
|
34
|
-
<div className="h-8 w-8 rounded-full bg-gradient-to-tr from-blue-600 to-indigo-500" />
|
|
35
|
-
<span className="text-xl font-bold tracking-tight text-gray-900">BrandName</span>
|
|
36
|
-
</div>
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Why This Matters
|
|
40
|
-
1. **Broken Links**: External image URLs often change, expire, or return 403 Forbidden when accessed from a Vercel deployment domain.
|
|
41
|
-
2. **File System Issues**: Downloading assets to `public/` during an automated AI build process often fails due to permissions, path resolution, or missing dependencies.
|
|
42
|
-
3. **Performance**: CSS-only logos render instantly and scale perfectly without network requests.
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# Troubleshooting & Common Errors
|
|
2
|
-
|
|
3
|
-
> Solutions for common issues encountered while building with the SDK.
|
|
4
|
-
|
|
5
|
-
## 1. "Cannot use import statement outside a module"
|
|
6
|
-
**Symptom**: Next.js build fails immediately on start.
|
|
7
|
-
**Cause**: Next.js is not transpiling the SDK package.
|
|
8
|
-
**Fix**: Add the package to `transpilePackages` in `next.config.js`:
|
|
9
|
-
```javascript
|
|
10
|
-
const nextConfig = {
|
|
11
|
-
transpilePackages: ['@explorer02/cfm-survey-sdk'],
|
|
12
|
-
};
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## 2. Infinite Re-renders / Re-fetching
|
|
16
|
-
**Symptom**: The browser freezes or the network tab shows hundreds of API requests to the survey endpoint.
|
|
17
|
-
**Cause**: Passing a new object reference to `options.placeholders` on every render.
|
|
18
|
-
**Fix**: Extract the placeholders object outside the component:
|
|
19
|
-
```tsx
|
|
20
|
-
// OUTSIDE the component
|
|
21
|
-
const SURVEY_PLACEHOLDERS = { FIRST_NAME: 'John' };
|
|
22
|
-
|
|
23
|
-
export default function SurveyPage() {
|
|
24
|
-
const { ... } = useSurveySDK({ options: { placeholders: SURVEY_PLACEHOLDERS } });
|
|
25
|
-
}
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## 3. "window is not defined" or "document is not defined"
|
|
29
|
-
**Symptom**: Next.js SSR crashes with DOM errors.
|
|
30
|
-
**Cause**: A component using the SDK is missing the `'use client'` directive. The SDK relies on browser APIs.
|
|
31
|
-
**Fix**: Add `'use client';` to the very top of `SurveyPage.tsx` and any file importing the SDK.
|
|
32
|
-
|
|
33
|
-
## 4. Clicking "Next" shows errors but doesn't scroll
|
|
34
|
-
**Symptom**: Required field validation fails, text appears, but the viewport doesn't move.
|
|
35
|
-
**Cause**: The DOM wrapper for the question is missing the `id` attribute.
|
|
36
|
-
**Fix**: Ensure `<section id={question.id}>` is present on the outermost element of every question card.
|
|
37
|
-
|
|
38
|
-
## 5. Survey renders completely empty
|
|
39
|
-
**Symptom**: `surveyQueryResults.data` is `null`, but there's no error.
|
|
40
|
-
**Cause**: The provided `instanceId` is empty, malformed, or has expired/been deleted on the server.
|
|
41
|
-
**Fix**: Verify the `instanceId` JWT token. Ask the client to provide a fresh one.
|
|
42
|
-
|
|
43
|
-
## 6. Icons/Emojis are missing or look broken
|
|
44
|
-
**Symptom**: CSAT scales show empty boxes instead of faces.
|
|
45
|
-
**Cause**: Missing peer dependencies.
|
|
46
|
-
**Fix**: Ensure `react-icons` is installed in the client project: `npm install react-icons`.
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Critical Operating Rules
|
|
2
|
-
|
|
3
|
-
> This folder contains the absolute, non-negotiable constraints you MUST follow when building a survey using `@explorer02/cfm-survey-sdk`.
|
|
4
|
-
|
|
5
|
-
## Files in This Folder
|
|
6
|
-
|
|
7
|
-
| File | Topic | Importance |
|
|
8
|
-
|------|-------|------------|
|
|
9
|
-
| `01-import-rules.md` | Imports and Next.js setup | **CRITICAL** (Build breaks without it) |
|
|
10
|
-
| `02-action-dispatching.md` | `onAction` pattern | **CRITICAL** (State breaks without it) |
|
|
11
|
-
| `03-scroll-navigation.md` | `id={question.id}` rule | **CRITICAL** (Validation UX breaks) |
|
|
12
|
-
| `04-logo-branding.md` | CSS-only logo mandate | **CRITICAL** (Deployment breaks) |
|
|
13
|
-
| `05-troubleshooting.md` | Common errors & fixes | Useful reference |
|
|
14
|
-
|
|
15
|
-
## The Golden Rule
|
|
16
|
-
|
|
17
|
-
**You are building a client application using a pre-compiled npm package.**
|
|
18
|
-
|
|
19
|
-
You are STRICTLY PROHIBITED from trying to modify, monkey-patch, or import internal files from inside `node_modules/@explorer02/cfm-survey-sdk`.
|
|
20
|
-
|
|
21
|
-
Everything you need is exported from the top-level barrel file.
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
// ✅ CORRECT
|
|
25
|
-
import { useSurveySDK, type SurveyQuestion } from '@explorer02/cfm-survey-sdk';
|
|
26
|
-
|
|
27
|
-
// ❌ WRONG — Build will fail immediately
|
|
28
|
-
import { mapQuestion } from '@explorer02/cfm-survey-sdk/src/fetchSurvey/utils';
|
|
29
|
-
```
|
|
File without changes
|
/package/templates/docs/{02-question-types → 02-reference/question-types}/05-rating-scale.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/templates/docs/{02-question-types → 02-reference/question-types}/09-matrix-rating.md
RENAMED
|
File without changes
|
/package/templates/docs/{02-question-types → 02-reference/question-types}/10-slider-matrix.md
RENAMED
|
File without changes
|
|
File without changes
|