@constructor-io/constructorio-ui-quizzes 1.3.12 → 1.4.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 +20 -20
- package/lib/cjs/components/BackButton/BackButton.js +12 -7
- package/lib/cjs/components/CTAButton/CTAButton.js +4 -3
- package/lib/cjs/components/CioQuiz/actions.js +1 -0
- package/lib/cjs/components/CioQuiz/index.js +16 -9
- package/lib/cjs/components/CioQuiz/quizApiReducer.js +15 -9
- package/lib/cjs/components/CioQuiz/quizLocalReducer.js +36 -8
- package/lib/cjs/components/ControlBar/ControlBar.js +6 -4
- package/lib/cjs/components/CoverTypeQuestion/CoverTypeQuestion.js +2 -7
- package/lib/cjs/components/OpenTextTypeQuestion/OpenTextTypeQuestion.js +4 -32
- package/lib/cjs/components/RedoButton/RedoButton.js +11 -4
- package/lib/cjs/components/ResultCard/ResultCard.js +3 -18
- package/lib/cjs/components/ResultContainer/ResultContainer.js +2 -2
- package/lib/cjs/components/ResultCtaButton/ResultCtaButton.js +8 -7
- package/lib/cjs/components/ResultHeroCard/ResultHeroCard.js +36 -0
- package/lib/cjs/components/SelectTypeQuestion/SelectTypeQuestion.js +6 -56
- package/lib/cjs/components/SessionPromptModal/SessionPromptModal.js +18 -6
- package/lib/cjs/components/ZeroResults/ZeroResults.js +5 -4
- package/lib/cjs/constants.js +40 -5
- package/lib/cjs/hooks/useConsoleErrors.js +2 -1
- package/lib/cjs/hooks/usePropsGetters/index.js +85 -0
- package/lib/cjs/hooks/usePropsGetters/useCoverQuestionProps.js +13 -0
- package/lib/cjs/hooks/usePropsGetters/useNextQuestionButtonProps.js +24 -0
- package/lib/cjs/hooks/usePropsGetters/useOpenTextInputProps.js +47 -0
- package/lib/cjs/hooks/usePropsGetters/usePreviousQuestionButtonProps.js +18 -0
- package/lib/cjs/hooks/usePropsGetters/useSelectInputProps.js +84 -0
- package/lib/cjs/hooks/useQuiz.js +14 -28
- package/lib/cjs/hooks/useQuizEvents/index.js +21 -16
- package/lib/cjs/hooks/useQuizEvents/useHydrateQuizLocalState.js +18 -0
- package/lib/cjs/hooks/useQuizEvents/useQuizAddToCart.js +2 -2
- package/lib/cjs/hooks/useQuizEvents/useQuizAnswerChangeHandler.js +48 -0
- package/lib/cjs/hooks/useQuizEvents/useQuizBackClick.js +5 -5
- package/lib/cjs/hooks/useQuizEvents/useQuizNextClick.js +13 -39
- package/lib/cjs/hooks/useQuizEvents/useQuizResetClick.js +20 -0
- package/lib/cjs/hooks/useQuizEvents/useQuizResultClick.js +2 -2
- package/lib/cjs/hooks/useQuizState/index.js +21 -0
- package/lib/cjs/hooks/{useQuizApiState.js → useQuizState/useQuizApiState.js} +15 -29
- package/lib/cjs/hooks/useQuizState/useQuizLocalState.js +30 -0
- package/lib/cjs/index.js +25 -0
- package/lib/cjs/services/index.js +3 -3
- package/lib/cjs/stories/Quiz/tests/mocks.js +69 -14
- package/lib/cjs/utils.js +23 -1
- package/lib/mjs/components/BackButton/BackButton.js +12 -7
- package/lib/mjs/components/CTAButton/CTAButton.js +4 -3
- package/lib/mjs/components/CioQuiz/actions.js +1 -0
- package/lib/mjs/components/CioQuiz/index.js +16 -9
- package/lib/mjs/components/CioQuiz/quizApiReducer.js +19 -7
- package/lib/mjs/components/CioQuiz/quizLocalReducer.js +36 -7
- package/lib/mjs/components/ControlBar/ControlBar.js +6 -4
- package/lib/mjs/components/CoverTypeQuestion/CoverTypeQuestion.js +2 -7
- package/lib/mjs/components/OpenTextTypeQuestion/OpenTextTypeQuestion.js +5 -32
- package/lib/mjs/components/RedoButton/RedoButton.js +11 -4
- package/lib/mjs/components/ResultCard/ResultCard.js +3 -15
- package/lib/mjs/components/ResultContainer/ResultContainer.js +2 -2
- package/lib/mjs/components/ResultCtaButton/ResultCtaButton.js +8 -7
- package/lib/mjs/components/ResultHeroCard/ResultHeroCard.js +31 -0
- package/lib/mjs/components/SelectTypeQuestion/SelectTypeQuestion.js +6 -55
- package/lib/mjs/components/SessionPromptModal/SessionPromptModal.js +18 -6
- package/lib/mjs/components/ZeroResults/ZeroResults.js +5 -4
- package/lib/mjs/constants.js +39 -4
- package/lib/mjs/hooks/useConsoleErrors.js +2 -1
- package/lib/mjs/hooks/usePropsGetters/index.js +72 -0
- package/lib/mjs/hooks/usePropsGetters/useCoverQuestionProps.js +10 -0
- package/lib/mjs/hooks/usePropsGetters/useNextQuestionButtonProps.js +20 -0
- package/lib/mjs/hooks/usePropsGetters/useOpenTextInputProps.js +43 -0
- package/lib/mjs/hooks/usePropsGetters/usePreviousQuestionButtonProps.js +14 -0
- package/lib/mjs/hooks/usePropsGetters/useSelectInputProps.js +79 -0
- package/lib/mjs/hooks/useQuiz.js +13 -21
- package/lib/mjs/hooks/useQuizEvents/index.js +21 -16
- package/lib/mjs/hooks/useQuizEvents/useHydrateQuizLocalState.js +16 -0
- package/lib/mjs/hooks/useQuizEvents/useQuizAddToCart.js +2 -2
- package/lib/mjs/hooks/useQuizEvents/useQuizAnswerChangeHandler.js +45 -0
- package/lib/mjs/hooks/useQuizEvents/useQuizBackClick.js +5 -5
- package/lib/mjs/hooks/useQuizEvents/useQuizNextClick.js +12 -38
- package/lib/mjs/hooks/useQuizEvents/useQuizResetClick.js +18 -0
- package/lib/mjs/hooks/useQuizEvents/useQuizResultClick.js +2 -2
- package/lib/mjs/hooks/useQuizState/index.js +18 -0
- package/lib/mjs/hooks/{useQuizApiState.js → useQuizState/useQuizApiState.js} +15 -28
- package/lib/mjs/hooks/useQuizState/useQuizLocalState.js +26 -0
- package/lib/mjs/index.js +14 -0
- package/lib/mjs/services/index.js +1 -1
- package/lib/mjs/stories/Quiz/tests/mocks.js +75 -12
- package/lib/mjs/utils.js +17 -0
- package/lib/styles.css +4 -0
- package/lib/types/components/BackButton/BackButton.d.ts +2 -2
- package/lib/types/components/CTAButton/CTAButton.d.ts +1 -0
- package/lib/types/components/CioQuiz/actions.d.ts +5 -6
- package/lib/types/components/CioQuiz/context.d.ts +13 -6
- package/lib/types/components/CioQuiz/quizApiReducer.d.ts +2 -2
- package/lib/types/components/CioQuiz/quizLocalReducer.d.ts +3 -5
- package/lib/types/components/ControlBar/ControlBar.d.ts +0 -4
- package/lib/types/components/OpenTextTypeQuestion/OpenTextTypeQuestion.d.ts +2 -6
- package/lib/types/components/RedoButton/RedoButton.d.ts +1 -1
- package/lib/types/components/ResultCtaButton/ResultCtaButton.d.ts +1 -2
- package/lib/types/components/ResultHeroCard/ResultHeroCard.d.ts +7 -0
- package/lib/types/components/SelectTypeQuestion/SelectTypeQuestion.d.ts +3 -0
- package/lib/types/components/ZeroResults/ZeroResults.d.ts +2 -5
- package/lib/types/constants.d.ts +5 -4
- package/lib/types/hooks/useConsoleErrors.d.ts +2 -2
- package/lib/types/hooks/usePropsGetters/index.d.ts +18 -0
- package/lib/types/hooks/usePropsGetters/useCoverQuestionProps.d.ts +2 -0
- package/lib/types/hooks/usePropsGetters/useNextQuestionButtonProps.d.ts +4 -0
- package/lib/types/hooks/usePropsGetters/useOpenTextInputProps.d.ts +2 -0
- package/lib/types/hooks/usePropsGetters/usePreviousQuestionButtonProps.d.ts +3 -0
- package/lib/types/hooks/usePropsGetters/useSelectInputProps.d.ts +2 -0
- package/lib/types/hooks/useQuizEvents/index.d.ts +4 -16
- package/lib/types/hooks/useQuizEvents/useHydrateQuizLocalState.d.ts +4 -0
- package/lib/types/hooks/useQuizEvents/useQuizAnswerChangeHandler.d.ts +5 -0
- package/lib/types/hooks/useQuizEvents/useQuizBackClick.d.ts +2 -1
- package/lib/types/hooks/useQuizEvents/useQuizNextClick.d.ts +2 -1
- package/lib/types/hooks/useQuizEvents/useQuizResetClick.d.ts +4 -0
- package/lib/types/hooks/useQuizState/index.d.ts +16 -0
- package/lib/types/hooks/useQuizState/useQuizApiState.d.ts +12 -0
- package/lib/types/hooks/useQuizState/useQuizLocalState.d.ts +8 -0
- package/lib/types/index.d.ts +11 -0
- package/lib/types/services/index.d.ts +1 -1
- package/lib/types/stories/Quiz/tests/mocks.d.ts +5 -2
- package/lib/types/types.d.ts +121 -11
- package/lib/types/utils.d.ts +4 -0
- package/package.json +1 -1
- package/lib/cjs/hooks/useQuizLocalState.js +0 -54
- package/lib/mjs/hooks/useQuizLocalState.js +0 -48
- package/lib/types/hooks/useQuizApiState.d.ts +0 -11
- package/lib/types/hooks/useQuizLocalState.d.ts +0 -10
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import { QuestionTypes } from '../../components/CioQuiz/actions';
|
|
3
|
+
// eslint-disable-next-line max-params
|
|
4
|
+
export default function useSelectInputProps(quizAnswerChanged, nextQuestion, currentQuestionData, answerInputs) {
|
|
5
|
+
const type = currentQuestionData?.type;
|
|
6
|
+
const hasImages = currentQuestionData?.options?.some((option) => option.images);
|
|
7
|
+
const [selected, setSelected] = useState({});
|
|
8
|
+
const singleSelectClicked = useRef({});
|
|
9
|
+
const toggleIdSelected = useCallback((id) => {
|
|
10
|
+
if (type === QuestionTypes.SingleSelect) {
|
|
11
|
+
singleSelectClicked.current = true;
|
|
12
|
+
setSelected({ [id]: true });
|
|
13
|
+
}
|
|
14
|
+
else if (type === QuestionTypes.MultipleSelect) {
|
|
15
|
+
if (selected[id]) {
|
|
16
|
+
const newState = { ...selected };
|
|
17
|
+
delete newState[id];
|
|
18
|
+
setSelected(newState);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
setSelected({ ...selected, [id]: true });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}, [selected, type]);
|
|
25
|
+
const onOptionKeyDown = (event, id) => {
|
|
26
|
+
if (event?.key === ' ' || event?.key === 'Enter') {
|
|
27
|
+
toggleIdSelected(id);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
// Update component local state
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (currentQuestionData?.type) {
|
|
33
|
+
const nextQuestionId = currentQuestionData.id;
|
|
34
|
+
const currentAnswer = answerInputs?.[nextQuestionId];
|
|
35
|
+
const prevSelected = {};
|
|
36
|
+
if (Array.isArray(currentAnswer?.value)) {
|
|
37
|
+
currentAnswer?.value?.forEach((answer) => {
|
|
38
|
+
prevSelected[Number(answer)] = true;
|
|
39
|
+
setSelected(prevSelected);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
singleSelectClicked.current = false;
|
|
44
|
+
return function clearState() {
|
|
45
|
+
setSelected({});
|
|
46
|
+
};
|
|
47
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
48
|
+
}, [currentQuestionData?.id]);
|
|
49
|
+
// Update global state
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (currentQuestionData?.type === 'multiple' || currentQuestionData?.type === 'single') {
|
|
52
|
+
const selectedAnswers = Object.keys(selected).filter((key) => selected[Number(key)]);
|
|
53
|
+
quizAnswerChanged(selectedAnswers);
|
|
54
|
+
}
|
|
55
|
+
}, [selected, currentQuestionData?.id, currentQuestionData?.type, quizAnswerChanged]);
|
|
56
|
+
// Go to next question only every time answerInputs (answers input state) changes...
|
|
57
|
+
// and it's a singleSelectQuestion and user has just clicked on an option
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (currentQuestionData?.type === 'single' && singleSelectClicked.current) {
|
|
60
|
+
nextQuestion();
|
|
61
|
+
}
|
|
62
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
63
|
+
}, [answerInputs]);
|
|
64
|
+
const getSelectInputProps = useCallback((option) => ({
|
|
65
|
+
className: `${!hasImages ? 'cio-question-option-container-text-only' : 'cio-question-option-container'} ${selected[option.id] ? 'selected' : ''}`,
|
|
66
|
+
onClick: () => {
|
|
67
|
+
toggleIdSelected(option.id);
|
|
68
|
+
},
|
|
69
|
+
onKeyDown: (event) => {
|
|
70
|
+
onOptionKeyDown(event, option.id);
|
|
71
|
+
},
|
|
72
|
+
role: 'button',
|
|
73
|
+
tabIndex: 0,
|
|
74
|
+
key: option.id,
|
|
75
|
+
}),
|
|
76
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
77
|
+
[currentQuestionData?.id, selected]);
|
|
78
|
+
return getSelectInputProps;
|
|
79
|
+
}
|
package/lib/mjs/hooks/useQuiz.js
CHANGED
|
@@ -1,31 +1,24 @@
|
|
|
1
1
|
import useCioClient from './useCioClient';
|
|
2
2
|
import useConsoleErrors from './useConsoleErrors';
|
|
3
|
+
import usePropsGetters from './usePropsGetters';
|
|
3
4
|
import usePrimaryColorStyles from './usePrimaryColorStyles';
|
|
4
|
-
import useQuizApiState from './useQuizApiState';
|
|
5
5
|
import useQuizEvents from './useQuizEvents';
|
|
6
|
-
import
|
|
7
|
-
const useQuiz = (
|
|
6
|
+
import useQuizState from './useQuizState';
|
|
7
|
+
const useQuiz = (quizOptions) => {
|
|
8
|
+
const { apiKey, cioJsClient, primaryColor } = quizOptions;
|
|
8
9
|
// Log console errors for required parameters quizId and resultsPageOptions
|
|
9
|
-
useConsoleErrors(
|
|
10
|
-
// Quiz Local state
|
|
11
|
-
const { quizLocalState, resetQuizLocalState, dispatchLocalState, hydrateQuizLocalState, hasQuizStoredState, resetQuizStoredState, } = useQuizLocalState(sessionStateOptions?.sessionStateKey);
|
|
10
|
+
useConsoleErrors(quizOptions);
|
|
12
11
|
// Quiz Cio Client
|
|
13
12
|
const cioClient = useCioClient({ apiKey, cioJsClient });
|
|
14
|
-
// Quiz API
|
|
15
|
-
const
|
|
13
|
+
// Quiz state (Local and API)
|
|
14
|
+
const quizState = useQuizState(quizOptions, cioClient);
|
|
16
15
|
// Quiz callback events
|
|
17
|
-
const quizEvents = useQuizEvents(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
dispatchLocalState,
|
|
22
|
-
resetQuizApiState,
|
|
23
|
-
resetQuizLocalState,
|
|
24
|
-
hydrateQuizLocalState,
|
|
25
|
-
resetQuizStoredState,
|
|
26
|
-
hasQuizStoredState,
|
|
27
|
-
});
|
|
16
|
+
const quizEvents = useQuizEvents(quizOptions, cioClient, quizState);
|
|
17
|
+
// Props getters
|
|
18
|
+
const { quizApiState, quizLocalState } = quizState;
|
|
19
|
+
const propGetters = usePropsGetters(quizEvents, quizApiState, quizLocalState);
|
|
28
20
|
const primaryColorStyles = usePrimaryColorStyles(primaryColor);
|
|
21
|
+
console.log('quizLocalState.answerInputs', quizLocalState.answerInputs);
|
|
29
22
|
return {
|
|
30
23
|
cioClient,
|
|
31
24
|
state: {
|
|
@@ -37,16 +30,15 @@ const useQuiz = ({ quizId, apiKey, cioJsClient, quizVersionId, resultsPageOption
|
|
|
37
30
|
requestState: quizApiState.quizRequestState,
|
|
38
31
|
versionId: quizLocalState.quizVersionId,
|
|
39
32
|
sessionId: quizLocalState.quizSessionId,
|
|
40
|
-
firstQuestion: quizApiState.quizFirstQuestion,
|
|
41
33
|
currentQuestion: quizApiState.quizCurrentQuestion,
|
|
42
34
|
results: quizApiState.quizResults,
|
|
43
35
|
resultsFilters: quizApiState.quizResultsFilters,
|
|
44
|
-
isFirstQuestion,
|
|
45
36
|
},
|
|
46
37
|
},
|
|
47
38
|
events: {
|
|
48
39
|
...quizEvents,
|
|
49
40
|
},
|
|
41
|
+
...propGetters,
|
|
50
42
|
primaryColorStyles,
|
|
51
43
|
};
|
|
52
44
|
};
|
|
@@ -1,37 +1,42 @@
|
|
|
1
1
|
import useQuizResultsLoaded from './useQuizResultsLoaded';
|
|
2
2
|
import useQuizResultClick from './useQuizResultClick';
|
|
3
3
|
import useQuizAddToCart from './useQuizAddToCart';
|
|
4
|
-
import useQuizNextClick from './useQuizNextClick';
|
|
5
4
|
import useQuizBackClick from './useQuizBackClick';
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import useQuizAnswerChangeHandler from './useQuizAnswerChangeHandler';
|
|
6
|
+
import useQuizNextClick from './useQuizNextClick';
|
|
7
|
+
import useQuizResetClick from './useQuizResetClick';
|
|
8
|
+
import useHydrateQuizLocalState from './useHydrateQuizLocalState';
|
|
9
|
+
import { resetQuizSessionStorageState } from '../../utils';
|
|
10
|
+
const useQuizEvents = (quizOptions, cioClient, quizState) => {
|
|
11
|
+
const { quizApiState, dispatchLocalState, dispatchApiState, hasQuizStoredState, quizStateKey, quizLocalState, } = quizState;
|
|
12
|
+
const { resultsPageOptions } = quizOptions;
|
|
8
13
|
const { onAddToCartClick, onQuizResultClick, onQuizResultsLoaded } = resultsPageOptions;
|
|
9
|
-
// Quiz
|
|
10
|
-
const
|
|
14
|
+
// Quiz answer change
|
|
15
|
+
const quizAnswerChanged = useQuizAnswerChangeHandler(quizApiState, dispatchLocalState);
|
|
16
|
+
// Quiz Next button click callback
|
|
17
|
+
const nextQuestion = useQuizNextClick(quizApiState, quizLocalState, dispatchLocalState);
|
|
11
18
|
// Quiz Back button click callback
|
|
12
|
-
const previousQuestion = useQuizBackClick(dispatchLocalState);
|
|
19
|
+
const previousQuestion = useQuizBackClick(quizApiState, dispatchLocalState);
|
|
13
20
|
// Quiz result add to cart callback
|
|
14
21
|
const addToCart = useQuizAddToCart(cioClient, quizApiState, onAddToCartClick);
|
|
15
22
|
// Quiz result click callback
|
|
16
23
|
const resultClick = useQuizResultClick(cioClient, quizApiState, onQuizResultClick);
|
|
17
24
|
// Quiz results loaded event
|
|
18
25
|
useQuizResultsLoaded(cioClient, quizApiState, onQuizResultsLoaded);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
resetQuizStoredState();
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
+
// Quiz reset
|
|
27
|
+
const resetQuiz = useQuizResetClick(quizStateKey, dispatchLocalState, dispatchApiState, quizApiState.quizResults);
|
|
28
|
+
// Quiz rehydrate
|
|
29
|
+
const hydrateQuizLocalState = useHydrateQuizLocalState(quizStateKey, dispatchLocalState);
|
|
26
30
|
return {
|
|
27
31
|
addToCart,
|
|
28
32
|
resultClick,
|
|
29
|
-
|
|
33
|
+
quizAnswerChanged,
|
|
30
34
|
previousQuestion,
|
|
35
|
+
nextQuestion,
|
|
31
36
|
resetQuiz,
|
|
32
37
|
hydrateQuiz: hydrateQuizLocalState,
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
hasSessionStorageState: hasQuizStoredState,
|
|
39
|
+
resetSessionStorageState: resetQuizSessionStorageState(quizStateKey),
|
|
35
40
|
};
|
|
36
41
|
};
|
|
37
42
|
export default useQuizEvents;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { QuestionTypes } from '../../components/CioQuiz/actions';
|
|
3
|
+
import { getStateFromSessionStorage } from '../../utils';
|
|
4
|
+
const useHydrateQuizLocalState = (quizStateKey, dispatchLocalState) => {
|
|
5
|
+
const quizState = getStateFromSessionStorage(quizStateKey);
|
|
6
|
+
const hydrateQuizLocalStateHandler = useCallback(() => {
|
|
7
|
+
if (quizState) {
|
|
8
|
+
dispatchLocalState({
|
|
9
|
+
type: QuestionTypes.Hydrate,
|
|
10
|
+
payload: quizState,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}, [dispatchLocalState, quizState]);
|
|
14
|
+
return hydrateQuizLocalStateHandler;
|
|
15
|
+
};
|
|
16
|
+
export default useHydrateQuizLocalState;
|
|
@@ -2,7 +2,7 @@ import { useCallback } from 'react';
|
|
|
2
2
|
import { trackQuizConversion } from '../../services';
|
|
3
3
|
import { isFunction } from '../../utils';
|
|
4
4
|
const useQuizAddToCart = (cioClient, quizApiState, onAddToCartClick) => {
|
|
5
|
-
const
|
|
5
|
+
const quizAddToCartClickHandler = useCallback((e, result, price) => {
|
|
6
6
|
e.preventDefault();
|
|
7
7
|
if (quizApiState.quizResults) {
|
|
8
8
|
// Tracking call
|
|
@@ -13,6 +13,6 @@ const useQuizAddToCart = (cioClient, quizApiState, onAddToCartClick) => {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
}, [quizApiState, cioClient, onAddToCartClick]);
|
|
16
|
-
return
|
|
16
|
+
return quizAddToCartClickHandler;
|
|
17
17
|
};
|
|
18
18
|
export default useQuizAddToCart;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { QuestionTypes } from '../../components/CioQuiz/actions';
|
|
3
|
+
const useQuizAnswerChangeHandler = (quizApiState, dispatchLocalState) => {
|
|
4
|
+
const quizAnswerChangedHandler = useCallback((payload) => {
|
|
5
|
+
const questionType = quizApiState.quizCurrentQuestion?.next_question.type;
|
|
6
|
+
const currentQuestion = quizApiState.quizCurrentQuestion;
|
|
7
|
+
switch (questionType) {
|
|
8
|
+
case QuestionTypes.Cover:
|
|
9
|
+
dispatchLocalState({
|
|
10
|
+
type: QuestionTypes.Cover,
|
|
11
|
+
payload: {
|
|
12
|
+
questionId: currentQuestion.next_question.id,
|
|
13
|
+
input: '',
|
|
14
|
+
isLastQuestion: currentQuestion.is_last_question,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
break;
|
|
18
|
+
case QuestionTypes.OpenText:
|
|
19
|
+
dispatchLocalState({
|
|
20
|
+
type: QuestionTypes.OpenText,
|
|
21
|
+
payload: {
|
|
22
|
+
questionId: currentQuestion.next_question.id,
|
|
23
|
+
input: payload,
|
|
24
|
+
isLastQuestion: currentQuestion.is_last_question,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
break;
|
|
28
|
+
case QuestionTypes.SingleSelect:
|
|
29
|
+
case QuestionTypes.MultipleSelect:
|
|
30
|
+
dispatchLocalState({
|
|
31
|
+
type: currentQuestion.next_question.type,
|
|
32
|
+
payload: {
|
|
33
|
+
questionId: currentQuestion.next_question.id,
|
|
34
|
+
input: payload,
|
|
35
|
+
isLastQuestion: currentQuestion.is_last_question,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
break;
|
|
39
|
+
default:
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}, [quizApiState, dispatchLocalState]);
|
|
43
|
+
return quizAnswerChangedHandler;
|
|
44
|
+
};
|
|
45
|
+
export default useQuizAnswerChangeHandler;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
2
|
import { QuestionTypes } from '../../components/CioQuiz/actions';
|
|
3
|
-
const useQuizBackClick = (dispatchLocalState) => {
|
|
4
|
-
const
|
|
3
|
+
const useQuizBackClick = (quizApiState, dispatchLocalState) => {
|
|
4
|
+
const quizBackClickHandler = useCallback(() => {
|
|
5
5
|
if (dispatchLocalState) {
|
|
6
|
-
dispatchLocalState({ type: QuestionTypes.Back });
|
|
6
|
+
dispatchLocalState({ type: QuestionTypes.Back, payload: quizApiState.quizCurrentQuestion });
|
|
7
7
|
}
|
|
8
|
-
}, [dispatchLocalState]);
|
|
9
|
-
return
|
|
8
|
+
}, [dispatchLocalState, quizApiState.quizCurrentQuestion]);
|
|
9
|
+
return quizBackClickHandler;
|
|
10
10
|
};
|
|
11
11
|
export default useQuizBackClick;
|
|
@@ -1,45 +1,19 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
2
|
import { QuestionTypes } from '../../components/CioQuiz/actions';
|
|
3
|
-
const useQuizNextClick = (quizApiState, dispatchLocalState) => {
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
const useQuizNextClick = (quizApiState, quizLocalState, dispatchLocalState) => {
|
|
4
|
+
const quizNexClickHandler = useCallback(() => {
|
|
5
|
+
const currentQuestion = quizApiState.quizCurrentQuestion?.next_question;
|
|
6
|
+
const currentQuestionId = currentQuestion?.id;
|
|
7
|
+
if (dispatchLocalState && currentQuestionId) {
|
|
8
|
+
const currentAnswerInput = quizLocalState.answerInputs[currentQuestionId];
|
|
9
|
+
if (currentAnswerInput?.value?.length || currentQuestion?.type === 'cover') {
|
|
9
10
|
dispatchLocalState({
|
|
10
|
-
type: QuestionTypes.
|
|
11
|
-
payload:
|
|
12
|
-
isLastQuestion: currentQuestion.is_last_question,
|
|
13
|
-
},
|
|
11
|
+
type: QuestionTypes.Next,
|
|
12
|
+
payload: quizApiState.quizCurrentQuestion,
|
|
14
13
|
});
|
|
15
|
-
|
|
16
|
-
case QuestionTypes.OpenText:
|
|
17
|
-
dispatchLocalState({
|
|
18
|
-
type: QuestionTypes.OpenText,
|
|
19
|
-
payload: {
|
|
20
|
-
questionId: currentQuestion.next_question.id,
|
|
21
|
-
input: payload,
|
|
22
|
-
isLastQuestion: currentQuestion.is_last_question,
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
break;
|
|
26
|
-
case QuestionTypes.SingleSelect:
|
|
27
|
-
case QuestionTypes.MultipleSelect:
|
|
28
|
-
dispatchLocalState({
|
|
29
|
-
type: currentQuestion.next_question.type === QuestionTypes.SingleSelect
|
|
30
|
-
? QuestionTypes.SingleSelect
|
|
31
|
-
: QuestionTypes.MultipleSelect,
|
|
32
|
-
payload: {
|
|
33
|
-
questionId: currentQuestion.next_question.id,
|
|
34
|
-
input: payload,
|
|
35
|
-
isLastQuestion: currentQuestion.is_last_question,
|
|
36
|
-
},
|
|
37
|
-
});
|
|
38
|
-
break;
|
|
39
|
-
default:
|
|
40
|
-
break;
|
|
14
|
+
}
|
|
41
15
|
}
|
|
42
|
-
}, [quizApiState,
|
|
43
|
-
return
|
|
16
|
+
}, [dispatchLocalState, quizApiState.quizCurrentQuestion, quizLocalState.answerInputs]);
|
|
17
|
+
return quizNexClickHandler;
|
|
44
18
|
};
|
|
45
19
|
export default useQuizNextClick;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { QuestionTypes, QuizAPIActionTypes, } from '../../components/CioQuiz/actions';
|
|
3
|
+
import { resetQuizSessionStorageState } from '../../utils';
|
|
4
|
+
const useQuizResetClick = (quizStateKey, dispatchLocalState, dispatchApiState, quizResults) => {
|
|
5
|
+
const quizResetClickHandler = useCallback(() => {
|
|
6
|
+
if (quizResults) {
|
|
7
|
+
dispatchLocalState({
|
|
8
|
+
type: QuestionTypes.Reset,
|
|
9
|
+
});
|
|
10
|
+
dispatchApiState({
|
|
11
|
+
type: QuizAPIActionTypes.RESET_QUIZ,
|
|
12
|
+
});
|
|
13
|
+
resetQuizSessionStorageState(quizStateKey);
|
|
14
|
+
}
|
|
15
|
+
}, [dispatchLocalState, dispatchApiState, quizStateKey, quizResults]);
|
|
16
|
+
return quizResetClickHandler;
|
|
17
|
+
};
|
|
18
|
+
export default useQuizResetClick;
|
|
@@ -2,7 +2,7 @@ import { useCallback } from 'react';
|
|
|
2
2
|
import { trackQuizResultClick } from '../../services';
|
|
3
3
|
import { isFunction } from '../../utils';
|
|
4
4
|
const useQuizResultClick = (cioClient, quizApiState, onQuizResultClick) => {
|
|
5
|
-
const
|
|
5
|
+
const quizResultClickHandler = useCallback((result, position) => {
|
|
6
6
|
if (quizApiState.quizResults) {
|
|
7
7
|
// Tracking call
|
|
8
8
|
trackQuizResultClick(cioClient, quizApiState.quizResults, result, position);
|
|
@@ -12,6 +12,6 @@ const useQuizResultClick = (cioClient, quizApiState, onQuizResultClick) => {
|
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
}, [quizApiState, cioClient, onQuizResultClick]);
|
|
15
|
-
return
|
|
15
|
+
return quizResultClickHandler;
|
|
16
16
|
};
|
|
17
17
|
export default useQuizResultClick;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import useQuizApiState from './useQuizApiState';
|
|
2
|
+
import useQuizLocalState from './useQuizLocalState';
|
|
3
|
+
const useQuizState = (quizOptions, cioClient) => {
|
|
4
|
+
const { sessionStateOptions } = quizOptions;
|
|
5
|
+
// Quiz Local state
|
|
6
|
+
const { quizLocalState, dispatchLocalState, hasQuizStoredState, quizStateKey } = useQuizLocalState(sessionStateOptions?.sessionStateKey);
|
|
7
|
+
// Quiz API state
|
|
8
|
+
const { quizApiState, dispatchApiState } = useQuizApiState(quizOptions, cioClient, quizLocalState, dispatchLocalState);
|
|
9
|
+
return {
|
|
10
|
+
quizApiState,
|
|
11
|
+
quizLocalState,
|
|
12
|
+
dispatchApiState,
|
|
13
|
+
dispatchLocalState,
|
|
14
|
+
hasQuizStoredState,
|
|
15
|
+
quizStateKey,
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export default useQuizState;
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { useEffect, useReducer } from 'react';
|
|
2
|
-
import { QuestionTypes, QuizAPIActionTypes, } from '
|
|
3
|
-
import apiReducer, { initialState } from '
|
|
4
|
-
import {
|
|
5
|
-
const
|
|
6
|
-
const [quizApiState,
|
|
7
|
-
const
|
|
8
|
-
const currentQuestionId = quizApiState.quizCurrentQuestion?.next_question.id;
|
|
9
|
-
const isFirstQuestion = firstQuestionId === currentQuestionId;
|
|
2
|
+
import { QuestionTypes, QuizAPIActionTypes, } from '../../components/CioQuiz/actions';
|
|
3
|
+
import apiReducer, { initialState, } from '../../components/CioQuiz/quizApiReducer';
|
|
4
|
+
import { getNextQuestion, getQuizResults } from '../../services';
|
|
5
|
+
const useQuizApiState = (quizOptions, cioClient, quizLocalState, dispatchLocalState) => {
|
|
6
|
+
const [quizApiState, dispatchApiState] = useReducer(apiReducer, initialState);
|
|
7
|
+
const { quizId, quizVersionId: quizVersionIdProp, resultsPageOptions } = quizOptions;
|
|
10
8
|
useEffect(() => {
|
|
11
9
|
(async () => {
|
|
12
|
-
|
|
10
|
+
dispatchApiState({
|
|
13
11
|
type: QuizAPIActionTypes.SET_IS_LOADING,
|
|
14
12
|
});
|
|
15
13
|
if (quizLocalState.isLastAnswer) {
|
|
@@ -21,7 +19,7 @@ const useFetchQuiz = (quizId, quizLocalState, dispatchLocalState, resultsPageOpt
|
|
|
21
19
|
quizSessionId: quizLocalState.quizSessionId,
|
|
22
20
|
});
|
|
23
21
|
// Set quiz results state
|
|
24
|
-
|
|
22
|
+
dispatchApiState({
|
|
25
23
|
type: QuizAPIActionTypes.SET_QUIZ_RESULTS,
|
|
26
24
|
payload: {
|
|
27
25
|
quizResults,
|
|
@@ -29,7 +27,7 @@ const useFetchQuiz = (quizId, quizLocalState, dispatchLocalState, resultsPageOpt
|
|
|
29
27
|
});
|
|
30
28
|
}
|
|
31
29
|
catch (error) {
|
|
32
|
-
|
|
30
|
+
dispatchApiState({
|
|
33
31
|
type: QuizAPIActionTypes.SET_IS_ERROR,
|
|
34
32
|
});
|
|
35
33
|
}
|
|
@@ -38,7 +36,7 @@ const useFetchQuiz = (quizId, quizLocalState, dispatchLocalState, resultsPageOpt
|
|
|
38
36
|
try {
|
|
39
37
|
const quizVersionId = quizLocalState.quizVersionId || quizVersionIdProp;
|
|
40
38
|
const { quizSessionId } = quizLocalState;
|
|
41
|
-
const questionResult = await
|
|
39
|
+
const questionResult = await getNextQuestion(cioClient, quizId, {
|
|
42
40
|
answers: quizLocalState.answers,
|
|
43
41
|
quizVersionId,
|
|
44
42
|
quizSessionId,
|
|
@@ -55,7 +53,7 @@ const useFetchQuiz = (quizId, quizLocalState, dispatchLocalState, resultsPageOpt
|
|
|
55
53
|
});
|
|
56
54
|
}
|
|
57
55
|
// Set current question state
|
|
58
|
-
|
|
56
|
+
dispatchApiState({
|
|
59
57
|
type: QuizAPIActionTypes.SET_CURRENT_QUESTION,
|
|
60
58
|
payload: {
|
|
61
59
|
quizCurrentQuestion: questionResult,
|
|
@@ -63,28 +61,17 @@ const useFetchQuiz = (quizId, quizLocalState, dispatchLocalState, resultsPageOpt
|
|
|
63
61
|
});
|
|
64
62
|
}
|
|
65
63
|
catch (error) {
|
|
66
|
-
|
|
64
|
+
dispatchApiState({
|
|
67
65
|
type: QuizAPIActionTypes.SET_IS_ERROR,
|
|
68
66
|
});
|
|
69
67
|
}
|
|
70
68
|
}
|
|
71
69
|
})();
|
|
72
70
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
73
|
-
}, [
|
|
74
|
-
cioClient,
|
|
75
|
-
quizId,
|
|
76
|
-
quizLocalState.answers,
|
|
77
|
-
quizLocalState.isLastAnswer,
|
|
78
|
-
resultsPageOptions?.numResultsToDisplay,
|
|
79
|
-
]);
|
|
80
|
-
const resetQuizApiState = () => {
|
|
81
|
-
dispatch({ type: QuizAPIActionTypes.RESET_QUIZ });
|
|
82
|
-
};
|
|
71
|
+
}, [cioClient, quizId, quizLocalState.answers, resultsPageOptions?.numResultsToDisplay]);
|
|
83
72
|
return {
|
|
84
|
-
cioClient,
|
|
85
73
|
quizApiState,
|
|
86
|
-
|
|
87
|
-
resetQuizApiState,
|
|
74
|
+
dispatchApiState,
|
|
88
75
|
};
|
|
89
76
|
};
|
|
90
|
-
export default
|
|
77
|
+
export default useQuizApiState;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useCallback, useEffect, useReducer } from 'react';
|
|
2
|
+
import quizLocalReducer, { initialState } from '../../components/CioQuiz/quizLocalReducer';
|
|
3
|
+
import { quizSessionStateKey } from '../../constants';
|
|
4
|
+
import { getStateFromSessionStorage, logger } from '../../utils';
|
|
5
|
+
const useQuizLocalState = (sessionStateKey) => {
|
|
6
|
+
const [quizLocalState, dispatch] = useReducer(quizLocalReducer, initialState);
|
|
7
|
+
const quizStateKey = sessionStateKey || quizSessionStateKey;
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
// don't save state if initial state
|
|
10
|
+
if (quizLocalState?.answers?.length) {
|
|
11
|
+
window?.sessionStorage?.setItem(quizStateKey, JSON.stringify(quizLocalState));
|
|
12
|
+
}
|
|
13
|
+
}, [quizLocalState, quizStateKey]);
|
|
14
|
+
const hasQuizStoredState = () => getStateFromSessionStorage(quizStateKey) !== null;
|
|
15
|
+
const dispatchLocalState = useCallback((action) => {
|
|
16
|
+
logger(action);
|
|
17
|
+
dispatch(action);
|
|
18
|
+
}, []);
|
|
19
|
+
return {
|
|
20
|
+
quizLocalState,
|
|
21
|
+
hasQuizStoredState,
|
|
22
|
+
dispatchLocalState,
|
|
23
|
+
quizStateKey,
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export default useQuizLocalState;
|
package/lib/mjs/index.js
CHANGED
|
@@ -1,2 +1,16 @@
|
|
|
1
1
|
import CioQuiz from './components/CioQuiz';
|
|
2
|
+
// Hook
|
|
3
|
+
export { default as useCioQuiz } from './hooks/useQuiz';
|
|
4
|
+
// Questions Components
|
|
5
|
+
export { default as QuizQuestions } from './components/QuizQuestions/index';
|
|
6
|
+
export { default as OpenTextQuestion } from './components/OpenTextTypeQuestion/OpenTextTypeQuestion';
|
|
7
|
+
export { default as CoverQuestion } from './components/CoverTypeQuestion/CoverTypeQuestion';
|
|
8
|
+
export { default as SelectQuestion } from './components/SelectTypeQuestion/SelectTypeQuestion';
|
|
9
|
+
// Results Components
|
|
10
|
+
export { default as Results } from './components/Results/Results';
|
|
11
|
+
export { default as ResultCard } from './components/ResultCard/ResultCard';
|
|
12
|
+
export { default as ResultContainer } from './components/ResultContainer/ResultContainer';
|
|
13
|
+
export { default as ResultFilters } from './components/ResultFilters/ResultFilters';
|
|
14
|
+
export { default as ResultHeroCard } from './components/ResultHeroCard/ResultHeroCard';
|
|
15
|
+
export * from './types';
|
|
2
16
|
export default CioQuiz;
|
|
@@ -9,7 +9,7 @@ export const getCioClient = (apiKey) => {
|
|
|
9
9
|
}
|
|
10
10
|
return undefined;
|
|
11
11
|
};
|
|
12
|
-
export const
|
|
12
|
+
export const getNextQuestion = (cioClient, quizId, parameters) => cioClient?.quizzes.getQuizNextQuestion(quizId, parameters);
|
|
13
13
|
export const getQuizResults = async (cioClient, quizId, parameters) => cioClient?.quizzes.getQuizResults(quizId, parameters);
|
|
14
14
|
// Tracking requests
|
|
15
15
|
export const trackQuizResultsLoaded = (cioClient, quizResults) => {
|