@explorer02/cfm-survey-sdk 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/const.d.ts +10 -0
- package/dist/cli/const.d.ts.map +1 -0
- package/dist/cli/const.js +13 -0
- package/dist/cli/const.js.map +1 -0
- package/dist/cli/constants.d.ts +9 -0
- package/dist/cli/constants.js +12 -0
- package/dist/cli/deploy.d.ts.map +1 -1
- package/dist/cli/deploy.js +10 -189
- package/dist/cli/deploy.js.map +1 -1
- package/dist/cli/index.js +8 -10
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/utils/exec.d.ts +4 -0
- package/dist/cli/utils/exec.d.ts.map +1 -0
- package/dist/cli/utils/exec.js +41 -0
- package/dist/cli/utils/exec.js.map +1 -0
- package/dist/cli/utils/nodeCheck.d.ts +2 -0
- package/dist/cli/utils/nodeCheck.d.ts.map +1 -0
- package/dist/cli/utils/nodeCheck.js +64 -0
- package/dist/cli/utils/nodeCheck.js.map +1 -0
- package/dist/cli/utils/prompts.d.ts +2 -0
- package/dist/cli/utils/prompts.d.ts.map +1 -0
- package/dist/cli/utils/prompts.js +29 -0
- package/dist/cli/utils/prompts.js.map +1 -0
- package/dist/cli/utils/vercelCliCheck.d.ts +6 -0
- package/dist/cli/utils/vercelCliCheck.d.ts.map +1 -0
- package/dist/cli/utils/vercelCliCheck.js +38 -0
- package/dist/cli/utils/vercelCliCheck.js.map +1 -0
- package/dist/cli/utils/vercelDeploy.d.ts +2 -0
- package/dist/cli/utils/vercelDeploy.d.ts.map +1 -0
- package/dist/cli/utils/vercelDeploy.js +21 -0
- package/dist/cli/utils/vercelDeploy.js.map +1 -0
- package/dist/cli/utils/vercelLoginCheck.d.ts +2 -0
- package/dist/cli/utils/vercelLoginCheck.d.ts.map +1 -0
- package/dist/cli/utils/vercelLoginCheck.js +42 -0
- package/dist/cli/utils/vercelLoginCheck.js.map +1 -0
- package/package.json +8 -2
- package/postinstall.js +40 -0
- package/templates/AGENT.md +1219 -0
- package/src/analytics/analyticsTracker.ts +0 -48
- package/src/analytics/types.ts +0 -80
- package/src/cli/deploy.ts +0 -205
- package/src/cli/index.ts +0 -33
- package/src/fetchSurvey/internalTypes.ts +0 -80
- package/src/fetchSurvey/logger/fetchLogger.ts +0 -34
- package/src/fetchSurvey/logger/mapperLogger.ts +0 -13
- package/src/fetchSurvey/telemetry/fetchTelemetry.ts +0 -26
- package/src/fetchSurvey/types.ts +0 -82
- package/src/fetchSurvey/useFetchSurvey.ts +0 -126
- package/src/fetchSurvey/utils/constants.ts +0 -11
- package/src/fetchSurvey/utils/extractSurveyLanguages.ts +0 -63
- package/src/fetchSurvey/utils/index.ts +0 -7
- package/src/fetchSurvey/utils/mapSurveyPages.ts +0 -35
- package/src/fetchSurvey/utils/mappers/index.ts +0 -2
- package/src/fetchSurvey/utils/mappers/questionMapper.ts +0 -213
- package/src/fetchSurvey/utils/mappers/surveyMapper.ts +0 -69
- package/src/fetchSurvey/utils/url.ts +0 -21
- package/src/index.ts +0 -6
- package/src/logger/logger.ts +0 -71
- package/src/queryClient.ts +0 -67
- package/src/submitSurvey/logger/resolutionLogger.ts +0 -13
- package/src/submitSurvey/logger/submitLogger.ts +0 -51
- package/src/submitSurvey/telemetry/submitTelemetry.ts +0 -33
- package/src/submitSurvey/types.ts +0 -51
- package/src/submitSurvey/useSubmitResponse.ts +0 -111
- package/src/submitSurvey/utils/constants.ts +0 -4
- package/src/submitSurvey/utils/formatters.ts +0 -33
- package/src/submitSurvey/utils/index.ts +0 -4
- package/src/submitSurvey/utils/url.ts +0 -17
- package/src/submitSurvey/utils/validation.ts +0 -48
- package/src/surveyPagination/actions/index.ts +0 -4
- package/src/surveyPagination/actions/useOnBack.ts +0 -37
- package/src/surveyPagination/actions/useOnChange.ts +0 -16
- package/src/surveyPagination/actions/useOnNext.ts +0 -99
- package/src/surveyPagination/actions/useOnSubmit.ts +0 -137
- package/src/surveyPagination/dispatchers/index.ts +0 -3
- package/src/surveyPagination/dispatchers/useCheckBacktrackChanges.ts +0 -35
- package/src/surveyPagination/dispatchers/useTrackOptionalSkips.ts +0 -21
- package/src/surveyPagination/dispatchers/useTrackPageTime.ts +0 -13
- package/src/surveyPagination/effects/index.ts +0 -2
- package/src/surveyPagination/effects/useResetPageStartTime.ts +0 -10
- package/src/surveyPagination/effects/useTrackMaxVisitedPage.ts +0 -12
- package/src/surveyPagination/logger/navigationLogger.ts +0 -25
- package/src/surveyPagination/logger/validationLogger.ts +0 -17
- package/src/surveyPagination/telemetry/pageTelemetry.ts +0 -22
- package/src/surveyPagination/telemetry/sessionTelemetry.ts +0 -55
- package/src/surveyPagination/types.ts +0 -42
- package/src/surveyPagination/useSurveyPagination.ts +0 -109
- package/src/surveyPagination/utils/index.ts +0 -2
- package/src/surveyPagination/utils/scroll.ts +0 -62
- package/src/surveyPagination/utils/validation.ts +0 -62
- package/src/surveyProgress/useSurveyProgress.ts +0 -42
- package/src/surveyProgress/utils/index.ts +0 -1
- package/src/surveyProgress/utils/progress.ts +0 -61
- package/src/surveySDK/constants.ts +0 -9
- package/src/surveySDK/types.ts +0 -22
- package/src/surveySDK/useSurveySDK.ts +0 -109
- package/tsconfig.json +0 -13
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
import { useQuery } from '@tanstack/react-query';
|
|
3
|
-
import { sdkQueryClient } from '../queryClient';
|
|
4
|
-
import type { Survey, SurveySession } from './types';
|
|
5
|
-
import type { ApiResponse } from './internalTypes';
|
|
6
|
-
import { buildSurveyUrl, mapSurvey, extractSession } from './utils';
|
|
7
|
-
import {
|
|
8
|
-
logFetchStart,
|
|
9
|
-
logFetchPerfFailure,
|
|
10
|
-
logFetchPerfSuccess,
|
|
11
|
-
logFetchSuccess,
|
|
12
|
-
logFetchError,
|
|
13
|
-
} from './logger/fetchLogger';
|
|
14
|
-
import { logMapWarning, logMapSuccess, logMapError } from './logger/mapperLogger';
|
|
15
|
-
import { trackFetchLatency, trackFetchError } from './telemetry/fetchTelemetry';
|
|
16
|
-
|
|
17
|
-
// Re-export all type definitions (domain entities and API response models)
|
|
18
|
-
export * from './types';
|
|
19
|
-
|
|
20
|
-
// Re-export all utility functions and configuration constants
|
|
21
|
-
export * from './utils';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Performs the network request and returns the raw API response.
|
|
25
|
-
*/
|
|
26
|
-
async function fetchRawSurveyData(url: string): Promise<ApiResponse> {
|
|
27
|
-
const startTime = performance.now();
|
|
28
|
-
logFetchStart(url);
|
|
29
|
-
try {
|
|
30
|
-
const response = await fetch(url, {
|
|
31
|
-
method: 'GET',
|
|
32
|
-
headers: { Accept: 'application/json' },
|
|
33
|
-
cache: 'force-cache',
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const durationMs = performance.now() - startTime;
|
|
37
|
-
|
|
38
|
-
if (!response.ok) {
|
|
39
|
-
logFetchPerfFailure(durationMs, response.status, url);
|
|
40
|
-
trackFetchError(response.status, url, `Survey fetch failed (${response.status})`);
|
|
41
|
-
throw new Error(`Survey fetch failed (${response.status})`);
|
|
42
|
-
}
|
|
43
|
-
const apiResponse = (await response.json()) as ApiResponse;
|
|
44
|
-
const responseString = JSON.stringify(apiResponse);
|
|
45
|
-
const sizeInBytes = new Blob([responseString]).size;
|
|
46
|
-
const payloadSize = `${(sizeInBytes / 1024).toFixed(2)} KB`;
|
|
47
|
-
logFetchPerfSuccess(durationMs, response.status, url, payloadSize);
|
|
48
|
-
|
|
49
|
-
trackFetchLatency(durationMs, response.status, url, payloadSize);
|
|
50
|
-
|
|
51
|
-
logFetchSuccess(apiResponse);
|
|
52
|
-
return apiResponse;
|
|
53
|
-
} catch (err: any) {
|
|
54
|
-
const durationMs = performance.now() - startTime;
|
|
55
|
-
logFetchPerfFailure(durationMs, 'FAILED', url);
|
|
56
|
-
trackFetchError('FAILED', url, err?.message || String(err));
|
|
57
|
-
logFetchError(err);
|
|
58
|
-
throw err;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* A custom React hook that manages fetching survey configurations, mapping the API response,
|
|
64
|
-
* and maintaining state for survey data, session tokens, loading states, and error handling.
|
|
65
|
-
* Uses TanStack Query with a singleton QueryClient to run independently of client providers.
|
|
66
|
-
*
|
|
67
|
-
* @param options Optional settings including active language code and placeholders mapping.
|
|
68
|
-
* @returns Object holding survey, session, loading status, and error references.
|
|
69
|
-
*/
|
|
70
|
-
export function useFetchSurvey(options?: { language?: string; placeholders?: Record<string, string> }) {
|
|
71
|
-
const url = buildSurveyUrl();
|
|
72
|
-
const targetLanguage = options?.language;
|
|
73
|
-
const placeholders = options?.placeholders;
|
|
74
|
-
|
|
75
|
-
// The query is keyed purely by url, meaning we fetch the survey layout only once.
|
|
76
|
-
// refetch on window focus, check all refetch policies
|
|
77
|
-
const {
|
|
78
|
-
data: apiResponse,
|
|
79
|
-
error,
|
|
80
|
-
isLoading,
|
|
81
|
-
isSuccess,
|
|
82
|
-
} = useQuery(
|
|
83
|
-
{
|
|
84
|
-
queryKey: ['survey', url],
|
|
85
|
-
queryFn: () => fetchRawSurveyData(url),
|
|
86
|
-
enabled: !!url,
|
|
87
|
-
},
|
|
88
|
-
sdkQueryClient
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
// Map the raw data to the active language context dynamically on the client side using useMemo
|
|
92
|
-
const mapped = useMemo(() => {
|
|
93
|
-
// Only map the survey if it has successfully fetched
|
|
94
|
-
if (!isSuccess) {
|
|
95
|
-
return { survey: null, session: null };
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (!apiResponse) {
|
|
99
|
-
logMapWarning();
|
|
100
|
-
return { survey: null, session: null };
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
const mappedSurvey = mapSurvey(apiResponse, targetLanguage, placeholders);
|
|
105
|
-
const surveySession = extractSession(apiResponse);
|
|
106
|
-
const updatedSession = surveySession ? { ...surveySession, language: mappedSurvey.language } : null;
|
|
107
|
-
|
|
108
|
-
logMapSuccess(mappedSurvey);
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
survey: mappedSurvey,
|
|
112
|
-
session: updatedSession,
|
|
113
|
-
};
|
|
114
|
-
} catch (err) {
|
|
115
|
-
logMapError(err);
|
|
116
|
-
return { survey: null, session: null };
|
|
117
|
-
}
|
|
118
|
-
}, [apiResponse, isSuccess, targetLanguage]);
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
survey: mapped.survey,
|
|
122
|
-
session: mapped.session,
|
|
123
|
-
fetching: isLoading,
|
|
124
|
-
fetchError: error,
|
|
125
|
-
};
|
|
126
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The API base URL for fetching survey configuration data.
|
|
3
|
-
*/
|
|
4
|
-
export const SURVEY_BASE_URL = 'https://custom-p0.feedbook.me/api/feedback/survey/cfm';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Fallback Instance ID/JWT Token representing standard default configuration.
|
|
8
|
-
* Used when no instanceId is provided or is invalid.
|
|
9
|
-
*/
|
|
10
|
-
export const DEFAULT_INSTANCE_ID =
|
|
11
|
-
'eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJBY2Nlc3MgVG9rZW4gR2VuZXJhdGVkIEJ5IFNwcmlua2xyIiwic3VydmV5SWQiOiI2YTJlNWM2NDFiOGRiMmY5MDQ2Nzg4ODUiLCJpc3MiOiJTUFJJTktMUiIsInR5cCI6IkpXVCIsInN1cnZleU1vZGUiOiJTVEFOREFSRCIsInN1cnZleUF1dGhlbnRpY2F0aW9uU3RhdGUiOiJOT1RfUkVRVUlSRUQiLCJkaXN0cmlidXRpb25FbnRpdHlJZCI6IjZhMmU1ZDEzNDRjYTkzZjc3YTVlMzcyNyIsImF1ZCI6IlNQUklOS0xSIiwibmJmIjoxNzgxNDIyMTc5LCJzY29wZSI6WyJSRUFEIiwiV1JJVEUiXSwic3RhdGljU3VydmV5IjoidHJ1ZSIsInN1cnZleVJlc3BvbmRlclNuVHlwZSI6IkVYVEVSTkFMX0FQUExJQ0FUSU9OIiwic3VydmV5TGFuZ3VhZ2UiOiJlbiIsInBhcnRuZXJJZCI6OTAwNCwidG9rZW5UeXBlIjoiQUNDRVNTIiwiYXV0aFR5cGUiOiJTVVJWRVlfUkVTUE9OU0UiLCJpYXQiOjE3ODE0MjMzNzksImp0aSI6InNwcmlua2xyIn0.B4ffi1szwM_xQKXTlr0kQc9mVOS4qVbB5e6ir4NFuCoOmNmsl3PB1QeFJ5jPaQ42s0KTpbufPam9ja0Z84CJ620l2WtuS1RModEv7ZtuMNLWOixzRxZMduC5-V7WV85H6gr1e-HzX7wgqrxTk2Z9iTr-8AVuczlwScarCfqLhA-JE_EXkFScHoehmH7QB5q5-BfcxU32iQNYOk5NyeEHGAAWkkyiGPdrbE27njPnhTunB3kKgCBvHHLq0KmgoN9x_KnrB53O_0Xai419TT5vkBWlu5a_uotZckX014eQpxYH02w_LeOF8iWEKYe6R9ge-6DSbelaJSt6U6O8Fq-aXw';
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import type { SurveyLanguage } from '../types';
|
|
2
|
-
import type { ApiResponse } from '../internalTypes';
|
|
3
|
-
|
|
4
|
-
const LANGUAGE_DISPLAY_NAMES: Record<string, string> = {
|
|
5
|
-
en: 'English',
|
|
6
|
-
hi: 'Hindi',
|
|
7
|
-
de: 'Deutsch',
|
|
8
|
-
es: 'Español',
|
|
9
|
-
fr: 'Français',
|
|
10
|
-
bn: 'Bengali',
|
|
11
|
-
gu: 'Gujarati',
|
|
12
|
-
it: 'Italiano',
|
|
13
|
-
ja: '日本語',
|
|
14
|
-
ko: '한국어',
|
|
15
|
-
mr: 'Marathi',
|
|
16
|
-
pa: 'Punjabi',
|
|
17
|
-
ta: 'Tamil',
|
|
18
|
-
te: 'Telugu',
|
|
19
|
-
ur: 'Urdu',
|
|
20
|
-
zh: '中文',
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Resolves the full human-readable display name for a given language code.
|
|
25
|
-
*
|
|
26
|
-
* @param code The ISO language code (e.g. 'de', 'en').
|
|
27
|
-
* @returns The resolved display name string.
|
|
28
|
-
*/
|
|
29
|
-
export function getLanguageName(code: string): string {
|
|
30
|
-
const norm = code.toLowerCase().trim();
|
|
31
|
-
return LANGUAGE_DISPLAY_NAMES[norm] || code.toUpperCase();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Traverses all questions and translations to gather all unique languages supported by the survey.
|
|
36
|
-
*
|
|
37
|
-
* @param api The raw API response envelope containing the DTO pages.
|
|
38
|
-
* @returns List of supported language objects with code and resolved names.
|
|
39
|
-
*/
|
|
40
|
-
export function extractSurveyLanguages(api: ApiResponse): SurveyLanguage[] {
|
|
41
|
-
const dto = api.cfmSurveyDTO;
|
|
42
|
-
const languagesSet = new Set<string>();
|
|
43
|
-
const defaultLanguage = dto?.baseLanguage ?? 'en';
|
|
44
|
-
languagesSet.add(defaultLanguage);
|
|
45
|
-
|
|
46
|
-
if (dto && Array.isArray(dto.surveyPages)) {
|
|
47
|
-
dto.surveyPages.forEach(page => {
|
|
48
|
-
(page.questionHolders ?? []).forEach(holder => {
|
|
49
|
-
const q = holder.question;
|
|
50
|
-
if (q && q.translations) {
|
|
51
|
-
Object.keys(q.translations).forEach(lang => {
|
|
52
|
-
languagesSet.add(lang);
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return Array.from(languagesSet).map(lang => ({
|
|
60
|
-
code: lang,
|
|
61
|
-
name: getLanguageName(lang),
|
|
62
|
-
}));
|
|
63
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { SurveyPageData } from '../types';
|
|
2
|
-
import type { ApiQuestion, ApiResponse } from '../internalTypes';
|
|
3
|
-
import { mapQuestion } from './mappers/questionMapper';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Maps the raw DTO survey pages and their questions into UI-friendly structure.
|
|
7
|
-
*
|
|
8
|
-
* @param api The raw API response envelope containing survey DTO pages.
|
|
9
|
-
* @param surveyLanguage The resolved target language.
|
|
10
|
-
* @param placeholders Optional dictionary mapping placeholder keys to replacement values.
|
|
11
|
-
* @returns Array of mapped SurveyPageData objects.
|
|
12
|
-
*/
|
|
13
|
-
export function mapSurveyPages(
|
|
14
|
-
api: ApiResponse,
|
|
15
|
-
surveyLanguage: string,
|
|
16
|
-
placeholders?: Record<string, string>
|
|
17
|
-
): SurveyPageData[] {
|
|
18
|
-
const dto = api.cfmSurveyDTO;
|
|
19
|
-
if (!dto || !Array.isArray(dto.surveyPages)) {
|
|
20
|
-
return [];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return dto.surveyPages.map((page, index) => {
|
|
24
|
-
const questions = (page.questionHolders ?? [])
|
|
25
|
-
.map(holder => holder.question)
|
|
26
|
-
.filter((q): q is ApiQuestion => Boolean(q))
|
|
27
|
-
.map(q => mapQuestion(q, surveyLanguage, placeholders));
|
|
28
|
-
|
|
29
|
-
return {
|
|
30
|
-
id: `page_${index}`,
|
|
31
|
-
title: `Page ${index + 1}`,
|
|
32
|
-
questions,
|
|
33
|
-
};
|
|
34
|
-
});
|
|
35
|
-
}
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import type { SurveyOption, SurveyQuestion } from '../../types';
|
|
2
|
-
import type { ApiAnswerDetail, ApiQuestion } from '../../internalTypes';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Normalizes different API string types to standardized UI question types.
|
|
6
|
-
*
|
|
7
|
-
* @param answerType The raw type string from the API.
|
|
8
|
-
* @returns Standardized widget representation ("rating" or "radio").
|
|
9
|
-
*/
|
|
10
|
-
export function normalizeType(answerType?: string): 'rating' | 'radio' | 'text' {
|
|
11
|
-
const type = (answerType ?? '').toUpperCase();
|
|
12
|
-
if (type === 'TEXTFIELD') {
|
|
13
|
-
return 'text';
|
|
14
|
-
}
|
|
15
|
-
// Group ratings, numeric scale questions, and matrix components into a rating widget.
|
|
16
|
-
if (type === 'RATING' || type === 'SCALE' || type === 'RATING_MATRIX') {
|
|
17
|
-
return 'rating';
|
|
18
|
-
}
|
|
19
|
-
// Fallback to standard multiple-choice radio option layout.
|
|
20
|
-
return 'radio';
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const SCALE_COLORS = [
|
|
24
|
-
'#e2001a', // 0
|
|
25
|
-
'#e4251b', // 1
|
|
26
|
-
'#ec610a', // 2
|
|
27
|
-
'#f18b00', // 3
|
|
28
|
-
'#f7b200', // 4
|
|
29
|
-
'#fcd900', // 5
|
|
30
|
-
'#d2dc00', // 6
|
|
31
|
-
'#9fca00', // 7
|
|
32
|
-
'#6bb300', // 8
|
|
33
|
-
'#339a00', // 9
|
|
34
|
-
'#008000', // 10
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Retrieves color representation based on rating scores.
|
|
39
|
-
* Matches client's 11-point NPS scale layout with a dynamic HSL fallback for other scale lengths.
|
|
40
|
-
*
|
|
41
|
-
* @param value Numerical score of the rating option.
|
|
42
|
-
* @returns Hex or HSL color string.
|
|
43
|
-
*/
|
|
44
|
-
export function getColor(value: number): string {
|
|
45
|
-
// If the value corresponds to our predefined 11-point scale, return the exact color.
|
|
46
|
-
return SCALE_COLORS[value] ?? '#e20074';
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Extracts helper boundaries / label text (e.g., "Not Likely" at min, "Neutral" at mid, and "Extremely Likely" at max)
|
|
51
|
-
* from the list of raw answer options returned by the API.
|
|
52
|
-
*
|
|
53
|
-
* @param answerDetails The list of answer details containing hint definitions.
|
|
54
|
-
* @param language Optional language code to fetch the translated label text.
|
|
55
|
-
* @returns Object holding resolved labels.
|
|
56
|
-
*/
|
|
57
|
-
export function extractHintLabels(
|
|
58
|
-
answerDetails: ApiAnswerDetail[] = [],
|
|
59
|
-
language?: string
|
|
60
|
-
): { minLabel?: string; midLabel?: string; maxLabel?: string } {
|
|
61
|
-
// Filter answer details that are flagged as hint text and are not hidden.
|
|
62
|
-
const hints = answerDetails
|
|
63
|
-
.filter(a => a.additional?.isHintText && !a.hidden)
|
|
64
|
-
.map(a => (language && a.translations?.[language]?.answerText) || a.answerText || '')
|
|
65
|
-
.filter(Boolean);
|
|
66
|
-
|
|
67
|
-
if (hints.length >= 3) {
|
|
68
|
-
return {
|
|
69
|
-
minLabel: hints[0],
|
|
70
|
-
midLabel: hints[1],
|
|
71
|
-
maxLabel: hints[2],
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
// The first hint represents the minimum bounds label.
|
|
77
|
-
minLabel: hints[0],
|
|
78
|
-
// The second hint represents the maximum bounds label.
|
|
79
|
-
maxLabel: hints[1],
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Builds option models that are safe for components to select and render.
|
|
85
|
-
* Generates automated numerical sequences for ratings if the server doesn't explicitly define options.
|
|
86
|
-
*
|
|
87
|
-
* @param question Raw API Question data structure.
|
|
88
|
-
* @param type The normalized UI question type.
|
|
89
|
-
* @param language Optional language code to fetch translated labels.
|
|
90
|
-
* @returns Mapped survey options list.
|
|
91
|
-
*/
|
|
92
|
-
export function buildOptions(
|
|
93
|
-
question: ApiQuestion,
|
|
94
|
-
type: 'rating' | 'radio' | 'text',
|
|
95
|
-
language?: string
|
|
96
|
-
): SurveyOption[] {
|
|
97
|
-
if (type === 'text') {
|
|
98
|
-
return [];
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const answerDetails = question.answerDetails ?? [];
|
|
102
|
-
// Filter out any hidden entries and metadata labels (hints) to get selectable responses.
|
|
103
|
-
const selectable = answerDetails.filter(a => !a.hidden && !a.additional?.isHintText);
|
|
104
|
-
|
|
105
|
-
// If the API defines explicit selectable options, parse them.
|
|
106
|
-
if (selectable.length > 0) {
|
|
107
|
-
const options = selectable.map(a => {
|
|
108
|
-
const rawText = (language && a.translations?.[language]?.answerText) || a.answerText || '';
|
|
109
|
-
const rawValue = a.answerText ?? '';
|
|
110
|
-
const numeric = Number(rawValue);
|
|
111
|
-
// Determine if value should be treated as a pure number or string.
|
|
112
|
-
const value = Number.isFinite(numeric) && rawValue.trim() !== '' ? numeric : rawValue;
|
|
113
|
-
|
|
114
|
-
const option: SurveyOption = {
|
|
115
|
-
label: rawText,
|
|
116
|
-
value,
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// Assign rating color styles if it is a rating scale question with numeric values.
|
|
120
|
-
if (type === 'rating' && typeof value === 'number') {
|
|
121
|
-
option.color = getColor(value);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return option;
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
return options;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// If no options are provided but the question is a rating, default to a standard 0 to 10 scale.
|
|
131
|
-
if (type === 'rating') {
|
|
132
|
-
const options = Array.from({ length: 11 }, (_, i) => ({
|
|
133
|
-
label: String(i),
|
|
134
|
-
value: i,
|
|
135
|
-
color: getColor(i),
|
|
136
|
-
}));
|
|
137
|
-
return options;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return [];
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export function mapQuestion(
|
|
144
|
-
raw: ApiQuestion,
|
|
145
|
-
language?: string,
|
|
146
|
-
placeholders?: Record<string, string>
|
|
147
|
-
): SurveyQuestion {
|
|
148
|
-
const type = normalizeType(raw.answerType);
|
|
149
|
-
const { minLabel, midLabel, maxLabel } = extractHintLabels(raw.answerDetails, language);
|
|
150
|
-
const options = buildOptions(raw, type, language);
|
|
151
|
-
const questionId = raw.id ?? '';
|
|
152
|
-
|
|
153
|
-
const configs = raw.questionConfigs ?? [];
|
|
154
|
-
const required = configs.find(c => c.key === 'REQUIRED')?.value?.[0] === 'true';
|
|
155
|
-
|
|
156
|
-
const reqErrConfig = configs.find(c => c.key === 'REQUIRED_ERROR_MESSAGE');
|
|
157
|
-
let requiredErrorMessage = reqErrConfig?.value?.[0];
|
|
158
|
-
if (language && reqErrConfig?.translations?.[language]?.value?.[0]) {
|
|
159
|
-
requiredErrorMessage = reqErrConfig.translations[language].value[0];
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const contentTypeConfig = configs.find(c => c.key === 'CONTENT_TYPE');
|
|
163
|
-
const maxCharConfig = contentTypeConfig?.childConfigs?.find(cc => cc.key === 'MAX_CHARACTER_COUNT');
|
|
164
|
-
const maxCharacterCount = maxCharConfig?.value?.[0] ? Number(maxCharConfig.value[0]) : undefined;
|
|
165
|
-
|
|
166
|
-
let midLabelIndex: number | undefined = undefined;
|
|
167
|
-
if (type === 'rating' && midLabel) {
|
|
168
|
-
if (options.length === 11) {
|
|
169
|
-
midLabelIndex = 7.5;
|
|
170
|
-
} else {
|
|
171
|
-
midLabelIndex = (options.length - 1) / 2;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
let text =
|
|
176
|
-
(language && raw.translations?.[language]?.questionRichText) ||
|
|
177
|
-
(language && raw.translations?.[language]?.questionText) ||
|
|
178
|
-
raw.questionRichText ||
|
|
179
|
-
raw.questionText ||
|
|
180
|
-
'';
|
|
181
|
-
|
|
182
|
-
if (placeholders) {
|
|
183
|
-
text = text.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
184
|
-
return placeholders[key] !== undefined ? placeholders[key] : match;
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Extract text input placeholder from answerDetails
|
|
189
|
-
let placeholder: string | undefined = undefined;
|
|
190
|
-
if (type === 'text') {
|
|
191
|
-
const textDetail = raw.answerDetails?.[0];
|
|
192
|
-
if (textDetail) {
|
|
193
|
-
placeholder = (language && textDetail.translations?.[language]?.answerText) || textDetail.answerText;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const question: SurveyQuestion = {
|
|
198
|
-
id: questionId,
|
|
199
|
-
text,
|
|
200
|
-
type,
|
|
201
|
-
options,
|
|
202
|
-
required,
|
|
203
|
-
...(requiredErrorMessage ? { requiredErrorMessage } : {}),
|
|
204
|
-
...(minLabel ? { minLabel } : {}),
|
|
205
|
-
...(midLabel ? { midLabel } : {}),
|
|
206
|
-
...(midLabelIndex !== undefined ? { midLabelIndex } : {}),
|
|
207
|
-
...(maxLabel ? { maxLabel } : {}),
|
|
208
|
-
...(maxCharacterCount !== undefined ? { maxCharacterCount } : {}),
|
|
209
|
-
...(placeholder ? { placeholder } : {}),
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
return question;
|
|
213
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import type { Survey, SurveyLanguage, SurveySession, SurveyPageData } from '../../types';
|
|
2
|
-
import type { ApiQuestion, ApiResponse } from '../../internalTypes';
|
|
3
|
-
import { extractSurveyLanguages } from '../extractSurveyLanguages';
|
|
4
|
-
import { mapSurveyPages } from '../mapSurveyPages';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Traverses different possible nesting structures of the Survey API configuration
|
|
8
|
-
* to extract a flat list of questions.
|
|
9
|
-
*
|
|
10
|
-
* @param api The root API response envelope.
|
|
11
|
-
* @returns Array of Raw API Questions.
|
|
12
|
-
*/
|
|
13
|
-
export function extractQuestions(api: ApiResponse): ApiQuestion[] {
|
|
14
|
-
const surveyPages = api.cfmSurveyDTO?.surveyPages ?? [];
|
|
15
|
-
return surveyPages.flatMap(
|
|
16
|
-
page => page.questionHolders?.map(holder => holder.question).filter((q): q is ApiQuestion => Boolean(q)) ?? []
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Extracts and initializes the session tracking metadata if the API returns a valid instance ID.
|
|
22
|
-
*
|
|
23
|
-
* @param api The root API response envelope.
|
|
24
|
-
* @returns SurveySession details or null if invalid.
|
|
25
|
-
*/
|
|
26
|
-
export function extractSession(api: ApiResponse): SurveySession | null {
|
|
27
|
-
if (!api.instanceId?.trim()) return null;
|
|
28
|
-
|
|
29
|
-
return {
|
|
30
|
-
instanceId: api.instanceId.trim(),
|
|
31
|
-
// Resolve survey language, falling back to base language configuration.
|
|
32
|
-
language: api.surveyLanguage ?? api.cfmSurveyDTO?.baseLanguage ?? 'en',
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Resolves the primary survey language based on input selection and API fallback values.
|
|
38
|
-
*
|
|
39
|
-
* @param api The raw API response envelope.
|
|
40
|
-
* @param language Optional target language selection override.
|
|
41
|
-
* @returns The resolved language code.
|
|
42
|
-
*/
|
|
43
|
-
export function resolveSurveyLanguage(api: ApiResponse, language?: string): string {
|
|
44
|
-
return language ?? api.surveyLanguage ?? api.cfmSurveyDTO?.baseLanguage ?? 'en';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Maps the raw API response layout configuration into a clean Survey data structure.
|
|
49
|
-
* Handles localization language setup and placeholder parsing.
|
|
50
|
-
*
|
|
51
|
-
* @param api The raw API response envelope.
|
|
52
|
-
* @param language Optional language locale string override.
|
|
53
|
-
* @param placeholders Optional dictionary mapping placeholder keys to replacement values.
|
|
54
|
-
* @returns The fully mapped Survey object.
|
|
55
|
-
*/
|
|
56
|
-
export function mapSurvey(api: ApiResponse, language?: string, placeholders?: Record<string, string>): Survey {
|
|
57
|
-
const surveyLanguage = resolveSurveyLanguage(api, language);
|
|
58
|
-
const languages = extractSurveyLanguages(api);
|
|
59
|
-
const pages = mapSurveyPages(api, surveyLanguage, placeholders);
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
id: api.cfmSurveyDTO?.id ?? '',
|
|
63
|
-
language: surveyLanguage,
|
|
64
|
-
languages,
|
|
65
|
-
pages,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { SURVEY_BASE_URL, DEFAULT_INSTANCE_ID } from './constants';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Constructs the external URL used to call the remote survey service api.
|
|
5
|
-
*
|
|
6
|
-
* @param instanceId The instance identifier token.
|
|
7
|
-
* @returns Fully constructed target URL.
|
|
8
|
-
*/
|
|
9
|
-
export function buildExternalSurveyUrl(instanceId: string): string {
|
|
10
|
-
return `${SURVEY_BASE_URL}?instanceId=${encodeURIComponent(instanceId)}&draftPreview=false`;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* High-level function that constructs the survey fetch URL.
|
|
15
|
-
*
|
|
16
|
-
* @returns Target URL for fetch requests.
|
|
17
|
-
*/
|
|
18
|
-
export function buildSurveyUrl(): string {
|
|
19
|
-
return buildExternalSurveyUrl(DEFAULT_INSTANCE_ID);
|
|
20
|
-
}
|
|
21
|
-
|
package/src/index.ts
DELETED
package/src/logger/logger.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'success' | 'perf' | 'analytics';
|
|
2
|
-
|
|
3
|
-
let loggingEnabled = false;
|
|
4
|
-
|
|
5
|
-
// CSS styles for console log level badges
|
|
6
|
-
const BADGE_STYLES: Record<LogLevel, string> = {
|
|
7
|
-
debug: 'background: #7f8c8d; color: #fff; padding: 2px 5px; border-radius: 3px; font-weight: bold;',
|
|
8
|
-
info: 'background: #2980b9; color: #fff; padding: 2px 5px; border-radius: 3px; font-weight: bold;',
|
|
9
|
-
warn: 'background: #f1c40f; color: #000; padding: 2px 5px; border-radius: 3px; font-weight: bold;',
|
|
10
|
-
error: 'background: #e74c3c; color: #fff; padding: 2px 5px; border-radius: 3px; font-weight: bold;',
|
|
11
|
-
success: 'background: #2ecc71; color: #fff; padding: 2px 5px; border-radius: 3px; font-weight: bold;',
|
|
12
|
-
perf: 'background: #9b59b6; color: #fff; padding: 2px 5px; border-radius: 3px; font-weight: bold;',
|
|
13
|
-
analytics: 'background: #e20074; color: #fff; padding: 2px 5px; border-radius: 3px; font-weight: bold;',
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Writes formatted badges and log details into the console if logging is enabled.
|
|
18
|
-
* Note: analytics level logs are always printed regardless of debug settings.
|
|
19
|
-
*
|
|
20
|
-
* @param level Logging categorization level (debug, info, warn, error, success, analytics).
|
|
21
|
-
* @param message Description message text.
|
|
22
|
-
* @param meta Optional auxiliary metadata/payload.
|
|
23
|
-
*/
|
|
24
|
-
function writeLog(level: LogLevel, message: string, meta?: any) {
|
|
25
|
-
if (!loggingEnabled && level !== 'analytics') return;
|
|
26
|
-
|
|
27
|
-
const timestamp = new Date().toLocaleTimeString();
|
|
28
|
-
const badge = `%c[SDK:${level.toUpperCase()}]`;
|
|
29
|
-
const style = BADGE_STYLES[level];
|
|
30
|
-
|
|
31
|
-
if (meta !== undefined) {
|
|
32
|
-
console.log(`[${timestamp}] ${badge}`, style, message, meta);
|
|
33
|
-
} else {
|
|
34
|
-
console.log(`[${timestamp}] ${badge}`, style, message);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* A central namespace containing logging helpers for debugging, warnings, success,
|
|
40
|
-
* and API monitoring. Output logs are formatted with custom browser styles.
|
|
41
|
-
*/
|
|
42
|
-
export const sdkLogger = {
|
|
43
|
-
setEnabled: (val: boolean) => {
|
|
44
|
-
loggingEnabled = val;
|
|
45
|
-
},
|
|
46
|
-
isEnabled: () => {
|
|
47
|
-
return loggingEnabled;
|
|
48
|
-
},
|
|
49
|
-
debug: (msg: string, meta?: any) => writeLog('debug', msg, meta),
|
|
50
|
-
info: (msg: string, meta?: any) => writeLog('info', msg, meta),
|
|
51
|
-
warn: (msg: string, meta?: any) => writeLog('warn', msg, meta),
|
|
52
|
-
error: (msg: string, meta?: any) => writeLog('error', msg, meta),
|
|
53
|
-
success: (msg: string, meta?: any) => writeLog('success', msg, meta),
|
|
54
|
-
analytics: (msg: string, meta?: any) => writeLog('analytics', msg, meta),
|
|
55
|
-
perf: (metric: {
|
|
56
|
-
apiName: string;
|
|
57
|
-
durationMs: number;
|
|
58
|
-
status: number | string;
|
|
59
|
-
url: string;
|
|
60
|
-
requestSize?: string;
|
|
61
|
-
responseSize?: string;
|
|
62
|
-
payloadSize?: string;
|
|
63
|
-
success: boolean;
|
|
64
|
-
}) => {
|
|
65
|
-
writeLog(
|
|
66
|
-
'perf',
|
|
67
|
-
`${metric.apiName} completed in ${metric.durationMs.toFixed(2)}ms | Status: ${metric.status}`,
|
|
68
|
-
metric
|
|
69
|
-
);
|
|
70
|
-
},
|
|
71
|
-
};
|