@constructor-io/constructorio-ui-quizzes 1.8.0 → 1.8.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.
@@ -8,7 +8,7 @@ exports.initialState = {
8
8
  quizRequestState: constants_1.RequestStates.Stale,
9
9
  };
10
10
  function apiReducer(state, action) {
11
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
11
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
12
12
  switch (action.type) {
13
13
  case actions_1.QuizAPIActionTypes.SET_IS_LOADING:
14
14
  return Object.assign(Object.assign({}, state), { quizRequestState: constants_1.RequestStates.Loading, quizCurrentQuestion: undefined, quizResults: undefined });
@@ -17,16 +17,16 @@ function apiReducer(state, action) {
17
17
  case actions_1.QuizAPIActionTypes.SET_CURRENT_QUESTION: {
18
18
  const { isOpenQuestion, isCoverQuestion, isSingleQuestion, isMultipleQuestion, isSelectQuestion, } = (0, utils_1.getQuestionTypes)((_c = (_b = (_a = action.payload) === null || _a === void 0 ? void 0 : _a.quizCurrentQuestion) === null || _b === void 0 ? void 0 : _b.next_question) === null || _c === void 0 ? void 0 : _c.type);
19
19
  const quizFirstQuestion = state.quizFirstQuestion || ((_d = action.payload) === null || _d === void 0 ? void 0 : _d.quizCurrentQuestion);
20
- return Object.assign(Object.assign({}, state), { quizRequestState: constants_1.RequestStates.Success, quizCurrentQuestion: Object.assign(Object.assign({}, (_e = action.payload) === null || _e === void 0 ? void 0 : _e.quizCurrentQuestion), { isFirstQuestion: (quizFirstQuestion === null || quizFirstQuestion === void 0 ? void 0 : quizFirstQuestion.next_question.id) ===
21
- ((_h = (_g = (_f = action.payload) === null || _f === void 0 ? void 0 : _f.quizCurrentQuestion) === null || _g === void 0 ? void 0 : _g.next_question) === null || _h === void 0 ? void 0 : _h.id), isOpenQuestion,
20
+ return Object.assign(Object.assign({}, state), { quizRequestState: constants_1.RequestStates.Success, quizCurrentQuestion: Object.assign(Object.assign({}, (_e = action.payload) === null || _e === void 0 ? void 0 : _e.quizCurrentQuestion), { isFirstQuestion: ((_f = quizFirstQuestion === null || quizFirstQuestion === void 0 ? void 0 : quizFirstQuestion.next_question) === null || _f === void 0 ? void 0 : _f.id) ===
21
+ ((_j = (_h = (_g = action.payload) === null || _g === void 0 ? void 0 : _g.quizCurrentQuestion) === null || _h === void 0 ? void 0 : _h.next_question) === null || _j === void 0 ? void 0 : _j.id), isOpenQuestion,
22
22
  isCoverQuestion,
23
23
  isSingleQuestion,
24
24
  isMultipleQuestion,
25
25
  isSelectQuestion }), quizFirstQuestion, quizResults: undefined, selectedOptionsWithAttributes: undefined });
26
26
  }
27
27
  case actions_1.QuizAPIActionTypes.SET_QUIZ_RESULTS: {
28
- const selectedOptionsWithAttributes = ((_j = action.payload) === null || _j === void 0 ? void 0 : _j.quizResults.quiz_selected_options.filter((option) => option.has_attribute).map((option) => option.value)) || [];
29
- return Object.assign(Object.assign({}, state), { quizRequestState: constants_1.RequestStates.Success, quizResults: (_k = action.payload) === null || _k === void 0 ? void 0 : _k.quizResults, quizCurrentQuestion: undefined, selectedOptionsWithAttributes });
28
+ const selectedOptionsWithAttributes = ((_k = action.payload) === null || _k === void 0 ? void 0 : _k.quizResults.quiz_selected_options.filter((option) => option.has_attribute).map((option) => option.value)) || [];
29
+ return Object.assign(Object.assign({}, state), { quizRequestState: constants_1.RequestStates.Success, quizResults: (_l = action.payload) === null || _l === void 0 ? void 0 : _l.quizResults, quizCurrentQuestion: undefined, selectedOptionsWithAttributes });
30
30
  }
31
31
  case actions_1.QuizAPIActionTypes.RESET_QUIZ:
32
32
  return exports.initialState;
@@ -5,6 +5,7 @@ const actions_1 = require("./actions");
5
5
  exports.initialState = {
6
6
  answers: [],
7
7
  answerInputs: {},
8
+ prevAnswerInputs: {},
8
9
  isLastAnswer: false,
9
10
  isQuizCompleted: false,
10
11
  };
@@ -26,7 +27,7 @@ function quizLocalReducer(state, action) {
26
27
  case actions_1.QuestionTypes.MultipleSelect:
27
28
  return Object.assign(Object.assign({}, state), { answerInputs: answerInputReducer(state.answerInputs, action), isLastAnswer: !!((_d = action.payload) === null || _d === void 0 ? void 0 : _d.isLastQuestion), isQuizCompleted: false });
28
29
  case actions_1.QuestionTypes.Next: {
29
- const { answers } = state;
30
+ const { answers, answerInputs } = state;
30
31
  const newAnswers = [...answers];
31
32
  const lastAnswerInputIndex = answers.length;
32
33
  const currentAnswerInput = (_e = Object.values(state.answerInputs)) === null || _e === void 0 ? void 0 : _e[lastAnswerInputIndex];
@@ -46,11 +47,13 @@ function quizLocalReducer(state, action) {
46
47
  default:
47
48
  newAnswers.push([]);
48
49
  }
49
- return Object.assign(Object.assign({}, state), { answers: newAnswers, isQuizCompleted: false });
50
+ return Object.assign(Object.assign({}, state), {
51
+ // We now commit current answers to prevAnswerInputs
52
+ prevAnswerInputs: answerInputs, answers: newAnswers, isQuizCompleted: false });
50
53
  }
51
54
  case actions_1.QuestionTypes.Back: {
52
- const newAnswerInputs = Object.assign({}, state.answerInputs);
53
- return Object.assign(Object.assign({}, state), { answerInputs: newAnswerInputs, answers: [...state.answers.slice(0, -1)], isLastAnswer: false, isQuizCompleted: false });
55
+ const prevAnswerInputs = Object.assign({}, state.prevAnswerInputs);
56
+ return Object.assign(Object.assign({}, state), { answerInputs: prevAnswerInputs, answers: [...state.answers.slice(0, -1)], isLastAnswer: false, isQuizCompleted: false });
54
57
  }
55
58
  case actions_1.QuestionTypes.Reset:
56
59
  return Object.assign({}, exports.initialState);
@@ -6,7 +6,7 @@ const context_1 = tslib_1.__importDefault(require("../CioQuiz/context"));
6
6
  function ProgressBar() {
7
7
  const { state } = (0, react_1.useContext)(context_1.default);
8
8
  const currentQuestion = state === null || state === void 0 ? void 0 : state.quiz.currentQuestion;
9
- if (!currentQuestion)
9
+ if (!(currentQuestion === null || currentQuestion === void 0 ? void 0 : currentQuestion.next_question))
10
10
  return null;
11
11
  return (react_1.default.createElement("div", { className: 'cio-question-progress-affixed-container' },
12
12
  react_1.default.createElement("div", { className: 'cio-question-progress-progress-container' },
@@ -15,8 +15,8 @@ function SelectTypeQuestion() {
15
15
  let instructions;
16
16
  if (state === null || state === void 0 ? void 0 : state.quiz.currentQuestion) {
17
17
  question = state.quiz.currentQuestion.next_question;
18
- hasImages = question.options.some((option) => option.images);
19
- instructions = question.type === actions_1.QuestionTypes.MultipleSelect && 'Select one or more options';
18
+ hasImages = question === null || question === void 0 ? void 0 : question.options.some((option) => option.images);
19
+ instructions = (question === null || question === void 0 ? void 0 : question.type) === actions_1.QuestionTypes.MultipleSelect && 'Select one or more options';
20
20
  }
21
21
  if (question) {
22
22
  return (react_1.default.createElement("div", { className: 'cio-select-question-container', "data-question-key": question.key },
@@ -3,13 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const react_1 = require("react");
4
4
  function useNextQuestionButtonProps(nextQuestion, quizApiState, quizLocalState) {
5
5
  const getNextQuestionButtonProps = (0, react_1.useCallback)(() => {
6
- var _a, _b, _c, _d, _e;
7
- const currentQuestionId = (_a = quizApiState.quizCurrentQuestion) === null || _a === void 0 ? void 0 : _a.next_question.id;
6
+ var _a, _b, _c, _d, _e, _f;
7
+ const currentQuestionId = (_b = (_a = quizApiState.quizCurrentQuestion) === null || _a === void 0 ? void 0 : _a.next_question) === null || _b === void 0 ? void 0 : _b.id;
8
8
  let buttonDisabled;
9
- if (currentQuestionId && !((_b = quizApiState.quizCurrentQuestion) === null || _b === void 0 ? void 0 : _b.isCoverQuestion)) {
9
+ if (currentQuestionId && !((_c = quizApiState.quizCurrentQuestion) === null || _c === void 0 ? void 0 : _c.isCoverQuestion)) {
10
10
  buttonDisabled =
11
- !((_c = quizLocalState.answerInputs[currentQuestionId]) === null || _c === void 0 ? void 0 : _c.value) ||
12
- !((_e = (_d = quizLocalState.answerInputs[currentQuestionId]) === null || _d === void 0 ? void 0 : _d.value) === null || _e === void 0 ? void 0 : _e.length);
11
+ !((_d = quizLocalState.answerInputs[currentQuestionId]) === null || _d === void 0 ? void 0 : _d.value) ||
12
+ !((_f = (_e = quizLocalState.answerInputs[currentQuestionId]) === null || _e === void 0 ? void 0 : _e.value) === null || _f === void 0 ? void 0 : _f.length);
13
13
  }
14
14
  return {
15
15
  className: buttonDisabled ? 'cio-question-cta-button disabled' : 'cio-question-cta-button',
@@ -4,43 +4,45 @@ const react_1 = require("react");
4
4
  const actions_1 = require("../../components/CioQuiz/actions");
5
5
  const useQuizAnswerChangeHandler = (quizApiState, dispatchLocalState) => {
6
6
  const quizAnswerChangedHandler = (0, react_1.useCallback)((payload) => {
7
- var _a;
8
- const questionType = (_a = quizApiState.quizCurrentQuestion) === null || _a === void 0 ? void 0 : _a.next_question.type;
7
+ var _a, _b;
8
+ const questionType = (_b = (_a = quizApiState.quizCurrentQuestion) === null || _a === void 0 ? void 0 : _a.next_question) === null || _b === void 0 ? void 0 : _b.type;
9
9
  const currentQuestion = quizApiState.quizCurrentQuestion;
10
- switch (questionType) {
11
- case actions_1.QuestionTypes.Cover:
12
- dispatchLocalState({
13
- type: actions_1.QuestionTypes.Cover,
14
- payload: {
15
- questionId: currentQuestion.next_question.id,
16
- input: '',
17
- isLastQuestion: currentQuestion.is_last_question,
18
- },
19
- });
20
- break;
21
- case actions_1.QuestionTypes.OpenText:
22
- dispatchLocalState({
23
- type: actions_1.QuestionTypes.OpenText,
24
- payload: {
25
- questionId: currentQuestion.next_question.id,
26
- input: payload,
27
- isLastQuestion: currentQuestion.is_last_question,
28
- },
29
- });
30
- break;
31
- case actions_1.QuestionTypes.SingleSelect:
32
- case actions_1.QuestionTypes.MultipleSelect:
33
- dispatchLocalState({
34
- type: currentQuestion.next_question.type,
35
- payload: {
36
- questionId: currentQuestion.next_question.id,
37
- input: payload,
38
- isLastQuestion: currentQuestion.is_last_question,
39
- },
40
- });
41
- break;
42
- default:
43
- break;
10
+ if (currentQuestion === null || currentQuestion === void 0 ? void 0 : currentQuestion.next_question) {
11
+ switch (questionType) {
12
+ case actions_1.QuestionTypes.Cover:
13
+ dispatchLocalState({
14
+ type: actions_1.QuestionTypes.Cover,
15
+ payload: {
16
+ questionId: currentQuestion.next_question.id,
17
+ input: '',
18
+ isLastQuestion: currentQuestion.is_last_question,
19
+ },
20
+ });
21
+ break;
22
+ case actions_1.QuestionTypes.OpenText:
23
+ dispatchLocalState({
24
+ type: actions_1.QuestionTypes.OpenText,
25
+ payload: {
26
+ questionId: currentQuestion.next_question.id,
27
+ input: payload,
28
+ isLastQuestion: currentQuestion.is_last_question,
29
+ },
30
+ });
31
+ break;
32
+ case actions_1.QuestionTypes.SingleSelect:
33
+ case actions_1.QuestionTypes.MultipleSelect:
34
+ dispatchLocalState({
35
+ type: currentQuestion.next_question.type,
36
+ payload: {
37
+ questionId: currentQuestion.next_question.id,
38
+ input: payload,
39
+ isLastQuestion: currentQuestion.is_last_question,
40
+ },
41
+ });
42
+ break;
43
+ default:
44
+ break;
45
+ }
44
46
  }
45
47
  }, [quizApiState, dispatchLocalState]);
46
48
  return quizAnswerChangedHandler;
@@ -10,36 +10,39 @@ const useQuizApiState = (quizOptions, cioClient, quizLocalState, skipToResults,
10
10
  ) => {
11
11
  const [quizApiState, dispatchApiState] = (0, react_1.useReducer)(quizApiReducer_1.default, quizApiReducer_1.initialState);
12
12
  const { quizId, quizVersionId: quizVersionIdProp, resultsPageOptions } = quizOptions;
13
+ const dispatchQuizResults = () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
14
+ try {
15
+ const quizResults = yield (0, services_1.getQuizResults)(cioClient, quizId, {
16
+ answers: quizLocalState.answers,
17
+ resultsPerPage: resultsPageOptions === null || resultsPageOptions === void 0 ? void 0 : resultsPageOptions.numResultsToDisplay,
18
+ quizVersionId: quizLocalState.quizVersionId,
19
+ quizSessionId: quizLocalState.quizSessionId,
20
+ });
21
+ // Set quiz results state
22
+ dispatchApiState({
23
+ type: actions_1.QuizAPIActionTypes.SET_QUIZ_RESULTS,
24
+ payload: {
25
+ quizResults,
26
+ },
27
+ });
28
+ if (!quizLocalState.isQuizCompleted)
29
+ dispatchLocalState({
30
+ type: actions_1.QuestionTypes.Complete,
31
+ });
32
+ }
33
+ catch (error) {
34
+ dispatchApiState({
35
+ type: actions_1.QuizAPIActionTypes.SET_IS_ERROR,
36
+ });
37
+ }
38
+ });
13
39
  (0, react_1.useEffect)(() => {
14
40
  (() => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
15
41
  dispatchApiState({
16
42
  type: actions_1.QuizAPIActionTypes.SET_IS_LOADING,
17
43
  });
18
44
  if (quizLocalState.isLastAnswer || skipToResults) {
19
- try {
20
- const quizResults = yield (0, services_1.getQuizResults)(cioClient, quizId, {
21
- answers: quizLocalState.answers,
22
- resultsPerPage: resultsPageOptions === null || resultsPageOptions === void 0 ? void 0 : resultsPageOptions.numResultsToDisplay,
23
- quizVersionId: quizLocalState.quizVersionId,
24
- quizSessionId: quizLocalState.quizSessionId,
25
- });
26
- // Set quiz results state
27
- dispatchApiState({
28
- type: actions_1.QuizAPIActionTypes.SET_QUIZ_RESULTS,
29
- payload: {
30
- quizResults,
31
- },
32
- });
33
- if (!quizLocalState.isQuizCompleted)
34
- dispatchLocalState({
35
- type: actions_1.QuestionTypes.Complete,
36
- });
37
- }
38
- catch (error) {
39
- dispatchApiState({
40
- type: actions_1.QuizAPIActionTypes.SET_IS_ERROR,
41
- });
42
- }
45
+ yield dispatchQuizResults();
43
46
  }
44
47
  else {
45
48
  try {
@@ -50,6 +53,10 @@ const useQuizApiState = (quizOptions, cioClient, quizLocalState, skipToResults,
50
53
  quizVersionId,
51
54
  quizSessionId,
52
55
  });
56
+ if (!questionResult.next_question) {
57
+ yield dispatchQuizResults();
58
+ return;
59
+ }
53
60
  // Update quizSessionId, quizVersionId
54
61
  if ((!quizSessionId && (questionResult === null || questionResult === void 0 ? void 0 : questionResult.quiz_session_id)) ||
55
62
  (!quizVersionId && questionResult.quiz_version_id)) {
@@ -9,6 +9,7 @@ const getCioClient = (apiKey) => {
9
9
  return new constructorio_client_javascript_1.default({
10
10
  apiKey,
11
11
  sendTrackingEvents: true,
12
+ version: 'cio-ui-quizzes',
12
13
  });
13
14
  }
14
15
  return undefined;
@@ -29,7 +29,7 @@ export default function apiReducer(state, action) {
29
29
  quizRequestState: RequestStates.Success,
30
30
  quizCurrentQuestion: {
31
31
  ...action.payload?.quizCurrentQuestion,
32
- isFirstQuestion: quizFirstQuestion?.next_question.id ===
32
+ isFirstQuestion: quizFirstQuestion?.next_question?.id ===
33
33
  action.payload?.quizCurrentQuestion?.next_question?.id,
34
34
  isOpenQuestion,
35
35
  isCoverQuestion,
@@ -2,6 +2,7 @@ import { QuestionTypes } from './actions';
2
2
  export const initialState = {
3
3
  answers: [],
4
4
  answerInputs: {},
5
+ prevAnswerInputs: {},
5
6
  isLastAnswer: false,
6
7
  isQuizCompleted: false,
7
8
  };
@@ -45,7 +46,7 @@ export default function quizLocalReducer(state, action) {
45
46
  isQuizCompleted: false,
46
47
  };
47
48
  case QuestionTypes.Next: {
48
- const { answers } = state;
49
+ const { answers, answerInputs } = state;
49
50
  const newAnswers = [...answers];
50
51
  const lastAnswerInputIndex = answers.length;
51
52
  const currentAnswerInput = Object.values(state.answerInputs)?.[lastAnswerInputIndex];
@@ -67,15 +68,17 @@ export default function quizLocalReducer(state, action) {
67
68
  }
68
69
  return {
69
70
  ...state,
71
+ // We now commit current answers to prevAnswerInputs
72
+ prevAnswerInputs: answerInputs,
70
73
  answers: newAnswers,
71
74
  isQuizCompleted: false,
72
75
  };
73
76
  }
74
77
  case QuestionTypes.Back: {
75
- const newAnswerInputs = { ...state.answerInputs };
78
+ const prevAnswerInputs = { ...state.prevAnswerInputs };
76
79
  return {
77
80
  ...state,
78
- answerInputs: newAnswerInputs,
81
+ answerInputs: prevAnswerInputs,
79
82
  answers: [...state.answers.slice(0, -1)],
80
83
  isLastAnswer: false,
81
84
  isQuizCompleted: false,
@@ -3,7 +3,7 @@ import QuizContext from '../CioQuiz/context';
3
3
  export default function ProgressBar() {
4
4
  const { state } = useContext(QuizContext);
5
5
  const currentQuestion = state?.quiz.currentQuestion;
6
- if (!currentQuestion)
6
+ if (!currentQuestion?.next_question)
7
7
  return null;
8
8
  return (React.createElement("div", { className: 'cio-question-progress-affixed-container' },
9
9
  React.createElement("div", { className: 'cio-question-progress-progress-container' },
@@ -11,8 +11,8 @@ function SelectTypeQuestion() {
11
11
  let instructions;
12
12
  if (state?.quiz.currentQuestion) {
13
13
  question = state.quiz.currentQuestion.next_question;
14
- hasImages = question.options.some((option) => option.images);
15
- instructions = question.type === QuestionTypes.MultipleSelect && 'Select one or more options';
14
+ hasImages = question?.options.some((option) => option.images);
15
+ instructions = question?.type === QuestionTypes.MultipleSelect && 'Select one or more options';
16
16
  }
17
17
  if (question) {
18
18
  return (React.createElement("div", { className: 'cio-select-question-container', "data-question-key": question.key },
@@ -1,7 +1,7 @@
1
1
  import { useCallback } from 'react';
2
2
  export default function useNextQuestionButtonProps(nextQuestion, quizApiState, quizLocalState) {
3
3
  const getNextQuestionButtonProps = useCallback(() => {
4
- const currentQuestionId = quizApiState.quizCurrentQuestion?.next_question.id;
4
+ const currentQuestionId = quizApiState.quizCurrentQuestion?.next_question?.id;
5
5
  let buttonDisabled;
6
6
  if (currentQuestionId && !quizApiState.quizCurrentQuestion?.isCoverQuestion) {
7
7
  buttonDisabled =
@@ -2,42 +2,44 @@ import { useCallback } from 'react';
2
2
  import { QuestionTypes } from '../../components/CioQuiz/actions';
3
3
  const useQuizAnswerChangeHandler = (quizApiState, dispatchLocalState) => {
4
4
  const quizAnswerChangedHandler = useCallback((payload) => {
5
- const questionType = quizApiState.quizCurrentQuestion?.next_question.type;
5
+ const questionType = quizApiState.quizCurrentQuestion?.next_question?.type;
6
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;
7
+ if (currentQuestion?.next_question) {
8
+ switch (questionType) {
9
+ case QuestionTypes.Cover:
10
+ dispatchLocalState({
11
+ type: QuestionTypes.Cover,
12
+ payload: {
13
+ questionId: currentQuestion.next_question.id,
14
+ input: '',
15
+ isLastQuestion: currentQuestion.is_last_question,
16
+ },
17
+ });
18
+ break;
19
+ case QuestionTypes.OpenText:
20
+ dispatchLocalState({
21
+ type: QuestionTypes.OpenText,
22
+ payload: {
23
+ questionId: currentQuestion.next_question.id,
24
+ input: payload,
25
+ isLastQuestion: currentQuestion.is_last_question,
26
+ },
27
+ });
28
+ break;
29
+ case QuestionTypes.SingleSelect:
30
+ case QuestionTypes.MultipleSelect:
31
+ dispatchLocalState({
32
+ type: currentQuestion.next_question.type,
33
+ payload: {
34
+ questionId: currentQuestion.next_question.id,
35
+ input: payload,
36
+ isLastQuestion: currentQuestion.is_last_question,
37
+ },
38
+ });
39
+ break;
40
+ default:
41
+ break;
42
+ }
41
43
  }
42
44
  }, [quizApiState, dispatchLocalState]);
43
45
  return quizAnswerChangedHandler;
@@ -7,36 +7,39 @@ const useQuizApiState = (quizOptions, cioClient, quizLocalState, skipToResults,
7
7
  ) => {
8
8
  const [quizApiState, dispatchApiState] = useReducer(apiReducer, initialState);
9
9
  const { quizId, quizVersionId: quizVersionIdProp, resultsPageOptions } = quizOptions;
10
+ const dispatchQuizResults = async () => {
11
+ try {
12
+ const quizResults = await getQuizResults(cioClient, quizId, {
13
+ answers: quizLocalState.answers,
14
+ resultsPerPage: resultsPageOptions?.numResultsToDisplay,
15
+ quizVersionId: quizLocalState.quizVersionId,
16
+ quizSessionId: quizLocalState.quizSessionId,
17
+ });
18
+ // Set quiz results state
19
+ dispatchApiState({
20
+ type: QuizAPIActionTypes.SET_QUIZ_RESULTS,
21
+ payload: {
22
+ quizResults,
23
+ },
24
+ });
25
+ if (!quizLocalState.isQuizCompleted)
26
+ dispatchLocalState({
27
+ type: QuestionTypes.Complete,
28
+ });
29
+ }
30
+ catch (error) {
31
+ dispatchApiState({
32
+ type: QuizAPIActionTypes.SET_IS_ERROR,
33
+ });
34
+ }
35
+ };
10
36
  useEffect(() => {
11
37
  (async () => {
12
38
  dispatchApiState({
13
39
  type: QuizAPIActionTypes.SET_IS_LOADING,
14
40
  });
15
41
  if (quizLocalState.isLastAnswer || skipToResults) {
16
- try {
17
- const quizResults = await getQuizResults(cioClient, quizId, {
18
- answers: quizLocalState.answers,
19
- resultsPerPage: resultsPageOptions?.numResultsToDisplay,
20
- quizVersionId: quizLocalState.quizVersionId,
21
- quizSessionId: quizLocalState.quizSessionId,
22
- });
23
- // Set quiz results state
24
- dispatchApiState({
25
- type: QuizAPIActionTypes.SET_QUIZ_RESULTS,
26
- payload: {
27
- quizResults,
28
- },
29
- });
30
- if (!quizLocalState.isQuizCompleted)
31
- dispatchLocalState({
32
- type: QuestionTypes.Complete,
33
- });
34
- }
35
- catch (error) {
36
- dispatchApiState({
37
- type: QuizAPIActionTypes.SET_IS_ERROR,
38
- });
39
- }
42
+ await dispatchQuizResults();
40
43
  }
41
44
  else {
42
45
  try {
@@ -47,6 +50,10 @@ const useQuizApiState = (quizOptions, cioClient, quizLocalState, skipToResults,
47
50
  quizVersionId,
48
51
  quizSessionId,
49
52
  });
53
+ if (!questionResult.next_question) {
54
+ await dispatchQuizResults();
55
+ return;
56
+ }
50
57
  // Update quizSessionId, quizVersionId
51
58
  if ((!quizSessionId && questionResult?.quiz_session_id) ||
52
59
  (!quizVersionId && questionResult.quiz_version_id)) {
@@ -5,6 +5,7 @@ export const getCioClient = (apiKey) => {
5
5
  return new ConstructorIOClient({
6
6
  apiKey,
7
7
  sendTrackingEvents: true,
8
+ version: 'cio-ui-quizzes',
8
9
  });
9
10
  }
10
11
  return undefined;
@@ -4,6 +4,7 @@ export type Answers = string[][];
4
4
  export type QuizLocalReducerState = {
5
5
  answers: Answers;
6
6
  answerInputs: AnswerInputState;
7
+ prevAnswerInputs: AnswerInputState;
7
8
  isLastAnswer: boolean;
8
9
  isQuizCompleted: boolean;
9
10
  quizVersionId?: string;
@@ -1,2 +1,3 @@
1
+ import { Nullable } from '@constructor-io/constructorio-client-javascript/lib/types';
1
2
  import { GetCoverQuestionProps, Question, QuizEventsReturn } from '../../types';
2
- export default function useCoverQuestionProps(setQuizAnswers: QuizEventsReturn.QuizAnswerChanged, currentQuestionData?: Question): GetCoverQuestionProps;
3
+ export default function useCoverQuestionProps(setQuizAnswers: QuizEventsReturn.QuizAnswerChanged, currentQuestionData?: Nullable<Question>): GetCoverQuestionProps;
@@ -1,2 +1,3 @@
1
+ import { Nullable } from '@constructor-io/constructorio-client-javascript/lib/types';
1
2
  import { AnswerInputState, GetOpenTextInputProps, Question, QuizEventsReturn } from '../../types';
2
- export default function useOpenTextInputProps(setQuizAnswers: QuizEventsReturn.QuizAnswerChanged, nextQuestion: QuizEventsReturn.NextQuestion, currentQuestionData?: Question, answerInputs?: AnswerInputState): GetOpenTextInputProps;
3
+ export default function useOpenTextInputProps(setQuizAnswers: QuizEventsReturn.QuizAnswerChanged, nextQuestion: QuizEventsReturn.NextQuestion, currentQuestionData?: Nullable<Question>, answerInputs?: AnswerInputState): GetOpenTextInputProps;
@@ -1,2 +1,3 @@
1
+ import { Nullable } from '@constructor-io/constructorio-client-javascript/lib/types';
1
2
  import { AnswerInputState, GetSelectInputProps, Question, QuizEventsReturn } from '../../types';
2
- export default function useSelectInputProps(quizAnswerChanged: QuizEventsReturn.QuizAnswerChanged, nextQuestion: QuizEventsReturn.NextQuestion, currentQuestionData?: Question, answerInputs?: AnswerInputState): GetSelectInputProps;
3
+ export default function useSelectInputProps(quizAnswerChanged: QuizEventsReturn.QuizAnswerChanged, nextQuestion: QuizEventsReturn.NextQuestion, currentQuestionData?: Nullable<Question>, answerInputs?: AnswerInputState): GetSelectInputProps;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructor-io/constructorio-ui-quizzes",
3
- "version": "1.8.0",
3
+ "version": "1.8.2",
4
4
  "description": "Constructor.io Quizzes UI library for web applications",
5
5
  "author": "constructor.io",
6
6
  "license": "MIT",