@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,137 +0,0 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
|
-
import { logSubmitInitiated, logPaginationSubmitError, logScrollWarning } from '../logger/navigationLogger';
|
|
3
|
-
import {
|
|
4
|
-
logValidationPassedSubmit,
|
|
5
|
-
logValidationErrorSubmit,
|
|
6
|
-
logValidationFailedSubmit,
|
|
7
|
-
} from '../logger/validationLogger';
|
|
8
|
-
import { trackValidationError } from '../telemetry/pageTelemetry';
|
|
9
|
-
import { trackSessionSummary } from '../telemetry/sessionTelemetry';
|
|
10
|
-
import { validateAllPages, findQuestionElement } from '../utils';
|
|
11
|
-
import type { SurveyPaginationContext } from '../types';
|
|
12
|
-
|
|
13
|
-
export function useOnSubmit(context: SurveyPaginationContext) {
|
|
14
|
-
const {
|
|
15
|
-
survey,
|
|
16
|
-
pages,
|
|
17
|
-
values,
|
|
18
|
-
submit,
|
|
19
|
-
currentPageIndex,
|
|
20
|
-
setCurrentPageIndex,
|
|
21
|
-
setValidationErrors,
|
|
22
|
-
trackPageTime,
|
|
23
|
-
trackOptionalSkips,
|
|
24
|
-
checkBacktrackChanges,
|
|
25
|
-
totalQuestionsCount,
|
|
26
|
-
paginationRefs,
|
|
27
|
-
} = context;
|
|
28
|
-
|
|
29
|
-
return useCallback(async () => {
|
|
30
|
-
if (!survey) return;
|
|
31
|
-
|
|
32
|
-
logSubmitInitiated();
|
|
33
|
-
let validation = null;
|
|
34
|
-
try {
|
|
35
|
-
validation = validateAllPages(pages, values, survey.language);
|
|
36
|
-
if (!validation) {
|
|
37
|
-
logValidationPassedSubmit();
|
|
38
|
-
}
|
|
39
|
-
} catch (err) {
|
|
40
|
-
logValidationFailedSubmit(err);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const refs = paginationRefs.current;
|
|
44
|
-
|
|
45
|
-
if (validation) {
|
|
46
|
-
logValidationErrorSubmit(validation);
|
|
47
|
-
|
|
48
|
-
// Track validation error attempt
|
|
49
|
-
const attempt = (refs.validationAttempt[validation.errorPageIndex] || 0) + 1;
|
|
50
|
-
refs.validationAttempt[validation.errorPageIndex] = attempt;
|
|
51
|
-
refs.validationErrorsCount += 1;
|
|
52
|
-
refs.validationHistory.push({
|
|
53
|
-
pageIndex: validation.errorPageIndex,
|
|
54
|
-
errors: validation.errors,
|
|
55
|
-
attemptNumber: attempt,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
trackValidationError(validation.errorPageIndex, validation.errors, attempt);
|
|
59
|
-
|
|
60
|
-
setValidationErrors(validation.errors);
|
|
61
|
-
setCurrentPageIndex(validation.errorPageIndex);
|
|
62
|
-
setTimeout(() => {
|
|
63
|
-
try {
|
|
64
|
-
const element = findQuestionElement(validation.firstErrorId);
|
|
65
|
-
if (element) {
|
|
66
|
-
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
67
|
-
}
|
|
68
|
-
} catch (err) {
|
|
69
|
-
logScrollWarning('Failed to scroll validation error element into view', err);
|
|
70
|
-
}
|
|
71
|
-
}, 100);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
setValidationErrors({});
|
|
76
|
-
|
|
77
|
-
// Clear validation attempt on success
|
|
78
|
-
delete refs.validationAttempt[currentPageIndex];
|
|
79
|
-
|
|
80
|
-
// Track final page time and skipped questions
|
|
81
|
-
trackPageTime(currentPageIndex);
|
|
82
|
-
trackOptionalSkips(currentPageIndex);
|
|
83
|
-
checkBacktrackChanges(currentPageIndex);
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
const result = await submit(values);
|
|
87
|
-
if (result && result.success) {
|
|
88
|
-
if (!refs.hasLoggedSummary) {
|
|
89
|
-
const totalDurationMs = performance.now() - refs.sessionStartTime;
|
|
90
|
-
|
|
91
|
-
// Calculate skipped optional questions
|
|
92
|
-
const skippedQuestionIds: string[] = [];
|
|
93
|
-
pages.forEach(page => {
|
|
94
|
-
page.questions.forEach(question => {
|
|
95
|
-
if (!question.required) {
|
|
96
|
-
const val = values[question.id];
|
|
97
|
-
if (val === undefined || val === '') {
|
|
98
|
-
skippedQuestionIds.push(question.id);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
const skippedQuestionsCount = skippedQuestionIds.length;
|
|
104
|
-
|
|
105
|
-
trackSessionSummary(
|
|
106
|
-
true,
|
|
107
|
-
refs.maxVisitedPageIndex,
|
|
108
|
-
totalDurationMs,
|
|
109
|
-
totalQuestionsCount,
|
|
110
|
-
totalQuestionsCount - skippedQuestionsCount,
|
|
111
|
-
skippedQuestionsCount,
|
|
112
|
-
skippedQuestionIds,
|
|
113
|
-
refs.validationErrorsCount,
|
|
114
|
-
refs.backtrackCount,
|
|
115
|
-
refs.validationHistory
|
|
116
|
-
);
|
|
117
|
-
refs.hasLoggedSummary = true;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
} catch (err) {
|
|
121
|
-
logPaginationSubmitError(err);
|
|
122
|
-
}
|
|
123
|
-
}, [
|
|
124
|
-
survey,
|
|
125
|
-
pages,
|
|
126
|
-
values,
|
|
127
|
-
submit,
|
|
128
|
-
currentPageIndex,
|
|
129
|
-
setCurrentPageIndex,
|
|
130
|
-
setValidationErrors,
|
|
131
|
-
trackPageTime,
|
|
132
|
-
trackOptionalSkips,
|
|
133
|
-
checkBacktrackChanges,
|
|
134
|
-
totalQuestionsCount,
|
|
135
|
-
paginationRefs,
|
|
136
|
-
]);
|
|
137
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { useCallback, RefObject } from 'react';
|
|
2
|
-
import type { SurveyPageData } from '../../fetchSurvey/types';
|
|
3
|
-
import type { SubmitAnswers } from '../../submitSurvey/types';
|
|
4
|
-
import { trackBacktrackRevisited } from '../telemetry/sessionTelemetry';
|
|
5
|
-
import type { SurveyPaginationRefs } from '../types';
|
|
6
|
-
|
|
7
|
-
export function useCheckBacktrackChanges(
|
|
8
|
-
pages: SurveyPageData[],
|
|
9
|
-
values: SubmitAnswers,
|
|
10
|
-
paginationRefs: RefObject<SurveyPaginationRefs>
|
|
11
|
-
) {
|
|
12
|
-
return useCallback(
|
|
13
|
-
(pageIndex: number) => {
|
|
14
|
-
const backtrackInfo = paginationRefs.current.backtrackSnapshots[pageIndex];
|
|
15
|
-
if (backtrackInfo) {
|
|
16
|
-
const pageQuestions = pages[pageIndex]?.questions ?? [];
|
|
17
|
-
const changedAnswers: Record<string, { oldValue: any; newValue: any }> = {};
|
|
18
|
-
let hasChanges = false;
|
|
19
|
-
pageQuestions.forEach(q => {
|
|
20
|
-
const oldVal = backtrackInfo.snapshot[q.id];
|
|
21
|
-
const newVal = values[q.id];
|
|
22
|
-
if (oldVal !== newVal) {
|
|
23
|
-
changedAnswers[q.id] = { oldValue: oldVal ?? null, newValue: newVal ?? null };
|
|
24
|
-
hasChanges = true;
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
if (hasChanges) {
|
|
28
|
-
trackBacktrackRevisited(backtrackInfo.fromPageIndex, pageIndex, changedAnswers);
|
|
29
|
-
}
|
|
30
|
-
delete paginationRefs.current.backtrackSnapshots[pageIndex];
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
[pages, values, paginationRefs]
|
|
34
|
-
);
|
|
35
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
|
-
import type { SurveyPageData } from '../../fetchSurvey/types';
|
|
3
|
-
import type { SubmitAnswers } from '../../submitSurvey/types';
|
|
4
|
-
import { trackOptionalQuestionSkipped } from '../telemetry/sessionTelemetry';
|
|
5
|
-
|
|
6
|
-
export function useTrackOptionalSkips(pages: SurveyPageData[], values: SubmitAnswers) {
|
|
7
|
-
return useCallback(
|
|
8
|
-
(pageIndex: number) => {
|
|
9
|
-
const pageQuestions = pages[pageIndex]?.questions ?? [];
|
|
10
|
-
pageQuestions.forEach(question => {
|
|
11
|
-
const isOptional = !question.required;
|
|
12
|
-
const val = values[question.id];
|
|
13
|
-
const hasNoValue = val === undefined || val === '';
|
|
14
|
-
if (isOptional && hasNoValue) {
|
|
15
|
-
trackOptionalQuestionSkipped(question.id, pageIndex);
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
},
|
|
19
|
-
[pages, values]
|
|
20
|
-
);
|
|
21
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { useCallback, RefObject } from 'react';
|
|
2
|
-
import { trackPageTimeSpent } from '../telemetry/pageTelemetry';
|
|
3
|
-
import type { SurveyPaginationRefs } from '../types';
|
|
4
|
-
|
|
5
|
-
export function useTrackPageTime(paginationRefs: RefObject<SurveyPaginationRefs>) {
|
|
6
|
-
return useCallback(
|
|
7
|
-
(pageIndex: number) => {
|
|
8
|
-
const durationMs = performance.now() - paginationRefs.current.pageStartTime;
|
|
9
|
-
trackPageTimeSpent(pageIndex, durationMs);
|
|
10
|
-
},
|
|
11
|
-
[paginationRefs]
|
|
12
|
-
);
|
|
13
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
|
-
import type { SurveyPaginationContext } from '../types';
|
|
3
|
-
|
|
4
|
-
export function useResetPageStartTime(context: SurveyPaginationContext): void {
|
|
5
|
-
const { currentPageIndex, paginationRefs } = context;
|
|
6
|
-
|
|
7
|
-
useEffect(() => {
|
|
8
|
-
paginationRefs.current.pageStartTime = performance.now();
|
|
9
|
-
}, [currentPageIndex, paginationRefs]);
|
|
10
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
|
-
import type { SurveyPaginationContext } from '../types';
|
|
3
|
-
|
|
4
|
-
export function useTrackMaxVisitedPage(context: SurveyPaginationContext): void {
|
|
5
|
-
const { currentPageIndex, paginationRefs } = context;
|
|
6
|
-
|
|
7
|
-
useEffect(() => {
|
|
8
|
-
if (currentPageIndex > paginationRefs.current.maxVisitedPageIndex) {
|
|
9
|
-
paginationRefs.current.maxVisitedPageIndex = currentPageIndex;
|
|
10
|
-
}
|
|
11
|
-
}, [currentPageIndex, paginationRefs]);
|
|
12
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { sdkLogger } from '../../logger/logger';
|
|
2
|
-
|
|
3
|
-
export function logChangeAnswer(questionId: string, value: string | number): void {
|
|
4
|
-
sdkLogger.info(`Answer changed for question: ${questionId}`, { value });
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function logScrollWarning(msg: string, err: any): void {
|
|
8
|
-
sdkLogger.warn(msg, err);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function logSubmitInitiated(): void {
|
|
12
|
-
sdkLogger.info('Initiating survey submission...');
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function logBackNavigation(currentIndex: number): void {
|
|
16
|
-
sdkLogger.info(`Navigating back from page index: ${currentIndex}`);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function logNextNavigation(currentIndex: number): void {
|
|
20
|
-
sdkLogger.info(`Navigating next from page index: ${currentIndex}`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function logPaginationSubmitError(err: any): void {
|
|
24
|
-
sdkLogger.error('Error encountered during pagination submit trigger', err);
|
|
25
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { sdkLogger } from '../../logger/logger';
|
|
2
|
-
|
|
3
|
-
export function logValidationPassedSubmit(): void {
|
|
4
|
-
sdkLogger.success('Survey validation passed on submit');
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function logValidationErrorSubmit(validation: any): void {
|
|
8
|
-
sdkLogger.warn('Full survey validation failed on submit', { validation });
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function logValidationFailedSubmit(err: any): void {
|
|
12
|
-
sdkLogger.error('Failed to run survey validation on submit', err);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function logValidationErrorPage(errors: any): void {
|
|
16
|
-
sdkLogger.warn('Page validation failed', { errors });
|
|
17
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { trackEvent } from '../../analytics/analyticsTracker';
|
|
2
|
-
|
|
3
|
-
export function trackPageTimeSpent(pageIndex: number, durationMs: number): void {
|
|
4
|
-
trackEvent({
|
|
5
|
-
eventName: 'page_time_spent',
|
|
6
|
-
metadata: {
|
|
7
|
-
pageIndex,
|
|
8
|
-
durationMs,
|
|
9
|
-
},
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function trackValidationError(pageIndex: number, errors: Record<string, string>, attemptNumber: number): void {
|
|
14
|
-
trackEvent({
|
|
15
|
-
eventName: 'validation_error',
|
|
16
|
-
metadata: {
|
|
17
|
-
pageIndex,
|
|
18
|
-
errors,
|
|
19
|
-
attemptNumber,
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { trackEvent } from '../../analytics/analyticsTracker';
|
|
2
|
-
|
|
3
|
-
export function trackSessionSummary(
|
|
4
|
-
completed: boolean,
|
|
5
|
-
maxVisitedPageIndex: number,
|
|
6
|
-
totalDurationMs: number,
|
|
7
|
-
totalQuestionsCount: number,
|
|
8
|
-
answeredQuestionsCount: number,
|
|
9
|
-
skippedQuestionsCount: number,
|
|
10
|
-
skippedQuestionIds: string[],
|
|
11
|
-
validationErrorsCount: number,
|
|
12
|
-
backtrackCount: number,
|
|
13
|
-
validationHistory: Array<{
|
|
14
|
-
pageIndex: number;
|
|
15
|
-
errors: Record<string, string>;
|
|
16
|
-
attemptNumber: number;
|
|
17
|
-
}>
|
|
18
|
-
): void {
|
|
19
|
-
trackEvent({
|
|
20
|
-
eventName: 'survey_session_summary',
|
|
21
|
-
metadata: {
|
|
22
|
-
maxVisitedPageIndex,
|
|
23
|
-
totalDurationMs,
|
|
24
|
-
completed,
|
|
25
|
-
totalQuestionsCount,
|
|
26
|
-
answeredQuestionsCount,
|
|
27
|
-
skippedQuestionsCount,
|
|
28
|
-
skippedQuestionIds,
|
|
29
|
-
validationErrorsCount,
|
|
30
|
-
backtrackCount,
|
|
31
|
-
validationHistory,
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function trackOptionalQuestionSkipped(questionId: string, pageIndex: number): void {
|
|
37
|
-
trackEvent({
|
|
38
|
-
eventName: 'optional_question_skipped',
|
|
39
|
-
metadata: {
|
|
40
|
-
questionId,
|
|
41
|
-
pageIndex,
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function trackBacktrackRevisited(fromPageIndex: number, toPageIndex: number, changedAnswers: any): void {
|
|
47
|
-
trackEvent({
|
|
48
|
-
eventName: 'backtrack_revisited',
|
|
49
|
-
metadata: {
|
|
50
|
-
fromPageIndex,
|
|
51
|
-
toPageIndex,
|
|
52
|
-
changedAnswers,
|
|
53
|
-
},
|
|
54
|
-
});
|
|
55
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { Dispatch, SetStateAction, RefObject } from 'react';
|
|
2
|
-
import type { Survey, SurveySession, SurveyPageData } from '../fetchSurvey/types';
|
|
3
|
-
import type { SubmitAnswers } from '../submitSurvey/types';
|
|
4
|
-
|
|
5
|
-
export type SurveyPaginationRefs = {
|
|
6
|
-
pageStartTime: number;
|
|
7
|
-
sessionStartTime: number;
|
|
8
|
-
maxVisitedPageIndex: number;
|
|
9
|
-
validationAttempt: Record<number, number>;
|
|
10
|
-
backtrackSnapshots: Record<number, { fromPageIndex: number; snapshot: Record<string, any> }>;
|
|
11
|
-
hasLoggedSummary: boolean;
|
|
12
|
-
validationErrorsCount: number;
|
|
13
|
-
backtrackCount: number;
|
|
14
|
-
validationHistory: Array<{
|
|
15
|
-
pageIndex: number;
|
|
16
|
-
errors: Record<string, string>;
|
|
17
|
-
attemptNumber: number;
|
|
18
|
-
}>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type SurveyPaginationContext = {
|
|
22
|
-
survey?: Survey | null;
|
|
23
|
-
session?: SurveySession | null;
|
|
24
|
-
pages: SurveyPageData[];
|
|
25
|
-
currentPageIndex: number;
|
|
26
|
-
setCurrentPageIndex: Dispatch<SetStateAction<number>>;
|
|
27
|
-
values: SubmitAnswers;
|
|
28
|
-
setValues: Dispatch<SetStateAction<SubmitAnswers>>;
|
|
29
|
-
validationErrors: Record<string, string>;
|
|
30
|
-
setValidationErrors: Dispatch<SetStateAction<Record<string, string>>>;
|
|
31
|
-
paginationRefs: RefObject<SurveyPaginationRefs>;
|
|
32
|
-
trackPageTime: (pageIndex: number) => void;
|
|
33
|
-
trackOptionalSkips: (pageIndex: number) => void;
|
|
34
|
-
checkBacktrackChanges: (pageIndex: number) => void;
|
|
35
|
-
submit: (values: SubmitAnswers) => Promise<any>;
|
|
36
|
-
totalQuestionsCount: number;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export type UseSurveyPaginationProps = {
|
|
40
|
-
survey?: Survey | null;
|
|
41
|
-
session?: SurveySession | null;
|
|
42
|
-
};
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { useState, useRef } from 'react';
|
|
2
|
-
import type { Survey, SurveySession } from '../fetchSurvey/useFetchSurvey';
|
|
3
|
-
import type { SubmitAnswers } from '../submitSurvey/types';
|
|
4
|
-
import { useSubmitResponse } from '../submitSurvey/useSubmitResponse';
|
|
5
|
-
import { useSurveyProgress } from '../surveyProgress/useSurveyProgress';
|
|
6
|
-
import {
|
|
7
|
-
useResetPageStartTime,
|
|
8
|
-
useTrackMaxVisitedPage,
|
|
9
|
-
} from './effects';
|
|
10
|
-
import { useOnBack, useOnChange, useOnNext, useOnSubmit } from './actions';
|
|
11
|
-
import { useTrackPageTime, useTrackOptionalSkips, useCheckBacktrackChanges } from './dispatchers';
|
|
12
|
-
import type { SurveyPaginationRefs, SurveyPaginationContext, UseSurveyPaginationProps } from './types';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* A custom React hook that manages survey pagination state, user answers,
|
|
16
|
-
* validation errors, and page-relative scrolling interactions.
|
|
17
|
-
*
|
|
18
|
-
* @param props The configuration properties holding survey details and session tokens.
|
|
19
|
-
* @returns An object containing page states, validation statuses, and interactive callbacks.
|
|
20
|
-
*/
|
|
21
|
-
export function useSurveyPagination({ survey, session }: UseSurveyPaginationProps) {
|
|
22
|
-
const [values, setValues] = useState<SubmitAnswers>({});
|
|
23
|
-
const [validationErrors, setValidationErrors] = useState<Record<string, string>>({});
|
|
24
|
-
const [currentPageIndex, setCurrentPageIndex] = useState(0);
|
|
25
|
-
|
|
26
|
-
const pages = survey?.pages ?? [];
|
|
27
|
-
const currentPage = pages[currentPageIndex];
|
|
28
|
-
const currentQuestions = currentPage?.questions ?? [];
|
|
29
|
-
|
|
30
|
-
// Integrate response submission
|
|
31
|
-
const { submit, data: submitData, loading: submitting, error: submitError } = useSubmitResponse(session, survey);
|
|
32
|
-
|
|
33
|
-
// Integrate progress tracking
|
|
34
|
-
const { progressPercentage, totalQuestionsCount, answeredQuestionsCount, isComplete } = useSurveyProgress({
|
|
35
|
-
survey,
|
|
36
|
-
values,
|
|
37
|
-
currentPageIndex,
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
// Consolidated Analytics & Pagination Refs
|
|
41
|
-
const paginationRefs = useRef<SurveyPaginationRefs>({
|
|
42
|
-
pageStartTime: performance.now(),
|
|
43
|
-
sessionStartTime: performance.now(),
|
|
44
|
-
maxVisitedPageIndex: 0,
|
|
45
|
-
validationAttempt: {},
|
|
46
|
-
backtrackSnapshots: {},
|
|
47
|
-
hasLoggedSummary: false,
|
|
48
|
-
validationErrorsCount: 0,
|
|
49
|
-
backtrackCount: 0,
|
|
50
|
-
validationHistory: [],
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// Instantiate dispatcher hooks
|
|
54
|
-
const trackPageTime = useTrackPageTime(paginationRefs);
|
|
55
|
-
const trackOptionalSkips = useTrackOptionalSkips(pages, values);
|
|
56
|
-
const checkBacktrackChanges = useCheckBacktrackChanges(pages, values, paginationRefs);
|
|
57
|
-
|
|
58
|
-
// Construct context object grouping parameters, functions, and state
|
|
59
|
-
const context: SurveyPaginationContext = {
|
|
60
|
-
survey,
|
|
61
|
-
session,
|
|
62
|
-
pages,
|
|
63
|
-
currentPageIndex,
|
|
64
|
-
setCurrentPageIndex,
|
|
65
|
-
values,
|
|
66
|
-
setValues,
|
|
67
|
-
validationErrors,
|
|
68
|
-
setValidationErrors,
|
|
69
|
-
paginationRefs,
|
|
70
|
-
trackPageTime,
|
|
71
|
-
trackOptionalSkips,
|
|
72
|
-
checkBacktrackChanges,
|
|
73
|
-
submit,
|
|
74
|
-
totalQuestionsCount,
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// Call modular effects
|
|
78
|
-
useTrackMaxVisitedPage(context);
|
|
79
|
-
|
|
80
|
-
useResetPageStartTime(context);
|
|
81
|
-
|
|
82
|
-
// Call modular actions
|
|
83
|
-
const onChange = useOnChange(context);
|
|
84
|
-
|
|
85
|
-
const onBack = useOnBack(context);
|
|
86
|
-
|
|
87
|
-
const onSubmit = useOnSubmit(context);
|
|
88
|
-
|
|
89
|
-
const onNext = useOnNext(context, onSubmit);
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
currentPageIndex,
|
|
93
|
-
values,
|
|
94
|
-
validationErrors,
|
|
95
|
-
currentQuestions,
|
|
96
|
-
pages,
|
|
97
|
-
onChange,
|
|
98
|
-
onBack,
|
|
99
|
-
onNext,
|
|
100
|
-
onSubmit,
|
|
101
|
-
progressPercentage,
|
|
102
|
-
totalQuestionsCount,
|
|
103
|
-
answeredQuestionsCount,
|
|
104
|
-
isComplete,
|
|
105
|
-
submitting,
|
|
106
|
-
submitError,
|
|
107
|
-
submitData,
|
|
108
|
-
};
|
|
109
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { SurveyPageData } from '../../fetchSurvey/types';
|
|
2
|
-
import { logScrollWarning } from '../logger/navigationLogger';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Resolves the DOM element corresponding to a given question ID.
|
|
6
|
-
* Expects the developer to assign standard ID attributes matching the question identifier.
|
|
7
|
-
*
|
|
8
|
-
* @param questionId The unique identifier of the target question.
|
|
9
|
-
* @returns The resolved HTMLElement, or null if server-side rendering or element not found.
|
|
10
|
-
*/
|
|
11
|
-
export function findQuestionElement(questionId: string): HTMLElement | null {
|
|
12
|
-
if (typeof document === 'undefined') return null;
|
|
13
|
-
return document.getElementById(questionId) || null;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Resolves the logical survey container boundary wrapping the question.
|
|
18
|
-
* Looks for semantic HTML containers (main, form) or defaults to parent hierarchy.
|
|
19
|
-
*
|
|
20
|
-
* @param firstQuestionEl The element of the first question on the active page.
|
|
21
|
-
* @returns The resolved survey container element.
|
|
22
|
-
*/
|
|
23
|
-
export function findSurveyContainer(firstQuestionEl: HTMLElement): HTMLElement {
|
|
24
|
-
return (
|
|
25
|
-
firstQuestionEl.closest('main') ||
|
|
26
|
-
firstQuestionEl.closest('form') ||
|
|
27
|
-
firstQuestionEl.parentElement ||
|
|
28
|
-
firstQuestionEl
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Scrolls the viewport to the top of the survey container for the specified page index.
|
|
34
|
-
*
|
|
35
|
-
* @param pages List of survey pages.
|
|
36
|
-
* @param pageIndex The target page index to navigate and scroll to.
|
|
37
|
-
*/
|
|
38
|
-
export function scrollToFirstQuestionOfPage(pages: SurveyPageData[], pageIndex: number): void {
|
|
39
|
-
try {
|
|
40
|
-
const targetPage = pages[pageIndex];
|
|
41
|
-
const firstQuestion = targetPage?.questions?.[0];
|
|
42
|
-
if (firstQuestion) {
|
|
43
|
-
setTimeout(() => {
|
|
44
|
-
try {
|
|
45
|
-
const questionEl = findQuestionElement(firstQuestion.id);
|
|
46
|
-
if (questionEl) {
|
|
47
|
-
const surveyContainer = findSurveyContainer(questionEl);
|
|
48
|
-
surveyContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
49
|
-
} else {
|
|
50
|
-
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
51
|
-
}
|
|
52
|
-
} catch (err) {
|
|
53
|
-
logScrollWarning('Failed to scroll page first question into view', err);
|
|
54
|
-
}
|
|
55
|
-
}, 50);
|
|
56
|
-
} else {
|
|
57
|
-
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
58
|
-
}
|
|
59
|
-
} catch (err) {
|
|
60
|
-
logScrollWarning('Failed to trigger scroll navigation', err);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { SurveyPageData, SurveyQuestion } from '../../fetchSurvey/types';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Validates a list of questions against user values and returns an error map.
|
|
5
|
-
*
|
|
6
|
-
* @param questions List of questions to validate.
|
|
7
|
-
* @param values User selected values mapped by question ID.
|
|
8
|
-
* @param language Active survey language code.
|
|
9
|
-
* @returns Object mapping question ID to localized validation error messages.
|
|
10
|
-
*/
|
|
11
|
-
export function validateQuestions(
|
|
12
|
-
questions: SurveyQuestion[],
|
|
13
|
-
values: Record<string, string | number>,
|
|
14
|
-
language?: string
|
|
15
|
-
): Record<string, string> {
|
|
16
|
-
const errors: Record<string, string> = {};
|
|
17
|
-
questions.forEach(question => {
|
|
18
|
-
if (question.required && (values[question.id] === undefined || values[question.id] === '')) {
|
|
19
|
-
errors[question.id] =
|
|
20
|
-
question.requiredErrorMessage ??
|
|
21
|
-
(language?.startsWith('de')
|
|
22
|
-
? 'Beantworten Sie bitte diese Frage bevor Sie fortfahren.'
|
|
23
|
-
: 'Please answer this question before you proceed.');
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
return errors;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Validates all survey pages and returns details of the first validation error found.
|
|
31
|
-
*
|
|
32
|
-
* @param pages List of pages to validate.
|
|
33
|
-
* @param values User selected values mapped by question ID.
|
|
34
|
-
* @param language Active survey language code.
|
|
35
|
-
* @returns Validation error details containing all errors, target error page index, and target error element ID, or null if all checks pass.
|
|
36
|
-
*/
|
|
37
|
-
export function validateAllPages(
|
|
38
|
-
pages: SurveyPageData[],
|
|
39
|
-
values: Record<string, string | number>,
|
|
40
|
-
language?: string
|
|
41
|
-
): { errors: Record<string, string>; errorPageIndex: number; firstErrorId: string } | null {
|
|
42
|
-
let errors: Record<string, string> = {};
|
|
43
|
-
let firstErrorId = '';
|
|
44
|
-
let errorPageIndex = -1;
|
|
45
|
-
|
|
46
|
-
for (let i = 0; i < pages.length; i++) {
|
|
47
|
-
const pageErrors = validateQuestions(pages[i].questions, values, language);
|
|
48
|
-
if (Object.keys(pageErrors).length > 0) {
|
|
49
|
-
errors = { ...errors, ...pageErrors };
|
|
50
|
-
if (errorPageIndex === -1) {
|
|
51
|
-
errorPageIndex = i;
|
|
52
|
-
firstErrorId = Object.keys(pageErrors)[0];
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (errorPageIndex !== -1) {
|
|
58
|
-
return { errors, errorPageIndex, firstErrorId };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return null;
|
|
62
|
-
}
|