@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
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
# Survey Page Orchestrator
|
|
2
|
-
|
|
3
|
-
> **Source**: `apps/client/src/components/SurveyPage.tsx`
|
|
4
|
-
> **Role**: The main entry point that wires the UI to the `useSurveySDK` hook.
|
|
5
|
-
|
|
6
|
-
## Setup & Wiring
|
|
7
|
-
|
|
8
|
-
The component must pass the `options` to `useSurveySDK`, including the **instanceId** provided by the client prompt.
|
|
9
|
-
|
|
10
|
-
```tsx
|
|
11
|
-
const SURVEY_PLACEHOLDERS = { FIRST_NAME: 'Customer' }; // Must be outside component!
|
|
12
|
-
|
|
13
|
-
export default function SurveyPage() {
|
|
14
|
-
const [selectedLanguage, setSelectedLanguage] = useState<string | undefined>("");
|
|
15
|
-
|
|
16
|
-
const { surveyQueryResults, submitSurveyResults, state, onAction } = useSurveySDK({
|
|
17
|
-
options: {
|
|
18
|
-
instanceId: 'YOUR_INSTANCE_ID_HERE', // From client prompt
|
|
19
|
-
language: selectedLanguage,
|
|
20
|
-
placeholders: SURVEY_PLACEHOLDERS,
|
|
21
|
-
debug: true,
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const survey = surveyQueryResults.data;
|
|
26
|
-
|
|
27
|
-
// ... render states
|
|
28
|
-
}
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## The 5 Render States
|
|
32
|
-
|
|
33
|
-
A complete `SurveyPage` must handle 5 distinct rendering states in this exact order:
|
|
34
|
-
|
|
35
|
-
### 1. Loading State
|
|
36
|
-
```tsx
|
|
37
|
-
if (surveyQueryResults.isLoading) {
|
|
38
|
-
return <LoadingView /> // Header, Footer, and a "Loading..." message
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### 2. Error State
|
|
43
|
-
```tsx
|
|
44
|
-
if (surveyQueryResults.error) {
|
|
45
|
-
return <ErrorView error={surveyQueryResults.error.message} />
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### 3. Empty State
|
|
50
|
-
```tsx
|
|
51
|
-
if (!survey) {
|
|
52
|
-
return <EmptyView /> // Header, Footer, and a "No survey data" message
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### 4. Submitted State
|
|
57
|
-
```tsx
|
|
58
|
-
if (submitSurveyResults.data) {
|
|
59
|
-
return <SubmitSummaryView /> // Header, Footer, and a "Thank you" message
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### 5. Active Survey State
|
|
64
|
-
The main render path. Must include:
|
|
65
|
-
1. `Header`
|
|
66
|
-
2. `ProgressBar` (passing `state.progressPercentage`)
|
|
67
|
-
3. `LanguageSelector` (passing `survey.languages`, `survey.language`, `setSelectedLanguage`)
|
|
68
|
-
4. The question list mapping over `state.currentQuestions`
|
|
69
|
-
5. Back / Next buttons
|
|
70
|
-
6. `Footer`
|
|
71
|
-
|
|
72
|
-
## Question Mapping Pattern
|
|
73
|
-
|
|
74
|
-
```tsx
|
|
75
|
-
<div className="space-y-12">
|
|
76
|
-
{state.currentQuestions.map(question => (
|
|
77
|
-
<Question
|
|
78
|
-
key={question.id}
|
|
79
|
-
question={question}
|
|
80
|
-
selectedValue={state.values[question.id]}
|
|
81
|
-
validationError={state.validationErrors[question.id]}
|
|
82
|
-
onSelect={value => onAction({
|
|
83
|
-
type: 'CHANGE',
|
|
84
|
-
payload: { questionId: question.id, value }
|
|
85
|
-
})}
|
|
86
|
-
/>
|
|
87
|
-
))}
|
|
88
|
-
</div>
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## Navigation Buttons Pattern
|
|
92
|
-
|
|
93
|
-
```tsx
|
|
94
|
-
{/* Back Button (hide on first page) */}
|
|
95
|
-
{state.currentPageIndex > 0 && (
|
|
96
|
-
<button onClick={() => onAction({ type: 'PREVIOUS' })}>
|
|
97
|
-
{survey.language?.startsWith('de') ? 'Zurück' : 'Back'}
|
|
98
|
-
</button>
|
|
99
|
-
)}
|
|
100
|
-
|
|
101
|
-
{/* Next/Submit Button */}
|
|
102
|
-
<button
|
|
103
|
-
onClick={() => onAction({ type: 'NEXT' })}
|
|
104
|
-
disabled={submitSurveyResults.isLoading}
|
|
105
|
-
>
|
|
106
|
-
{submitSurveyResults.isLoading
|
|
107
|
-
? (survey.language?.startsWith('de') ? 'Wird gesendet...' : 'Submitting...')
|
|
108
|
-
: state.currentPageIndex < survey.pages.length - 1
|
|
109
|
-
? (survey.language?.startsWith('de') ? 'Weiter' : 'Next')
|
|
110
|
-
: (survey.language?.startsWith('de') ? 'Absenden' : 'Submit')
|
|
111
|
-
}
|
|
112
|
-
</button>
|
|
113
|
-
```
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# Question Dispatcher
|
|
2
|
-
|
|
3
|
-
> **Source**: `apps/client/src/components/Question.tsx`
|
|
4
|
-
> **Role**: Wrapper card component that routes to the correct scale component based on question type.
|
|
5
|
-
|
|
6
|
-
## Props Interface
|
|
7
|
-
|
|
8
|
-
```typescript
|
|
9
|
-
type QuestionProps = {
|
|
10
|
-
question: SurveyQuestion;
|
|
11
|
-
selectedValue?: AnswerValue;
|
|
12
|
-
validationError?: string;
|
|
13
|
-
onSelect: (value: AnswerValue) => void;
|
|
14
|
-
};
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Structure & Styling Rules (CRITICAL)
|
|
18
|
-
|
|
19
|
-
Every question is wrapped in a standard HTML section. It **MUST** have a border around the entire question block to separate them visually, and it **MUST** handle rich text (HTML) provided by the SDK safely.
|
|
20
|
-
|
|
21
|
-
```tsx
|
|
22
|
-
<section
|
|
23
|
-
id={question.id}
|
|
24
|
-
className="space-y-6 rounded-xl border border-gray-200 bg-white p-6 md:p-8 shadow-sm transition-all hover:shadow-md"
|
|
25
|
-
>
|
|
26
|
-
{/* 1. Question Text (Rich Text with required asterisk) */}
|
|
27
|
-
<h2 className="text-lg md:text-xl font-semibold leading-relaxed text-gray-900 flex items-start gap-1">
|
|
28
|
-
{/* dangerouslySetInnerHTML handles strong, em, and link tags from the SDK */}
|
|
29
|
-
<span dangerouslySetInnerHTML={{ __html: question.text }} className="prose prose-sm max-w-none" />
|
|
30
|
-
{question.required && <span className="text-[#e20074] shrink-0">*</span>}
|
|
31
|
-
</h2>
|
|
32
|
-
|
|
33
|
-
{/* 2. Question Description (Rich Text) */}
|
|
34
|
-
{question.description && (
|
|
35
|
-
<div
|
|
36
|
-
className="text-sm text-gray-600 mt-2 leading-relaxed prose prose-sm max-w-none"
|
|
37
|
-
dangerouslySetInnerHTML={{ __html: question.description }}
|
|
38
|
-
/>
|
|
39
|
-
)}
|
|
40
|
-
|
|
41
|
-
{/* 3. The Scale Component (Dispatcher switch statement) */}
|
|
42
|
-
<div className="pt-4">
|
|
43
|
-
{question.type === 'rating' && <RatingScale ... />}
|
|
44
|
-
{/* ... other types ... */}
|
|
45
|
-
</div>
|
|
46
|
-
|
|
47
|
-
{/* 4. Validation Error Banner */}
|
|
48
|
-
{validationError && (
|
|
49
|
-
<div className="mt-6 rounded-lg border-l-4 border-l-[#e20074] bg-red-50 p-4">
|
|
50
|
-
<p className="text-sm font-bold text-gray-900 leading-tight flex items-center gap-2">
|
|
51
|
-
<span className="text-[#e20074]">⚠</span> {validationError}
|
|
52
|
-
</p>
|
|
53
|
-
</div>
|
|
54
|
-
)}
|
|
55
|
-
</section>
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
**⚠️ CRITICAL RULES**:
|
|
59
|
-
1. **DOM ID**: The wrapper element **MUST** have `id={question.id}` for the scroll-to-error validation to work!
|
|
60
|
-
2. **Borders**: The wrapper **MUST** have `border border-gray-200 rounded-xl`.
|
|
61
|
-
3. **Rich Text**: `question.text` and `question.description` MUST be rendered using `dangerouslySetInnerHTML` because the SDK sends formatted HTML. Do not render them as raw strings.
|
|
62
|
-
4. **Spacing**: Use `space-y-6` and `p-6 md:p-8` for generous internal padding.
|
|
63
|
-
|
|
64
|
-
## Inline vs Dedicated Components
|
|
65
|
-
|
|
66
|
-
While complex scales (like Matrix, Slider, FileUpload) get their own dedicated files (e.g. `CsatMatrixScale.tsx`), some simpler types are handled directly inline within `Question.tsx` to reduce boilerplate:
|
|
67
|
-
|
|
68
|
-
1. **`radio` (MCQ)**:
|
|
69
|
-
- Each option is a card: `border rounded-lg p-4 flex items-center gap-3 cursor-pointer transition-colors`.
|
|
70
|
-
- Hover state: `hover:border-[#e20074] hover:bg-pink-50`.
|
|
71
|
-
- Selected state: `border-[#e20074] bg-pink-50`.
|
|
72
|
-
- Custom radio dot: `<div className={`h-5 w-5 rounded-full border-2 ${isSelected ? 'border-[#e20074]' : 'border-gray-300'} flex items-center justify-center`}><div className={`h-2.5 w-2.5 rounded-full bg-[#e20074] ${isSelected ? 'block' : 'hidden'}`} /></div>`
|
|
73
|
-
2. **`text`**: Inline `<textarea>` or `<input type="text">` with `border-gray-300 focus:border-[#e20074] focus:ring-[#e20074] rounded-lg w-full`.
|
|
74
|
-
3. **`text_and_media`**: Inline `<video>` or `<img>` tag with `rounded-lg`.
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# File Upload Architectural Blueprint
|
|
2
|
-
|
|
3
|
-
> **Target Component**: `FileUploadScale`
|
|
4
|
-
> **Handles**: `type: 'file_upload'`
|
|
5
|
-
|
|
6
|
-
## Core Responsibility
|
|
7
|
-
Provide a robust drag-and-drop zone and enforce complex file size and type limits before updating state.
|
|
8
|
-
|
|
9
|
-
## State Management
|
|
10
|
-
- `selectedValue`: Expects `UploadedFile[]` (array of objects with `name`, `size`, `type`).
|
|
11
|
-
- **Mutation**: Since we aren't uploading to a real server in the UI stub, you must read the `File` from the hidden `<input>`, create a mock `UploadedFile` object with a fake `mediaUrl` and `id`, and dispatch it via `onSelect`.
|
|
12
|
-
|
|
13
|
-
## Configuration Matrix (CRITICAL FOR PLANNING)
|
|
14
|
-
|
|
15
|
-
Before calling `onSelect`, your component MUST validate against these properties:
|
|
16
|
-
|
|
17
|
-
### 1. `supportedFileFormats`
|
|
18
|
-
- Build the `accept` attribute string for the hidden input: `question.supportedFileFormats?.map(f => \`.\${f.toLowerCase()}\`).join(',')`.
|
|
19
|
-
|
|
20
|
-
### 2. `maxFileCount`
|
|
21
|
-
- If `selectedValue.length >= maxFileCount`, prevent further additions and show an error state.
|
|
22
|
-
|
|
23
|
-
### 3. `fileSizeLimit` & `fileSizeLimitType`
|
|
24
|
-
- If `fileSizeLimitType === 'PER_FILE'`, validate that the incoming file's `size` (in MB) is `<= fileSizeLimit`.
|
|
25
|
-
- If `fileSizeLimitType === 'IN_TOTAL'`, calculate the sum of all existing `selectedValue` sizes plus the incoming file size, and validate against `fileSizeLimit`.
|
|
26
|
-
|
|
27
|
-
## UI/UX Specifications
|
|
28
|
-
|
|
29
|
-
1. **Dropzone**:
|
|
30
|
-
- `border-2 border-dashed border-gray-300 rounded-xl bg-gray-50 p-8 text-center cursor-pointer transition-colors hover:border-[#e20074] hover:bg-pink-50`.
|
|
31
|
-
- Render a Cloud SVG icon.
|
|
32
|
-
- Display the instruction text (`question.uploadMessage`) and the dynamic limits text cleanly.
|
|
33
|
-
|
|
34
|
-
2. **File List**:
|
|
35
|
-
- Render existing files as distinct cards underneath the dropzone.
|
|
36
|
-
- `flex items-center justify-between p-3 mt-3 border border-gray-200 rounded-lg bg-white shadow-sm`.
|
|
37
|
-
- Include a distinct red Trash/Remove button.
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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
|