Source

externalCode/quizDetailScreen.js

/**
 * @typedef {Object} QuizDetailVM
 * @property {Boolean} showCategoryScore Returns `true` if category score should be shown
 * @property {Boolean} hideResultQuizTime Returns `true` if result quiz time should be hidden
 * @property {Boolean} hideResultPoints Returns `true` if result points should be hidden
 * @property {Boolean} showAverageResult Returns `true` if average result should be shown
 * @property {Boolean} btnViewQuestionHidden Returns `true` if review button should be hidden
 */

/**
 * @typedef {Object} ResultDetailsProps
 * @property {Object} result Quiz result details
 * @property {QuizDetailVM} quizVM
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {TranslationFunction} t
 */

/**
 * @typedef {Object} DetailCategoryTitleProps
 * @property {ResultDetailsProps}
 */

/**
 * @typedef {Object} ResultMessageProps
 * @property {ResultDetailsProps}
 */

/**
 * @typedef {Object} CategoryScoreComponentProps
 * @property {ResultDetailsProps}
 */

/**
 * @typedef {Object} ResultPointsComponentProps
 * @property {ResultDetailsProps}
 */

/**
 * @typedef {Object} ResultIconComponentProps
 * @property {ResultDetailsProps}
 */

/**
 * @typedef {Object} RecapMessageProps
 * @property {ResultDetailsProps}
 */

/**
 * @typedef {Object} ReviewQuizButtonProps
 * @property {ResultDetailsProps}
 * @property {Number} bottomSafeArea
 * @property {Function} onReviewClick Helper function that navigates to Quiz Review screen
 * @property {Object} labels Learndash labels
 */

/**
 * @class
 * Quiz Detail Screen Hooks.
 * Instance name: quizDetailApi
  
   You can use these hooks to customize the quiz detail screen components in your app such as customizing the result message, recap message and so on.
 * @example
 * externalCodeSetup.quizDetailApi.METHOD_NAME
 */
export class QuizDetailApi {
	DetailCategoryTitle = null;

	/**
	 * You can use this to customize the component that displays the "Category" title.
	 * For example, you can change the styling of the text component.
	 * @method
	 * @param {React.ComponentType<DetailCategoryTitleProps>} DetailCategoryTitle
	 * @example
	 *
	 * externalCodeSetup.quizDetailApi.setDetailCategoryTitle(({
	 *   result,
	 *   quizVM,
	 *   global,
	 *   t
	 * }) =>
	 *     Array.isArray(result.cats) &&
	 *     result.cats.length &&
	 *     quizVM.showCategoryScore && (
	 *         <Text style={global.resultsSubTitle}>
	 *             {t("quiz:quizCategories")}
	 *         </Text>
	 *     )
	 * )
	 */
	setDetailCategoryTitle = DetailCategoryTitle => {
		this.DetailCategoryTitle = DetailCategoryTitle;
	};

	CategoryScoreComponent = null;

	/**
	 * You can use this to customize the category scores component.
	 * @method
	 * @param {React.ComponentType<CategoryScoreComponentProps>} CategoryScoreComponent
	 * @example
	 *
	 * ...
	 *
	 * import { View, Text, StyleSheet } from "react-native"
	 * import {
	 *     FontWeights
	 * } from "@src/styles/global";
	 *
	 * export const applyCustomCode = (externalCodeSetup: any) => {
	 *
	 *     externalCodeSetup.quizDetailApi.setCategoryScoreComponent(({
	 *         result,
	 *         quizVM,
	 *         global,
	 *         colors
	 *     }) => {
	 *
	 *         const firstC = 6;
	 *         const secondC = 1.6;
	 *         const thirdC = 2.4;
	 *
	 *         return Array.isArray(result.cats) &&
	 *             result.cats.length &&
	 *             quizVM.showCategoryScore && (
	 *                 <View
	 *                     style={[
	 *                         {
	 *                             marginTop: 15,
	 *                             borderBottomWidth: StyleSheet.hairlineWidth,
	 *                             borderBottomColor: colors.borderColor
	 *                         }
	 *                     ]}
	 *                 >
	 *                     {result.cats.map((item, index) => {
	 *                         return (
	 *                             <View key={index} style={[global.row, { marginBottom: 15 }]}>
	 *                                 <Text
	 *                                     style={{
	 *                                         ...global.textAlt,
	 *                                         fontWeight: FontWeights.medium,
	 *                                         flex: firstC
	 *                                     }}
	 *                                 >
	 *                                     {item.name}
	 *                                 </Text>
	 *                                 <Text
	 *                                     style={[
	 *                                         global.textAlt,
	 *                                         {
	 *                                             fontWeight: FontWeights.medium,
	 *                                             marginLeft: "auto",
	 *                                             color: "#8D8F97",
	 *                                             flex: secondC
	 *                                         }
	 *                                     ]}
	 *                                 >
	 *                                     {item.result.toFixed(0)}%
	 *                                 </Text>
	 *                                 <Text
	 *                                     style={[
	 *                                         global.textAlt,
	 *                                         {
	 *                                             fontWeight: FontWeights.medium,
	 *                                             marginLeft: "auto",
	 *                                             color: "#8D8F97",
	 *                                             flex: thirdC
	 *                                         }
	 *                                     ]}
	 *                                 />
	 *                             </View>
	 *                         );
	 *                     })}
	 *                 </View>
	 *             )
	 *     })
	 * }
	 */
	setCategoryScoreComponent = CategoryScoreComponent => {
		this.CategoryScoreComponent = CategoryScoreComponent;
	};

	ResultPointsComponent = null;

	/**
	 * You can use this to customize the points component.
	 * @method
	 * @param {React.ComponentType<ResultPointsComponentProps>} ResultPointsComponent
	 * @example
	 *
	 * ...
	 *
	 *import { View, Text } from "react-native"
	 *import {
	 *    FontWeights
	 *} from "@src/styles/global";
	 *
	 *export const applyCustomCode = (externalCodeSetup: any) => {
	 *
	 *    externalCodeSetup.quizDetailApi.setResultPointsComponent(({
	 *        quizVM,
	 *        global,
	 *        colors,
	 *        t,
	 *        result
	 *    }) => {
	 *
	 *        const firstC = 6;
	 *        const secondC = 1.6;
	 *        const thirdC = 2.4;
	 *
	 *        return !quizVM.hideResultPoints && (
	 *            <View style={[{ marginTop: 25 }]}>
	 *                <View style={[global.row, { marginBottom: 15 }]}>
	 *                    <Text
	 *                        style={{
	 *                            ...global.text,
	 *                            fontWeight: FontWeights.medium,
	 *                            flex: firstC
	 *                        }}
	 *                    >
	 *                        {t("quiz:quizYourScore")}
	 *                    </Text>
	 *                    <Text
	 *                        style={[
	 *                            global.textAlt,
	 *                            {
	 *                                color: colors.descTextColor,
	 *                                flex: secondC,
	 *                                fontSize: 16,
	 *                                fontWeight: FontWeights.medium
	 *                            }
	 *                        ]}
	 *                    >
	 *                        {Math.round((result.result || 0) * 100) / 100}%
	 *                    </Text>
	 *                    <Text
	 *                        style={[
	 *                            global.textAlt,
	 *                            {
	 *                                color: colors.descTextColor,
	 *                                flex: thirdC,
	 *                                textAlign: "right",
	 *                                fontSize: 16,
	 *                                fontWeight: FontWeights.medium
	 *                            }
	 *                        ]}
	 *                    >
	 *                        {t("quiz:pointsCount", {
	 *                            count: parseInt(result.awarded_points) || 0
	 *                        })}
	 *                    </Text>
	 *                </View>
	 *                <View style={[global.row, {marginBottom: 15}]}>
	 *                    <Text
	 *                        style={{
	 *                            ...global.text,
	 *                            fontWeight: FontWeights.medium,
	 *                            flex: firstC
	 *                        }}
	 *                    >
	 *                        {t("quiz:passingScore")}
	 *                    </Text>
	 *                    <Text
	 *                        style={[
	 *                            global.textAlt,
	 *                            {
	 *                                color: colors.descTextColor,
	 *                                flex: secondC,
	 *                                fontSize: 16,
	 *                                fontWeight: FontWeights.medium
	 *                            }
	 *                        ]}
	 *                    >
	 *                        {Math.round(result.passing_percentage * 100) / 100}%
	 *                    </Text>
	 *                    <Text
	 *                        style={[
	 *                            global.textAlt,
	 *                            {
	 *                                color: colors.descTextColor,
	 *                                flex: thirdC,
	 *                                textAlign: "right",
	 *                                fontSize: 16,
	 *                                fontWeight: FontWeights.medium
	 *                            }
	 *                        ]}
	 *                     >
	 *                         {t("quiz:pointsCount", {
	 *                             count:
	 *                                 parseInt(
	 *                                     Math.round(
	 *                                         result.possible_points * result.passing_percentage
	 *                                     ) / 100
	 *                                 ) || 0
	 *                         })}
	 *                     </Text>
	 *                 </View>
	 *             </View>
	 *         )
	 *     })
	 * }
	 */
	setResultPointsComponent = ResultPointsComponent => {
		this.ResultPointsComponent = ResultPointsComponent;
	};

	ResultIconComponent = null;

	/**
	 * You can use this to change the icon displayed in the screen.
	 * For example, you can use your own image instead of the default success and fail images.
	 * @method
	 * @param {React.ComponentType<ResultIconComponentProps>} ResultIconComponent
	 * @example
	 *
	 * ...
	 *
	 * import Icon from "@src/components/Icon";
	 * import {SUCCESS_COLOR, WARNING_COLOR} from "@src/styles/global";
	 *
	 * export const applyCustomCode = (externalCodeSetup: any) => {
	 *     externalCodeSetup.quizDetailApi.setResultIconComponent(({result}) => (
	 *         <View
	 *             style={{
	 *                 marginTop: 15,
	 *                 justifyContent: "center",
	 *                 alignItems: "center"
	 *             }}
	 *         >
	 *             <View
	 *                 style={{
	 *                     paddingLeft: 40,
	 *                     paddingRight: 40,
	 *                     alignItems: "center"
	 *                 }}
	 *             >
	 *                 {result.is_pass ? (
	 *                     <Icon
	 *                         icon={{fontIconName: "check", weight: 200}}
	 *                         tintColor={SUCCESS_COLOR}
	 *                         style={{
	 *                             width: 50,
	 *                             height: 50,
	 *                             marginTop: 25
	 *                         }}
	 *                     />
	 *                 ) : (
	 *                     <Icon
	 *                         icon={{fontIconName: "times", weight: 200}}
	 *                         tintColor={WARNING_COLOR}
	 *                         style={{
	 *                             width: 50,
	 *                             height: 50,
	 *                             marginTop: 25
	 *                         }}
	 *                     />
	 *                 )}
	 *             </View>
	 *         </View>
	 *     ));
	 * }
	 */
	setResultIconComponent = ResultIconComponent => {
		this.ResultIconComponent = ResultIconComponent;
	};

	ResultMessage = null;

	/**
	 * You can use this to customize the result message displayed.
	 * @method
	 * @param {React.ComponentType<ResultMessageProps>} ResultMessage
	 * @example <caption> Implement deep linking to the result message </caption>
	 *
	 * //In custom_code/ResultMessage.js...
	 *
	 * import React from "react";
	 * import {View} from "react-native";
	 * import HTML from "react-native-render-html";
	 * import {withNavigation} from "@src/components/hocs/withNavigation";
	 * import withDeeplinkClickHandler from "../../src/components/hocs/withDeeplinkClickHandler";
	 * import { compose } from "recompose";
	 *
	 * const ResultMessage =  ({
	 *     result,
	 *     global,
	 *     colors,
	 *     attemptDeepLink
	 * }) => <View
	 *     style={{
	 *       width: "100%",
	 *       marginTop: 16,
	 *       paddingHorizontal: 16
	 *     }}
	 *   >
	 *     {!!result.message && (
	 *       <HTML
	 *         onLinkPress={attemptDeepLink(false)}
	 *         contentStyle={{marginHorizontal: 20}}
	 *         html={`<center>${result.message}</center>`}
	 *         baseFontStyle={global.text}
	 *         tagsStyles={{
	 *           center: {
	 *             alignItems: "center"
	 *           },
	 *           h1: {
	 *             marginBottom: 10
	 *           },
	 *           h2: {
	 *             marginBottom: 10
	 *           },
	 *           h3: {
	 *             marginBottom: 10
	 *           },
	 *           h4: {
	 *             marginBottom: 10
	 *           },
	 *           h5: {
	 *             marginBottom: 10
	 *           },
	 *           h6: {
	 *             marginBottom: 10
	 *           },
	 *           p: {
	 *             marginTop: 0,
	 *             marginBottom: 10
	 *           },
	 *           a: {
	 *             color: colors.linkColor,
	 *             textDecorationLine: "none"
	 *           }
	 *         }}
	 *       />
	 *     )}
	 *   </View>
	 *
	 * export default compose(
	 *     withNavigation,
	 *     withDeeplinkClickHandler
	 * )(ResultMessage)
	 *
	 *  //In custom_code/index.js...
	 *
	 * import ResultMessage from "./components/ResultMessage";
	 * export const applyCustomCode = (externalCodeSetup: any) => {
	 *   externalCodeSetup.quizDetailApi.setResultMessage(props => <ResultMessage {...props} /> );
	 * }
	 *
	 */
	setResultMessage = ResultMessage => {
		this.ResultMessage = ResultMessage;
	};

	RecapMessage = null;

	/**
	 * You can use this to customize the recap message text below the result message.
	 * @method
	 * @param {React.ComponentType<RecapMessageProps>} RecapMessage
	 * @example
	 *
	 * ...
	 *
	 * externalCodeSetup.quizDetailApi.setRecapMessage(({ quizVM, global, colors, t }) => (
	 *   !quizVM.btnViewQuestionHidden && (
	 *       <Text
	 *           style={[
	 *               global.textAlt,
	 *               {
	 *                   marginHorizontal: 20,
	 *                   color: colors.descTextColor,
	 *                   textAlign: "center",
	 *                   marginBottom: 36
	 *               }
	 *           ]}
	 *       >
	 *           {t("quiz:recap")}
	 *       </Text>
	 *   )
	 * ))
	 */
	setRecapMessage = RecapMessage => {
		this.RecapMessage = RecapMessage;
	};

	ReviewQuizButton = null;

	/**
	 * You can use this to customize the ReviewQuizButton component which by default, navigates you to the QuizReview screen.
	 * @method
	 * @param {React.ComponentType<ReviewQuizButtonProps>} ReviewQuizButton
	 * @example
	 *
	 * ...
	 *
	 * import AppButton from "@src/components/AppButton";
	 *
	 * export const applyCustomCode = (externalCodeSetup: any) => {
	 *     externalCodeSetup.quizDetailApi.setReviewQuizButton(({
	 *         quizVM,
	 *         global,
	 *         colors,
	 *         t,
	 *         labels,
	 *         onReviewClick,
	 *         bottomSafeArea
	 *     }) => !quizVM.btnViewQuestionHidden && (
	 *         <View
	 *             style={[
	 *                 {
	 *                     paddingTop: 16,
	 *                     paddingHorizontal: 20,
	 *                     backgroundColor: "#fff",
	 *                     borderTopWidth: StyleSheet.hairlineWidth,
	 *                     borderTopColor: "#C6C6C8",
	 *                     paddingBottom: bottomSafeArea
	 *                 }
	 *             ]}
	 *         >
	 *             <AppButton
	 *                 style={[
	 *                     { backgroundColor: colors.secondaryButtonBg, height: 40 }
	 *                 ]}
	 *                 onPress={onReviewClick}
	 *                 labelStyle={{
	 *                     ...global.quizReviewButtonLabel,
	 *                     color: colors.secondaryButtonColor
	 *                 }}
	 *                 label={t("quiz:reviewQuiz", { quiz: labels.quiz })}
	 *                 global={global}
	 *                 loading={false}
	 *             />
	 *         </View>
	 *     ))
	 * }
	 *
	 */
	setReviewQuizButton = ReviewQuizButton => {
		this.ReviewQuizButton = ReviewQuizButton;
	};
}