@constructor-io/constructorio-ui-quizzes 1.18.0 → 1.19.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/constructorio-ui-quizzes-bundled.js +21 -21
- package/lib/cjs/components/CioQuiz/actions.js +5 -3
- package/lib/cjs/components/CioQuiz/index.js +2 -1
- package/lib/cjs/components/CioQuiz/quizApiReducer.js +3 -0
- package/lib/cjs/components/CioQuiz/quizLocalReducer.js +23 -12
- package/lib/cjs/hooks/usePropsGetters/index.js +6 -3
- package/lib/cjs/hooks/usePropsGetters/useJumpToQuestionButtonProps.js +34 -0
- package/lib/cjs/hooks/usePropsGetters/useSelectInputProps.js +3 -2
- package/lib/cjs/hooks/useQuiz.js +7 -1
- package/lib/cjs/hooks/useQuizEvents/index.js +7 -0
- package/lib/cjs/hooks/useQuizEvents/useJumpToQuestion.js +25 -0
- package/lib/cjs/hooks/useQuizState/useQuizApiState.js +1 -1
- package/lib/cjs/hooks/useQuizState/useSessionStorageState.js +2 -1
- package/lib/cjs/version.js +1 -1
- package/lib/mjs/components/CioQuiz/actions.js +5 -3
- package/lib/mjs/components/CioQuiz/index.js +2 -1
- package/lib/mjs/components/CioQuiz/quizApiReducer.js +8 -0
- package/lib/mjs/components/CioQuiz/quizLocalReducer.js +35 -39
- package/lib/mjs/hooks/usePropsGetters/index.js +6 -3
- package/lib/mjs/hooks/usePropsGetters/useJumpToQuestionButtonProps.js +29 -0
- package/lib/mjs/hooks/usePropsGetters/useSelectInputProps.js +3 -2
- package/lib/mjs/hooks/useQuiz.js +7 -1
- package/lib/mjs/hooks/useQuizEvents/index.js +7 -0
- package/lib/mjs/hooks/useQuizEvents/useJumpToQuestion.js +21 -0
- package/lib/mjs/hooks/useQuizState/useQuizApiState.js +1 -1
- package/lib/mjs/hooks/useQuizState/useSessionStorageState.js +3 -2
- package/lib/mjs/version.js +1 -1
- package/lib/types/components/CioQuiz/actions.d.ts +13 -6
- package/lib/types/components/CioQuiz/context.d.ts +2 -1
- package/lib/types/hooks/usePropsGetters/index.d.ts +9 -2
- package/lib/types/hooks/usePropsGetters/useJumpToQuestionButtonProps.d.ts +4 -0
- package/lib/types/hooks/usePropsGetters/useSelectInputProps.d.ts +1 -1
- package/lib/types/hooks/useQuizEvents/useJumpToQuestion.d.ts +11 -0
- package/lib/types/hooks/useQuizEvents/useQuizResetClick.d.ts +1 -1
- package/lib/types/types.d.ts +10 -0
- package/lib/types/version.d.ts +1 -1
- package/package.json +2 -2
|
@@ -16,6 +16,7 @@ var QuestionTypes;
|
|
|
16
16
|
QuestionTypes["Reset"] = "reset";
|
|
17
17
|
QuestionTypes["Hydrate"] = "hydrate";
|
|
18
18
|
QuestionTypes["Complete"] = "complete";
|
|
19
|
+
QuestionTypes["JumpToQuestion"] = "jump_to_question";
|
|
19
20
|
})(QuestionTypes = exports.QuestionTypes || (exports.QuestionTypes = {}));
|
|
20
21
|
// API actions
|
|
21
22
|
var QuizAPIActionTypes;
|
|
@@ -25,7 +26,8 @@ var QuizAPIActionTypes;
|
|
|
25
26
|
QuizAPIActionTypes[QuizAPIActionTypes["SET_QUIZ_RESULTS"] = 2] = "SET_QUIZ_RESULTS";
|
|
26
27
|
QuizAPIActionTypes[QuizAPIActionTypes["SET_CURRENT_QUESTION"] = 3] = "SET_CURRENT_QUESTION";
|
|
27
28
|
QuizAPIActionTypes[QuizAPIActionTypes["RESET_QUIZ"] = 4] = "RESET_QUIZ";
|
|
28
|
-
QuizAPIActionTypes[QuizAPIActionTypes["
|
|
29
|
-
QuizAPIActionTypes[QuizAPIActionTypes["
|
|
30
|
-
QuizAPIActionTypes[QuizAPIActionTypes["
|
|
29
|
+
QuizAPIActionTypes[QuizAPIActionTypes["JUMP_TO_QUESTION"] = 5] = "JUMP_TO_QUESTION";
|
|
30
|
+
QuizAPIActionTypes[QuizAPIActionTypes["SET_QUIZ_SHARED_RESULTS"] = 6] = "SET_QUIZ_SHARED_RESULTS";
|
|
31
|
+
QuizAPIActionTypes[QuizAPIActionTypes["SET_QUIZ_RESULTS_CONFIG"] = 7] = "SET_QUIZ_RESULTS_CONFIG";
|
|
32
|
+
QuizAPIActionTypes[QuizAPIActionTypes["SET_QUIZ_RESULTS_CONFIG_ERROR"] = 8] = "SET_QUIZ_RESULTS_CONFIG_ERROR";
|
|
31
33
|
})(QuizAPIActionTypes = exports.QuizAPIActionTypes || (exports.QuizAPIActionTypes = {}));
|
|
@@ -16,7 +16,7 @@ const ProgressBar_1 = tslib_1.__importDefault(require("../ProgressBar/ProgressBa
|
|
|
16
16
|
const actions_1 = require("./actions");
|
|
17
17
|
function CioQuiz(props) {
|
|
18
18
|
var _a;
|
|
19
|
-
const { cioClient, state, events: { hydrateQuiz, resetSessionStorageState }, getAddToCartButtonProps, getAddToFavoritesButtonProps, getCoverQuestionProps, getHydrateQuizButtonProps, getNextQuestionButtonProps, getSkipQuestionButtonProps, getOpenTextInputProps, getPreviousQuestionButtonProps, getQuizImageProps, getQuizResultButtonProps, getQuizResultLinkProps, getResetQuizButtonProps, getSelectInputProps, primaryColorStyles, getShareResultsButtonProps, } = (0, useQuiz_1.default)(props);
|
|
19
|
+
const { cioClient, state, events: { hydrateQuiz, resetSessionStorageState }, getAddToCartButtonProps, getAddToFavoritesButtonProps, getCoverQuestionProps, getHydrateQuizButtonProps, getNextQuestionButtonProps, getSkipQuestionButtonProps, getJumpToQuestionButtonProps, getOpenTextInputProps, getPreviousQuestionButtonProps, getQuizImageProps, getQuizResultButtonProps, getQuizResultLinkProps, getResetQuizButtonProps, getSelectInputProps, primaryColorStyles, getShareResultsButtonProps, } = (0, useQuiz_1.default)(props);
|
|
20
20
|
const [showSessionPrompt, setShowSessionPrompt] = (0, react_1.useState)(false);
|
|
21
21
|
const [showShareModal, setShowShareModal] = (0, react_1.useState)(false);
|
|
22
22
|
const { callbacks, sessionStateOptions, questionsPageOptions, resultCardOptions, resultsPageOptions, } = props;
|
|
@@ -40,6 +40,7 @@ function CioQuiz(props) {
|
|
|
40
40
|
getHydrateQuizButtonProps,
|
|
41
41
|
getNextQuestionButtonProps,
|
|
42
42
|
getSkipQuestionButtonProps,
|
|
43
|
+
getJumpToQuestionButtonProps,
|
|
43
44
|
getOpenTextInputProps,
|
|
44
45
|
getPreviousQuestionButtonProps,
|
|
45
46
|
getQuizImageProps,
|
|
@@ -35,6 +35,9 @@ function apiReducer(state, action) {
|
|
|
35
35
|
case actions_1.QuizAPIActionTypes.SET_QUIZ_SHARED_RESULTS: {
|
|
36
36
|
return Object.assign(Object.assign({}, state), { quizRequestState: constants_1.RequestStates.Success, quizResults: (_o = action.payload) === null || _o === void 0 ? void 0 : _o.quizResults, quizCurrentQuestion: undefined, selectedOptionsWithAttributes: (_p = action.payload) === null || _p === void 0 ? void 0 : _p.quizResults.attributes });
|
|
37
37
|
}
|
|
38
|
+
case actions_1.QuizAPIActionTypes.JUMP_TO_QUESTION: {
|
|
39
|
+
return Object.assign(Object.assign({}, state), { quizResults: undefined, selectedOptionsWithAttributes: undefined, matchedOptions: undefined });
|
|
40
|
+
}
|
|
38
41
|
case actions_1.QuizAPIActionTypes.SET_QUIZ_RESULTS_CONFIG: {
|
|
39
42
|
return Object.assign(Object.assign({}, state), { metadata: (_q = action.payload) === null || _q === void 0 ? void 0 : _q.quizResultsConfig.metadata, resultsConfig: (_r = action.payload) === null || _r === void 0 ? void 0 : _r.quizResultsConfig.results_config });
|
|
40
43
|
}
|
|
@@ -8,12 +8,6 @@ exports.initialState = {
|
|
|
8
8
|
prevAnswerInputs: {},
|
|
9
9
|
isQuizCompleted: false,
|
|
10
10
|
};
|
|
11
|
-
function answerInputReducer(state, action) {
|
|
12
|
-
return Object.assign(Object.assign({}, state), { [String(action.payload.questionId)]: {
|
|
13
|
-
type: action.type,
|
|
14
|
-
value: action.payload.input,
|
|
15
|
-
} });
|
|
16
|
-
}
|
|
17
11
|
function handleNextQuestion(state) {
|
|
18
12
|
var _a;
|
|
19
13
|
const { answers, answerInputs } = state;
|
|
@@ -40,20 +34,21 @@ function handleNextQuestion(state) {
|
|
|
40
34
|
// We now commit current answers to prevAnswerInputs
|
|
41
35
|
prevAnswerInputs: answerInputs, answers: newAnswers, isQuizCompleted: false });
|
|
42
36
|
}
|
|
37
|
+
const handleAnswerInput = (state, action) => (Object.assign(Object.assign({}, state), { answerInputs: Object.assign(Object.assign({}, state.answerInputs), { [String(action.payload.questionId)]: {
|
|
38
|
+
type: action.type,
|
|
39
|
+
value: action.payload.input,
|
|
40
|
+
} }), isQuizCompleted: false }));
|
|
41
|
+
// eslint-disable-next-line complexity
|
|
43
42
|
function quizLocalReducer(state, action) {
|
|
43
|
+
var _a;
|
|
44
44
|
switch (action.type) {
|
|
45
45
|
case actions_1.QuestionTypes.OpenText:
|
|
46
|
-
return Object.assign(Object.assign({}, state), { answerInputs: answerInputReducer(state.answerInputs, action), isQuizCompleted: false });
|
|
47
46
|
case actions_1.QuestionTypes.Cover:
|
|
48
|
-
return Object.assign(Object.assign({}, state), { answerInputs: answerInputReducer(state.answerInputs, action), isQuizCompleted: false });
|
|
49
47
|
case actions_1.QuestionTypes.SingleSelect:
|
|
50
|
-
return Object.assign(Object.assign({}, state), { answerInputs: answerInputReducer(state.answerInputs, action), isQuizCompleted: false });
|
|
51
48
|
case actions_1.QuestionTypes.MultipleSelect:
|
|
52
|
-
return Object.assign(Object.assign({}, state), { answerInputs: answerInputReducer(state.answerInputs, action), isQuizCompleted: false });
|
|
53
49
|
case actions_1.QuestionTypes.SingleFilterValue:
|
|
54
|
-
return Object.assign(Object.assign({}, state), { answerInputs: answerInputReducer(state.answerInputs, action), isQuizCompleted: false });
|
|
55
50
|
case actions_1.QuestionTypes.MultipleFilterValues:
|
|
56
|
-
return
|
|
51
|
+
return handleAnswerInput(state, action);
|
|
57
52
|
case actions_1.QuestionTypes.Next: {
|
|
58
53
|
return handleNextQuestion(state);
|
|
59
54
|
}
|
|
@@ -84,6 +79,22 @@ function quizLocalReducer(state, action) {
|
|
|
84
79
|
const prevAnswerInputs = Object.assign({}, state.prevAnswerInputs);
|
|
85
80
|
return Object.assign(Object.assign({}, state), { answerInputs: prevAnswerInputs, answers: [...state.answers.slice(0, -1)], isQuizCompleted: false });
|
|
86
81
|
}
|
|
82
|
+
case actions_1.QuestionTypes.JumpToQuestion: {
|
|
83
|
+
const questionId = (_a = action.payload) === null || _a === void 0 ? void 0 : _a.questionId;
|
|
84
|
+
if (questionId === undefined)
|
|
85
|
+
return state;
|
|
86
|
+
const prevAnswerInputs = Object.assign({}, state.prevAnswerInputs);
|
|
87
|
+
// Remove all keys greater than questionId from answerInputs
|
|
88
|
+
const filteredAnswerInputs = {};
|
|
89
|
+
Object.keys(prevAnswerInputs).forEach((key) => {
|
|
90
|
+
if (parseInt(key, 10) >= questionId)
|
|
91
|
+
return;
|
|
92
|
+
filteredAnswerInputs[key] = prevAnswerInputs[key];
|
|
93
|
+
});
|
|
94
|
+
// Calculate the number of questions to keep (questions <= questionId)
|
|
95
|
+
const questionsToKeep = Object.keys(filteredAnswerInputs).length;
|
|
96
|
+
return Object.assign(Object.assign({}, state), { answerInputs: filteredAnswerInputs, prevAnswerInputs: filteredAnswerInputs, answers: state.answers.slice(0, questionsToKeep), isQuizCompleted: false });
|
|
97
|
+
}
|
|
87
98
|
case actions_1.QuestionTypes.Reset:
|
|
88
99
|
return Object.assign({}, exports.initialState);
|
|
89
100
|
case actions_1.QuestionTypes.Hydrate:
|
|
@@ -9,14 +9,16 @@ const useNextQuestionButtonProps_1 = tslib_1.__importDefault(require("./useNextQ
|
|
|
9
9
|
const usePreviousQuestionButtonProps_1 = tslib_1.__importDefault(require("./usePreviousQuestionButtonProps"));
|
|
10
10
|
const useAddToFavoritesButtonProps_1 = tslib_1.__importDefault(require("./useAddToFavoritesButtonProps"));
|
|
11
11
|
const useSkipQuestionButtonProps_1 = tslib_1.__importDefault(require("./useSkipQuestionButtonProps"));
|
|
12
|
-
const
|
|
12
|
+
const useJumpToQuestionButtonProps_1 = tslib_1.__importDefault(require("./useJumpToQuestionButtonProps"));
|
|
13
|
+
const usePropsGetters = ({ questionsPageOptions, favoriteItems, quizEvents, quizApiState, quizLocalState, }) => {
|
|
13
14
|
var _a, _b, _c;
|
|
14
|
-
const { quizAnswerChanged, nextQuestion, skipQuestion, previousQuestion, resetQuiz, hydrateQuiz, addToCart, addToFavorites, resultClick, } = quizEvents;
|
|
15
|
+
const { quizAnswerChanged, nextQuestion, skipQuestion, previousQuestion, resetQuiz, hydrateQuiz, addToCart, addToFavorites, resultClick, jumpToQuestion, } = quizEvents;
|
|
15
16
|
const getOpenTextInputProps = (0, useOpenTextInputProps_1.default)(quizAnswerChanged, nextQuestion, (_a = quizApiState.quizCurrentQuestion) === null || _a === void 0 ? void 0 : _a.next_question, quizLocalState.answerInputs);
|
|
16
17
|
const getCoverQuestionProps = (0, useCoverQuestionProps_1.default)(quizAnswerChanged, (_b = quizApiState.quizCurrentQuestion) === null || _b === void 0 ? void 0 : _b.next_question);
|
|
17
|
-
const getSelectInputProps = (0, useSelectInputProps_1.default)(quizAnswerChanged, nextQuestion, (_c = quizApiState.quizCurrentQuestion) === null || _c === void 0 ? void 0 : _c.next_question, quizLocalState.answerInputs);
|
|
18
|
+
const getSelectInputProps = (0, useSelectInputProps_1.default)(quizAnswerChanged, nextQuestion, (_c = quizApiState.quizCurrentQuestion) === null || _c === void 0 ? void 0 : _c.next_question, quizLocalState.answerInputs, questionsPageOptions === null || questionsPageOptions === void 0 ? void 0 : questionsPageOptions.nextQuestionOnSingleSelect);
|
|
18
19
|
const getNextQuestionButtonProps = (0, useNextQuestionButtonProps_1.default)(nextQuestion, quizApiState, quizLocalState);
|
|
19
20
|
const getSkipQuestionButtonProps = (0, useSkipQuestionButtonProps_1.default)(skipQuestion, quizApiState);
|
|
21
|
+
const getJumpToQuestionButtonProps = (0, useJumpToQuestionButtonProps_1.default)(jumpToQuestion, quizApiState, quizLocalState);
|
|
20
22
|
const getPreviousQuestionButtonProps = (0, usePreviousQuestionButtonProps_1.default)(quizApiState, previousQuestion);
|
|
21
23
|
const getResetQuizButtonProps = (0, react_1.useCallback)((stylesType = 'primary') => ({
|
|
22
24
|
className: stylesType === 'primary' ? 'cio-question-cta-button' : 'cio-question-redo-button',
|
|
@@ -88,6 +90,7 @@ const usePropsGetters = (quizEvents, quizApiState, quizLocalState, favoriteItems
|
|
|
88
90
|
getQuizResultButtonProps,
|
|
89
91
|
getQuizResultLinkProps,
|
|
90
92
|
getSkipQuestionButtonProps,
|
|
93
|
+
getJumpToQuestionButtonProps,
|
|
91
94
|
};
|
|
92
95
|
};
|
|
93
96
|
exports.default = usePropsGetters;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const react_1 = require("react");
|
|
4
|
+
function useJumpToQuestionButtonProps(jumpToQuestion, quizApiState, quizLocalState) {
|
|
5
|
+
var _a, _b;
|
|
6
|
+
const getJumpToQuestionButtonProps = (0, react_1.useCallback)((id) => {
|
|
7
|
+
var _a, _b;
|
|
8
|
+
let buttonDisabled;
|
|
9
|
+
const currentQuestionId = (_b = (_a = quizApiState.quizCurrentQuestion) === null || _a === void 0 ? void 0 : _a.next_question) === null || _b === void 0 ? void 0 : _b.id;
|
|
10
|
+
const answerIds = Object.keys(quizLocalState.prevAnswerInputs);
|
|
11
|
+
const isInvalidQuestionId = answerIds && !answerIds.includes(String(id));
|
|
12
|
+
const isCurrentOrFutureQuestionId = currentQuestionId && id >= currentQuestionId;
|
|
13
|
+
if (isInvalidQuestionId || isCurrentOrFutureQuestionId) {
|
|
14
|
+
buttonDisabled = true;
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
className: buttonDisabled ? 'cio-question-cta-button disabled' : 'cio-question-cta-button',
|
|
18
|
+
tabIndex: buttonDisabled ? -1 : 0,
|
|
19
|
+
'aria-disabled': buttonDisabled ? 'true' : 'false',
|
|
20
|
+
'aria-describedby': buttonDisabled ? 'jump-to-button-help' : '',
|
|
21
|
+
disabled: !!buttonDisabled,
|
|
22
|
+
type: 'button',
|
|
23
|
+
onClick: () => {
|
|
24
|
+
jumpToQuestion(id);
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}, [
|
|
28
|
+
quizLocalState.prevAnswerInputs,
|
|
29
|
+
(_b = (_a = quizApiState.quizCurrentQuestion) === null || _a === void 0 ? void 0 : _a.next_question) === null || _b === void 0 ? void 0 : _b.id,
|
|
30
|
+
jumpToQuestion,
|
|
31
|
+
]);
|
|
32
|
+
return getJumpToQuestionButtonProps;
|
|
33
|
+
}
|
|
34
|
+
exports.default = useJumpToQuestionButtonProps;
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const react_1 = require("react");
|
|
4
4
|
const actions_1 = require("../../components/CioQuiz/actions");
|
|
5
5
|
// eslint-disable-next-line max-params
|
|
6
|
-
function useSelectInputProps(quizAnswerChanged, nextQuestion, currentQuestionData, answerInputs) {
|
|
6
|
+
function useSelectInputProps(quizAnswerChanged, nextQuestion, currentQuestionData, answerInputs, nextQuestionOnSingleSelect = true) {
|
|
7
7
|
var _a;
|
|
8
8
|
const type = currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.type;
|
|
9
9
|
const hasImages = (_a = currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.options) === null || _a === void 0 ? void 0 : _a.some((option) => option.images);
|
|
@@ -79,7 +79,8 @@ function useSelectInputProps(quizAnswerChanged, nextQuestion, currentQuestionDat
|
|
|
79
79
|
(0, react_1.useEffect)(() => {
|
|
80
80
|
if (((currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.type) === actions_1.QuestionTypes.SingleSelect ||
|
|
81
81
|
(currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.type) === actions_1.QuestionTypes.SingleFilterValue) &&
|
|
82
|
-
singleSelectClicked.current
|
|
82
|
+
singleSelectClicked.current &&
|
|
83
|
+
nextQuestionOnSingleSelect) {
|
|
83
84
|
nextQuestion();
|
|
84
85
|
}
|
|
85
86
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
package/lib/cjs/hooks/useQuiz.js
CHANGED
|
@@ -20,7 +20,13 @@ const useQuiz = (quizOptions) => {
|
|
|
20
20
|
const quizEvents = (0, useQuizEvents_1.default)(quizOptions, cioClient, quizState);
|
|
21
21
|
// Props getters
|
|
22
22
|
const { quizApiState, quizLocalState, quizSessionStorageState } = quizState;
|
|
23
|
-
const propGetters = (0, usePropsGetters_1.default)(
|
|
23
|
+
const propGetters = (0, usePropsGetters_1.default)({
|
|
24
|
+
quizEvents,
|
|
25
|
+
quizApiState,
|
|
26
|
+
quizLocalState,
|
|
27
|
+
favoriteItems: resultsPageOptions === null || resultsPageOptions === void 0 ? void 0 : resultsPageOptions.favoriteItems,
|
|
28
|
+
questionsPageOptions: quizOptions.questionsPageOptions,
|
|
29
|
+
});
|
|
24
30
|
const primaryColorStyles = (0, usePrimaryColorStyles_1.default)(primaryColor);
|
|
25
31
|
return Object.assign(Object.assign({ cioClient, state: {
|
|
26
32
|
answers: {
|
|
@@ -12,6 +12,7 @@ const useHydrateQuizLocalState_1 = tslib_1.__importDefault(require("./useHydrate
|
|
|
12
12
|
const utils_1 = require("../../utils");
|
|
13
13
|
const useQuizAddToFavorites_1 = tslib_1.__importDefault(require("./useQuizAddToFavorites"));
|
|
14
14
|
const useQuizSkipClick_1 = tslib_1.__importDefault(require("./useQuizSkipClick"));
|
|
15
|
+
const useJumpToQuestion_1 = tslib_1.__importDefault(require("./useJumpToQuestion"));
|
|
15
16
|
const useQuizEvents = (quizOptions, cioClient, quizState) => {
|
|
16
17
|
const { quizApiState, dispatchLocalState, dispatchApiState, quizLocalState, quizSessionStorageState, } = quizState;
|
|
17
18
|
const { callbacks } = quizOptions;
|
|
@@ -38,6 +39,11 @@ const useQuizEvents = (quizOptions, cioClient, quizState) => {
|
|
|
38
39
|
dispatchApiState,
|
|
39
40
|
quizResults: quizApiState.quizResults,
|
|
40
41
|
});
|
|
42
|
+
const jumpToQuestion = (0, useJumpToQuestion_1.default)({
|
|
43
|
+
dispatchLocalState,
|
|
44
|
+
dispatchApiState,
|
|
45
|
+
quizApiState,
|
|
46
|
+
});
|
|
41
47
|
// Quiz rehydrate
|
|
42
48
|
const hydrateQuizLocalState = (0, useHydrateQuizLocalState_1.default)(quizOptions.quizId, quizSessionStorageState, dispatchLocalState);
|
|
43
49
|
return {
|
|
@@ -49,6 +55,7 @@ const useQuizEvents = (quizOptions, cioClient, quizState) => {
|
|
|
49
55
|
nextQuestion,
|
|
50
56
|
skipQuestion,
|
|
51
57
|
resetQuiz,
|
|
58
|
+
jumpToQuestion,
|
|
52
59
|
hydrateQuiz: hydrateQuizLocalState,
|
|
53
60
|
resetSessionStorageState,
|
|
54
61
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const react_1 = require("react");
|
|
4
|
+
const actions_1 = require("../../components/CioQuiz/actions");
|
|
5
|
+
const useJumpToQuestion = (props) => {
|
|
6
|
+
var _a;
|
|
7
|
+
const { dispatchLocalState, dispatchApiState, quizApiState } = props;
|
|
8
|
+
const quizJumpToQuestionClickHandler = (0, react_1.useCallback)((questionId) => {
|
|
9
|
+
var _a;
|
|
10
|
+
const currentQuestionId = (_a = quizApiState.quizCurrentQuestion) === null || _a === void 0 ? void 0 : _a.id;
|
|
11
|
+
if (questionId >= currentQuestionId) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
dispatchLocalState({
|
|
15
|
+
type: actions_1.QuestionTypes.JumpToQuestion,
|
|
16
|
+
payload: { questionId },
|
|
17
|
+
});
|
|
18
|
+
dispatchApiState({
|
|
19
|
+
type: actions_1.QuizAPIActionTypes.JUMP_TO_QUESTION,
|
|
20
|
+
payload: { questionId },
|
|
21
|
+
});
|
|
22
|
+
}, [(_a = quizApiState.quizCurrentQuestion) === null || _a === void 0 ? void 0 : _a.id, dispatchLocalState, dispatchApiState]);
|
|
23
|
+
return quizJumpToQuestionClickHandler;
|
|
24
|
+
};
|
|
25
|
+
exports.default = useJumpToQuestion;
|
|
@@ -81,7 +81,7 @@ const useQuizApiState = (quizOptions, cioClient, quizLocalState, skipToResults,
|
|
|
81
81
|
dispatchQuizResultsConfig();
|
|
82
82
|
return;
|
|
83
83
|
}
|
|
84
|
-
const { onQuizResultsConfigLoaded } = callbacks;
|
|
84
|
+
const { onQuizResultsConfigLoaded } = callbacks || {};
|
|
85
85
|
if (onQuizResultsConfigLoaded && (0, utils_1.isFunction)(onQuizResultsConfigLoaded)) {
|
|
86
86
|
onQuizResultsConfigLoaded(quizApiState.resultsConfig, quizApiState.metadata);
|
|
87
87
|
}
|
|
@@ -6,6 +6,7 @@ const constants_1 = require("../../constants");
|
|
|
6
6
|
const useSessionStorageState = (quizId, quizLocalState, sessionStateOptions, enableHydration) => {
|
|
7
7
|
var _a;
|
|
8
8
|
const quizSessionStorageStateKey = (sessionStateOptions === null || sessionStateOptions === void 0 ? void 0 : sessionStateOptions.sessionStateKey) || constants_1.quizSessionStateKey;
|
|
9
|
+
const [quizData, setQuizData] = (0, react_1.useState)((0, utils_1.getStateFromSessionStorage)(quizSessionStorageStateKey));
|
|
9
10
|
// Save state to session storage
|
|
10
11
|
(0, react_1.useEffect)(() => {
|
|
11
12
|
var _a, _b;
|
|
@@ -14,9 +15,9 @@ const useSessionStorageState = (quizId, quizLocalState, sessionStateOptions, ena
|
|
|
14
15
|
const data = (0, utils_1.getStateFromSessionStorage)(quizSessionStorageStateKey);
|
|
15
16
|
const dataToSave = Object.assign(Object.assign({}, data), { [quizId]: quizLocalState });
|
|
16
17
|
(_b = window === null || window === void 0 ? void 0 : window.sessionStorage) === null || _b === void 0 ? void 0 : _b.setItem(quizSessionStorageStateKey, JSON.stringify(dataToSave));
|
|
18
|
+
setQuizData(data);
|
|
17
19
|
}
|
|
18
20
|
}, [quizLocalState, quizSessionStorageStateKey, enableHydration, quizId]);
|
|
19
|
-
const quizData = (0, utils_1.getStateFromSessionStorage)(quizSessionStorageStateKey);
|
|
20
21
|
const skipToResults = !!enableHydration &&
|
|
21
22
|
!!((_a = quizData === null || quizData === void 0 ? void 0 : quizData[quizId]) === null || _a === void 0 ? void 0 : _a.isQuizCompleted) &&
|
|
22
23
|
!(sessionStateOptions === null || sessionStateOptions === void 0 ? void 0 : sessionStateOptions.showSessionModalOnResults);
|
package/lib/cjs/version.js
CHANGED
|
@@ -13,6 +13,7 @@ export var QuestionTypes;
|
|
|
13
13
|
QuestionTypes["Reset"] = "reset";
|
|
14
14
|
QuestionTypes["Hydrate"] = "hydrate";
|
|
15
15
|
QuestionTypes["Complete"] = "complete";
|
|
16
|
+
QuestionTypes["JumpToQuestion"] = "jump_to_question";
|
|
16
17
|
})(QuestionTypes || (QuestionTypes = {}));
|
|
17
18
|
// API actions
|
|
18
19
|
export var QuizAPIActionTypes;
|
|
@@ -22,7 +23,8 @@ export var QuizAPIActionTypes;
|
|
|
22
23
|
QuizAPIActionTypes[QuizAPIActionTypes["SET_QUIZ_RESULTS"] = 2] = "SET_QUIZ_RESULTS";
|
|
23
24
|
QuizAPIActionTypes[QuizAPIActionTypes["SET_CURRENT_QUESTION"] = 3] = "SET_CURRENT_QUESTION";
|
|
24
25
|
QuizAPIActionTypes[QuizAPIActionTypes["RESET_QUIZ"] = 4] = "RESET_QUIZ";
|
|
25
|
-
QuizAPIActionTypes[QuizAPIActionTypes["
|
|
26
|
-
QuizAPIActionTypes[QuizAPIActionTypes["
|
|
27
|
-
QuizAPIActionTypes[QuizAPIActionTypes["
|
|
26
|
+
QuizAPIActionTypes[QuizAPIActionTypes["JUMP_TO_QUESTION"] = 5] = "JUMP_TO_QUESTION";
|
|
27
|
+
QuizAPIActionTypes[QuizAPIActionTypes["SET_QUIZ_SHARED_RESULTS"] = 6] = "SET_QUIZ_SHARED_RESULTS";
|
|
28
|
+
QuizAPIActionTypes[QuizAPIActionTypes["SET_QUIZ_RESULTS_CONFIG"] = 7] = "SET_QUIZ_RESULTS_CONFIG";
|
|
29
|
+
QuizAPIActionTypes[QuizAPIActionTypes["SET_QUIZ_RESULTS_CONFIG_ERROR"] = 8] = "SET_QUIZ_RESULTS_CONFIG_ERROR";
|
|
28
30
|
})(QuizAPIActionTypes || (QuizAPIActionTypes = {}));
|
|
@@ -12,7 +12,7 @@ import { convertPrimaryColorsToString, renderImages } from '../../utils';
|
|
|
12
12
|
import ProgressBar from '../ProgressBar/ProgressBar';
|
|
13
13
|
import { QuestionTypes } from './actions';
|
|
14
14
|
export default function CioQuiz(props) {
|
|
15
|
-
const { cioClient, state, events: { hydrateQuiz, resetSessionStorageState }, getAddToCartButtonProps, getAddToFavoritesButtonProps, getCoverQuestionProps, getHydrateQuizButtonProps, getNextQuestionButtonProps, getSkipQuestionButtonProps, getOpenTextInputProps, getPreviousQuestionButtonProps, getQuizImageProps, getQuizResultButtonProps, getQuizResultLinkProps, getResetQuizButtonProps, getSelectInputProps, primaryColorStyles, getShareResultsButtonProps, } = useQuiz(props);
|
|
15
|
+
const { cioClient, state, events: { hydrateQuiz, resetSessionStorageState }, getAddToCartButtonProps, getAddToFavoritesButtonProps, getCoverQuestionProps, getHydrateQuizButtonProps, getNextQuestionButtonProps, getSkipQuestionButtonProps, getJumpToQuestionButtonProps, getOpenTextInputProps, getPreviousQuestionButtonProps, getQuizImageProps, getQuizResultButtonProps, getQuizResultLinkProps, getResetQuizButtonProps, getSelectInputProps, primaryColorStyles, getShareResultsButtonProps, } = useQuiz(props);
|
|
16
16
|
const [showSessionPrompt, setShowSessionPrompt] = useState(false);
|
|
17
17
|
const [showShareModal, setShowShareModal] = useState(false);
|
|
18
18
|
const { callbacks, sessionStateOptions, questionsPageOptions, resultCardOptions, resultsPageOptions, } = props;
|
|
@@ -36,6 +36,7 @@ export default function CioQuiz(props) {
|
|
|
36
36
|
getHydrateQuizButtonProps,
|
|
37
37
|
getNextQuestionButtonProps,
|
|
38
38
|
getSkipQuestionButtonProps,
|
|
39
|
+
getJumpToQuestionButtonProps,
|
|
39
40
|
getOpenTextInputProps,
|
|
40
41
|
getPreviousQuestionButtonProps,
|
|
41
42
|
getQuizImageProps,
|
|
@@ -71,6 +71,14 @@ export default function apiReducer(state, action) {
|
|
|
71
71
|
selectedOptionsWithAttributes: action.payload?.quizResults.attributes,
|
|
72
72
|
};
|
|
73
73
|
}
|
|
74
|
+
case QuizAPIActionTypes.JUMP_TO_QUESTION: {
|
|
75
|
+
return {
|
|
76
|
+
...state,
|
|
77
|
+
quizResults: undefined,
|
|
78
|
+
selectedOptionsWithAttributes: undefined,
|
|
79
|
+
matchedOptions: undefined,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
74
82
|
case QuizAPIActionTypes.SET_QUIZ_RESULTS_CONFIG: {
|
|
75
83
|
return {
|
|
76
84
|
...state,
|
|
@@ -5,15 +5,6 @@ export const initialState = {
|
|
|
5
5
|
prevAnswerInputs: {},
|
|
6
6
|
isQuizCompleted: false,
|
|
7
7
|
};
|
|
8
|
-
function answerInputReducer(state, action) {
|
|
9
|
-
return {
|
|
10
|
-
...state,
|
|
11
|
-
[String(action.payload.questionId)]: {
|
|
12
|
-
type: action.type,
|
|
13
|
-
value: action.payload.input,
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
8
|
function handleNextQuestion(state) {
|
|
18
9
|
const { answers, answerInputs } = state;
|
|
19
10
|
const newAnswers = [...answers];
|
|
@@ -43,44 +34,27 @@ function handleNextQuestion(state) {
|
|
|
43
34
|
isQuizCompleted: false,
|
|
44
35
|
};
|
|
45
36
|
}
|
|
37
|
+
const handleAnswerInput = (state, action) => ({
|
|
38
|
+
...state,
|
|
39
|
+
answerInputs: {
|
|
40
|
+
...state.answerInputs,
|
|
41
|
+
[String(action.payload.questionId)]: {
|
|
42
|
+
type: action.type,
|
|
43
|
+
value: action.payload.input,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
isQuizCompleted: false,
|
|
47
|
+
});
|
|
48
|
+
// eslint-disable-next-line complexity
|
|
46
49
|
export default function quizLocalReducer(state, action) {
|
|
47
50
|
switch (action.type) {
|
|
48
51
|
case QuestionTypes.OpenText:
|
|
49
|
-
return {
|
|
50
|
-
...state,
|
|
51
|
-
answerInputs: answerInputReducer(state.answerInputs, action),
|
|
52
|
-
isQuizCompleted: false,
|
|
53
|
-
};
|
|
54
52
|
case QuestionTypes.Cover:
|
|
55
|
-
return {
|
|
56
|
-
...state,
|
|
57
|
-
answerInputs: answerInputReducer(state.answerInputs, action),
|
|
58
|
-
isQuizCompleted: false,
|
|
59
|
-
};
|
|
60
53
|
case QuestionTypes.SingleSelect:
|
|
61
|
-
return {
|
|
62
|
-
...state,
|
|
63
|
-
answerInputs: answerInputReducer(state.answerInputs, action),
|
|
64
|
-
isQuizCompleted: false,
|
|
65
|
-
};
|
|
66
54
|
case QuestionTypes.MultipleSelect:
|
|
67
|
-
return {
|
|
68
|
-
...state,
|
|
69
|
-
answerInputs: answerInputReducer(state.answerInputs, action),
|
|
70
|
-
isQuizCompleted: false,
|
|
71
|
-
};
|
|
72
55
|
case QuestionTypes.SingleFilterValue:
|
|
73
|
-
return {
|
|
74
|
-
...state,
|
|
75
|
-
answerInputs: answerInputReducer(state.answerInputs, action),
|
|
76
|
-
isQuizCompleted: false,
|
|
77
|
-
};
|
|
78
56
|
case QuestionTypes.MultipleFilterValues:
|
|
79
|
-
return
|
|
80
|
-
...state,
|
|
81
|
-
answerInputs: answerInputReducer(state.answerInputs, action),
|
|
82
|
-
isQuizCompleted: false,
|
|
83
|
-
};
|
|
57
|
+
return handleAnswerInput(state, action);
|
|
84
58
|
case QuestionTypes.Next: {
|
|
85
59
|
return handleNextQuestion(state);
|
|
86
60
|
}
|
|
@@ -120,6 +94,28 @@ export default function quizLocalReducer(state, action) {
|
|
|
120
94
|
isQuizCompleted: false,
|
|
121
95
|
};
|
|
122
96
|
}
|
|
97
|
+
case QuestionTypes.JumpToQuestion: {
|
|
98
|
+
const questionId = action.payload?.questionId;
|
|
99
|
+
if (questionId === undefined)
|
|
100
|
+
return state;
|
|
101
|
+
const prevAnswerInputs = { ...state.prevAnswerInputs };
|
|
102
|
+
// Remove all keys greater than questionId from answerInputs
|
|
103
|
+
const filteredAnswerInputs = {};
|
|
104
|
+
Object.keys(prevAnswerInputs).forEach((key) => {
|
|
105
|
+
if (parseInt(key, 10) >= questionId)
|
|
106
|
+
return;
|
|
107
|
+
filteredAnswerInputs[key] = prevAnswerInputs[key];
|
|
108
|
+
});
|
|
109
|
+
// Calculate the number of questions to keep (questions <= questionId)
|
|
110
|
+
const questionsToKeep = Object.keys(filteredAnswerInputs).length;
|
|
111
|
+
return {
|
|
112
|
+
...state,
|
|
113
|
+
answerInputs: filteredAnswerInputs,
|
|
114
|
+
prevAnswerInputs: filteredAnswerInputs,
|
|
115
|
+
answers: state.answers.slice(0, questionsToKeep),
|
|
116
|
+
isQuizCompleted: false,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
123
119
|
case QuestionTypes.Reset:
|
|
124
120
|
return {
|
|
125
121
|
...initialState,
|
|
@@ -6,13 +6,15 @@ import useNextQuestionButtonProps from './useNextQuestionButtonProps';
|
|
|
6
6
|
import usePreviousQuestionButtonProps from './usePreviousQuestionButtonProps';
|
|
7
7
|
import useAddToFavoritesButtonProps from './useAddToFavoritesButtonProps';
|
|
8
8
|
import useSkipQuestionButtonProps from './useSkipQuestionButtonProps';
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
import useJumpToQuestionButtonProps from './useJumpToQuestionButtonProps';
|
|
10
|
+
const usePropsGetters = ({ questionsPageOptions, favoriteItems, quizEvents, quizApiState, quizLocalState, }) => {
|
|
11
|
+
const { quizAnswerChanged, nextQuestion, skipQuestion, previousQuestion, resetQuiz, hydrateQuiz, addToCart, addToFavorites, resultClick, jumpToQuestion, } = quizEvents;
|
|
11
12
|
const getOpenTextInputProps = useOpenTextInputProps(quizAnswerChanged, nextQuestion, quizApiState.quizCurrentQuestion?.next_question, quizLocalState.answerInputs);
|
|
12
13
|
const getCoverQuestionProps = useCoverQuestionProps(quizAnswerChanged, quizApiState.quizCurrentQuestion?.next_question);
|
|
13
|
-
const getSelectInputProps = useSelectInputProps(quizAnswerChanged, nextQuestion, quizApiState.quizCurrentQuestion?.next_question, quizLocalState.answerInputs);
|
|
14
|
+
const getSelectInputProps = useSelectInputProps(quizAnswerChanged, nextQuestion, quizApiState.quizCurrentQuestion?.next_question, quizLocalState.answerInputs, questionsPageOptions?.nextQuestionOnSingleSelect);
|
|
14
15
|
const getNextQuestionButtonProps = useNextQuestionButtonProps(nextQuestion, quizApiState, quizLocalState);
|
|
15
16
|
const getSkipQuestionButtonProps = useSkipQuestionButtonProps(skipQuestion, quizApiState);
|
|
17
|
+
const getJumpToQuestionButtonProps = useJumpToQuestionButtonProps(jumpToQuestion, quizApiState, quizLocalState);
|
|
16
18
|
const getPreviousQuestionButtonProps = usePreviousQuestionButtonProps(quizApiState, previousQuestion);
|
|
17
19
|
const getResetQuizButtonProps = useCallback((stylesType = 'primary') => ({
|
|
18
20
|
className: stylesType === 'primary' ? 'cio-question-cta-button' : 'cio-question-redo-button',
|
|
@@ -75,6 +77,7 @@ const usePropsGetters = (quizEvents, quizApiState, quizLocalState, favoriteItems
|
|
|
75
77
|
getQuizResultButtonProps,
|
|
76
78
|
getQuizResultLinkProps,
|
|
77
79
|
getSkipQuestionButtonProps,
|
|
80
|
+
getJumpToQuestionButtonProps,
|
|
78
81
|
};
|
|
79
82
|
};
|
|
80
83
|
export default usePropsGetters;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
export default function useJumpToQuestionButtonProps(jumpToQuestion, quizApiState, quizLocalState) {
|
|
3
|
+
const getJumpToQuestionButtonProps = useCallback((id) => {
|
|
4
|
+
let buttonDisabled;
|
|
5
|
+
const currentQuestionId = quizApiState.quizCurrentQuestion?.next_question?.id;
|
|
6
|
+
const answerIds = Object.keys(quizLocalState.prevAnswerInputs);
|
|
7
|
+
const isInvalidQuestionId = answerIds && !answerIds.includes(String(id));
|
|
8
|
+
const isCurrentOrFutureQuestionId = currentQuestionId && id >= currentQuestionId;
|
|
9
|
+
if (isInvalidQuestionId || isCurrentOrFutureQuestionId) {
|
|
10
|
+
buttonDisabled = true;
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
className: buttonDisabled ? 'cio-question-cta-button disabled' : 'cio-question-cta-button',
|
|
14
|
+
tabIndex: buttonDisabled ? -1 : 0,
|
|
15
|
+
'aria-disabled': buttonDisabled ? 'true' : 'false',
|
|
16
|
+
'aria-describedby': buttonDisabled ? 'jump-to-button-help' : '',
|
|
17
|
+
disabled: !!buttonDisabled,
|
|
18
|
+
type: 'button',
|
|
19
|
+
onClick: () => {
|
|
20
|
+
jumpToQuestion(id);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}, [
|
|
24
|
+
quizLocalState.prevAnswerInputs,
|
|
25
|
+
quizApiState.quizCurrentQuestion?.next_question?.id,
|
|
26
|
+
jumpToQuestion,
|
|
27
|
+
]);
|
|
28
|
+
return getJumpToQuestionButtonProps;
|
|
29
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
2
2
|
import { QuestionTypes } from '../../components/CioQuiz/actions';
|
|
3
3
|
// eslint-disable-next-line max-params
|
|
4
|
-
export default function useSelectInputProps(quizAnswerChanged, nextQuestion, currentQuestionData, answerInputs) {
|
|
4
|
+
export default function useSelectInputProps(quizAnswerChanged, nextQuestion, currentQuestionData, answerInputs, nextQuestionOnSingleSelect = true) {
|
|
5
5
|
const type = currentQuestionData?.type;
|
|
6
6
|
const hasImages = currentQuestionData?.options?.some((option) => option.images);
|
|
7
7
|
const [selected, setSelected] = useState({});
|
|
@@ -78,7 +78,8 @@ export default function useSelectInputProps(quizAnswerChanged, nextQuestion, cur
|
|
|
78
78
|
useEffect(() => {
|
|
79
79
|
if ((currentQuestionData?.type === QuestionTypes.SingleSelect ||
|
|
80
80
|
currentQuestionData?.type === QuestionTypes.SingleFilterValue) &&
|
|
81
|
-
singleSelectClicked.current
|
|
81
|
+
singleSelectClicked.current &&
|
|
82
|
+
nextQuestionOnSingleSelect) {
|
|
82
83
|
nextQuestion();
|
|
83
84
|
}
|
|
84
85
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
package/lib/mjs/hooks/useQuiz.js
CHANGED
|
@@ -16,7 +16,13 @@ const useQuiz = (quizOptions) => {
|
|
|
16
16
|
const quizEvents = useQuizEvents(quizOptions, cioClient, quizState);
|
|
17
17
|
// Props getters
|
|
18
18
|
const { quizApiState, quizLocalState, quizSessionStorageState } = quizState;
|
|
19
|
-
const propGetters = usePropsGetters(
|
|
19
|
+
const propGetters = usePropsGetters({
|
|
20
|
+
quizEvents,
|
|
21
|
+
quizApiState,
|
|
22
|
+
quizLocalState,
|
|
23
|
+
favoriteItems: resultsPageOptions?.favoriteItems,
|
|
24
|
+
questionsPageOptions: quizOptions.questionsPageOptions,
|
|
25
|
+
});
|
|
20
26
|
const primaryColorStyles = usePrimaryColorStyles(primaryColor);
|
|
21
27
|
return {
|
|
22
28
|
cioClient,
|
|
@@ -9,6 +9,7 @@ import useHydrateQuizLocalState from './useHydrateQuizLocalState';
|
|
|
9
9
|
import { resetQuizSessionStorageState } from '../../utils';
|
|
10
10
|
import useQuizAddToFavorites from './useQuizAddToFavorites';
|
|
11
11
|
import useQuizSkipClick from './useQuizSkipClick';
|
|
12
|
+
import useJumpToQuestion from './useJumpToQuestion';
|
|
12
13
|
const useQuizEvents = (quizOptions, cioClient, quizState) => {
|
|
13
14
|
const { quizApiState, dispatchLocalState, dispatchApiState, quizLocalState, quizSessionStorageState, } = quizState;
|
|
14
15
|
const { callbacks } = quizOptions;
|
|
@@ -35,6 +36,11 @@ const useQuizEvents = (quizOptions, cioClient, quizState) => {
|
|
|
35
36
|
dispatchApiState,
|
|
36
37
|
quizResults: quizApiState.quizResults,
|
|
37
38
|
});
|
|
39
|
+
const jumpToQuestion = useJumpToQuestion({
|
|
40
|
+
dispatchLocalState,
|
|
41
|
+
dispatchApiState,
|
|
42
|
+
quizApiState,
|
|
43
|
+
});
|
|
38
44
|
// Quiz rehydrate
|
|
39
45
|
const hydrateQuizLocalState = useHydrateQuizLocalState(quizOptions.quizId, quizSessionStorageState, dispatchLocalState);
|
|
40
46
|
return {
|
|
@@ -46,6 +52,7 @@ const useQuizEvents = (quizOptions, cioClient, quizState) => {
|
|
|
46
52
|
nextQuestion,
|
|
47
53
|
skipQuestion,
|
|
48
54
|
resetQuiz,
|
|
55
|
+
jumpToQuestion,
|
|
49
56
|
hydrateQuiz: hydrateQuizLocalState,
|
|
50
57
|
resetSessionStorageState,
|
|
51
58
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { QuestionTypes, QuizAPIActionTypes, } from '../../components/CioQuiz/actions';
|
|
3
|
+
const useJumpToQuestion = (props) => {
|
|
4
|
+
const { dispatchLocalState, dispatchApiState, quizApiState } = props;
|
|
5
|
+
const quizJumpToQuestionClickHandler = useCallback((questionId) => {
|
|
6
|
+
const currentQuestionId = quizApiState.quizCurrentQuestion?.id;
|
|
7
|
+
if (questionId >= currentQuestionId) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
dispatchLocalState({
|
|
11
|
+
type: QuestionTypes.JumpToQuestion,
|
|
12
|
+
payload: { questionId },
|
|
13
|
+
});
|
|
14
|
+
dispatchApiState({
|
|
15
|
+
type: QuizAPIActionTypes.JUMP_TO_QUESTION,
|
|
16
|
+
payload: { questionId },
|
|
17
|
+
});
|
|
18
|
+
}, [quizApiState.quizCurrentQuestion?.id, dispatchLocalState, dispatchApiState]);
|
|
19
|
+
return quizJumpToQuestionClickHandler;
|
|
20
|
+
};
|
|
21
|
+
export default useJumpToQuestion;
|
|
@@ -89,7 +89,7 @@ const useQuizApiState = (quizOptions, cioClient, quizLocalState, skipToResults,
|
|
|
89
89
|
dispatchQuizResultsConfig();
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
|
-
const { onQuizResultsConfigLoaded } = callbacks;
|
|
92
|
+
const { onQuizResultsConfigLoaded } = callbacks || {};
|
|
93
93
|
if (onQuizResultsConfigLoaded && isFunction(onQuizResultsConfigLoaded)) {
|
|
94
94
|
onQuizResultsConfigLoaded(quizApiState.resultsConfig, quizApiState.metadata);
|
|
95
95
|
}
|