Source

externalCode/quizReviewApi.ts

import * as React from "react";
import {NavigationService, TTranslationFunction} from "./types";

export const API_NAME = "quizReviewApi";

/**
 * QuizReviewRadioIconProps
 */
type QuizReviewRadioIconProps = {
	/**
	 * Returns `true` if radio is used in a multiple choice question
	 */
	multiselect: boolean,
	/**
	 * Default styles for the radio
	 */
	styles: Record<any, any>,
	/**
	 * Returns `true` if the answer selected is wrong
	 */
	isWrong: boolean | undefined,
	/**
	 * Returns `true` if the answer selected is correct
	 */
	isRight: boolean | undefined,
	/**
	 * Returns the default resource used in the radio
	 */
	multipleChoiceIcon: number,
	/**
	 * Answer details
	 */
	radio: Record<any, any>
};

/**
 * QuizReviewRadioDescriptionProps
 */
type QuizReviewRadioDescriptionProps = {
	/**
	 * Index of the answer
	 */
	index: number,
	/**
	 * Default color of the description component
	 */
	color: string,
	/**
	 * Default styles for the description
	 */
	styles: Record<any, any>,
	/**
	 * Font details
	 */
	baseFontStyle: Record<any, any>,
	/**
	 * Description of the answer
	 */
	description: string,

	/**
	 * Default renderers for the HTML component
	 */
	renderers: Record<any, any>
};

/**
 * QuizReviewFreeAnswerComponentProps
 */
type QuizReviewFreeAnswerComponentProps = {
	/**
	 * Answer details
	 */
	answer: Record<any, any>,
	/**
	 * Returns `true` if answer is correct
	 */
	correct: boolean,
	/**
	 * Default styles
	 */
	styles: Record<any, any>,
	/**
	 * Default success or fail icon
	 */
	icon: Record<any, any>,
	/**
	 * Default tint color for success or fail status
	 */
	tintColor: string,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>
};

/**
 * QuizReviewQuestionClosedComponentProps
 */
type QuizReviewQuestionClosedComponentProps = {
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * Default styles
	 */
	styles: Record<any, any>,
	/**
	 * Question and answer details
	 */
	questionText: string,
	/**
	 * Default tags styles for rendering the HTML
	 */
	tagsStyles: Record<any, any>
};

/**
 * QuizReviewQuestionSortItemComponentProps
 */
type QuizReviewQuestionSortItemComponentProps = {
	/**
	 * Default wrapper for sort component
	 */
	Component: React.ComponentType,
	/**
	 * Default styles
	 */
	styles: Record<any, any>,
	/**
	 * Item data
	 */
	data: Record<any, any>,
	/**
	 * Default icon for sort component
	 */
	icon: Record<any, any>,
	/**
	 * Returns `true` if component is being dragged
	 */
	active: boolean
};

/**
 * QuizReviewQuestionEssayComponentProps
 */
type QuizReviewQuestionEssayComponentProps = {
	/**
	 * Default styles
	 */
	styles: Record<any, any>,

	t: TTranslationFunction,
	/**
	 * App global style
	 */
	global: Record<any, any>
};

/**
 * QuizReviewQuestionAssessmentHTMLProps
 */
type QuizReviewQuestionAssessmentHTMLProps = {
	/**
	 * Question assessment details
	 */
	item: Record<any, any>,
	/**
	 * Index of item
	 */
	index: number,
	/**
	 * Default styles
	 */
	styles: Record<any, any>,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * Default tags styles which can be used for rendering the question assessment HTML description
	 */
	tagsStyles: Record<any, any>
};

/**
 * QuizReviewHTMLQuestionTitleProps
 */
type QuizReviewHTMLQuestionTitleProps = {
	/**
	 * Default tags styles
	 */
	tagsStyles: Record<any, any>,
	/**
	 * Default font style
	 */
	baseFontStyle: Record<any, any>,
	/**
	 * Returns the question title in html format
	 */
	html: string,
	/**
	 * Default image max width when generated by the HTML component
	 */
	imageMaxWidth: number,
	/**
	 * Handles link press for the HTML component
	 */
	onLinkPress: Function,
	/**
	 * Default ignored tags
	 */
	ignoredTags: string[],
	/**
	 * Default classes styles
	 */
	classesStyles: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,

	navigation: NavigationService
};

/**
 * AnswerResultModalMessageProps
 */
type AnswerResultModalMessageProps = {
	/**
	 * App global style
	 */
	global: Record<any, any>,

	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Default styles
	 */
	styles: Record<any, any>,

	/**
	 * Answer details
	 */
	answerResult: Record<any, any>,

	t: TTranslationFunction,

	/**
	 * Returns `true` if a summary message should be visible
	 */
	showSummaryMessage: boolean,

	/**
	 * Returns the source of an icon if answer is correct
	 */
	correctIcon: number,
	/**
	 * Returns the source of an icon if answer is incorrect
	 */
	inCorrectIcon: number,

	/**
	 * Returns default appropriate icon color
	 */
	iconColor: string
};

/**
 * AnswerResultMessageProps
 */
type AnswerResultMessageProps = {
	/**
	 * Returns `true` if summary message should be hidden
	 */
	hideSummaryMessage: undefined | boolean,
	/**
	 * App global style
	 */
	global: Record<any, any>,

	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Answer details
	 */
	answer: Record<any, any>
};

/**
 * QuestionCountComponentProps
 */
type QuestionCountComponentProps = {
	hideTitle: undefined | boolean,
	/**
	 * Default styles
	 */
	styles: Record<any, any>,

	t: TTranslationFunction,

	/**
	 * Learndash labels
	 */
	labels: Record<any, any>,

	/**
	 * Total number of questions
	 */
	total: number,
	/**
	 * Current question number
	 */
	questionNumber: number
};

/**
 * @class
 * Quiz Review Hooks.
 * Instance name: quizReviewApi
 
   You can use this hook to customize the components available when reviewing a quiz or an answer to a quiz.
   This includes the components in the modal if "Custom Answer Feedback" is enabled and the Quiz Review Screen (this screen shows up when "Review Quiz" button is pressed while in the Quiz Details screen).
 * @example
 * externalCodeSetup.quizReviewApi.METHOD_NAME
 */
export class QuizReviewApi {
	RadioIcon: React.ComponentType<QuizReviewRadioIconProps> | null = null;

	/**
	 * You can use this hook to change the radio icon component used in a single, multiple choice, or assessment question.
	 * For example, you can change the "correct" or "wrong" icon, change the component's color etc.
	 * @method
	 * @param {React.ComponentType<QuizReviewRadioIconProps>} RadioIcon
	 * @example
	 *
	 * externalCodeSetup.quizReviewApi.setRadioIcon(props => {
	 *   const {styles, isWrong, isRight, multiselect, multipleChoiceIcon} = props;
	 *   return multiselect ? (
	 *       <Image
	 *           style={[
	 *               styles.iconStyle,
	 *               styles.selectedStyleMultiple,
	 *               isWrong === true ? {tintColor: styles.wrongColor} : {},
	 *               isRight === true ? {tintColor: styles.rightColor} : {}
	 *           ]}
	 *           resizeMode={"contain"}
	 *           source={multipleChoiceIcon}
	 *       />
	 *   ) : (
	 *       <View
	 *           style={[
	 *               styles.radio,
	 *               {borderColor: styles.borderColor},
	 *               styles.uncheckedColor && {borderColor: styles.uncheckedColor},
	 *               styles.selectedStyleSingle,
	 *               isWrong === true ? {borderColor: styles.wrongColor} : {},
	 *               isRight === true ? {borderColor: styles.rightColor} : {}
	 *           ]}
	 *       />
	 *   );
	 * });
	 *
	 */
	setRadioIcon = (
		RadioIcon: React.ComponentType<QuizReviewRadioIconProps> | null
	) => {
		this.RadioIcon = RadioIcon;
	};

	RadioDescription: React.ComponentType<
		QuizReviewRadioDescriptionProps
	> | null = null;

	/**
	 * You can use this hook to customize the label in a radio component when reviewing the answer.
	 * Questions that use radio components as an answer include: "Single choice", "Multiple choice", and "Assessment" type of questions.
	 * @method
	 * @param {React.ComponentType<QuizReviewRadioDescriptionProps>} RadioDescription
	 * @example
	 *
	 * ...
	 *
	 * import HTML from "react-native-render-html";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.quizReviewApi.setRadioDescription(
	 *         ({index, color, styles, baseFontStyle, description}) => (
	 *             <HTML
	 *                 key={index + color}
	 *                 containerStyle={styles.containerStyle}
	 *                 baseFontStyle={baseFontStyle}
	 *                 html={description}
	 *             />
	 *         )
	 *     );
	 * }
	 */
	setRadioDescription = (
		RadioDescription: React.ComponentType<
			QuizReviewRadioDescriptionProps
		> | null
	) => {
		this.RadioDescription = RadioDescription;
	};

	FreeAnswerComponent: React.ComponentType<
		QuizReviewFreeAnswerComponentProps
	> | null = null;

	/**
	 * You can use this hook to customize the displayed answer of free choice type of questions in a quiz review screen or modal.
	 * This hook is also used to customize the label component of "Essay / Open Answer" type of questions if the answer format is set to `Text entry`.
	 * If the answer format is set to `File upload`, use the `setQuestionEssayComponent` hook.
	 * @method
	 * @param {React.ComponentType<QuizReviewFreeAnswerComponentProps>} FreeAnswerComponent
	 * @example
	 *
	 * externalCodeSetup.quizReviewApi.setFreeAnswerComponent(
	 *     ({styles, global, answer, icon, tintColor}) => (
	 *         <View style={styles.container}>
	 *             <Text style={[global.text]}>{answer.sentItems[0]}</Text>
	 *             <Icon icon={icon} tintColor={tintColor} styles={styles.icon} />
	 *         </View>
	 *     )
	 * );
	 */
	setFreeAnswerComponent = (
		FreeAnswerComponent: React.ComponentType<
			QuizReviewFreeAnswerComponentProps
		> | null
	) => {
		this.FreeAnswerComponent = FreeAnswerComponent;
	};

	QuestionEssayComponent: React.ComponentType<
		QuizReviewQuestionEssayComponentProps
	> | null = null;

	/**
	 * You can use this hook to customize the file uploaded message when answering an "Essay / Open Answer" type of questions with a file upload answer format.
	 * To customize a text entry answer format, use `setFreeAnswerComponent` hook.
	 * @method
	 * @param {React.ComponentType<QuizReviewQuestionEssayComponentProps>} QuestionEssayComponent
	 * @example
	 *
	 * externalCodeSetup.quizReviewApi.setQuestionEssayComponent(
	 *    ({global, styles, t}) => (
	 *        <Text style={[global.text, styles.text]}>{t("quiz:essayUploaded")}</Text>
	 *    )
	 * );
	 */
	setQuestionEssayComponent = (
		QuestionEssayComponent: React.ComponentType<
			QuizReviewQuestionEssayComponentProps
		> | null
	) => {
		this.QuestionEssayComponent = QuestionEssayComponent;
	};

	QuestionClosedComponent: React.ComponentType<
		QuizReviewQuestionClosedComponentProps
	> | null = null;

	/**
	 * You can use this hook to customize the displayed answer for "Fill in the blank" type of questions.
	 * @method
	 * @param {React.ComponentType<QuizReviewQuestionClosedComponentProps>} QuestionClosedComponent
	 * @example
	 * ...
	 *
	 * import HTML from "react-native-render-html";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *
	 *     externalCodeSetup.quizReviewApi.setQuestionClosedComponent(
	 *         ({global, styles, questionText, tagsStyles}) => (
	 *             <View style={[global.courseRoundBox, styles.container]}>
	 *                 <HTML
	 *                     html={questionText}
	 *                     baseFontStyle={global.text}
	 *                     tagsStyles={tagsStyles}
	 *                     onLinkPress={() => {}}
	 *                 />
	 *             </View>
	 *         )
	 *     );
	 * }
	 */
	setQuestionClosedComponent = (
		QuestionClosedComponent: React.ComponentType<
			QuizReviewQuestionClosedComponentProps
		> | null
	) => {
		this.QuestionClosedComponent = QuestionClosedComponent;
	};

	QuestionSortItemComponent: React.ComponentType<
		QuizReviewQuestionSortItemComponentProps
	> | null = null;

	/**
	 * You can use this hook to customize the displayed answer when answering a "sorting" choice question type.
	 * For example, you can change the component's color, icon, or text display.
	 * @method
	 * @param {React.ComponentType<QuizReviewQuestionSortItemComponentProps>} QuestionSortItemComponent
	 * @example <caption> Change the text color of the item component when dragging </caption>
	 *
	 * ...
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *   externalCodeSetup.quizReviewApi.setQuestionSortItemComponent(({
	 *       Component,
	 *       styles,
	 *       data,
	 *       icon,
	 *       active
	 *   }) => {
	 *       let titleStyle = styles.title;
	 *       if (active){
	 *           titleStyle = {
	 *               ...styles.title,
	 *               color: 'red'
	 *           }
	 *       }
	 *       return (
	 *           <Component style={styles.containerStyle}>
	 *               <Text style={titleStyle}>{data.title}</Text>
	 *               <Image style={styles.icon} source={icon} />
	 *           </Component>
	 *       );
	 *   });
	 * }
	 */
	setQuestionSortItemComponent = (
		QuestionSortItemComponent: React.ComponentType<
			QuizReviewQuestionSortItemComponentProps
		> | null
	) => {
		this.QuestionSortItemComponent = QuestionSortItemComponent;
	};

	QuestionAssessmentHTML: React.ComponentType<
		QuizReviewQuestionAssessmentHTMLProps
	> | null = null;

	/**
	 * You can use this hook to customize the "Less true" or "More true" components when reviewing an "Assessment" type of question.
	 * @method
	 * @param {QuizReviewQuestionAssessmentHTMLProps} QuestionAssessmentHTML
	 * @example
	 *
	 * ...
	 *
	 * import HTML from "react-native-render-html";
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *   externalCodeSetup.quizReviewApi.setQuestionAssessmentHTML(
	 *       ({item, index, styles, global, tagsStyles}) => (
	 *           <View key={index}>
	 *               <HTML
	 *                   html={item.value}
	 *                   containerStyle={styles.container}
	 *                   baseFontStyle={global.text}
	 *                   tagsStyles={tagsStyles}
	 *                   onLinkPress={() => {}}
	 *               />
	 *           </View>
	 *       )
	 *   );
	 * }
	 */
	setQuestionAssessmentHTML = (
		QuestionAssessmentHTML: React.ComponentType<
			QuizReviewQuestionAssessmentHTMLProps
		> | null
	) => {
		this.QuestionAssessmentHTML = QuestionAssessmentHTML;
	};

	HTMLQuestionTitle: React.ComponentType<
		QuizReviewHTMLQuestionTitleProps
	> | null = null;

	/**
	 * You can use this hook to customize the question title components (if they are rendered as HTML tags instead of Blocks) in the Quiz Review screen and modal.
	 * @method
	 * @param {QuizReviewHTMLQuestionTitleProps} HTMLQuestionTitle
	 * @example
	 *
	 * ...
	 *
	 * import {sourceRenderer} from "@src/utils/htmlRender";
	 * import HTML from "react-native-render-html";
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.quizReviewApi.setHTMLQuestionTitle(
	 *         ({
	 *             tagsStyles,
	 *             baseFontStyle,
	 *             html,
	 *             imageMaxWidth,
	 *             classesStyles,
	 *             onLinkPress,
	 *             ignoredTags,
	 *             colors,
	 *             navigation
	 *         }) => (
	 *             <HTML
	 *                 tagsStyles={tagsStyles}
	 *                 baseFontStyle={baseFontStyle}
	 *                 html={html}
	 *                 imagesMaxWidth={imageMaxWidth}
	 *                 onLinkPress={onLinkPress}
	 *                 ignoredTags={ignoredTags}
	 *                 classesStyles={classesStyles}
	 *                 alterChildren={node => {
	 *                     // removing <a/> if the parent node is audio
	 *                     if (node.name === "a" && node.parent?.name === "audio") {
	 *                         return [];
	 *                     }
	 *                 }}
	 *                 renderers={{
	 *                     source: (htmlAttribs, children, convertedCSSStyles, passProps) =>
	 *                         sourceRenderer(
	 *                             htmlAttribs,
	 *                             children,
	 *                             convertedCSSStyles,
	 *                             passProps,
	 *                             colors,
	 *                             navigation
	 *                         )
	 *                 }}
	 *             />
	 *         )
	 *     );
	 * }
	 */
	setHTMLQuestionTitle = (
		HTMLQuestionTitle: React.ComponentType<
			QuizReviewHTMLQuestionTitleProps
		> | null
	) => {
		this.HTMLQuestionTitle = HTMLQuestionTitle;
	};

	AnswerResultModalMessage: React.ComponentType<
		AnswerResultModalMessageProps
	> | null = null;

	/**
	 * You can use this hook to customize the "correct" or "incorrect" message that is displayed in the Quiz Review modal.
	 * @method
	 * @param {AnswerResultModalMessageProps} AnswerResultModalMessage
	 * @example
	 *
	 * ...
	 *
	 * import QuestionSummaryMessage from "@src/components/Questions/QuestionSummaryMessage";
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.quizReviewApi.setAnswerResultModalMessage(
	 *         ({
	 *             global,
	 *             colors,
	 *             styles,
	 *             answerResult,
	 *             t,
	 *             showSummaryMessage,
	 *             correctIcon,
	 *             inCorrectIcon
	 *         }) => {
	 *             return (
	 *                 <View style={styles.container}>
	 *                     <Image
	 *                         style={styles.image}
	 *                         source={answerResult.isCorrect ? correctIcon : inCorrectIcon}
	 *                     />
	 *                     <Text style={styles.status}>
	 *                         {answerResult.isCorrect ? t("quiz:correct") : t("quiz:incorrect")}
	 *                     </Text>
	 *                     {showSummaryMessage && (
	 *                         <View style={styles.summaryMessageContainer}>
	 *                             <QuestionSummaryMessage
	 *                                 message={answerResult.message}
	 *                                 global={global}
	 *                                 colors={colors}
	 *                             />
	 *                         </View>
	 *                     )}
	 *                 </View>
	 *             );
	 *         }
	 *     );
	 * }
	 *
	 */
	setAnswerResultModalMessage = (
		AnswerResultModalMessage: React.ComponentType<
			AnswerResultModalMessageProps
		> | null
	) => {
		this.AnswerResultModalMessage = AnswerResultModalMessage;
	};

	AnswerResultMessage: React.ComponentType<
		AnswerResultMessageProps
	> | null = null;

	/**
	 * You can use this hook to customize the "correct" or "incorrect" message that is displayed in the Quiz Review screen.
	 * @method
	 * @param {AnswerResultMessageProps} AnswerResultMessage
	 * @example
	 *
	 * ...
	 *
	 * import QuestionSummaryMessage from "@src/components/Questions/QuestionSummaryMessage";
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.quizReviewApi.setAnswerResultMessage(({
	 *         hideSummaryMessage,
	 *         global,
	 *         colors,
	 *         answer
	 *     }) => {
	 *         return hideSummaryMessage !== true ? (
	 *             <View>
	 *                 <QuestionSummaryMessage
	 *                     global={global}
	 *                     colors={colors}
	 *                     message={answer.message}
	 *                 />
	 *             </View>
	 *         ) : null;
	 *     });
	 * }
	 *
	 */
	setAnswerResultMessage = (
		AnswerResultMessage: React.ComponentType<AnswerResultMessageProps> | null
	) => {
		this.AnswerResultMessage = AnswerResultMessage;
	};

	QuestionCountComponent: React.ComponentType<
		QuestionCountComponentProps
	> | null = null;

	/**
	 * You can use this hook to customize the question count component ("Question 1 of 10" text) in the Quiz Review screen.
	 * @method
	 * @param {QuestionCountComponentProps} QuestionCountComponent
	 * @example
	 *
	 *
	 * externalCodeSetup.quizReviewApi.setQuestionCountComponent(
	 *   ({hideTitle, styles, t, labels, questionNumber, total}) => {
	 *       return !hideTitle ? (
	 *           <Text style={styles.text}>
	 *               {t("quiz:questionCount", {
	 *                   question: labels.question,
	 *                   current: questionNumber + 1,
	 *                   total: total || ""
	 *               })}
	 *           </Text>
	 *       ) : null;
	 *   }
	 * );
	 *
	 *
	 */
	setQuestionCountComponent = (
		QuestionCountComponent: React.ComponentType<
			QuestionCountComponentProps
		> | null
	) => {
		this.QuestionCountComponent = QuestionCountComponent;
	};
}