@constructor-io/constructorio-ui-quizzes 1.0.1

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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +88 -0
  3. package/lib/cjs/components/BackButton/BackButton.js +12 -0
  4. package/lib/cjs/components/CTAButton/CTAButton.js +10 -0
  5. package/lib/cjs/components/CioQuiz/actions.js +12 -0
  6. package/lib/cjs/components/CioQuiz/context.js +5 -0
  7. package/lib/cjs/components/CioQuiz/index.js +115 -0
  8. package/lib/cjs/components/CioQuiz/reducer.js +32 -0
  9. package/lib/cjs/components/ControlBar/ControlBar.js +13 -0
  10. package/lib/cjs/components/CoverTypeQuestion/CoverTypeQuestion.js +42 -0
  11. package/lib/cjs/components/OpenTextTypeQuestion/OpenTextTypeQuestion.js +66 -0
  12. package/lib/cjs/components/QuestionDescription/QuestionDescription.js +9 -0
  13. package/lib/cjs/components/QuestionTitle/QuestionTitle.js +9 -0
  14. package/lib/cjs/components/QuizQuestions/index.js +17 -0
  15. package/lib/cjs/components/RedoButton/RedoButton.js +12 -0
  16. package/lib/cjs/components/RedoButton/RedoSVG.js +15 -0
  17. package/lib/cjs/components/ResultCard/ResultCard.js +45 -0
  18. package/lib/cjs/components/ResultContainer/ResultContainer.js +39 -0
  19. package/lib/cjs/components/ResultCtaButton/ResultCtaButton.js +16 -0
  20. package/lib/cjs/components/ResultFilters/ResultFilters.js +30 -0
  21. package/lib/cjs/components/Results/Results.js +16 -0
  22. package/lib/cjs/components/SelectTypeQuestion/SelectTypeQuestion.js +90 -0
  23. package/lib/cjs/components/Spinner/Spinner.js +12 -0
  24. package/lib/cjs/components/ZeroResults/ZeroResults.js +13 -0
  25. package/lib/cjs/constants.js +36 -0
  26. package/lib/cjs/hooks/useCioClient.js +11 -0
  27. package/lib/cjs/index.js +5 -0
  28. package/lib/cjs/stories/Quiz/argTypes.js +30 -0
  29. package/lib/cjs/types.js +2 -0
  30. package/lib/cjs/utils.js +97 -0
  31. package/lib/mjs/components/BackButton/BackButton.js +9 -0
  32. package/lib/mjs/components/CTAButton/CTAButton.js +7 -0
  33. package/lib/mjs/components/CioQuiz/actions.js +9 -0
  34. package/lib/mjs/components/CioQuiz/context.js +2 -0
  35. package/lib/mjs/components/CioQuiz/index.js +111 -0
  36. package/lib/mjs/components/CioQuiz/reducer.js +55 -0
  37. package/lib/mjs/components/ControlBar/ControlBar.js +10 -0
  38. package/lib/mjs/components/CoverTypeQuestion/CoverTypeQuestion.js +37 -0
  39. package/lib/mjs/components/OpenTextTypeQuestion/OpenTextTypeQuestion.js +61 -0
  40. package/lib/mjs/components/QuestionDescription/QuestionDescription.js +6 -0
  41. package/lib/mjs/components/QuestionTitle/QuestionTitle.js +6 -0
  42. package/lib/mjs/components/QuizQuestions/index.js +13 -0
  43. package/lib/mjs/components/RedoButton/RedoButton.js +9 -0
  44. package/lib/mjs/components/RedoButton/RedoSVG.js +12 -0
  45. package/lib/mjs/components/ResultCard/ResultCard.js +37 -0
  46. package/lib/mjs/components/ResultContainer/ResultContainer.js +34 -0
  47. package/lib/mjs/components/ResultCtaButton/ResultCtaButton.js +12 -0
  48. package/lib/mjs/components/ResultFilters/ResultFilters.js +27 -0
  49. package/lib/mjs/components/Results/Results.js +9 -0
  50. package/lib/mjs/components/SelectTypeQuestion/SelectTypeQuestion.js +85 -0
  51. package/lib/mjs/components/Spinner/Spinner.js +8 -0
  52. package/lib/mjs/components/ZeroResults/ZeroResults.js +10 -0
  53. package/lib/mjs/constants.js +33 -0
  54. package/lib/mjs/hooks/useCioClient.js +9 -0
  55. package/lib/mjs/index.js +2 -0
  56. package/lib/mjs/stories/Quiz/argTypes.js +27 -0
  57. package/lib/mjs/types.js +1 -0
  58. package/lib/mjs/utils.js +83 -0
  59. package/lib/styles.css +689 -0
  60. package/lib/types/components/BackButton/BackButton.d.ts +3 -0
  61. package/lib/types/components/CTAButton/CTAButton.d.ts +6 -0
  62. package/lib/types/components/CioQuiz/actions.d.ts +25 -0
  63. package/lib/types/components/CioQuiz/context.d.ts +17 -0
  64. package/lib/types/components/CioQuiz/index.d.ts +14 -0
  65. package/lib/types/components/CioQuiz/reducer.d.ts +12 -0
  66. package/lib/types/components/ControlBar/ControlBar.d.ts +10 -0
  67. package/lib/types/components/CoverTypeQuestion/CoverTypeQuestion.d.ts +2 -0
  68. package/lib/types/components/OpenTextTypeQuestion/OpenTextTypeQuestion.d.ts +7 -0
  69. package/lib/types/components/QuestionDescription/QuestionDescription.d.ts +6 -0
  70. package/lib/types/components/QuestionTitle/QuestionTitle.d.ts +6 -0
  71. package/lib/types/components/QuizQuestions/index.d.ts +5 -0
  72. package/lib/types/components/RedoButton/RedoButton.d.ts +6 -0
  73. package/lib/types/components/RedoButton/RedoSVG.d.ts +3 -0
  74. package/lib/types/components/ResultCard/ResultCard.d.ts +11 -0
  75. package/lib/types/components/ResultContainer/ResultContainer.d.ts +7 -0
  76. package/lib/types/components/ResultCtaButton/ResultCtaButton.d.ts +9 -0
  77. package/lib/types/components/ResultFilters/ResultFilters.d.ts +6 -0
  78. package/lib/types/components/Results/Results.d.ts +10 -0
  79. package/lib/types/components/SelectTypeQuestion/SelectTypeQuestion.d.ts +3 -0
  80. package/lib/types/components/Spinner/Spinner.d.ts +2 -0
  81. package/lib/types/components/ZeroResults/ZeroResults.d.ts +6 -0
  82. package/lib/types/constants.d.ts +11 -0
  83. package/lib/types/hooks/useCioClient.d.ts +8 -0
  84. package/lib/types/index.d.ts +2 -0
  85. package/lib/types/stories/Quiz/argTypes.d.ts +30 -0
  86. package/lib/types/types.d.ts +1 -0
  87. package/lib/types/utils.d.ts +31 -0
  88. package/package.json +91 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Constructor.io
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # Constructor.io Quizzes UI Library
2
+
3
+ A UI Library that provides React components to manage the fetching and rendering logic for [Constructor.io's Quizzes](https://constructor.io/products/quizzes/).
4
+
5
+ ## Introduction
6
+
7
+ [Constructor.io's Quizzes](https://constructor.io/products/quizzes/) are interactive experiences that personalizes the shopping journey for each of your customers. This UI library simplifies the integration process by providing React Components that handle the fetching and rendering logic for Quizzes. Typescript support is available.
8
+
9
+ [Our storybook docs](https://constructor-io.github.io/constructorio-ui-quizzes) are the best place to explore the behavior and the available configuration options for this UI Library.
10
+
11
+ ![Quizzes-UI-Example](assets/coffee-quiz.gif)
12
+
13
+ ## How to use this UI Library
14
+
15
+ ### Install
16
+
17
+ ```bash
18
+ npm i @constructor-io/constructorio-ui-quizzes
19
+ ```
20
+
21
+ The `CioQuiz` component handles state management, data fetching, and rendering logic for the entire quiz.
22
+
23
+ ```jsx
24
+ import CioQuiz from '@constructor-io/constructorio-ui-quizzes';
25
+
26
+ function YourComponent() {
27
+ return (
28
+ <div>
29
+ <CioQuiz quizId="coffee-quiz" apiKey="key_wJSdZSiesX5hiVLt" />
30
+ </div>
31
+ );
32
+ ```
33
+
34
+ ## Custom Styling
35
+
36
+ ### Library defaults
37
+
38
+ By default, importing React components from this library does not pull any css into your project.
39
+
40
+ If you wish to use some starter styles from this library, add an import statement similar to the example import statement below:
41
+
42
+ ```js
43
+ import '@constructor-io/constructorio-ui-quizzes/styles.css';
44
+ ```
45
+
46
+ - These starter styles can be used as a foundation to build on top of, or just as a reference for you to replace completely.
47
+ - To opt out of all default styling, do not import the `styles.css` stylesheet.
48
+ - All starter styles in this library are scoped within the `.cio-quiz` css selector.
49
+ - These starter styles are intended to be extended by layering in your own css rules
50
+ - If you import the starter styles, `CioQuiz` component will take up the full width and height of its parent container
51
+
52
+ ## Troubleshooting
53
+
54
+ ### Known Issues
55
+
56
+ **ESLint**
57
+
58
+ There is a known issue with ESLint where it fails to resolve the paths exposed in the `exports` statement of NPM packages. If you are receiving the following error, you can safely disable ESLint using `// eslint-disable-line` for that line.
59
+
60
+ `Unable to resolve path to module '@constructor-io/constructorio-ui-quizzes/styles.css'`
61
+
62
+ Relevant open issues:
63
+
64
+ [Issue 1868](https://github.com/import-js/eslint-plugin-import/issues/1868)
65
+
66
+ [Issue 1810](https://github.com/import-js/eslint-plugin-import/issues/1810)
67
+
68
+ ## Local Development
69
+
70
+ ### Development scripts
71
+
72
+ ```bash
73
+ npm ci # install dependencies for local dev
74
+ npm run dev # start a local dev server for Storybook
75
+ npm run lint # run linter
76
+ ```
77
+
78
+ ### Maintain Library
79
+
80
+ ```bash
81
+ npm run compile # generate lib folder for publishing to npm
82
+ npm run build-storybook # generate storybook static bundle for deploy with GH Pages
83
+ ```
84
+
85
+ ## Supporting Docs
86
+
87
+ - [Storybook 7 Introduction](https://storybook.js.org/docs/7.0/react/get-started/introduction)
88
+ - [Typescript Docs](https://www.typescriptlang.org/docs/)
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ function BackButton(props) {
6
+ // eslint-disable-next-line
7
+ const { disabled } = props;
8
+ return (react_1.default.createElement("button", Object.assign({ type: 'button', className: `cio-question-back-button ${disabled ? 'disabled' : ''}` }, props),
9
+ react_1.default.createElement("svg", { width: '8', height: '12', viewBox: '0 0 8 12', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
10
+ react_1.default.createElement("path", { d: 'M6.06313 1.06268L0.964522 5.43176C0.882383 5.50218 0.816449 5.58954 0.771245 5.68785C0.726041 5.78615 0.702637 5.89306 0.702637 6.00126C0.702637 6.10946 0.726041 6.21637 0.771245 6.31467C0.816449 6.41297 0.882383 6.50033 0.964522 6.57076L6.06313 10.9398C6.5498 11.3568 7.30153 11.0111 7.30153 10.3703V1.63093C7.30153 0.990168 6.5498 0.644468 6.06313 1.06268Z', fill: 'currentColor' }))));
11
+ }
12
+ exports.default = BackButton;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ function CTAButton(props) {
6
+ const { ctaText = 'Continue', disabled, className = 'cio-button-container' } = props, rest = tslib_1.__rest(props, ["ctaText", "disabled", "className"]);
7
+ return (react_1.default.createElement("div", { className: `${className || ''}` },
8
+ react_1.default.createElement("button", Object.assign({ type: 'button', className: `${disabled ? 'cio-question-cta-button disabled' : 'cio-question-cta-button'}` }, rest), ctaText || 'Continue')));
9
+ }
10
+ exports.default = CTAButton;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QuestionTypes = void 0;
4
+ var QuestionTypes;
5
+ (function (QuestionTypes) {
6
+ QuestionTypes["OpenText"] = "open";
7
+ QuestionTypes["Cover"] = "cover";
8
+ QuestionTypes["SingleSelect"] = "single";
9
+ QuestionTypes["MultipleSelect"] = "multiple";
10
+ QuestionTypes["Back"] = "back";
11
+ QuestionTypes["Reset"] = "reset";
12
+ })(QuestionTypes = exports.QuestionTypes || (exports.QuestionTypes = {}));
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ exports.default = react_1.default.createContext({});
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importStar(require("react"));
5
+ const context_1 = tslib_1.__importDefault(require("./context"));
6
+ const reducer_1 = tslib_1.__importStar(require("./reducer"));
7
+ const actions_1 = require("./actions");
8
+ const QuizQuestions_1 = tslib_1.__importDefault(require("../QuizQuestions"));
9
+ const ResultContainer_1 = tslib_1.__importDefault(require("../ResultContainer/ResultContainer"));
10
+ const constants_1 = require("../../constants");
11
+ const utils_1 = require("../../utils");
12
+ const Spinner_1 = tslib_1.__importDefault(require("../Spinner/Spinner"));
13
+ const useCioClient_1 = tslib_1.__importDefault(require("../../hooks/useCioClient"));
14
+ function CioQuiz(props) {
15
+ const { quizId, apiKey, cioJsClient, resultsPageOptions, quizVersionId: quizVersionIdProp, } = props;
16
+ if (!quizId) {
17
+ // eslint-disable-next-line no-console
18
+ console.error('quizId is a required field of type string');
19
+ }
20
+ const cioClient = (0, useCioClient_1.default)({ apiKey, cioJsClient });
21
+ const [state, dispatch] = (0, react_1.useReducer)(reducer_1.default, reducer_1.initialState);
22
+ const [requestState, setRequestState] = (0, react_1.useState)(constants_1.RequestStates.Stale);
23
+ const [questionResponse, setQuestionResponse] = (0, react_1.useState)();
24
+ const [resultsResponse, setResultsResponse] = (0, react_1.useState)();
25
+ const [firstQuestion, setFirstQuestion] = (0, react_1.useState)();
26
+ const [quizVersionId, setQuizVersionId] = (0, react_1.useState)(quizVersionIdProp || '');
27
+ const [quizSessionId, setQuizSessionId] = (0, react_1.useState)('');
28
+ const isFirstQuestion = (firstQuestion === null || firstQuestion === void 0 ? void 0 : firstQuestion.next_question.id) === (questionResponse === null || questionResponse === void 0 ? void 0 : questionResponse.next_question.id);
29
+ const quizNextHandler = (0, react_1.useCallback)((action) => {
30
+ if (action) {
31
+ dispatch(action);
32
+ }
33
+ }, [dispatch]);
34
+ const quizBackHandler = (0, react_1.useCallback)(() => {
35
+ if (dispatch) {
36
+ dispatch({ type: actions_1.QuestionTypes.Back });
37
+ }
38
+ }, [dispatch]);
39
+ const contextValue = {
40
+ dispatch,
41
+ questionResponse,
42
+ state,
43
+ resultsResponse,
44
+ isFirstQuestion,
45
+ quizNextHandler,
46
+ quizBackHandler,
47
+ };
48
+ (0, react_1.useEffect)(() => {
49
+ (() => tslib_1.__awaiter(this, void 0, void 0, function* () {
50
+ if (cioClient) {
51
+ setRequestState(constants_1.RequestStates.Loading);
52
+ if (state.isLastAnswer) {
53
+ try {
54
+ const quizResults = yield (0, utils_1.getQuizResults)(cioClient, quizId, {
55
+ answers: state.answers,
56
+ resultsPerPage: resultsPageOptions === null || resultsPageOptions === void 0 ? void 0 : resultsPageOptions.numResultsToDisplay,
57
+ quizVersionId,
58
+ quizSessionId,
59
+ });
60
+ setResultsResponse(quizResults);
61
+ setRequestState(constants_1.RequestStates.Success);
62
+ setQuestionResponse(undefined);
63
+ }
64
+ catch (error) {
65
+ setResultsResponse(undefined);
66
+ setRequestState(constants_1.RequestStates.Error);
67
+ }
68
+ }
69
+ else {
70
+ try {
71
+ const questionResult = yield (0, utils_1.getNextQuestion)(cioClient, quizId, {
72
+ answers: state.answers,
73
+ quizVersionId,
74
+ quizSessionId,
75
+ });
76
+ setQuestionResponse(questionResult);
77
+ setRequestState(constants_1.RequestStates.Success);
78
+ setResultsResponse(undefined);
79
+ if (!quizVersionId && (questionResult === null || questionResult === void 0 ? void 0 : questionResult.quiz_version_id)) {
80
+ setQuizVersionId(questionResult.quiz_version_id);
81
+ }
82
+ if (!quizSessionId && (questionResult === null || questionResult === void 0 ? void 0 : questionResult.quiz_session_id)) {
83
+ setQuizSessionId(questionResult.quiz_session_id);
84
+ }
85
+ }
86
+ catch (error) {
87
+ setRequestState(constants_1.RequestStates.Error);
88
+ }
89
+ }
90
+ }
91
+ }))();
92
+ // eslint-disable-next-line react-hooks/exhaustive-deps
93
+ }, [cioClient, state, quizId, state.isLastAnswer, resultsPageOptions === null || resultsPageOptions === void 0 ? void 0 : resultsPageOptions.numResultsToDisplay]);
94
+ (0, react_1.useEffect)(() => {
95
+ if (!firstQuestion) {
96
+ setFirstQuestion(questionResponse);
97
+ }
98
+ // eslint-disable-next-line react-hooks/exhaustive-deps
99
+ }, [questionResponse]);
100
+ const resetQuizSessionId = () => {
101
+ setQuizSessionId('');
102
+ };
103
+ if (requestState === constants_1.RequestStates.Loading) {
104
+ return (react_1.default.createElement("div", { className: 'cio-quiz' },
105
+ react_1.default.createElement(Spinner_1.default, null)));
106
+ }
107
+ if (requestState === constants_1.RequestStates.Success) {
108
+ return (react_1.default.createElement("div", { className: 'cio-quiz' },
109
+ react_1.default.createElement(context_1.default.Provider, { value: contextValue },
110
+ resultsResponse && (react_1.default.createElement(ResultContainer_1.default, { options: resultsPageOptions, resetQuizSessionId: resetQuizSessionId })),
111
+ questionResponse && react_1.default.createElement(QuizQuestions_1.default, { questionResponse: questionResponse }))));
112
+ }
113
+ return null;
114
+ }
115
+ exports.default = CioQuiz;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initialState = void 0;
4
+ const actions_1 = require("./actions");
5
+ exports.initialState = {
6
+ answers: [],
7
+ answerInputs: {},
8
+ isLastAnswer: false,
9
+ };
10
+ function answerInputReducer(state, action) {
11
+ return Object.assign(Object.assign({}, state), { [String(action.payload.questionId)]: action.payload.input });
12
+ }
13
+ function reducer(state, action) {
14
+ var _a, _b, _c, _d, _e, _f;
15
+ switch (action.type) {
16
+ case actions_1.QuestionTypes.OpenText:
17
+ return Object.assign(Object.assign({}, state), { answers: [...state.answers, ['true']], answerInputs: answerInputReducer(state.answerInputs, action), isLastAnswer: !!((_a = action.payload) === null || _a === void 0 ? void 0 : _a.isLastQuestion) });
18
+ case actions_1.QuestionTypes.Cover:
19
+ return Object.assign(Object.assign({}, state), { answers: [...state.answers, ['seen']], isLastAnswer: !!((_b = action.payload) === null || _b === void 0 ? void 0 : _b.isLastQuestion) });
20
+ case actions_1.QuestionTypes.SingleSelect:
21
+ return Object.assign(Object.assign({}, state), { answers: [...state.answers, (_c = action.payload) === null || _c === void 0 ? void 0 : _c.input], answerInputs: answerInputReducer(state.answerInputs, action), isLastAnswer: !!((_d = action.payload) === null || _d === void 0 ? void 0 : _d.isLastQuestion) });
22
+ case actions_1.QuestionTypes.MultipleSelect:
23
+ return Object.assign(Object.assign({}, state), { answers: [...state.answers, (_e = action.payload) === null || _e === void 0 ? void 0 : _e.input], answerInputs: answerInputReducer(state.answerInputs, action), isLastAnswer: !!((_f = action.payload) === null || _f === void 0 ? void 0 : _f.isLastQuestion) });
24
+ case actions_1.QuestionTypes.Back:
25
+ return Object.assign(Object.assign({}, state), { answers: [...state.answers.slice(0, -1)], isLastAnswer: false });
26
+ case actions_1.QuestionTypes.Reset:
27
+ return Object.assign({}, exports.initialState);
28
+ default:
29
+ return state;
30
+ }
31
+ }
32
+ exports.default = reducer;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ const BackButton_1 = tslib_1.__importDefault(require("../BackButton/BackButton"));
6
+ const CTAButton_1 = tslib_1.__importDefault(require("../CTAButton/CTAButton"));
7
+ function ControlBar(props) {
8
+ const { showBackButton, backButtonHandler, ctaButtonText, nextButtonHandler, isNextButtonDisabled, } = props;
9
+ return (react_1.default.createElement("div", { className: 'cio-question-buttons-container' },
10
+ showBackButton && react_1.default.createElement(BackButton_1.default, { onClick: backButtonHandler }),
11
+ react_1.default.createElement(CTAButton_1.default, { disabled: isNextButtonDisabled, ctaText: ctaButtonText, onClick: nextButtonHandler })));
12
+ }
13
+ exports.default = ControlBar;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importStar(require("react"));
5
+ const QuestionTitle_1 = tslib_1.__importDefault(require("../QuestionTitle/QuestionTitle"));
6
+ const context_1 = tslib_1.__importDefault(require("../CioQuiz/context"));
7
+ const QuestionDescription_1 = tslib_1.__importDefault(require("../QuestionDescription/QuestionDescription"));
8
+ const utils_1 = require("../../utils");
9
+ const actions_1 = require("../CioQuiz/actions");
10
+ const ControlBar_1 = tslib_1.__importDefault(require("../ControlBar/ControlBar"));
11
+ function CoverTypeQuestion() {
12
+ var _a;
13
+ const { questionResponse, quizBackHandler, quizNextHandler, isFirstQuestion } = (0, react_1.useContext)(context_1.default);
14
+ let question;
15
+ if (questionResponse) {
16
+ question = questionResponse.next_question;
17
+ }
18
+ const hasImage = (_a = question === null || question === void 0 ? void 0 : question.images) === null || _a === void 0 ? void 0 : _a.primary_url;
19
+ const onNextClick = () => {
20
+ if (quizNextHandler) {
21
+ quizNextHandler({
22
+ type: actions_1.QuestionTypes.Cover,
23
+ payload: {
24
+ isLastQuestion: questionResponse === null || questionResponse === void 0 ? void 0 : questionResponse.is_last_question,
25
+ },
26
+ });
27
+ }
28
+ };
29
+ if (question) {
30
+ return (react_1.default.createElement("div", { className: `
31
+ cio-container${hasImage ? '--with-image' : ''}
32
+ cio-cover-question-container${hasImage ? '--with-image' : ''}
33
+ ` },
34
+ react_1.default.createElement("div", { className: 'cio-question-content' },
35
+ react_1.default.createElement(QuestionTitle_1.default, { title: question === null || question === void 0 ? void 0 : question.title }),
36
+ react_1.default.createElement(QuestionDescription_1.default, { description: question.description }),
37
+ react_1.default.createElement(ControlBar_1.default, { nextButtonHandler: onNextClick, backButtonHandler: quizBackHandler, showBackButton: !isFirstQuestion, ctaButtonText: question === null || question === void 0 ? void 0 : question.cta_text })),
38
+ hasImage ? (0, utils_1.renderImages)(question.images, 'cio-question-image-container') : ''));
39
+ }
40
+ return null;
41
+ }
42
+ exports.default = CoverTypeQuestion;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importStar(require("react"));
5
+ const QuestionTitle_1 = tslib_1.__importDefault(require("../QuestionTitle/QuestionTitle"));
6
+ const QuestionDescription_1 = tslib_1.__importDefault(require("../QuestionDescription/QuestionDescription"));
7
+ const utils_1 = require("../../utils");
8
+ const context_1 = tslib_1.__importDefault(require("../CioQuiz/context"));
9
+ const actions_1 = require("../CioQuiz/actions");
10
+ const ControlBar_1 = tslib_1.__importDefault(require("../ControlBar/ControlBar"));
11
+ function OpenTextQuestion(props) {
12
+ var _a;
13
+ const { initialValue = '', onChangeHandler: userDefinedHandler = null } = props;
14
+ const { questionResponse, quizBackHandler, quizNextHandler, isFirstQuestion, state } = (0, react_1.useContext)(context_1.default);
15
+ const [openTextInput, setOpenTextInput] = (0, react_1.useState)(initialValue);
16
+ let question;
17
+ if (questionResponse) {
18
+ question = questionResponse.next_question;
19
+ }
20
+ const onChangeHandler = (e) => {
21
+ setOpenTextInput(e.target.value);
22
+ if (userDefinedHandler) {
23
+ userDefinedHandler(e);
24
+ }
25
+ };
26
+ const onNextClick = () => {
27
+ if (quizNextHandler && openTextInput && questionResponse) {
28
+ quizNextHandler({
29
+ type: actions_1.QuestionTypes.OpenText,
30
+ payload: {
31
+ questionId: questionResponse.next_question.id,
32
+ input: openTextInput,
33
+ isLastQuestion: questionResponse.is_last_question,
34
+ },
35
+ });
36
+ }
37
+ };
38
+ const onKeyDownHandler = (e) => {
39
+ const { key } = e;
40
+ if (key === 'Enter') {
41
+ onNextClick();
42
+ }
43
+ };
44
+ (0, react_1.useEffect)(() => {
45
+ var _a;
46
+ if (questionResponse) {
47
+ const openTextAnswer = ((_a = state === null || state === void 0 ? void 0 : state.answerInputs) === null || _a === void 0 ? void 0 : _a[questionResponse === null || questionResponse === void 0 ? void 0 : questionResponse.next_question.id]) || initialValue;
48
+ setOpenTextInput(openTextAnswer);
49
+ }
50
+ }, [questionResponse, state, initialValue]);
51
+ if (question) {
52
+ const hasImage = (_a = question === null || question === void 0 ? void 0 : question.images) === null || _a === void 0 ? void 0 : _a.primary_url;
53
+ return (react_1.default.createElement("div", { className: `
54
+ cio-container${hasImage ? '--with-image' : ''}
55
+ cio-open-text-question-container${hasImage ? '--with-image' : ''}
56
+ ` },
57
+ hasImage ? (0, utils_1.renderImages)(question.images, 'cio-question-image-container') : '',
58
+ react_1.default.createElement("div", { className: 'cio-question-content' },
59
+ react_1.default.createElement(QuestionTitle_1.default, { title: question.title }),
60
+ react_1.default.createElement(QuestionDescription_1.default, { description: question.description }),
61
+ react_1.default.createElement("input", { className: 'cio-question-input-text', placeholder: question.input_placeholder || 'Answer here...', value: openTextInput, onChange: onChangeHandler, onKeyDown: onKeyDownHandler }),
62
+ react_1.default.createElement(ControlBar_1.default, { nextButtonHandler: onNextClick, isNextButtonDisabled: !openTextInput, backButtonHandler: quizBackHandler, showBackButton: !isFirstQuestion, ctaButtonText: question === null || question === void 0 ? void 0 : question.cta_text }))));
63
+ }
64
+ return null;
65
+ }
66
+ exports.default = OpenTextQuestion;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ function QuestionDescription(props) {
6
+ const { description } = props;
7
+ return react_1.default.createElement("p", { className: 'cio-question-description' }, description);
8
+ }
9
+ exports.default = QuestionDescription;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ function QuestionTitle(props) {
6
+ const { title } = props;
7
+ return react_1.default.createElement("h1", { className: 'cio-question-title' }, title);
8
+ }
9
+ exports.default = QuestionTitle;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ const OpenTextTypeQuestion_1 = tslib_1.__importDefault(require("../OpenTextTypeQuestion/OpenTextTypeQuestion"));
6
+ const CoverTypeQuestion_1 = tslib_1.__importDefault(require("../CoverTypeQuestion/CoverTypeQuestion"));
7
+ const SelectTypeQuestion_1 = tslib_1.__importDefault(require("../SelectTypeQuestion/SelectTypeQuestion"));
8
+ const utils_1 = require("../../utils");
9
+ function QuizQuestions(props) {
10
+ const { questionResponse: { next_question: nextQuestion }, } = props;
11
+ const questionTypes = (0, utils_1.getQuestionTypes)(nextQuestion === null || nextQuestion === void 0 ? void 0 : nextQuestion.type);
12
+ return (react_1.default.createElement(react_1.default.Fragment, null,
13
+ questionTypes.isOpenQuestion && react_1.default.createElement(OpenTextTypeQuestion_1.default, { key: nextQuestion === null || nextQuestion === void 0 ? void 0 : nextQuestion.id }),
14
+ questionTypes.isCoverQuestion && react_1.default.createElement(CoverTypeQuestion_1.default, { key: nextQuestion === null || nextQuestion === void 0 ? void 0 : nextQuestion.id }),
15
+ questionTypes.isSelectQuestion && react_1.default.createElement(SelectTypeQuestion_1.default, { key: nextQuestion === null || nextQuestion === void 0 ? void 0 : nextQuestion.id })));
16
+ }
17
+ exports.default = QuizQuestions;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ const RedoSVG_1 = tslib_1.__importDefault(require("./RedoSVG"));
6
+ function RedoButton(props) {
7
+ const { redoText = 'Redo Quiz', disabled } = props, rest = tslib_1.__rest(props, ["redoText", "disabled"]);
8
+ return (react_1.default.createElement("button", Object.assign({ type: 'button', className: `${disabled ? 'cio-question-redo-button disabled' : 'cio-question-redo-button'}` }, rest),
9
+ react_1.default.createElement(RedoSVG_1.default, null),
10
+ react_1.default.createElement("span", null, redoText)));
11
+ }
12
+ exports.default = RedoButton;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ function RedoSVG() {
6
+ return (react_1.default.createElement("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
7
+ react_1.default.createElement("g", { clipPath: 'url(#clip0_7495_177230)' },
8
+ react_1.default.createElement("path", { d: 'M0.667969 2.66699V6.66699H4.66797', stroke: '#0A0B0C', strokeWidth: '1.33333', strokeLinecap: 'round', strokeLinejoin: 'round' }),
9
+ react_1.default.createElement("path", { d: 'M15.332 13.333V9.33301H11.332', stroke: '#0A0B0C', strokeWidth: '1.33333', strokeLinecap: 'round', strokeLinejoin: 'round' }),
10
+ react_1.default.createElement("path", { d: 'M13.6613 6.00038C13.3232 5.0449 12.7485 4.19064 11.991 3.51732C11.2334 2.844 10.3177 2.37355 9.32911 2.14988C8.34056 1.92621 7.31147 1.9566 6.33784 2.23823C5.36422 2.51985 4.4778 3.04352 3.7613 3.76038L0.667969 6.66704M15.3346 9.33371L12.2413 12.2404C11.5248 12.9572 10.6384 13.4809 9.66476 13.7625C8.69114 14.0441 7.66204 14.0745 6.67349 13.8509C5.68495 13.6272 4.76917 13.1568 4.01161 12.4834C3.25406 11.8101 2.67941 10.9559 2.3413 10.0004', stroke: '#0A0B0C', strokeWidth: '1.33333', strokeLinecap: 'round', strokeLinejoin: 'round' })),
11
+ react_1.default.createElement("defs", null,
12
+ react_1.default.createElement("clipPath", { id: 'clip0_7495_177230' },
13
+ react_1.default.createElement("rect", { width: '16', height: '16', fill: 'white' })))));
14
+ }
15
+ exports.default = RedoSVG;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ const ResultCtaButton_1 = tslib_1.__importDefault(require("../ResultCtaButton/ResultCtaButton"));
6
+ function ResultCard(props) {
7
+ var _a, _b, _c;
8
+ const { result, addToCartCallback, clickItemCallback, salePriceKey, regularPriceKey } = props;
9
+ const salePrice = salePriceKey && ((_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a[salePriceKey]);
10
+ const regularPrice = regularPriceKey && ((_b = result === null || result === void 0 ? void 0 : result.data) === null || _b === void 0 ? void 0 : _b[regularPriceKey]);
11
+ const clickHandler = () => {
12
+ if (clickItemCallback && typeof clickItemCallback === 'function') {
13
+ clickItemCallback(result);
14
+ }
15
+ };
16
+ const keyDownHandler = (event) => {
17
+ if ((event === null || event === void 0 ? void 0 : event.key) === ' ' || (event === null || event === void 0 ? void 0 : event.key) === 'Enter') {
18
+ if (clickItemCallback && typeof clickItemCallback === 'function') {
19
+ clickItemCallback(result);
20
+ }
21
+ }
22
+ };
23
+ const resultCardContent = () => {
24
+ var _a;
25
+ return (react_1.default.createElement(react_1.default.Fragment, null,
26
+ react_1.default.createElement("div", { className: 'cio-result-card-image' },
27
+ react_1.default.createElement("img", { src: (_a = result.data) === null || _a === void 0 ? void 0 : _a.image_url, alt: 'product' })),
28
+ react_1.default.createElement("div", { className: 'cio-result-card-text' },
29
+ react_1.default.createElement("p", { className: 'cio-result-card-title' }, result.value),
30
+ react_1.default.createElement("div", { className: 'cio-result-card-prices' },
31
+ salePrice && react_1.default.createElement("span", { className: 'cio-result-card-sale-price' },
32
+ "$",
33
+ salePrice),
34
+ regularPrice && (react_1.default.createElement("span", { className: `cio-result-card-regular-price${salePrice ? '--strike-through' : ''}` },
35
+ "$",
36
+ regularPrice)))),
37
+ react_1.default.createElement(ResultCtaButton_1.default, { item: result, callback: addToCartCallback })));
38
+ };
39
+ if (clickItemCallback) {
40
+ return (react_1.default.createElement("div", { onClick: clickHandler, onKeyDown: keyDownHandler, className: 'cio-result-card', role: 'button', tabIndex: 0 }, resultCardContent()));
41
+ }
42
+ return (react_1.default.createElement("div", { className: 'cio-result-card' },
43
+ react_1.default.createElement("a", { className: 'cio-result-card-anchor', href: (_c = result.data) === null || _c === void 0 ? void 0 : _c.url }, resultCardContent())));
44
+ }
45
+ exports.default = ResultCard;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importStar(require("react"));
5
+ const RedoButton_1 = tslib_1.__importDefault(require("../RedoButton/RedoButton"));
6
+ const actions_1 = require("../CioQuiz/actions");
7
+ const context_1 = tslib_1.__importDefault(require("../CioQuiz/context"));
8
+ const ResultFilters_1 = tslib_1.__importDefault(require("../ResultFilters/ResultFilters"));
9
+ const ZeroResults_1 = tslib_1.__importDefault(require("../ZeroResults/ZeroResults"));
10
+ const Results_1 = tslib_1.__importDefault(require("../Results/Results"));
11
+ function ResultContainer(props) {
12
+ var _a, _b, _c;
13
+ const { options, resetQuizSessionId } = props;
14
+ const { addToCartCallback, clickItemCallback, resultCardSalePriceKey, resultCardRegularPriceKey, } = options;
15
+ const { resultsResponse } = (0, react_1.useContext)(context_1.default);
16
+ const { dispatch } = (0, react_1.useContext)(context_1.default);
17
+ const filterExpression = (_a = resultsResponse === null || resultsResponse === void 0 ? void 0 : resultsResponse.request) === null || _a === void 0 ? void 0 : _a.collection_filter_expression;
18
+ const zeroResults = !((_c = (_b = resultsResponse === null || resultsResponse === void 0 ? void 0 : resultsResponse.response) === null || _b === void 0 ? void 0 : _b.results) === null || _c === void 0 ? void 0 : _c.length);
19
+ const resultsTitle = zeroResults ? 'Oops, there are no results' : 'Here are your results';
20
+ const onResetClick = () => {
21
+ if (dispatch && resultsResponse) {
22
+ resetQuizSessionId();
23
+ dispatch({
24
+ type: actions_1.QuestionTypes.Reset,
25
+ });
26
+ }
27
+ };
28
+ if (resultsResponse) {
29
+ return (react_1.default.createElement("div", { className: 'cio-results-container' },
30
+ react_1.default.createElement("h1", { className: 'cio-results-title' }, resultsTitle),
31
+ react_1.default.createElement("div", { className: 'cio-results-filter-and-redo-container' },
32
+ react_1.default.createElement(ResultFilters_1.default, { filters: filterExpression }),
33
+ react_1.default.createElement(RedoButton_1.default, { onClick: onResetClick })),
34
+ !zeroResults && (react_1.default.createElement(Results_1.default, { addToCartCallback: addToCartCallback, clickItemCallback: clickItemCallback, resultCardSalePriceKey: resultCardSalePriceKey, resultCardRegularPriceKey: resultCardRegularPriceKey })),
35
+ zeroResults && react_1.default.createElement(ZeroResults_1.default, null)));
36
+ }
37
+ return react_1.default.createElement("div", null, "Loading");
38
+ }
39
+ exports.default = ResultContainer;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ function ResultCtaButton(props) {
6
+ const { item, callback, className } = props;
7
+ const clickHandler = (e) => {
8
+ e.preventDefault();
9
+ if (callback && typeof callback === 'function') {
10
+ e.stopPropagation();
11
+ callback(item);
12
+ }
13
+ };
14
+ return (react_1.default.createElement("button", { type: 'button', className: `cio-result-card-cta-button ${className || ''}`, onClick: clickHandler }, "Add to Cart"));
15
+ }
16
+ exports.default = ResultCtaButton;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ function ResultFilters(props) {
6
+ const { filters } = props;
7
+ const isValueExpression = (exp) => 'name' in exp && 'value' in exp;
8
+ const isAndFilter = (exp) => 'and' in exp;
9
+ const isOrFilter = (exp) => 'or' in exp;
10
+ const getFilterValuesFromExpression = (exp) => {
11
+ if (!exp) {
12
+ return [];
13
+ }
14
+ if (isAndFilter(exp)) {
15
+ return exp.and.flatMap((innerExpression) => getFilterValuesFromExpression(innerExpression));
16
+ }
17
+ if (isOrFilter(exp)) {
18
+ return exp.or.flatMap((innerExpression) => getFilterValuesFromExpression(innerExpression));
19
+ }
20
+ if (isValueExpression(exp)) {
21
+ return [exp.value];
22
+ }
23
+ return [];
24
+ };
25
+ const filterValues = [...new Set(getFilterValuesFromExpression(filters))];
26
+ return (react_1.default.createElement("div", { className: 'cio-results-filter-container' },
27
+ react_1.default.createElement("p", null, "Because you answered"),
28
+ react_1.default.createElement("div", { className: 'cio-results-filter-options' }, filterValues === null || filterValues === void 0 ? void 0 : filterValues.map((filter) => (react_1.default.createElement("div", { className: 'cio-results-filter-option', key: filter }, filter))))));
29
+ }
30
+ exports.default = ResultFilters;