@constructor-io/constructorio-ui-quizzes 1.4.1 → 1.4.3

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,12 +8,12 @@ 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, _l, _m;
11
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
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 });
15
15
  case actions_1.QuizAPIActionTypes.SET_IS_ERROR:
16
- return Object.assign(Object.assign({}, state), { quizRequestState: constants_1.RequestStates.Error, quizCurrentQuestion: undefined, quizResults: undefined });
16
+ return Object.assign(Object.assign({}, state), { quizRequestState: constants_1.RequestStates.Error, quizCurrentQuestion: undefined, quizResults: undefined, selectedOptionsWithAttributes: undefined });
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);
@@ -22,12 +22,11 @@ function apiReducer(state, action) {
22
22
  isCoverQuestion,
23
23
  isSingleQuestion,
24
24
  isMultipleQuestion,
25
- isSelectQuestion }), quizFirstQuestion, quizResults: undefined });
25
+ isSelectQuestion }), quizFirstQuestion, quizResults: undefined, selectedOptionsWithAttributes: undefined });
26
26
  }
27
27
  case actions_1.QuizAPIActionTypes.SET_QUIZ_RESULTS: {
28
- const filterExpression = ((_l = (_k = (_j = action.payload) === null || _j === void 0 ? void 0 : _j.quizResults) === null || _k === void 0 ? void 0 : _k.request) === null || _l === void 0 ? void 0 : _l.collection_filter_expression) || null;
29
- const quizResultsFilters = [...new Set((0, utils_1.getFilterValuesFromExpression)(filterExpression))];
30
- return Object.assign(Object.assign({}, state), { quizRequestState: constants_1.RequestStates.Success, quizResults: (_m = action.payload) === null || _m === void 0 ? void 0 : _m.quizResults, quizResultsFilters, quizCurrentQuestion: undefined });
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 });
31
30
  }
32
31
  case actions_1.QuizAPIActionTypes.RESET_QUIZ:
33
32
  return exports.initialState;
@@ -13,12 +13,12 @@ function ResultContainer(props) {
13
13
  const { resultCardSalePriceKey, resultCardRegularPriceKey } = options;
14
14
  const { state } = (0, react_1.useContext)(context_1.default);
15
15
  const zeroResults = !((_c = (_b = (_a = state === null || state === void 0 ? void 0 : state.quiz.results) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.results) === null || _c === void 0 ? void 0 : _c.length);
16
- const resultsTitle = zeroResults ? 'Oops, there are no results' : 'Here are your results';
16
+ const resultsTitle = zeroResults ? '' : 'Here are your results';
17
17
  if (state === null || state === void 0 ? void 0 : state.quiz.results) {
18
18
  return (react_1.default.createElement("div", { className: 'cio-results-container' },
19
19
  react_1.default.createElement("h1", { className: 'cio-results-title' }, resultsTitle),
20
20
  react_1.default.createElement("div", { className: 'cio-results-filter-and-redo-container' },
21
- react_1.default.createElement(ResultFilters_1.default, null),
21
+ react_1.default.createElement(ResultFilters_1.default, { hasNoResults: zeroResults }),
22
22
  react_1.default.createElement(RedoButton_1.default, null)),
23
23
  !zeroResults && (react_1.default.createElement(Results_1.default, { resultCardSalePriceKey: resultCardSalePriceKey, resultCardRegularPriceKey: resultCardRegularPriceKey })),
24
24
  zeroResults && react_1.default.createElement(ZeroResults_1.default, null)));
@@ -3,11 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const react_1 = tslib_1.__importStar(require("react"));
5
5
  const context_1 = tslib_1.__importDefault(require("../CioQuiz/context"));
6
- function ResultFilters() {
6
+ function ResultFilters({ hasNoResults }) {
7
7
  var _a;
8
8
  const { state } = (0, react_1.useContext)(context_1.default);
9
9
  return (react_1.default.createElement("div", { className: 'cio-results-filter-container' },
10
- react_1.default.createElement("p", null, "Because you answered"),
11
- react_1.default.createElement("div", { className: 'cio-results-filter-options' }, (_a = state === null || state === void 0 ? void 0 : state.quiz.resultsFilters) === null || _a === void 0 ? void 0 : _a.map((filter) => (react_1.default.createElement("div", { className: 'cio-results-filter-option', key: filter }, filter))))));
10
+ react_1.default.createElement("p", null, hasNoResults ? 'Your preferences' : 'Because you answered'),
11
+ react_1.default.createElement("div", { className: 'cio-results-filter-options' }, (_a = state === null || state === void 0 ? void 0 : state.quiz.selectedOptionsWithAttributes) === null || _a === void 0 ? void 0 : _a.map((option) => (react_1.default.createElement("div", { className: 'cio-results-filter-option', key: option }, option))))));
12
12
  }
13
13
  exports.default = ResultFilters;
@@ -7,8 +7,7 @@ const context_1 = tslib_1.__importDefault(require("../CioQuiz/context"));
7
7
  function ZeroResults() {
8
8
  const { getResetQuizButtonProps } = (0, react_1.useContext)(context_1.default);
9
9
  return (react_1.default.createElement("div", { className: 'cio-zero-results' },
10
- react_1.default.createElement("h3", { className: 'cio-zero-results-subtitle' }, "Sorry, it seems like we couldn\u2019t find results based on your answers."),
11
- react_1.default.createElement("p", { className: 'cio-zero-results-description' }, "This is embarrassing \uD83D\uDE22. It might be that some of the questions are not properly set up from our end. Would you give us another try?"),
12
- react_1.default.createElement(CTAButton_1.default, { ctaText: 'Try Again', propsGetters: getResetQuizButtonProps })));
10
+ react_1.default.createElement("h3", { className: 'cio-zero-results-subtitle' }, "Sorry, we couldn\u2019t find products that perfectly match your preferences."),
11
+ react_1.default.createElement(CTAButton_1.default, { ctaText: 'Redo Quiz', propsGetters: getResetQuizButtonProps })));
13
12
  }
14
13
  exports.default = ZeroResults;
@@ -33,7 +33,7 @@ const useQuiz = (quizOptions) => {
33
33
  sessionId: quizLocalState.quizSessionId,
34
34
  currentQuestion: quizApiState.quizCurrentQuestion,
35
35
  results: quizApiState.quizResults,
36
- resultsFilters: quizApiState.quizResultsFilters,
36
+ selectedOptionsWithAttributes: quizApiState.selectedOptionsWithAttributes,
37
37
  },
38
38
  }, events: Object.assign({}, quizEvents) }, propGetters), { primaryColorStyles });
39
39
  };
@@ -105,8 +105,12 @@ const getMockState = (question) => ({
105
105
  quiz_id: '',
106
106
  quiz_session_id: '',
107
107
  quiz_version_id: '',
108
+ quiz_selected_options: [
109
+ { value: 'Option 1', has_attribute: true },
110
+ { value: 'Option 2', has_attribute: true },
111
+ ],
108
112
  },
109
- resultsFilters: ['Chocolate', 'Medium'],
113
+ selectedOptionsWithAttributes: ['Option 1', 'Option 2'],
110
114
  },
111
115
  });
112
116
  exports.getMockState = getMockState;
package/lib/cjs/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.convertPrimaryColorsToString = exports.rgbToHsl = exports.sleep = exports.logger = exports.resetQuizSessionStorageState = exports.getStateFromSessionStorage = exports.getFilterValuesFromExpression = exports.isFunction = exports.getPreferredColorScheme = exports.getQuestionTypes = exports.stringify = exports.stringifyWithDefaults = exports.functionStrings = exports.getStoryParams = exports.renderImages = void 0;
3
+ exports.convertPrimaryColorsToString = exports.rgbToHsl = exports.sleep = exports.logger = exports.resetQuizSessionStorageState = exports.getStateFromSessionStorage = exports.isFunction = exports.getPreferredColorScheme = exports.getQuestionTypes = exports.stringify = exports.stringifyWithDefaults = exports.functionStrings = exports.getStoryParams = exports.renderImages = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  /* eslint-disable no-console */
6
6
  const react_1 = tslib_1.__importDefault(require("react"));
@@ -105,25 +105,6 @@ function isFunction(fn) {
105
105
  return fn && typeof fn === 'function';
106
106
  }
107
107
  exports.isFunction = isFunction;
108
- const isValueExpression = (exp) => 'name' in exp && 'value' in exp;
109
- const isAndFilter = (exp) => 'and' in exp;
110
- const isOrFilter = (exp) => 'or' in exp;
111
- const getFilterValuesFromExpression = (exp) => {
112
- if (!exp) {
113
- return [];
114
- }
115
- if (isAndFilter(exp)) {
116
- return exp.and.flatMap((innerExpression) => (0, exports.getFilterValuesFromExpression)(innerExpression));
117
- }
118
- if (isOrFilter(exp)) {
119
- return exp.or.flatMap((innerExpression) => (0, exports.getFilterValuesFromExpression)(innerExpression));
120
- }
121
- if (isValueExpression(exp)) {
122
- return [exp.value];
123
- }
124
- return [];
125
- };
126
- exports.getFilterValuesFromExpression = getFilterValuesFromExpression;
127
108
  const getStateFromSessionStorage = (quizStateKey) => {
128
109
  var _a;
129
110
  const state = (_a = window === null || window === void 0 ? void 0 : window.sessionStorage) === null || _a === void 0 ? void 0 : _a.getItem(quizStateKey);
@@ -1,5 +1,5 @@
1
1
  import { RequestStates } from '../../constants';
2
- import { getFilterValuesFromExpression, getQuestionTypes } from '../../utils';
2
+ import { getQuestionTypes } from '../../utils';
3
3
  import { QuizAPIActionTypes } from './actions';
4
4
  export const initialState = {
5
5
  quizRequestState: RequestStates.Stale,
@@ -19,6 +19,7 @@ export default function apiReducer(state, action) {
19
19
  quizRequestState: RequestStates.Error,
20
20
  quizCurrentQuestion: undefined,
21
21
  quizResults: undefined,
22
+ selectedOptionsWithAttributes: undefined,
22
23
  };
23
24
  case QuizAPIActionTypes.SET_CURRENT_QUESTION: {
24
25
  const { isOpenQuestion, isCoverQuestion, isSingleQuestion, isMultipleQuestion, isSelectQuestion, } = getQuestionTypes(action.payload?.quizCurrentQuestion?.next_question?.type);
@@ -38,17 +39,19 @@ export default function apiReducer(state, action) {
38
39
  },
39
40
  quizFirstQuestion,
40
41
  quizResults: undefined,
42
+ selectedOptionsWithAttributes: undefined,
41
43
  };
42
44
  }
43
45
  case QuizAPIActionTypes.SET_QUIZ_RESULTS: {
44
- const filterExpression = action.payload?.quizResults?.request?.collection_filter_expression || null;
45
- const quizResultsFilters = [...new Set(getFilterValuesFromExpression(filterExpression))];
46
+ const selectedOptionsWithAttributes = action.payload?.quizResults.quiz_selected_options
47
+ .filter((option) => option.has_attribute)
48
+ .map((option) => option.value) || [];
46
49
  return {
47
50
  ...state,
48
51
  quizRequestState: RequestStates.Success,
49
52
  quizResults: action.payload?.quizResults,
50
- quizResultsFilters,
51
53
  quizCurrentQuestion: undefined,
54
+ selectedOptionsWithAttributes,
52
55
  };
53
56
  }
54
57
  case QuizAPIActionTypes.RESET_QUIZ:
@@ -9,12 +9,12 @@ export default function ResultContainer(props) {
9
9
  const { resultCardSalePriceKey, resultCardRegularPriceKey } = options;
10
10
  const { state } = useContext(QuizContext);
11
11
  const zeroResults = !state?.quiz.results?.response?.results?.length;
12
- const resultsTitle = zeroResults ? 'Oops, there are no results' : 'Here are your results';
12
+ const resultsTitle = zeroResults ? '' : 'Here are your results';
13
13
  if (state?.quiz.results) {
14
14
  return (React.createElement("div", { className: 'cio-results-container' },
15
15
  React.createElement("h1", { className: 'cio-results-title' }, resultsTitle),
16
16
  React.createElement("div", { className: 'cio-results-filter-and-redo-container' },
17
- React.createElement(ResultFilters, null),
17
+ React.createElement(ResultFilters, { hasNoResults: zeroResults }),
18
18
  React.createElement(RedoButton, null)),
19
19
  !zeroResults && (React.createElement(Results, { resultCardSalePriceKey: resultCardSalePriceKey, resultCardRegularPriceKey: resultCardRegularPriceKey })),
20
20
  zeroResults && React.createElement(ZeroResults, null)));
@@ -1,9 +1,9 @@
1
1
  import React, { useContext } from 'react';
2
2
  import QuizContext from '../CioQuiz/context';
3
- function ResultFilters() {
3
+ function ResultFilters({ hasNoResults }) {
4
4
  const { state } = useContext(QuizContext);
5
5
  return (React.createElement("div", { className: 'cio-results-filter-container' },
6
- React.createElement("p", null, "Because you answered"),
7
- React.createElement("div", { className: 'cio-results-filter-options' }, state?.quiz.resultsFilters?.map((filter) => (React.createElement("div", { className: 'cio-results-filter-option', key: filter }, filter))))));
6
+ React.createElement("p", null, hasNoResults ? 'Your preferences' : 'Because you answered'),
7
+ React.createElement("div", { className: 'cio-results-filter-options' }, state?.quiz.selectedOptionsWithAttributes?.map((option) => (React.createElement("div", { className: 'cio-results-filter-option', key: option }, option))))));
8
8
  }
9
9
  export default ResultFilters;
@@ -4,8 +4,7 @@ import QuizContext from '../CioQuiz/context';
4
4
  function ZeroResults() {
5
5
  const { getResetQuizButtonProps } = useContext(QuizContext);
6
6
  return (React.createElement("div", { className: 'cio-zero-results' },
7
- React.createElement("h3", { className: 'cio-zero-results-subtitle' }, "Sorry, it seems like we couldn\u2019t find results based on your answers."),
8
- React.createElement("p", { className: 'cio-zero-results-description' }, "This is embarrassing \uD83D\uDE22. It might be that some of the questions are not properly set up from our end. Would you give us another try?"),
9
- React.createElement(CTAButton, { ctaText: 'Try Again', propsGetters: getResetQuizButtonProps })));
7
+ React.createElement("h3", { className: 'cio-zero-results-subtitle' }, "Sorry, we couldn\u2019t find products that perfectly match your preferences."),
8
+ React.createElement(CTAButton, { ctaText: 'Redo Quiz', propsGetters: getResetQuizButtonProps })));
10
9
  }
11
10
  export default ZeroResults;
@@ -32,7 +32,7 @@ const useQuiz = (quizOptions) => {
32
32
  sessionId: quizLocalState.quizSessionId,
33
33
  currentQuestion: quizApiState.quizCurrentQuestion,
34
34
  results: quizApiState.quizResults,
35
- resultsFilters: quizApiState.quizResultsFilters,
35
+ selectedOptionsWithAttributes: quizApiState.selectedOptionsWithAttributes,
36
36
  },
37
37
  },
38
38
  events: {
@@ -117,8 +117,12 @@ export const getMockState = (question) => ({
117
117
  quiz_id: '',
118
118
  quiz_session_id: '',
119
119
  quiz_version_id: '',
120
+ quiz_selected_options: [
121
+ { value: 'Option 1', has_attribute: true },
122
+ { value: 'Option 2', has_attribute: true },
123
+ ],
120
124
  },
121
- resultsFilters: ['Chocolate', 'Medium'],
125
+ selectedOptionsWithAttributes: ['Option 1', 'Option 2'],
122
126
  },
123
127
  });
124
128
  const mockElementProps = {
package/lib/mjs/utils.js CHANGED
@@ -93,24 +93,6 @@ export function getPreferredColorScheme() {
93
93
  export function isFunction(fn) {
94
94
  return fn && typeof fn === 'function';
95
95
  }
96
- const isValueExpression = (exp) => 'name' in exp && 'value' in exp;
97
- const isAndFilter = (exp) => 'and' in exp;
98
- const isOrFilter = (exp) => 'or' in exp;
99
- export const getFilterValuesFromExpression = (exp) => {
100
- if (!exp) {
101
- return [];
102
- }
103
- if (isAndFilter(exp)) {
104
- return exp.and.flatMap((innerExpression) => getFilterValuesFromExpression(innerExpression));
105
- }
106
- if (isOrFilter(exp)) {
107
- return exp.or.flatMap((innerExpression) => getFilterValuesFromExpression(innerExpression));
108
- }
109
- if (isValueExpression(exp)) {
110
- return [exp.value];
111
- }
112
- return [];
113
- };
114
96
  export const getStateFromSessionStorage = (quizStateKey) => {
115
97
  const state = window?.sessionStorage?.getItem(quizStateKey);
116
98
  if (state) {
package/lib/styles.css CHANGED
@@ -432,15 +432,10 @@
432
432
  font-weight: 500;
433
433
  font-size: 1.25rem;
434
434
  line-height: 1.5rem;
435
+ margin-bottom: 2rem;
435
436
  color: var(--gray-dust-500);
436
437
  margin-top: 0;
437
438
  }
438
- .cio-zero-results-description {
439
- color: var(--gray-dust-100);
440
- line-height: 1.25rem;
441
- margin-top: 0;
442
- }
443
-
444
439
  .cio-zero-results .cio-button-container {
445
440
  width: 14rem;
446
441
  margin-right: auto;
@@ -565,7 +560,6 @@
565
560
  /* Container */
566
561
  .cio-container--with-image {
567
562
  display: flex;
568
- justify-content: center;
569
563
  align-items: center;
570
564
  margin-bottom: 0;
571
565
  padding-bottom: 0;
@@ -582,7 +576,6 @@
582
576
 
583
577
  /* Cover Page Component */
584
578
  .cio-cover-question-container--with-image {
585
- justify-content: center;
586
579
  margin-bottom: 0;
587
580
  padding-bottom: 0;
588
581
  }
@@ -629,6 +622,7 @@
629
622
  padding: 6% 2%;
630
623
  align-items: center;
631
624
  flex-direction: row;
625
+ justify-content: center;
632
626
  }
633
627
  .cio-cover-question-container--with-image {
634
628
  flex-direction: row-reverse;
@@ -6,7 +6,7 @@ export type QuizAPIReducerState = {
6
6
  quizCurrentQuestion?: CurrentQuestion;
7
7
  quizFirstQuestion?: NextQuestionResponse;
8
8
  quizResults?: QuizResultsResponse;
9
- quizResultsFilters?: string[];
9
+ selectedOptionsWithAttributes?: string[];
10
10
  };
11
11
  export declare const initialState: QuizAPIReducerState;
12
12
  export default function apiReducer(state: QuizAPIReducerState, action: ActionQuizAPI): QuizAPIReducerState;
@@ -1,3 +1,6 @@
1
1
  /// <reference types="react" />
2
- declare function ResultFilters(): JSX.Element;
2
+ interface ResultFiltersProps {
3
+ hasNoResults: boolean;
4
+ }
5
+ declare function ResultFilters({ hasNoResults }: ResultFiltersProps): JSX.Element;
3
6
  export default ResultFilters;
@@ -44,7 +44,7 @@ export interface QuizReturnState {
44
44
  sessionId?: string;
45
45
  currentQuestion?: CurrentQuestion | undefined;
46
46
  results?: QuizResultsResponse | undefined;
47
- resultsFilters?: string[];
47
+ selectedOptionsWithAttributes?: string[];
48
48
  };
49
49
  }
50
50
  export type AnswerInputState = {
@@ -1,4 +1,3 @@
1
- import { FilterExpression } from '@constructor-io/constructorio-client-javascript/lib/types';
2
1
  import { QuestionTypes } from './components/CioQuiz/actions';
3
2
  import { QuizLocalReducerState } from './components/CioQuiz/quizLocalReducer';
4
3
  import { PrimaryColorStyles, QuestionImages } from './types';
@@ -37,7 +36,6 @@ export declare const getQuestionTypes: (questionType?: `${QuestionTypes}`) => {
37
36
  };
38
37
  export declare function getPreferredColorScheme(): string;
39
38
  export declare function isFunction(fn: any): boolean;
40
- export declare const getFilterValuesFromExpression: (exp: FilterExpression | null) => string[];
41
39
  export declare const getStateFromSessionStorage: (quizStateKey: string) => QuizLocalReducerState | null;
42
40
  export declare const resetQuizSessionStorageState: (quizStateKey: string) => () => void;
43
41
  export declare const logger: (action: any) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructor-io/constructorio-ui-quizzes",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "description": "Constructor.io Quizzes UI library for web applications",
5
5
  "author": "constructor.io",
6
6
  "license": "MIT",
@@ -54,7 +54,7 @@
54
54
  "check-license": "license-checker --production --onlyAllow 'Apache-2.0;BSD-3-Clause;MIT;0BSD;BSD-2-Clause' --excludePackages 'picocolors@1.0.0'"
55
55
  },
56
56
  "peerDependencies": {
57
- "@constructor-io/constructorio-client-javascript": "^2.35.12",
57
+ "@constructor-io/constructorio-client-javascript": "^2.35.14",
58
58
  "react": ">=16.12.0",
59
59
  "react-dom": ">=16.12.0",
60
60
  "tslib": "^2.4.0"