@constructor-io/constructorio-ui-quizzes 1.4.6 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,12 +5,14 @@ const react_1 = tslib_1.__importStar(require("react"));
5
5
  const context_1 = tslib_1.__importDefault(require("./context"));
6
6
  const QuizQuestions_1 = tslib_1.__importDefault(require("../QuizQuestions"));
7
7
  const ResultContainer_1 = tslib_1.__importDefault(require("../ResultContainer/ResultContainer"));
8
+ const ControlBar_1 = tslib_1.__importDefault(require("../ControlBar/ControlBar"));
8
9
  const constants_1 = require("../../constants");
9
10
  const Spinner_1 = tslib_1.__importDefault(require("../Spinner/Spinner"));
10
11
  const useQuiz_1 = tslib_1.__importDefault(require("../../hooks/useQuiz"));
11
12
  const SessionPromptModal_1 = tslib_1.__importDefault(require("../SessionPromptModal/SessionPromptModal"));
12
13
  const utils_1 = require("../../utils");
13
14
  function CioQuiz(props) {
15
+ var _a;
14
16
  const { cioClient, state, events: { hydrateQuiz, hasSessionStorageState, resetSessionStorageState }, getAddToCartButtonProps, getCoverQuestionProps, getHydrateQuizButtonProps, getNextQuestionButtonProps, getOpenTextInputProps, getPreviousQuestionButtonProps, getQuizImageProps, getQuizResultButtonProps, getQuizResultLinkProps, getResetQuizButtonProps, getSelectInputProps, primaryColorStyles, } = (0, useQuiz_1.default)(props);
15
17
  const [showSessionPrompt, setShowSessionPrompt] = (0, react_1.useState)(false);
16
18
  const { resultsPageOptions, sessionStateOptions } = props;
@@ -46,16 +48,23 @@ function CioQuiz(props) {
46
48
  primaryColorStyles,
47
49
  };
48
50
  if (state.quiz.requestState === constants_1.RequestStates.Loading) {
49
- return (react_1.default.createElement("div", { className: 'cio-quiz' },
51
+ return (react_1.default.createElement("div", { className: 'cio-quiz cio-quiz-loading' },
50
52
  react_1.default.createElement(Spinner_1.default, null)));
51
53
  }
54
+ const questionData = (_a = state.quiz.currentQuestion) === null || _a === void 0 ? void 0 : _a.next_question;
55
+ const questionType = questionData === null || questionData === void 0 ? void 0 : questionData.type;
56
+ const questionImages = questionData === null || questionData === void 0 ? void 0 : questionData.images;
57
+ const displayBackgroundImage = (questionType === 'single' || questionType === 'multiple') && questionImages;
52
58
  if (state.quiz.requestState === constants_1.RequestStates.Success) {
53
59
  return (react_1.default.createElement("div", { className: 'cio-quiz' },
60
+ displayBackgroundImage && (0, utils_1.renderImages)(questionImages, 'cio-question-background-image'),
54
61
  react_1.default.createElement("style", null,
55
62
  ".cio-quiz ",
56
63
  (0, utils_1.convertPrimaryColorsToString)(primaryColorStyles)),
57
64
  react_1.default.createElement(SessionPromptModal_1.default, { resetStoredState: resetSessionStorageState, continueSession: hydrateQuiz, showSessionPrompt: showSessionPrompt, setShowSessionPrompt: setShowSessionPrompt }),
58
- react_1.default.createElement(context_1.default.Provider, { value: contextValue }, state.quiz.results || state.quiz.skipToResults ? (react_1.default.createElement(ResultContainer_1.default, { options: resultsPageOptions })) : (state.quiz.currentQuestion && react_1.default.createElement(QuizQuestions_1.default, null)))));
65
+ react_1.default.createElement(context_1.default.Provider, { value: contextValue }, state.quiz.results || state.quiz.skipToResults ? (react_1.default.createElement(ResultContainer_1.default, { options: resultsPageOptions })) : (state.quiz.currentQuestion && (react_1.default.createElement(react_1.default.Fragment, null,
66
+ react_1.default.createElement(QuizQuestions_1.default, null),
67
+ react_1.default.createElement(ControlBar_1.default, { ctaButtonText: (questionData === null || questionData === void 0 ? void 0 : questionData.cta_text) || undefined })))))));
59
68
  }
60
69
  return null;
61
70
  }
@@ -6,7 +6,6 @@ const QuestionTitle_1 = tslib_1.__importDefault(require("../QuestionTitle/Questi
6
6
  const context_1 = tslib_1.__importDefault(require("../CioQuiz/context"));
7
7
  const QuestionDescription_1 = tslib_1.__importDefault(require("../QuestionDescription/QuestionDescription"));
8
8
  const utils_1 = require("../../utils");
9
- const ControlBar_1 = tslib_1.__importDefault(require("../ControlBar/ControlBar"));
10
9
  function CoverTypeQuestion() {
11
10
  var _a;
12
11
  const { state } = (0, react_1.useContext)(context_1.default);
@@ -23,8 +22,7 @@ function CoverTypeQuestion() {
23
22
  hasImage ? (0, utils_1.renderImages)(question.images, 'cio-question-image-container') : '',
24
23
  react_1.default.createElement("div", { className: 'cio-question-content' },
25
24
  react_1.default.createElement(QuestionTitle_1.default, { title: question === null || question === void 0 ? void 0 : question.title }),
26
- react_1.default.createElement(QuestionDescription_1.default, { description: question.description }),
27
- react_1.default.createElement(ControlBar_1.default, { ctaButtonText: question === null || question === void 0 ? void 0 : question.cta_text }))));
25
+ react_1.default.createElement(QuestionDescription_1.default, { description: question.description }))));
28
26
  }
29
27
  return null;
30
28
  }
@@ -6,7 +6,6 @@ const QuestionTitle_1 = tslib_1.__importDefault(require("../QuestionTitle/Questi
6
6
  const QuestionDescription_1 = tslib_1.__importDefault(require("../QuestionDescription/QuestionDescription"));
7
7
  const utils_1 = require("../../utils");
8
8
  const context_1 = tslib_1.__importDefault(require("../CioQuiz/context"));
9
- const ControlBar_1 = tslib_1.__importDefault(require("../ControlBar/ControlBar"));
10
9
  function OpenTextQuestion() {
11
10
  var _a;
12
11
  const { state, getOpenTextInputProps } = (0, react_1.useContext)(context_1.default);
@@ -24,8 +23,7 @@ function OpenTextQuestion() {
24
23
  react_1.default.createElement("div", { className: 'cio-question-content' },
25
24
  react_1.default.createElement(QuestionTitle_1.default, { title: question.title }),
26
25
  react_1.default.createElement(QuestionDescription_1.default, { description: question.description }),
27
- getOpenTextInputProps && react_1.default.createElement("input", Object.assign({}, getOpenTextInputProps())),
28
- react_1.default.createElement(ControlBar_1.default, { ctaButtonText: question === null || question === void 0 ? void 0 : question.cta_text }))));
26
+ getOpenTextInputProps && react_1.default.createElement("input", Object.assign({}, getOpenTextInputProps())))));
29
27
  }
30
28
  return null;
31
29
  }
@@ -6,7 +6,7 @@ const ResultCtaButton_1 = tslib_1.__importDefault(require("../ResultCtaButton/Re
6
6
  const context_1 = tslib_1.__importDefault(require("../CioQuiz/context"));
7
7
  function ResultCard(props) {
8
8
  var _a, _b, _c, _d;
9
- const { result, salePriceKey, regularPriceKey, resultPosition, ratingCountKey, ratingScoreKey } = props;
9
+ const { result, salePriceKey, regularPriceKey, resultPosition, ratingCountKey, ratingScoreKey, renderResultCardPriceDetails, } = props;
10
10
  const { customClickItemCallback, getQuizResultButtonProps, getQuizResultLinkProps } = (0, react_1.useContext)(context_1.default);
11
11
  const salePrice = salePriceKey && ((_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a[salePriceKey]);
12
12
  const regularPrice = regularPriceKey && ((_b = result === null || result === void 0 ? void 0 : result.data) === null || _b === void 0 ? void 0 : _b[regularPriceKey]);
@@ -28,13 +28,13 @@ function ResultCard(props) {
28
28
  "(",
29
29
  ratingCount,
30
30
  ")")),
31
- react_1.default.createElement("div", { className: 'cio-result-card-prices' },
31
+ renderResultCardPriceDetails ? (renderResultCardPriceDetails(result)) : (react_1.default.createElement("div", { className: 'cio-result-card-prices' },
32
32
  salePrice && react_1.default.createElement("span", { className: 'cio-result-card-sale-price' },
33
33
  "$",
34
34
  salePrice),
35
35
  regularPrice && (react_1.default.createElement("span", { className: `cio-result-card-regular-price${salePrice ? '--strike-through' : ''}` },
36
36
  "$",
37
- regularPrice)))))));
37
+ regularPrice))))))));
38
38
  };
39
39
  const resultCardContentWithoutLink = () => getQuizResultButtonProps && (react_1.default.createElement("div", Object.assign({}, getQuizResultButtonProps({ result, position: resultPosition, type: 'button' })), resultCardContent()));
40
40
  const resultCardContentWithLink = () => getQuizResultLinkProps && (react_1.default.createElement("a", Object.assign({ className: 'cio-result-card-anchor', rel: 'noreferrer', target: '_blank' }, getQuizResultLinkProps({ result, position: resultPosition, type: 'link' })), resultCardContent()));
@@ -11,7 +11,7 @@ const Spinner_1 = tslib_1.__importDefault(require("../Spinner/Spinner"));
11
11
  function ResultContainer(props) {
12
12
  var _a, _b, _c;
13
13
  const { options } = props;
14
- const { resultCardSalePriceKey, resultCardRegularPriceKey, resultCardRatingCountKey, resultCardRatingScoreKey, } = options;
14
+ const { resultCardSalePriceKey, resultCardRegularPriceKey, resultCardRatingCountKey, resultCardRatingScoreKey, renderResultCardPriceDetails, } = options;
15
15
  const { state } = (0, react_1.useContext)(context_1.default);
16
16
  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);
17
17
  const resultsTitle = zeroResults ? '' : 'Here are your results';
@@ -21,7 +21,7 @@ function ResultContainer(props) {
21
21
  react_1.default.createElement("div", { className: 'cio-results-filter-and-redo-container' },
22
22
  react_1.default.createElement(ResultFilters_1.default, { hasNoResults: zeroResults }),
23
23
  react_1.default.createElement(RedoButton_1.default, null)),
24
- !zeroResults && (react_1.default.createElement(Results_1.default, { resultCardSalePriceKey: resultCardSalePriceKey, resultCardRegularPriceKey: resultCardRegularPriceKey, resultCardRatingCountKey: resultCardRatingCountKey, resultCardRatingScoreKey: resultCardRatingScoreKey })),
24
+ !zeroResults && (react_1.default.createElement(Results_1.default, { resultCardSalePriceKey: resultCardSalePriceKey, resultCardRegularPriceKey: resultCardRegularPriceKey, resultCardRatingCountKey: resultCardRatingCountKey, resultCardRatingScoreKey: resultCardRatingScoreKey, renderResultCardPriceDetails: renderResultCardPriceDetails })),
25
25
  zeroResults && react_1.default.createElement(ZeroResults_1.default, null)));
26
26
  }
27
27
  return (react_1.default.createElement("div", { className: 'cio-results-container' },
@@ -6,11 +6,11 @@ const context_1 = tslib_1.__importDefault(require("../CioQuiz/context"));
6
6
  const ResultCard_1 = tslib_1.__importDefault(require("../ResultCard/ResultCard"));
7
7
  function Results(props) {
8
8
  var _a, _b, _c, _d;
9
- const { resultCardSalePriceKey, resultCardRegularPriceKey, resultCardRatingCountKey, resultCardRatingScoreKey, } = props;
9
+ const { resultCardSalePriceKey, resultCardRegularPriceKey, resultCardRatingCountKey, resultCardRatingScoreKey, renderResultCardPriceDetails, } = props;
10
10
  const { state } = (0, react_1.useContext)(context_1.default);
11
11
  return (react_1.default.createElement("div", { className: 'cio-results' }, (_d = (_c = (_b = (_a = state === null || state === void 0 ? void 0 : state.quiz) === null || _a === void 0 ? void 0 : _a.results) === null || _b === void 0 ? void 0 : _b.response) === null || _c === void 0 ? void 0 : _c.results) === null || _d === void 0 ? void 0 : _d.map((result, index) => {
12
12
  var _a;
13
- return (react_1.default.createElement(ResultCard_1.default, { result: result, key: (_a = result.data) === null || _a === void 0 ? void 0 : _a.id, salePriceKey: resultCardSalePriceKey, regularPriceKey: resultCardRegularPriceKey, ratingCountKey: resultCardRatingCountKey, ratingScoreKey: resultCardRatingScoreKey, resultPosition: index + 1 }));
13
+ return (react_1.default.createElement(ResultCard_1.default, { result: result, key: (_a = result.data) === null || _a === void 0 ? void 0 : _a.id, salePriceKey: resultCardSalePriceKey, regularPriceKey: resultCardRegularPriceKey, ratingCountKey: resultCardRatingCountKey, ratingScoreKey: resultCardRatingScoreKey, renderResultCardPriceDetails: renderResultCardPriceDetails, resultPosition: index + 1 }));
14
14
  })));
15
15
  }
16
16
  exports.default = Results;
@@ -6,7 +6,6 @@ const QuestionTitle_1 = tslib_1.__importDefault(require("../QuestionTitle/Questi
6
6
  const QuestionDescription_1 = tslib_1.__importDefault(require("../QuestionDescription/QuestionDescription"));
7
7
  const context_1 = tslib_1.__importDefault(require("../CioQuiz/context"));
8
8
  const utils_1 = require("../../utils");
9
- const ControlBar_1 = tslib_1.__importDefault(require("../ControlBar/ControlBar"));
10
9
  const actions_1 = require("../CioQuiz/actions");
11
10
  function SelectTypeQuestion() {
12
11
  var _a;
@@ -29,8 +28,7 @@ function SelectTypeQuestion() {
29
28
  ? 'cio-question-options-container-text-only'
30
29
  : 'cio-question-options-container'}` }, (_a = question === null || question === void 0 ? void 0 : question.options) === null || _a === void 0 ? void 0 : _a.map((option) => getSelectInputProps && (react_1.default.createElement("div", Object.assign({}, getSelectInputProps(option)),
31
30
  option.images ? (0, utils_1.renderImages)(option.images, 'cio-question-option-image') : '',
32
- react_1.default.createElement("div", { className: 'cio-question-option-value' }, option === null || option === void 0 ? void 0 : option.value))))),
33
- react_1.default.createElement(ControlBar_1.default, { ctaButtonText: (question === null || question === void 0 ? void 0 : question.cta_text) || 'Continue' })));
31
+ react_1.default.createElement("div", { className: 'cio-question-option-value' }, option === null || option === void 0 ? void 0 : option.value)))))));
34
32
  }
35
33
  return null;
36
34
  }
@@ -20,6 +20,7 @@ exports.componentDescription = `- import \`CioQuiz\` to render in your JSX.
20
20
  - \`resultCardSalePriceKey\` is an optional parameter that specifies the metadata field name for the sale price
21
21
  - \`resultCardRatingCountKey\` is an optional parameter that specifies the metadata field name for the ratings count
22
22
  - \`resultCardRatingScoreKey\` is an optional parameter that specifies the metadata field name for the ratings score
23
+ - \`renderResultCardPriceDetails\` is an optional render function to render custom prices section in result card
23
24
  - \`sessionStateOptions\` lets you configure the session modal behavior
24
25
  - \`showSessionModal\` is a boolean used to decide whether to show the session modal. The default behavior is to show the session modal
25
26
  - \`showSessionModalOnResults\` is a boolean to decide whether to show the session modal after reaching the results page. The default behavior is to not show the session modal
@@ -76,6 +76,7 @@ const getMockState = (question) => ({
76
76
  ratingCount: '12',
77
77
  ratingScore: '4',
78
78
  image_url: 'https://demo.constructor.io/sandbox_files/farmstandquizassets/HiThereNameInput.png',
79
+ discount: '59.9',
79
80
  },
80
81
  },
81
82
  {
@@ -2,11 +2,12 @@ import React, { useEffect, useState } from 'react';
2
2
  import QuizContext from './context';
3
3
  import QuizQuestions from '../QuizQuestions';
4
4
  import ResultContainer from '../ResultContainer/ResultContainer';
5
+ import ControlBar from '../ControlBar/ControlBar';
5
6
  import { RequestStates } from '../../constants';
6
7
  import Spinner from '../Spinner/Spinner';
7
8
  import useQuiz from '../../hooks/useQuiz';
8
9
  import SessionPromptModal from '../SessionPromptModal/SessionPromptModal';
9
- import { convertPrimaryColorsToString } from '../../utils';
10
+ import { convertPrimaryColorsToString, renderImages } from '../../utils';
10
11
  export default function CioQuiz(props) {
11
12
  const { cioClient, state, events: { hydrateQuiz, hasSessionStorageState, resetSessionStorageState }, getAddToCartButtonProps, getCoverQuestionProps, getHydrateQuizButtonProps, getNextQuestionButtonProps, getOpenTextInputProps, getPreviousQuestionButtonProps, getQuizImageProps, getQuizResultButtonProps, getQuizResultLinkProps, getResetQuizButtonProps, getSelectInputProps, primaryColorStyles, } = useQuiz(props);
12
13
  const [showSessionPrompt, setShowSessionPrompt] = useState(false);
@@ -43,16 +44,23 @@ export default function CioQuiz(props) {
43
44
  primaryColorStyles,
44
45
  };
45
46
  if (state.quiz.requestState === RequestStates.Loading) {
46
- return (React.createElement("div", { className: 'cio-quiz' },
47
+ return (React.createElement("div", { className: 'cio-quiz cio-quiz-loading' },
47
48
  React.createElement(Spinner, null)));
48
49
  }
50
+ const questionData = state.quiz.currentQuestion?.next_question;
51
+ const questionType = questionData?.type;
52
+ const questionImages = questionData?.images;
53
+ const displayBackgroundImage = (questionType === 'single' || questionType === 'multiple') && questionImages;
49
54
  if (state.quiz.requestState === RequestStates.Success) {
50
55
  return (React.createElement("div", { className: 'cio-quiz' },
56
+ displayBackgroundImage && renderImages(questionImages, 'cio-question-background-image'),
51
57
  React.createElement("style", null,
52
58
  ".cio-quiz ",
53
59
  convertPrimaryColorsToString(primaryColorStyles)),
54
60
  React.createElement(SessionPromptModal, { resetStoredState: resetSessionStorageState, continueSession: hydrateQuiz, showSessionPrompt: showSessionPrompt, setShowSessionPrompt: setShowSessionPrompt }),
55
- React.createElement(QuizContext.Provider, { value: contextValue }, state.quiz.results || state.quiz.skipToResults ? (React.createElement(ResultContainer, { options: resultsPageOptions })) : (state.quiz.currentQuestion && React.createElement(QuizQuestions, null)))));
61
+ React.createElement(QuizContext.Provider, { value: contextValue }, state.quiz.results || state.quiz.skipToResults ? (React.createElement(ResultContainer, { options: resultsPageOptions })) : (state.quiz.currentQuestion && (React.createElement(React.Fragment, null,
62
+ React.createElement(QuizQuestions, null),
63
+ React.createElement(ControlBar, { ctaButtonText: questionData?.cta_text || undefined })))))));
56
64
  }
57
65
  return null;
58
66
  }
@@ -3,7 +3,6 @@ import QuestionTitle from '../QuestionTitle/QuestionTitle';
3
3
  import QuizContext from '../CioQuiz/context';
4
4
  import QuestionDescription from '../QuestionDescription/QuestionDescription';
5
5
  import { renderImages } from '../../utils';
6
- import ControlBar from '../ControlBar/ControlBar';
7
6
  export default function CoverTypeQuestion() {
8
7
  const { state } = useContext(QuizContext);
9
8
  let question;
@@ -19,8 +18,7 @@ export default function CoverTypeQuestion() {
19
18
  hasImage ? renderImages(question.images, 'cio-question-image-container') : '',
20
19
  React.createElement("div", { className: 'cio-question-content' },
21
20
  React.createElement(QuestionTitle, { title: question?.title }),
22
- React.createElement(QuestionDescription, { description: question.description }),
23
- React.createElement(ControlBar, { ctaButtonText: question?.cta_text }))));
21
+ React.createElement(QuestionDescription, { description: question.description }))));
24
22
  }
25
23
  return null;
26
24
  }
@@ -3,7 +3,6 @@ import QuestionTitle from '../QuestionTitle/QuestionTitle';
3
3
  import QuestionDescription from '../QuestionDescription/QuestionDescription';
4
4
  import { renderImages } from '../../utils';
5
5
  import QuizContext from '../CioQuiz/context';
6
- import ControlBar from '../ControlBar/ControlBar';
7
6
  function OpenTextQuestion() {
8
7
  const { state, getOpenTextInputProps } = useContext(QuizContext);
9
8
  let question;
@@ -20,8 +19,7 @@ function OpenTextQuestion() {
20
19
  React.createElement("div", { className: 'cio-question-content' },
21
20
  React.createElement(QuestionTitle, { title: question.title }),
22
21
  React.createElement(QuestionDescription, { description: question.description }),
23
- getOpenTextInputProps && React.createElement("input", { ...getOpenTextInputProps() }),
24
- React.createElement(ControlBar, { ctaButtonText: question?.cta_text }))));
22
+ getOpenTextInputProps && React.createElement("input", { ...getOpenTextInputProps() }))));
25
23
  }
26
24
  return null;
27
25
  }
@@ -2,7 +2,7 @@ import React, { useContext } from 'react';
2
2
  import ResultCtaButton from '../ResultCtaButton/ResultCtaButton';
3
3
  import QuizContext from '../CioQuiz/context';
4
4
  export default function ResultCard(props) {
5
- const { result, salePriceKey, regularPriceKey, resultPosition, ratingCountKey, ratingScoreKey } = props;
5
+ const { result, salePriceKey, regularPriceKey, resultPosition, ratingCountKey, ratingScoreKey, renderResultCardPriceDetails, } = props;
6
6
  const { customClickItemCallback, getQuizResultButtonProps, getQuizResultLinkProps } = useContext(QuizContext);
7
7
  const salePrice = salePriceKey && result?.data?.[salePriceKey];
8
8
  const regularPrice = regularPriceKey && result?.data?.[regularPriceKey];
@@ -22,13 +22,13 @@ export default function ResultCard(props) {
22
22
  "(",
23
23
  ratingCount,
24
24
  ")")),
25
- React.createElement("div", { className: 'cio-result-card-prices' },
25
+ renderResultCardPriceDetails ? (renderResultCardPriceDetails(result)) : (React.createElement("div", { className: 'cio-result-card-prices' },
26
26
  salePrice && React.createElement("span", { className: 'cio-result-card-sale-price' },
27
27
  "$",
28
28
  salePrice),
29
29
  regularPrice && (React.createElement("span", { className: `cio-result-card-regular-price${salePrice ? '--strike-through' : ''}` },
30
30
  "$",
31
- regularPrice)))))));
31
+ regularPrice))))))));
32
32
  const resultCardContentWithoutLink = () => getQuizResultButtonProps && (React.createElement("div", { ...getQuizResultButtonProps({ result, position: resultPosition, type: 'button' }) }, resultCardContent()));
33
33
  const resultCardContentWithLink = () => getQuizResultLinkProps && (React.createElement("a", { className: 'cio-result-card-anchor', rel: 'noreferrer', target: '_blank', ...getQuizResultLinkProps({ result, position: resultPosition, type: 'link' }) }, resultCardContent()));
34
34
  return (React.createElement("div", { className: 'cio-result-card' },
@@ -7,7 +7,7 @@ import Results from '../Results/Results';
7
7
  import Spinner from '../Spinner/Spinner';
8
8
  export default function ResultContainer(props) {
9
9
  const { options } = props;
10
- const { resultCardSalePriceKey, resultCardRegularPriceKey, resultCardRatingCountKey, resultCardRatingScoreKey, } = options;
10
+ const { resultCardSalePriceKey, resultCardRegularPriceKey, resultCardRatingCountKey, resultCardRatingScoreKey, renderResultCardPriceDetails, } = options;
11
11
  const { state } = useContext(QuizContext);
12
12
  const zeroResults = !state?.quiz.results?.response?.results?.length;
13
13
  const resultsTitle = zeroResults ? '' : 'Here are your results';
@@ -17,7 +17,7 @@ export default function ResultContainer(props) {
17
17
  React.createElement("div", { className: 'cio-results-filter-and-redo-container' },
18
18
  React.createElement(ResultFilters, { hasNoResults: zeroResults }),
19
19
  React.createElement(RedoButton, null)),
20
- !zeroResults && (React.createElement(Results, { resultCardSalePriceKey: resultCardSalePriceKey, resultCardRegularPriceKey: resultCardRegularPriceKey, resultCardRatingCountKey: resultCardRatingCountKey, resultCardRatingScoreKey: resultCardRatingScoreKey })),
20
+ !zeroResults && (React.createElement(Results, { resultCardSalePriceKey: resultCardSalePriceKey, resultCardRegularPriceKey: resultCardRegularPriceKey, resultCardRatingCountKey: resultCardRatingCountKey, resultCardRatingScoreKey: resultCardRatingScoreKey, renderResultCardPriceDetails: renderResultCardPriceDetails })),
21
21
  zeroResults && React.createElement(ZeroResults, null)));
22
22
  }
23
23
  return (React.createElement("div", { className: 'cio-results-container' },
@@ -2,8 +2,8 @@ import React, { useContext } from 'react';
2
2
  import QuizContext from '../CioQuiz/context';
3
3
  import ResultCard from '../ResultCard/ResultCard';
4
4
  function Results(props) {
5
- const { resultCardSalePriceKey, resultCardRegularPriceKey, resultCardRatingCountKey, resultCardRatingScoreKey, } = props;
5
+ const { resultCardSalePriceKey, resultCardRegularPriceKey, resultCardRatingCountKey, resultCardRatingScoreKey, renderResultCardPriceDetails, } = props;
6
6
  const { state } = useContext(QuizContext);
7
- return (React.createElement("div", { className: 'cio-results' }, state?.quiz?.results?.response?.results?.map((result, index) => (React.createElement(ResultCard, { result: result, key: result.data?.id, salePriceKey: resultCardSalePriceKey, regularPriceKey: resultCardRegularPriceKey, ratingCountKey: resultCardRatingCountKey, ratingScoreKey: resultCardRatingScoreKey, resultPosition: index + 1 })))));
7
+ return (React.createElement("div", { className: 'cio-results' }, state?.quiz?.results?.response?.results?.map((result, index) => (React.createElement(ResultCard, { result: result, key: result.data?.id, salePriceKey: resultCardSalePriceKey, regularPriceKey: resultCardRegularPriceKey, ratingCountKey: resultCardRatingCountKey, ratingScoreKey: resultCardRatingScoreKey, renderResultCardPriceDetails: renderResultCardPriceDetails, resultPosition: index + 1 })))));
8
8
  }
9
9
  export default Results;
@@ -3,7 +3,6 @@ import QuestionTitle from '../QuestionTitle/QuestionTitle';
3
3
  import QuestionDescription from '../QuestionDescription/QuestionDescription';
4
4
  import QuizContext from '../CioQuiz/context';
5
5
  import { renderImages } from '../../utils';
6
- import ControlBar from '../ControlBar/ControlBar';
7
6
  import { QuestionTypes } from '../CioQuiz/actions';
8
7
  function SelectTypeQuestion() {
9
8
  const { state, getSelectInputProps } = useContext(QuizContext);
@@ -25,8 +24,7 @@ function SelectTypeQuestion() {
25
24
  ? 'cio-question-options-container-text-only'
26
25
  : 'cio-question-options-container'}` }, question?.options?.map((option) => getSelectInputProps && (React.createElement("div", { ...getSelectInputProps(option) },
27
26
  option.images ? renderImages(option.images, 'cio-question-option-image') : '',
28
- React.createElement("div", { className: 'cio-question-option-value' }, option?.value))))),
29
- React.createElement(ControlBar, { ctaButtonText: question?.cta_text || 'Continue' })));
27
+ React.createElement("div", { className: 'cio-question-option-value' }, option?.value)))))));
30
28
  }
31
29
  return null;
32
30
  }
@@ -17,6 +17,7 @@ export const componentDescription = `- import \`CioQuiz\` to render in your JSX.
17
17
  - \`resultCardSalePriceKey\` is an optional parameter that specifies the metadata field name for the sale price
18
18
  - \`resultCardRatingCountKey\` is an optional parameter that specifies the metadata field name for the ratings count
19
19
  - \`resultCardRatingScoreKey\` is an optional parameter that specifies the metadata field name for the ratings score
20
+ - \`renderResultCardPriceDetails\` is an optional render function to render custom prices section in result card
20
21
  - \`sessionStateOptions\` lets you configure the session modal behavior
21
22
  - \`showSessionModal\` is a boolean used to decide whether to show the session modal. The default behavior is to show the session modal
22
23
  - \`showSessionModalOnResults\` is a boolean to decide whether to show the session modal after reaching the results page. The default behavior is to not show the session modal
@@ -88,6 +88,7 @@ export const getMockState = (question) => ({
88
88
  ratingCount: '12',
89
89
  ratingScore: '4',
90
90
  image_url: 'https://demo.constructor.io/sandbox_files/farmstandquizassets/HiThereNameInput.png',
91
+ discount: '59.9',
91
92
  },
92
93
  },
93
94
  {
package/lib/styles.css CHANGED
@@ -57,13 +57,17 @@
57
57
  min-height: 100%;
58
58
  height: 100%;
59
59
  overflow: auto;
60
- display: flex;
61
- justify-content: center;
62
60
  background-color: #ffffff;
63
61
  color: var(--gray-dust-500);
64
62
  font-size: 16px;
65
63
  }
66
64
 
65
+ /* Container for the loading spinner */
66
+ .cio-quiz.cio-quiz-loading {
67
+ display: flex;
68
+ justify-content: center;
69
+ }
70
+
67
71
  .cio-quiz button {
68
72
  cursor: pointer;
69
73
  }
@@ -77,7 +81,9 @@
77
81
  width: 100%;
78
82
  position: relative;
79
83
  align-self: start;
80
- min-height: calc(100% - 2rem); /* Full height - margin */
84
+ height: calc(
85
+ 100% - 2rem - calc(var(--bottom-bar-height))
86
+ ); /* Full height - margin - control bar */
81
87
  }
82
88
  .cio-container--with-image {
83
89
  display: flex;
@@ -86,7 +92,15 @@
86
92
  padding-bottom: var(--bottom-bar-height);
87
93
  position: relative;
88
94
  align-self: start;
89
- min-height: 100%;
95
+ height: calc(100% - calc(var(--bottom-bar-height))); /* Full height - margin - control bar */
96
+ }
97
+
98
+ /* Background image */
99
+ .cio-question-background-image {
100
+ height: calc(100% - 4px);
101
+ width: 100%;
102
+ position: absolute;
103
+ z-index: -1;
90
104
  }
91
105
 
92
106
  /* Session Prompt Modal */
@@ -163,8 +177,9 @@
163
177
  width: 100%;
164
178
  object-fit: cover;
165
179
  max-height: var(--container-image-small-height);
166
- height: var(--container-image-small-height); /* Fixed height for layout shifts*/
180
+ height: var(--container-image-small-height); /* Fixed height for layout shifts */
167
181
  display: flex;
182
+ align-self: stretch;
168
183
  }
169
184
 
170
185
  /* Input */
@@ -192,7 +207,7 @@
192
207
  height: var(--bottom-bar-height);
193
208
  padding: 8px 16px;
194
209
  display: flex;
195
- position: absolute;
210
+ position: sticky;
196
211
  bottom: 0px;
197
212
  left: 0px;
198
213
  background: white;
@@ -280,6 +295,7 @@
280
295
  display: flex;
281
296
  flex-direction: column;
282
297
  cursor: pointer;
298
+ background-color: white;
283
299
  }
284
300
  .cio-question-option-container.selected {
285
301
  outline: 3px solid var(--primary-color-variant-600);
@@ -302,12 +318,15 @@
302
318
  display: flex;
303
319
  flex-direction: column;
304
320
  align-items: center;
305
- align-self: start;
306
321
  max-width: 1200px;
307
322
  padding: 1rem;
308
323
  margin-top: 2rem;
309
- min-height: calc(100% - 3rem); /* Full height - padding - margin */
324
+ min-height: calc(
325
+ 100% - 2rem - calc(var(--bottom-bar-height))
326
+ ); /* Full height - padding - margin */
310
327
  width: 100%;
328
+ margin-right: auto;
329
+ margin-left: auto;
311
330
  }
312
331
  .cio-question-options-container {
313
332
  display: flex;
@@ -337,6 +356,7 @@
337
356
  width: 100%;
338
357
  margin: auto;
339
358
  cursor: pointer;
359
+ background-color: white;
340
360
  }
341
361
 
342
362
  /* Option Image */
@@ -383,6 +403,8 @@
383
403
  padding: 2rem 1rem;
384
404
  display: flex;
385
405
  flex-direction: column;
406
+ margin-right: auto;
407
+ margin-left: auto;
386
408
  }
387
409
  .cio-results-title {
388
410
  margin-top: 0;
@@ -510,6 +532,11 @@
510
532
  .cio-result-card-rating-score {
511
533
  margin-right: 5px;
512
534
  }
535
+ .cio-result-card-discount {
536
+ font-weight: normal;
537
+ font-size: .9em;
538
+ margin-top: 4px;
539
+ }
513
540
 
514
541
  /* Result CTA Button */
515
542
  .cio-result-card-cta-button {
@@ -574,7 +601,6 @@
574
601
 
575
602
  /* Image */
576
603
  .cio-question-image-container {
577
- height: 100%;
578
604
  flex-basis: 50%;
579
605
  flex-shrink: 0;
580
606
  border-radius: 4px;
@@ -623,6 +649,7 @@
623
649
  .cio-container {
624
650
  align-items: center;
625
651
  margin-top: 0;
652
+ height: calc(100% - calc(var(--bottom-bar-height))); /* Full height - control bar */
626
653
  }
627
654
  .cio-container--with-image {
628
655
  padding: 6% 2%;
@@ -641,10 +668,8 @@
641
668
 
642
669
  /* Image */
643
670
  .cio-question-image-container {
644
- max-height: 100%;
645
- }
646
- .cio-cover-question-container--with-image .cio-question-image-container {
647
671
  max-height: unset;
672
+ height: unset;
648
673
  }
649
674
 
650
675
  /* Content */
@@ -662,14 +687,6 @@
662
687
  margin-bottom: 2rem;
663
688
  }
664
689
 
665
- /* CTA Button Component */
666
- .cio-question-buttons-container {
667
- position: sticky;
668
- padding: 0;
669
- margin: 0;
670
- align-items: center;
671
- }
672
-
673
690
  /* Cover Component */
674
691
  .cio-cover-question-container--with-image {
675
692
  padding: 0;
@@ -686,9 +703,11 @@
686
703
  }
687
704
  .cio-select-question-container {
688
705
  justify-content: center;
689
- margin: 0;
706
+ margin-bottom: 0;
707
+ margin-top: 0;
690
708
  padding: 2rem;
691
709
  padding-bottom: 0;
710
+ min-height: calc(100% - calc(var(--bottom-bar-height))); /* Full height - padding - margin */
692
711
  }
693
712
  .cio-question-option-container {
694
713
  width: calc(25% - 13px);
@@ -7,6 +7,7 @@ interface ResultCardProps {
7
7
  ratingCountKey?: string;
8
8
  ratingScoreKey?: string;
9
9
  resultPosition: number;
10
+ renderResultCardPriceDetails?: (result: QuizResultDataPartial) => JSX.Element;
10
11
  }
11
12
  export default function ResultCard(props: ResultCardProps): JSX.Element;
12
13
  export {};
@@ -1,7 +1,7 @@
1
1
  export declare const apiKey = "key_wJSdZSiesX5hiVLt";
2
2
  export declare const quizId = "coffee-quiz";
3
3
  export declare const quizSessionStateKey = "constructorIOQuizState";
4
- export declare const componentDescription = "- import `CioQuiz` to render in your JSX.\n- This component handles state management, data fetching, and rendering logic.\n- To use this component, `quizId`, `resultsPageOptions`, and one of `apiKey` or `cioJsClient` are required.\n- `resultsPageOptions` lets you configure the results page\n - `onAddToCartClick` is a callback function that will be called when the \"Add to cart\" button is clicked\n - `onQuizResultClick` is an optional callback function that will be called when the result card is clicked. The default behavior is redirecting the user to the item's URL\n - `onQuizResultsLoaded` is an optional callback function that will be called when the quiz results are loaded\n - `resultCardRegularPriceKey` is a parameter that specifies the metadata field name for the regular price\n - `resultCardSalePriceKey` is an optional parameter that specifies the metadata field name for the sale price \n - `resultCardRatingCountKey` is an optional parameter that specifies the metadata field name for the ratings count \n - `resultCardRatingScoreKey` is an optional parameter that specifies the metadata field name for the ratings score \n- `sessionStateOptions` lets you configure the session modal behavior\n - `showSessionModal` is a boolean used to decide whether to show the session modal. The default behavior is to show the session modal\n - `showSessionModalOnResults` is a boolean to decide whether to show the session modal after reaching the results page. The default behavior is to not show the session modal\n - `sessionStateKey` is a custom string that will be used as a session storage key\n- Use different props to configure the behavior of this component.\n- The following stories show how different props affect the component's behavior\n\n> Note: `cioJsClient` refers to an instance of the [constructorio-client-javascript](https://www.npmjs.com/package/@constructor-io/constructorio-client-javascript)\n";
4
+ export declare const componentDescription = "- import `CioQuiz` to render in your JSX.\n- This component handles state management, data fetching, and rendering logic.\n- To use this component, `quizId`, `resultsPageOptions`, and one of `apiKey` or `cioJsClient` are required.\n- `resultsPageOptions` lets you configure the results page\n - `onAddToCartClick` is a callback function that will be called when the \"Add to cart\" button is clicked\n - `onQuizResultClick` is an optional callback function that will be called when the result card is clicked. The default behavior is redirecting the user to the item's URL\n - `onQuizResultsLoaded` is an optional callback function that will be called when the quiz results are loaded\n - `resultCardRegularPriceKey` is a parameter that specifies the metadata field name for the regular price\n - `resultCardSalePriceKey` is an optional parameter that specifies the metadata field name for the sale price \n - `resultCardRatingCountKey` is an optional parameter that specifies the metadata field name for the ratings count \n - `resultCardRatingScoreKey` is an optional parameter that specifies the metadata field name for the ratings score \n - `renderResultCardPriceDetails` is an optional render function to render custom prices section in result card \n- `sessionStateOptions` lets you configure the session modal behavior\n - `showSessionModal` is a boolean used to decide whether to show the session modal. The default behavior is to show the session modal\n - `showSessionModalOnResults` is a boolean to decide whether to show the session modal after reaching the results page. The default behavior is to not show the session modal\n - `sessionStateKey` is a custom string that will be used as a session storage key\n- Use different props to configure the behavior of this component.\n- The following stories show how different props affect the component's behavior\n\n> Note: `cioJsClient` refers to an instance of the [constructorio-client-javascript](https://www.npmjs.com/package/@constructor-io/constructorio-client-javascript)\n";
5
5
  export declare const hookDescription = "- import `useCioQuiz` and call this custom hook in a functional component.\n- This hook leaves rendering logic up to you, while handling:\n - state management\n - data fetching\n - keyboard navigation\n - mouse interactions\n - focus and submit event handling\n- Since the markup is controlled by you, the default styles might not be applied if you have a different DOM structure\n- To use this hook, an `apiKey` and `quizId` are required, and `resultsPageOptions` must be passed to the `useCioQuiz` hook to configure behavior. All other values are optional.\n- use the <a href=\"https://kentcdodds.com/blog/how-to-give-rendering-control-to-users-with-prop-getters\" target=\"__blank\">prop getters</a> and other variables returned by this hook (below) to leverage the functionality described above with jsx elements in your react component definitions\n\nCalling the `useCioQuiz` hook returns an object with the following keys:\n\n```jsx\nconst {\n // must be used for a hooks integrations\n state: QuizReturnState, // Quiz state\n events: [{...}], // array of quiz events\n getAddToCartButtonProps: () => ({...})), // prop getter for jsx add to cart button for quiz result,\n getCoverQuestionProps: () => ({...})), // prop getter for jsx quiz cover question,\n getHydrateQuizButtonProps: () => ({...})), // prop getter for jsx hydrate quiz button,\n getNextQuestionButtonProps: () => ({...})), // prop getter for jsx next button to traverse the quiz,\n getPreviousQuestionButtonProps: () => ({...})), // prop getter for jsx back button to traverse the quiz, \n getOpenTextInputProps: () => ({...})), // prop getter for jsx open text input,\n getSelectInputProps: () => ({...})), // prop getter for jsx select input for select type questions,\n getQuizImageProps: () => ({...})), // prop getter for jsx quiz image,\n getQuizResultButtonProps: () => ({...})), // prop getter for jsx result card click as a button,\n getQuizResultLinkProps: () => ({...})), // prop getter for jsx result card click as a link. Should be spread into <a> tags,\n getResetQuizButtonProps: () => ({...})), // prop getter for jsx reset quiz button,\n cioClient, // instance of constructorio-client-javascript\n } = useCioQuiz(args);\n```\n\n> Note: when we say `cioClient`, we are referring to an instance of the [constructorio-client-javascript](https://www.npmjs.com/package/@constructor-io/constructorio-client-javascript)\n";
6
6
  export declare const basicDescription = "Pass an `apiKey` and a `quizId` to request questions and quiz results from Constructor's servers";
7
7
  export declare const cioJsClientDescription = "If you are already using an instance of the `ConstructorIOClient`, you can pass a `cioJsClient` instead of an `apiKey` to request results from Constructor's servers\n\n> Note: `cioJsClient` refers to an instance of the [constructorio-client-javascript](https://www.npmjs.com/package/@constructor-io/constructorio-client-javascript)";
@@ -10,6 +10,7 @@ export interface ResultCardProps {
10
10
  resultCardRegularPriceKey?: string;
11
11
  resultCardRatingCountKey?: string;
12
12
  resultCardRatingScoreKey?: string;
13
+ renderResultCardPriceDetails?: (result: QuizResultDataPartial) => JSX.Element;
13
14
  }
14
15
  export declare namespace QuizResultsEventsProps {
15
16
  type OnQuizResultsLoaded = (results: QuizResultDataPartial) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructor-io/constructorio-ui-quizzes",
3
- "version": "1.4.6",
3
+ "version": "1.5.0",
4
4
  "description": "Constructor.io Quizzes UI library for web applications",
5
5
  "author": "constructor.io",
6
6
  "license": "MIT",