@constructor-io/constructorio-ui-quizzes 1.17.24 → 1.17.25

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,6 +8,8 @@ var QuestionTypes;
8
8
  QuestionTypes["Cover"] = "cover";
9
9
  QuestionTypes["SingleSelect"] = "single";
10
10
  QuestionTypes["MultipleSelect"] = "multiple";
11
+ QuestionTypes["SingleFilterValue"] = "single_filter_value";
12
+ QuestionTypes["MultipleFilterValues"] = "multiple_filter_values";
11
13
  QuestionTypes["Next"] = "next";
12
14
  QuestionTypes["Skip"] = "skip";
13
15
  QuestionTypes["Back"] = "back";
@@ -13,6 +13,7 @@ const SessionPromptModal_1 = tslib_1.__importDefault(require("../SessionPromptMo
13
13
  const ShareResultsModal_1 = tslib_1.__importDefault(require("../ShareResultsModal/ShareResultsModal"));
14
14
  const utils_1 = require("../../utils");
15
15
  const ProgressBar_1 = tslib_1.__importDefault(require("../ProgressBar/ProgressBar"));
16
+ const actions_1 = require("./actions");
16
17
  function CioQuiz(props) {
17
18
  var _a;
18
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);
@@ -70,7 +71,9 @@ function CioQuiz(props) {
70
71
  const questionData = (_a = state.quiz.currentQuestion) === null || _a === void 0 ? void 0 : _a.next_question;
71
72
  const questionType = questionData === null || questionData === void 0 ? void 0 : questionData.type;
72
73
  const questionImages = questionData === null || questionData === void 0 ? void 0 : questionData.images;
73
- const displayBackgroundImage = (questionType === 'single' || questionType === 'multiple') && questionImages;
74
+ const displayBackgroundImage = (questionType === actions_1.QuestionTypes.SingleSelect ||
75
+ questionType === actions_1.QuestionTypes.MultipleSelect) &&
76
+ questionImages;
74
77
  if (state.quiz.requestState === constants_1.RequestStates.Success) {
75
78
  return (react_1.default.createElement("div", { className: 'cio-quiz', style: { overflow: showShareModal || showSessionPrompt ? 'hidden' : undefined } },
76
79
  displayBackgroundImage && (0, utils_1.renderImages)(questionImages, 'cio-question-background-image'),
@@ -15,14 +15,16 @@ function apiReducer(state, action) {
15
15
  case actions_1.QuizAPIActionTypes.SET_IS_ERROR:
16
16
  return Object.assign(Object.assign({}, state), { quizRequestState: constants_1.RequestStates.Error, quizCurrentQuestion: undefined, quizResults: undefined, selectedOptionsWithAttributes: undefined, matchedOptions: undefined });
17
17
  case actions_1.QuizAPIActionTypes.SET_CURRENT_QUESTION: {
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);
18
+ const { isOpenQuestion, isCoverQuestion, isSingleQuestion, isMultipleQuestion, isSelectQuestion, isSingleFilterQuestion, isMultipleFilterQuestion, } = (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
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
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
- isSelectQuestion }), quizFirstQuestion, quizResults: undefined, selectedOptionsWithAttributes: undefined, matchedOptions: undefined });
25
+ isSelectQuestion,
26
+ isSingleFilterQuestion,
27
+ isMultipleFilterQuestion }), quizFirstQuestion, quizResults: undefined, selectedOptionsWithAttributes: undefined, matchedOptions: undefined });
26
28
  }
27
29
  case actions_1.QuizAPIActionTypes.SET_QUIZ_RESULTS: {
28
30
  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)) || [];
@@ -14,8 +14,33 @@ function answerInputReducer(state, action) {
14
14
  value: action.payload.input,
15
15
  } });
16
16
  }
17
- function quizLocalReducer(state, action) {
17
+ function handleNextQuestion(state) {
18
18
  var _a;
19
+ const { answers, answerInputs } = state;
20
+ const newAnswers = [...answers];
21
+ const lastAnswerInputIndex = answers.length;
22
+ const currentAnswerInput = (_a = Object.values(state.answerInputs)) === null || _a === void 0 ? void 0 : _a[lastAnswerInputIndex];
23
+ switch (currentAnswerInput.type) {
24
+ case actions_1.QuestionTypes.OpenText:
25
+ newAnswers.push(['true']);
26
+ break;
27
+ case actions_1.QuestionTypes.Cover:
28
+ newAnswers.push(['seen']);
29
+ break;
30
+ case actions_1.QuestionTypes.SingleSelect:
31
+ case actions_1.QuestionTypes.MultipleSelect:
32
+ case actions_1.QuestionTypes.SingleFilterValue:
33
+ case actions_1.QuestionTypes.MultipleFilterValues:
34
+ newAnswers.push(currentAnswerInput.value.map((answer) => answer.id));
35
+ break;
36
+ default:
37
+ newAnswers.push([]);
38
+ }
39
+ return Object.assign(Object.assign({}, state), {
40
+ // We now commit current answers to prevAnswerInputs
41
+ prevAnswerInputs: answerInputs, answers: newAnswers, isQuizCompleted: false });
42
+ }
43
+ function quizLocalReducer(state, action) {
19
44
  switch (action.type) {
20
45
  case actions_1.QuestionTypes.OpenText:
21
46
  return Object.assign(Object.assign({}, state), { answerInputs: answerInputReducer(state.answerInputs, action), isQuizCompleted: false });
@@ -25,28 +50,12 @@ function quizLocalReducer(state, action) {
25
50
  return Object.assign(Object.assign({}, state), { answerInputs: answerInputReducer(state.answerInputs, action), isQuizCompleted: false });
26
51
  case actions_1.QuestionTypes.MultipleSelect:
27
52
  return Object.assign(Object.assign({}, state), { answerInputs: answerInputReducer(state.answerInputs, action), isQuizCompleted: false });
53
+ case actions_1.QuestionTypes.SingleFilterValue:
54
+ return Object.assign(Object.assign({}, state), { answerInputs: answerInputReducer(state.answerInputs, action), isQuizCompleted: false });
55
+ case actions_1.QuestionTypes.MultipleFilterValues:
56
+ return Object.assign(Object.assign({}, state), { answerInputs: answerInputReducer(state.answerInputs, action), isQuizCompleted: false });
28
57
  case actions_1.QuestionTypes.Next: {
29
- const { answers, answerInputs } = state;
30
- const newAnswers = [...answers];
31
- const lastAnswerInputIndex = answers.length;
32
- const currentAnswerInput = (_a = Object.values(state.answerInputs)) === null || _a === void 0 ? void 0 : _a[lastAnswerInputIndex];
33
- switch (currentAnswerInput.type) {
34
- case actions_1.QuestionTypes.OpenText:
35
- newAnswers.push(['true']);
36
- break;
37
- case actions_1.QuestionTypes.Cover:
38
- newAnswers.push(['seen']);
39
- break;
40
- case actions_1.QuestionTypes.SingleSelect:
41
- case actions_1.QuestionTypes.MultipleSelect:
42
- newAnswers.push(currentAnswerInput.value.map((answer) => answer.id));
43
- break;
44
- default:
45
- newAnswers.push([]);
46
- }
47
- return Object.assign(Object.assign({}, state), {
48
- // We now commit current answers to prevAnswerInputs
49
- prevAnswerInputs: answerInputs, answers: newAnswers, isQuizCompleted: false });
58
+ return handleNextQuestion(state);
50
59
  }
51
60
  case actions_1.QuestionTypes.Skip: {
52
61
  const { answers, answerInputs } = state;
@@ -62,6 +71,8 @@ function quizLocalReducer(state, action) {
62
71
  break;
63
72
  case actions_1.QuestionTypes.SingleSelect:
64
73
  case actions_1.QuestionTypes.MultipleSelect:
74
+ case actions_1.QuestionTypes.SingleFilterValue:
75
+ case actions_1.QuestionTypes.MultipleFilterValues:
65
76
  default:
66
77
  newAnswers.push([]);
67
78
  }
@@ -16,7 +16,10 @@ function SelectTypeQuestion() {
16
16
  if (state === null || state === void 0 ? void 0 : state.quiz.currentQuestion) {
17
17
  question = state.quiz.currentQuestion.next_question;
18
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';
19
+ instructions =
20
+ ((question === null || question === void 0 ? void 0 : question.type) === actions_1.QuestionTypes.MultipleSelect ||
21
+ question.type === actions_1.QuestionTypes.MultipleFilterValues) &&
22
+ 'Select one or more options';
20
23
  }
21
24
  if (question) {
22
25
  return (react_1.default.createElement("div", { className: 'cio-select-question-container', "data-cnstrc-question-type": question.type, "data-question-key": question.key },
@@ -10,11 +10,12 @@ function useSelectInputProps(quizAnswerChanged, nextQuestion, currentQuestionDat
10
10
  const [selected, setSelected] = (0, react_1.useState)({});
11
11
  const singleSelectClicked = (0, react_1.useRef)({});
12
12
  const toggleIdSelected = (0, react_1.useCallback)((id) => {
13
- if (type === actions_1.QuestionTypes.SingleSelect) {
13
+ if (type === actions_1.QuestionTypes.SingleSelect || type === actions_1.QuestionTypes.SingleFilterValue) {
14
14
  singleSelectClicked.current = true;
15
15
  setSelected({ [id]: true });
16
+ return;
16
17
  }
17
- else if (type === actions_1.QuestionTypes.MultipleSelect) {
18
+ if (type === actions_1.QuestionTypes.MultipleSelect || type === actions_1.QuestionTypes.MultipleFilterValues) {
18
19
  if (selected[id]) {
19
20
  const newState = Object.assign({}, selected);
20
21
  delete newState[id];
@@ -52,11 +53,20 @@ function useSelectInputProps(quizAnswerChanged, nextQuestion, currentQuestionDat
52
53
  }, [currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.id]);
53
54
  // Update global state
54
55
  (0, react_1.useEffect)(() => {
55
- var _a, _b;
56
- if ((currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.type) === 'multiple' || (currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.type) === 'single') {
56
+ var _a, _b, _c, _d;
57
+ if ((currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.type) === actions_1.QuestionTypes.MultipleSelect ||
58
+ (currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.type) === actions_1.QuestionTypes.SingleSelect) {
57
59
  const selectedAnswers = (_b = (_a = currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.options) === null || _a === void 0 ? void 0 : _a.filter((opt) => selected[Number(opt.id)])) === null || _b === void 0 ? void 0 : _b.map((opt) => ({ id: opt.id, value: opt.value }));
58
60
  quizAnswerChanged(selectedAnswers);
59
61
  }
62
+ if ((currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.type) === actions_1.QuestionTypes.MultipleFilterValues ||
63
+ (currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.type) === actions_1.QuestionTypes.SingleFilterValue) {
64
+ const selectedAnswers = (_d = (_c = currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.options) === null || _c === void 0 ? void 0 : _c.filter((opt) => selected[String(opt.id)])) === null || _d === void 0 ? void 0 : _d.map((opt) => ({
65
+ id: opt.id,
66
+ value: opt.value,
67
+ }));
68
+ quizAnswerChanged(selectedAnswers);
69
+ }
60
70
  }, [
61
71
  selected,
62
72
  currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.id,
@@ -67,7 +77,9 @@ function useSelectInputProps(quizAnswerChanged, nextQuestion, currentQuestionDat
67
77
  // Go to next question only every time answerInputs (answers input state) changes...
68
78
  // and it's a singleSelectQuestion and user has just clicked on an option
69
79
  (0, react_1.useEffect)(() => {
70
- if ((currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.type) === 'single' && singleSelectClicked.current) {
80
+ if (((currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.type) === actions_1.QuestionTypes.SingleSelect ||
81
+ (currentQuestionData === null || currentQuestionData === void 0 ? void 0 : currentQuestionData.type) === actions_1.QuestionTypes.SingleFilterValue) &&
82
+ singleSelectClicked.current) {
71
83
  nextQuestion();
72
84
  }
73
85
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -29,6 +29,8 @@ const useQuizAnswerChangeHandler = (quizApiState, dispatchLocalState) => {
29
29
  break;
30
30
  case actions_1.QuestionTypes.SingleSelect:
31
31
  case actions_1.QuestionTypes.MultipleSelect:
32
+ case actions_1.QuestionTypes.SingleFilterValue:
33
+ case actions_1.QuestionTypes.MultipleFilterValues:
32
34
  dispatchLocalState({
33
35
  type: currentQuestion.next_question.type,
34
36
  payload: {
package/lib/cjs/utils.js CHANGED
@@ -77,13 +77,17 @@ const getQuestionTypes = (questionType) => {
77
77
  const isCoverQuestion = questionType === actions_1.QuestionTypes.Cover;
78
78
  const isSingleQuestion = questionType === actions_1.QuestionTypes.SingleSelect;
79
79
  const isMultipleQuestion = questionType === actions_1.QuestionTypes.MultipleSelect;
80
- const isSelectQuestion = isSingleQuestion || isMultipleQuestion;
80
+ const isSingleFilterQuestion = questionType === actions_1.QuestionTypes.SingleFilterValue;
81
+ const isMultipleFilterQuestion = questionType === actions_1.QuestionTypes.MultipleFilterValues;
82
+ const isSelectQuestion = isSingleQuestion || isMultipleQuestion || isSingleFilterQuestion || isMultipleFilterQuestion;
81
83
  return {
82
84
  isOpenQuestion,
83
85
  isCoverQuestion,
84
86
  isSingleQuestion,
85
87
  isMultipleQuestion,
86
88
  isSelectQuestion,
89
+ isSingleFilterQuestion,
90
+ isMultipleFilterQuestion,
87
91
  };
88
92
  };
89
93
  exports.getQuestionTypes = getQuestionTypes;
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = '1.17.24';
3
+ exports.default = '1.17.25';
@@ -5,6 +5,8 @@ export var QuestionTypes;
5
5
  QuestionTypes["Cover"] = "cover";
6
6
  QuestionTypes["SingleSelect"] = "single";
7
7
  QuestionTypes["MultipleSelect"] = "multiple";
8
+ QuestionTypes["SingleFilterValue"] = "single_filter_value";
9
+ QuestionTypes["MultipleFilterValues"] = "multiple_filter_values";
8
10
  QuestionTypes["Next"] = "next";
9
11
  QuestionTypes["Skip"] = "skip";
10
12
  QuestionTypes["Back"] = "back";
@@ -10,6 +10,7 @@ import SessionPromptModal from '../SessionPromptModal/SessionPromptModal';
10
10
  import ShareResultsModal from '../ShareResultsModal/ShareResultsModal';
11
11
  import { convertPrimaryColorsToString, renderImages } from '../../utils';
12
12
  import ProgressBar from '../ProgressBar/ProgressBar';
13
+ import { QuestionTypes } from './actions';
13
14
  export default function CioQuiz(props) {
14
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
16
  const [showSessionPrompt, setShowSessionPrompt] = useState(false);
@@ -66,7 +67,9 @@ export default function CioQuiz(props) {
66
67
  const questionData = state.quiz.currentQuestion?.next_question;
67
68
  const questionType = questionData?.type;
68
69
  const questionImages = questionData?.images;
69
- const displayBackgroundImage = (questionType === 'single' || questionType === 'multiple') && questionImages;
70
+ const displayBackgroundImage = (questionType === QuestionTypes.SingleSelect ||
71
+ questionType === QuestionTypes.MultipleSelect) &&
72
+ questionImages;
70
73
  if (state.quiz.requestState === RequestStates.Success) {
71
74
  return (React.createElement("div", { className: 'cio-quiz', style: { overflow: showShareModal || showSessionPrompt ? 'hidden' : undefined } },
72
75
  displayBackgroundImage && renderImages(questionImages, 'cio-question-background-image'),
@@ -23,7 +23,7 @@ export default function apiReducer(state, action) {
23
23
  matchedOptions: undefined,
24
24
  };
25
25
  case QuizAPIActionTypes.SET_CURRENT_QUESTION: {
26
- const { isOpenQuestion, isCoverQuestion, isSingleQuestion, isMultipleQuestion, isSelectQuestion, } = getQuestionTypes(action.payload?.quizCurrentQuestion?.next_question?.type);
26
+ const { isOpenQuestion, isCoverQuestion, isSingleQuestion, isMultipleQuestion, isSelectQuestion, isSingleFilterQuestion, isMultipleFilterQuestion, } = getQuestionTypes(action.payload?.quizCurrentQuestion?.next_question?.type);
27
27
  const quizFirstQuestion = state.quizFirstQuestion || action.payload?.quizCurrentQuestion;
28
28
  return {
29
29
  ...state,
@@ -37,6 +37,8 @@ export default function apiReducer(state, action) {
37
37
  isSingleQuestion,
38
38
  isMultipleQuestion,
39
39
  isSelectQuestion,
40
+ isSingleFilterQuestion,
41
+ isMultipleFilterQuestion,
40
42
  },
41
43
  quizFirstQuestion,
42
44
  quizResults: undefined,
@@ -14,6 +14,35 @@ function answerInputReducer(state, action) {
14
14
  },
15
15
  };
16
16
  }
17
+ function handleNextQuestion(state) {
18
+ const { answers, answerInputs } = state;
19
+ const newAnswers = [...answers];
20
+ const lastAnswerInputIndex = answers.length;
21
+ const currentAnswerInput = Object.values(state.answerInputs)?.[lastAnswerInputIndex];
22
+ switch (currentAnswerInput.type) {
23
+ case QuestionTypes.OpenText:
24
+ newAnswers.push(['true']);
25
+ break;
26
+ case QuestionTypes.Cover:
27
+ newAnswers.push(['seen']);
28
+ break;
29
+ case QuestionTypes.SingleSelect:
30
+ case QuestionTypes.MultipleSelect:
31
+ case QuestionTypes.SingleFilterValue:
32
+ case QuestionTypes.MultipleFilterValues:
33
+ newAnswers.push(currentAnswerInput.value.map((answer) => answer.id));
34
+ break;
35
+ default:
36
+ newAnswers.push([]);
37
+ }
38
+ return {
39
+ ...state,
40
+ // We now commit current answers to prevAnswerInputs
41
+ prevAnswerInputs: answerInputs,
42
+ answers: newAnswers,
43
+ isQuizCompleted: false,
44
+ };
45
+ }
17
46
  export default function quizLocalReducer(state, action) {
18
47
  switch (action.type) {
19
48
  case QuestionTypes.OpenText:
@@ -40,32 +69,20 @@ export default function quizLocalReducer(state, action) {
40
69
  answerInputs: answerInputReducer(state.answerInputs, action),
41
70
  isQuizCompleted: false,
42
71
  };
43
- case QuestionTypes.Next: {
44
- const { answers, answerInputs } = state;
45
- const newAnswers = [...answers];
46
- const lastAnswerInputIndex = answers.length;
47
- const currentAnswerInput = Object.values(state.answerInputs)?.[lastAnswerInputIndex];
48
- switch (currentAnswerInput.type) {
49
- case QuestionTypes.OpenText:
50
- newAnswers.push(['true']);
51
- break;
52
- case QuestionTypes.Cover:
53
- newAnswers.push(['seen']);
54
- break;
55
- case QuestionTypes.SingleSelect:
56
- case QuestionTypes.MultipleSelect:
57
- newAnswers.push(currentAnswerInput.value.map((answer) => answer.id));
58
- break;
59
- default:
60
- newAnswers.push([]);
61
- }
72
+ case QuestionTypes.SingleFilterValue:
62
73
  return {
63
74
  ...state,
64
- // We now commit current answers to prevAnswerInputs
65
- prevAnswerInputs: answerInputs,
66
- answers: newAnswers,
75
+ answerInputs: answerInputReducer(state.answerInputs, action),
67
76
  isQuizCompleted: false,
68
77
  };
78
+ case QuestionTypes.MultipleFilterValues:
79
+ return {
80
+ ...state,
81
+ answerInputs: answerInputReducer(state.answerInputs, action),
82
+ isQuizCompleted: false,
83
+ };
84
+ case QuestionTypes.Next: {
85
+ return handleNextQuestion(state);
69
86
  }
70
87
  case QuestionTypes.Skip: {
71
88
  const { answers, answerInputs } = state;
@@ -81,6 +98,8 @@ export default function quizLocalReducer(state, action) {
81
98
  break;
82
99
  case QuestionTypes.SingleSelect:
83
100
  case QuestionTypes.MultipleSelect:
101
+ case QuestionTypes.SingleFilterValue:
102
+ case QuestionTypes.MultipleFilterValues:
84
103
  default:
85
104
  newAnswers.push([]);
86
105
  }
@@ -12,7 +12,10 @@ function SelectTypeQuestion() {
12
12
  if (state?.quiz.currentQuestion) {
13
13
  question = state.quiz.currentQuestion.next_question;
14
14
  hasImages = question?.options.some((option) => option.images);
15
- instructions = question?.type === QuestionTypes.MultipleSelect && 'Select one or more options';
15
+ instructions =
16
+ (question?.type === QuestionTypes.MultipleSelect ||
17
+ question.type === QuestionTypes.MultipleFilterValues) &&
18
+ 'Select one or more options';
16
19
  }
17
20
  if (question) {
18
21
  return (React.createElement("div", { className: 'cio-select-question-container', "data-cnstrc-question-type": question.type, "data-question-key": question.key },
@@ -7,11 +7,12 @@ export default function useSelectInputProps(quizAnswerChanged, nextQuestion, cur
7
7
  const [selected, setSelected] = useState({});
8
8
  const singleSelectClicked = useRef({});
9
9
  const toggleIdSelected = useCallback((id) => {
10
- if (type === QuestionTypes.SingleSelect) {
10
+ if (type === QuestionTypes.SingleSelect || type === QuestionTypes.SingleFilterValue) {
11
11
  singleSelectClicked.current = true;
12
12
  setSelected({ [id]: true });
13
+ return;
13
14
  }
14
- else if (type === QuestionTypes.MultipleSelect) {
15
+ if (type === QuestionTypes.MultipleSelect || type === QuestionTypes.MultipleFilterValues) {
15
16
  if (selected[id]) {
16
17
  const newState = { ...selected };
17
18
  delete newState[id];
@@ -48,12 +49,23 @@ export default function useSelectInputProps(quizAnswerChanged, nextQuestion, cur
48
49
  }, [currentQuestionData?.id]);
49
50
  // Update global state
50
51
  useEffect(() => {
51
- if (currentQuestionData?.type === 'multiple' || currentQuestionData?.type === 'single') {
52
+ if (currentQuestionData?.type === QuestionTypes.MultipleSelect ||
53
+ currentQuestionData?.type === QuestionTypes.SingleSelect) {
52
54
  const selectedAnswers = currentQuestionData?.options
53
55
  ?.filter((opt) => selected[Number(opt.id)])
54
56
  ?.map((opt) => ({ id: opt.id, value: opt.value }));
55
57
  quizAnswerChanged(selectedAnswers);
56
58
  }
59
+ if (currentQuestionData?.type === QuestionTypes.MultipleFilterValues ||
60
+ currentQuestionData?.type === QuestionTypes.SingleFilterValue) {
61
+ const selectedAnswers = currentQuestionData?.options
62
+ ?.filter((opt) => selected[String(opt.id)])
63
+ ?.map((opt) => ({
64
+ id: opt.id,
65
+ value: opt.value,
66
+ }));
67
+ quizAnswerChanged(selectedAnswers);
68
+ }
57
69
  }, [
58
70
  selected,
59
71
  currentQuestionData?.id,
@@ -64,7 +76,9 @@ export default function useSelectInputProps(quizAnswerChanged, nextQuestion, cur
64
76
  // Go to next question only every time answerInputs (answers input state) changes...
65
77
  // and it's a singleSelectQuestion and user has just clicked on an option
66
78
  useEffect(() => {
67
- if (currentQuestionData?.type === 'single' && singleSelectClicked.current) {
79
+ if ((currentQuestionData?.type === QuestionTypes.SingleSelect ||
80
+ currentQuestionData?.type === QuestionTypes.SingleFilterValue) &&
81
+ singleSelectClicked.current) {
68
82
  nextQuestion();
69
83
  }
70
84
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -26,6 +26,8 @@ const useQuizAnswerChangeHandler = (quizApiState, dispatchLocalState) => {
26
26
  break;
27
27
  case QuestionTypes.SingleSelect:
28
28
  case QuestionTypes.MultipleSelect:
29
+ case QuestionTypes.SingleFilterValue:
30
+ case QuestionTypes.MultipleFilterValues:
29
31
  dispatchLocalState({
30
32
  type: currentQuestion.next_question.type,
31
33
  payload: {
package/lib/mjs/utils.js CHANGED
@@ -70,13 +70,17 @@ export const getQuestionTypes = (questionType) => {
70
70
  const isCoverQuestion = questionType === QuestionTypes.Cover;
71
71
  const isSingleQuestion = questionType === QuestionTypes.SingleSelect;
72
72
  const isMultipleQuestion = questionType === QuestionTypes.MultipleSelect;
73
- const isSelectQuestion = isSingleQuestion || isMultipleQuestion;
73
+ const isSingleFilterQuestion = questionType === QuestionTypes.SingleFilterValue;
74
+ const isMultipleFilterQuestion = questionType === QuestionTypes.MultipleFilterValues;
75
+ const isSelectQuestion = isSingleQuestion || isMultipleQuestion || isSingleFilterQuestion || isMultipleFilterQuestion;
74
76
  return {
75
77
  isOpenQuestion,
76
78
  isCoverQuestion,
77
79
  isSingleQuestion,
78
80
  isMultipleQuestion,
79
81
  isSelectQuestion,
82
+ isSingleFilterQuestion,
83
+ isMultipleFilterQuestion,
80
84
  };
81
85
  };
82
86
  export function getPreferredColorScheme() {
@@ -1 +1 @@
1
- export default '1.17.24';
1
+ export default '1.17.25';
@@ -5,6 +5,8 @@ export declare enum QuestionTypes {
5
5
  Cover = "cover",
6
6
  SingleSelect = "single",
7
7
  MultipleSelect = "multiple",
8
+ SingleFilterValue = "single_filter_value",
9
+ MultipleFilterValues = "multiple_filter_values",
8
10
  Next = "next",
9
11
  Skip = "skip",
10
12
  Back = "back",
@@ -23,7 +25,7 @@ interface Action<Type, Payload = {}> {
23
25
  type: Type;
24
26
  payload?: Payload;
25
27
  }
26
- export type ActionAnswerInputQuestion = Action<QuestionTypes.OpenText, OpenTextQuestionPayload> | Action<QuestionTypes.SingleSelect, SelectQuestionPayload> | Action<QuestionTypes.MultipleSelect, SelectQuestionPayload> | Action<QuestionTypes.Cover, CoverQuestionPayload>;
28
+ export type ActionAnswerInputQuestion = Action<QuestionTypes.OpenText, OpenTextQuestionPayload> | Action<QuestionTypes.SingleSelect, SelectQuestionPayload> | Action<QuestionTypes.MultipleSelect, SelectQuestionPayload> | Action<QuestionTypes.SingleFilterValue, SelectQuestionPayload> | Action<QuestionTypes.MultipleFilterValues, SelectQuestionPayload> | Action<QuestionTypes.Cover, CoverQuestionPayload>;
27
29
  export type ActionAnswerQuestion = ActionAnswerInputQuestion | Action<QuestionTypes.Next, CurrentQuestion> | Action<QuestionTypes.Skip, CurrentQuestion> | Action<QuestionTypes.Back, CurrentQuestion> | Action<QuestionTypes.Reset> | Action<QuestionTypes.Complete> | Action<QuestionTypes.Hydrate, Partial<QuizLocalReducerState>>;
28
30
  export declare enum QuizAPIActionTypes {
29
31
  SET_IS_LOADING = 0,
@@ -105,13 +105,15 @@ export interface QuizSessionStorageState {
105
105
  skipToResults: boolean;
106
106
  hasSessionStorageState: () => boolean;
107
107
  }
108
- export type InputQuestionsTypes = QuestionTypes.OpenText | QuestionTypes.Cover | QuestionTypes.SingleSelect | QuestionTypes.MultipleSelect;
108
+ export type InputQuestionsTypes = QuestionTypes.OpenText | QuestionTypes.Cover | QuestionTypes.SingleSelect | QuestionTypes.MultipleSelect | QuestionTypes.SingleFilterValue | QuestionTypes.MultipleFilterValues;
109
109
  export type CurrentQuestion = NextQuestionResponse & {
110
110
  isFirstQuestion: boolean;
111
111
  isOpenQuestion: boolean;
112
112
  isCoverQuestion: boolean;
113
113
  isSingleQuestion: boolean;
114
114
  isMultipleQuestion: boolean;
115
+ isSingleFilterQuestion: boolean;
116
+ isMultipleFilterQuestion: boolean;
115
117
  isSelectQuestion: boolean;
116
118
  };
117
119
  export declare namespace QuizEventsReturn {
@@ -217,7 +219,7 @@ export interface SelectInputProps {
217
219
  onKeyDown: React.KeyboardEventHandler<HTMLElement>;
218
220
  role: 'button';
219
221
  tabIndex: number;
220
- key: number;
222
+ key: number | string;
221
223
  }
222
224
  export type GetOpenTextInputProps = () => OpenTextInputProps;
223
225
  export type GetCoverQuestionProps = () => CoverQuestionProps;
@@ -27,6 +27,8 @@ export declare const getQuestionTypes: (questionType?: `${QuestionTypes}`) => {
27
27
  isSingleQuestion: boolean;
28
28
  isMultipleQuestion: boolean;
29
29
  isSelectQuestion: boolean;
30
+ isSingleFilterQuestion: boolean;
31
+ isMultipleFilterQuestion: boolean;
30
32
  };
31
33
  export declare function getPreferredColorScheme(): string;
32
34
  export declare function isFunction(fn: any): boolean;
@@ -1,2 +1,2 @@
1
- declare const _default: "1.17.24";
1
+ declare const _default: "1.17.25";
2
2
  export default _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructor-io/constructorio-ui-quizzes",
3
- "version": "1.17.24",
3
+ "version": "1.17.25",
4
4
  "description": "Constructor.io Quizzes UI library for web applications",
5
5
  "author": "Constructor.io Corporation",
6
6
  "license": "MIT",
@@ -59,7 +59,7 @@
59
59
  "check-license": "license-checker --production --onlyAllow 'Apache-2.0;BSD-3-Clause;MIT;0BSD;BSD-2-Clause' --excludePackages 'picocolors@1.0.0'"
60
60
  },
61
61
  "peerDependencies": {
62
- "@constructor-io/constructorio-client-javascript": "^2.42.3",
62
+ "@constructor-io/constructorio-client-javascript": "^2.65.1",
63
63
  "react": ">=16.12.0",
64
64
  "react-dom": ">=16.12.0",
65
65
  "tslib": "^2.4.0"
@@ -112,6 +112,7 @@
112
112
  "typescript": "^4.9.4",
113
113
  "vite": "^4.2.1",
114
114
  "vite-plugin-css-injected-by-js": "^3.1.0",
115
- "webpack": "^5.75.0"
115
+ "webpack": "^5.75.0",
116
+ "whatwg-fetch": "^3.6.20"
116
117
  }
117
118
  }