import * as React from "react";
import {
TTranslationFunction,
QuestionViewModel,
NavigationService
} from "./types";
export const API_NAME = "quizAnswersApi";
/**
* RadioIconProps
*/
type RadioIconProps = {
/**
* 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>
};
/**
* RadioDescriptionProps
*/
type RadioDescriptionProps = {
/**
* Index of the answer
*/
index: number,
/**
* Default styles for the description
*/
styles: Record<any, any>,
/**
* Font details
*/
baseFontStyle: Record<any, any>,
/**
* Description of the answer
*/
description: string,
/**
* List of tags to be ignored by the html renderer
*/
ignoredTags: string[],
navigation: NavigationService
};
/**
* RadioOnPressCallbackProps
*/
type RadioOnPressCallbackProps = {
/**
* Selects the radio
*/
setRadioState: Function,
/**
* Returns `true` if radio is used in a multiple choice question
*/
multiselect: boolean,
/**
* Answer details
*/
radios: Record<any, any>[],
/**
* Selected answers
*/
selected: number[],
/**
* Index of the pressed radio
*/
index: number
};
/**
* FreeAnswerComponentProps
*/
type FreeAnswerComponentProps = {
/**
* Default wrapper for input component
*/
Wrapper: React.ComponentType,
/**
* Calls default function when wrapper is pressed
*/
wrapperOnPress: Function,
/**
* Default styles for the input
*/
styles: Record<any, any>,
/**
* Returns the default value of the input
*/
defaultValue: string | undefined,
/**
* Updates the answer in the input component
*/
onChangeText: Function,
t: TTranslationFunction,
question: QuestionViewModel
};
/**
* QuestionClosedComponentProps
*/
type QuestionClosedComponentProps = {
contentId: string,
/**
* Source to render in the webview
*/
source: Record<any, any>,
/**
* Updates the answer in the input component
*/
inputChange: Function,
typography: Function,
/**
* Default css for webview
*/
htmlStylesCss: string,
/**
* Default css for webview
*/
htmlAdjustedCss: string,
/**
* Default tags styles for rendering the HTML
*/
tagsStyles: Record<any, any>,
/**
* Default font styles for rendering the HTML
*/
baseFontStyle: Record<any, any>,
/**
* Question to render in the HTML component
*/
questionText: string,
/**
* Can be used for `staticContentMaxWidth`
*/
computedWidth: number,
/**
* Default alterChildren value which can be used for the HTML component
*/
alterChildren: Function,
/**
* Implements deep linking in the HTML component
*/
onLinkPress: Function,
/**
* Default list of ignored tags
*/
ignoredTags: string[],
/**
* Default renderer value which can be used for the HTML component
*/
renderers: Function
};
/**
* QuestionSortItemComponentProps
*/
type QuestionSortItemComponentProps = {
/**
* 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: number,
/**
* Returns `true` if component is being dragged
*/
active: boolean
};
/**
* SortItemOnDragStartCallbackProps
*/
type SortItemOnDragStartCallbackProps = {
/**
* Calls the `dragStart` function
*/
dragStart: Function,
/**
* Index of the item related to `data` where the event was executed
*/
index: number,
/**
* Answer details
*/
data: Record<any, any>[],
/**
* Order of answers displayed
*/
order: number[]
};
/**
* SortItemOnDraggingCallbackProps
*/
type SortItemOnDraggingCallbackProps = {
/**
* Calls the `dragging` function
*/
dragging: Function,
/**
* Answer details
*/
data: Record<any, any>[],
/**
* Order of answers displayed
*/
order: number[]
};
/**
* SortItemOnDragEndCallbackProps
*/
type SortItemOnDragEndCallbackProps = {
/**
* Calls the `dragEnd` function
*/
dragEnd: Function,
/**
* Index of the item related to `data` where the event was executed
*/
index: number,
/**
* Answer details
*/
data: Record<any, any>[],
/**
* Order of answers displayed
*/
order: number[]
};
/**
* QuestionEssayComponentProps
*/
type QuestionEssayComponentProps = {
/**
* Default styles
*/
styles: Record<any, any>,
/**
* Returns a string if an error was encountered
*/
error: null | string,
t: TTranslationFunction,
/**
* App global style
*/
global: Record<any, any>,
/**
* App colors
*/
colors: Record<any, any>,
/**
* Calls function to enable upload
*/
onPress: Function,
/**
* Returns `true` if icon should be visible
*/
showIcon: boolean,
/**
* Returns `true` if file is currently uploading
*/
showLoading: boolean,
/**
* Default icon
*/
icon: string | number,
/**
* Default title of upload button
*/
title: string
};
/**
* QuestionAssessmentHTMLProps
*/
type QuestionAssessmentHTMLProps = {
/**
* 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>
};
/**
* MatrixItemOnDragStartCallbackProps
*/
type MatrixItemOnDragStartCallbackProps = {
/**
* Calls the `dragStart` function
*/
dragStart: Function,
/**
* Index of item
*/
index: number,
/**
* Answer details
*/
item: Record<any, any>
};
/**
* MatrixItemOnDraggingCallbackProps
*/
type MatrixItemOnDraggingCallbackProps = {
/**
* Calls the `dragging` function
*/
dragging: Function,
/**
* Index of item
*/
index: number,
/**
* Answer details
*/
item: Record<any, any>
};
/**
* MatrixItemOnDragEndCallbackProps
*/
type MatrixItemOnDragEndCallbackProps = {
/**
* Calls the `dragEnd` function
*/
dragEnd: Function,
/**
* Index of item
*/
index: number,
/**
* Answer details
*/
item: Record<any, any>
};
/**
* RadioContainerProps
*/
type RadioContainerProps = {
/**
* Default styles
*/
styles: Record<any, any>,
/**
* Index of the component
*/
key: number,
/**
* Returns the default component used
*/
Component: React.FC,
/**
* Calls the function used when the component is pressed
*/
onPress: Function,
/**
* Returns `true` if the component is selected
*/
selected: boolean,
/**
* Returns `true` if the component is set to be numbered
*/
numbered: boolean,
/**
* Default children components
*/
children: React.FC
};
/**
* @class
* Quiz Answers Hooks.
* Instance name: quizAnswersApi
You can use this hook to customize answer components when answering a quiz such as adding an onPress function to a single choice answer or customizing how the answer text is displayed.
* @example
* externalCodeSetup.quizAnswersApi.METHOD_NAME
*/
export class QuizAnswersApi {
RadioIcon: React.ComponentType<RadioIconProps> | 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<RadioIconProps>} RadioIcon
* @example
*
* ...
*
* import Icon from "@src/components/Icon";
*
* export const applyCustomCode = (externalCodeSetup) => {
* externalCodeSetup.quizAnswersApi.setRadioIcon(props => {
* const {styles, isWrong, isRight, multiselect, multipleChoiceIcon} = props;
* return multiselect ? (
* <Icon
* icon={multipleChoiceIcon}
* tintColor={styles.iconColor}
* styles={styles.iconStyle}
* />
* ) : (
* <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<RadioIconProps> | null) => {
this.RadioIcon = RadioIcon;
};
RadioDescription: React.ComponentType<RadioDescriptionProps> | null = null;
/**
* You can use this hook to customize the answer in a radio component.
* Questions that use radio components as an answer include: "Single choice", "Multiple choice", and "Assessment" type of questions.
* @method
* @param {React.ComponentType<RadioDescriptionProps>} RadioDescription
* @example
*
* ...
*
* import HTML from "react-native-render-html";
* import {imgRenderer, sourceRenderer} from "@src/utils/htmlRender";
*
* export const applyCustomCode = (externalCodeSetup) => {
* externalCodeSetup.quizAnswersApi.setRadioDescription(
* ({index, styles, baseFontStyle, description, ignoredTags, navigation}) => (
* <HTML
* key={index}
* containerStyle={styles.containerStyle}
* alterChildren={node => {
* if (
* node.name === "a" &&
* (node.parent?.name === "audio" || node.parent?.name === "video")
* ) {
* return [];
* }
* }}
* ignoredTags={ignoredTags}
* baseFontStyle={baseFontStyle}
* html={description}
* renderers={{
* img: imgRenderer({height: 150}),
* source: (htmlAttribs, children, convertedCSSStyles, passProps) =>
* sourceRenderer(
* htmlAttribs,
* children,
* convertedCSSStyles,
* passProps,
* styles.colors,
* navigation,
* styles.sourceRenderer
* )
* }}
* />
* )
* );
* }
*/
setRadioDescription = (
RadioDescription: React.ComponentType<RadioDescriptionProps> | null
) => {
this.RadioDescription = RadioDescription;
};
RadioContainer: React.ComponentType<RadioContainerProps> | null = null;
/**
* You can use this hook to customize the container in a radio component.
* Questions that use radio components as an answer include: "Single choice", "Multiple choice", and "Assessment" type of questions.
* @method
* @param {React.ComponentType<RadioContainerProps>} RadioContainer
* @example <caption> Add a border to the component when selected </caption>
*
* externalCodeSetup.quizAnswersApi.setRadioContainer(props => {
* const {Component, key, onPress, styles, selected, children} = props;
*
* const borderSelectedStyle = {
* borderWidth: 1,
* borderColor: "#007cff"
* };
*
* return (
* <Component
* activeOpacity={0.9}
* key={key}
* onPress={onPress}
* style={[styles.container, selected && borderSelectedStyle]}
* >
* <View
* style={[
* styles.container,
* selected && borderSelectedStyle,
* {
*
* marginLeft: -17,
* marginRight: -17,
* marginBottom: 3,
* marginTop: 3
* }
* ]}
* >
* {children}
* </View>
* </Component>
* );
* });
* }
*/
setRadioContainer = (
RadioContainer: React.ComponentType<RadioContainerProps> | null
) => {
this.RadioContainer = RadioContainer;
};
radioOnPressCallback:
| ((props: RadioOnPressCallbackProps) => void)
| null = null;
/**
* You can use this hook to customize the behavior of selecting a radio component when answering a single, multiple choice, or assessment question.
* For example, you can do an API request before selecting the radio component.
* @method
* @param {RadioOnPressCallbackProps} radioOnPressCallback
* @example <caption> Call an API before selecting the answer </caption>
*
* externalCodeSetup.quizAnswersApi.setRadioOnPressCallback(
* ({setRadioState, multiselect, radios, selected, index}) => {
* fetch("https://buddyboss.com")
* .then(res => res.json())
* .then(json => {
* if (json.id === 1) {
* setRadioState();
* }
* })
* .catch(e => {
* console.log("Error", e);
* setRadioState();
* });
* }
* );
*/
setRadioOnPressCallback = (
radioOnPressCallback: ((props: RadioOnPressCallbackProps) => void) | null
) => {
this.radioOnPressCallback = radioOnPressCallback;
};
FreeAnswerComponent: React.ComponentType<
FreeAnswerComponentProps
> | null = null;
/**
* You can use this hook to customize the text input component of free choice type of questions.
* This hook is also used to customize the text input 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<FreeAnswerComponentProps>} FreeAnswerComponent
* @example
*
* ...
*
* import {View, Text, TextInput} from "react-native";
*
* export const applyCustomCode = (externalCodeSetup) => {
* externalCodeSetup.quizAnswersApi.setFreeAnswerComponent(props => {
* const {
* Wrapper,
* wrapperOnPress,
* styles,
* t,
* defaultValue,
* onChangeText
* } = props;
*
* return (
* <Wrapper onPress={wrapperOnPress} style={styles.wrapperStyle}>
* <View style={styles.containerStyle}>
* <Text>Add your answer below</Text>
* <TextInput
* placeholder={t("quiz:writeHere")}
* autocomplete="off"
* spellCheck={false}
* autoCorrect={false}
* autoGrow
* multiline
* defaultValue={defaultValue}
* style={styles.inputStyle}
* placeholderTextColor={styles.placeholderTextColor}
* onChangeText={onChangeText}
* underlineColorAndroid="transparent"
* />
* </View>
* </Wrapper>
* );
* });
* }
*/
setFreeAnswerComponent = (
FreeAnswerComponent: React.ComponentType<FreeAnswerComponentProps> | null
) => {
this.FreeAnswerComponent = FreeAnswerComponent;
};
QuestionEssayComponent: React.ComponentType<
QuestionEssayComponentProps
> | null = null;
/**
* You can use this hook to customize the component for 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<QuestionEssayComponentProps>} QuestionEssayComponent
* @example
*
* ...
*
* import QuizButton from "@src/components/QuizButton";
*
* export const applyCustomCode = (externalCodeSetup) => {
* externalCodeSetup.quizAnswersApi.setQuestionEssayComponent(
* ({
* styles,
* error,
* t,
* global,
* onPress,
* showIcon,
* showLoading,
* icon,
* colors,
* title
* }) => {
* return (
* <View style={styles.container}>
* <View style={styles.innerContainer}>
* {error && <Text style={styles.errorText}>{error}</Text>}
*
* <Text>Please use the required font for the document</Text>
* <Text style={styles.title}>{t("quiz:uploadFile")}</Text>
*
* <QuizButton
* global={global}
* onPress={onPress}
* showIcon={showIcon}
* showLoading={showLoading}
* icon={icon}
* tintColor={colors.secondaryButtonColor}
* title={title}
* />
* </View>
* </View>
* );
* }
* );
* }
*/
setQuestionEssayComponent = (
QuestionEssayComponent: React.ComponentType<
QuestionEssayComponentProps
> | null
) => {
this.QuestionEssayComponent = QuestionEssayComponent;
};
QuestionClosedComponent: React.ComponentType<
QuestionClosedComponentProps
> | null = null;
/**
* You can use this hook to customize the component for answering "Fill in the blank" type of questions.
* By default, the component to input the answer is generated using a webview.
* See `quizApi.setQuestionClosedRenderMode` hook on how to change the render mode of the answer component.
* @method
* @param {React.ComponentType<QuestionClosedComponentProps>} QuestionClosedComponent
* @example <caption> Customize the webview component </caption>
*
* ...
*
* import WebViewInput from "@src/components/Questions/WebViewInput";
*
* export const applyCustomCode = (externalCodeSetup) => {
* externalCodeSetup.quizAnswersApi.setQuestionClosedComponent(
* ({
* contentId,
* source,
* inputChange,
* typography,
* htmlStylesCss,
* htmlAdjustedCss
* }) => {
* return (
* <>
* <Text>HTML generated in webview</Text>
* <WebViewInput
* contentId={contentId}
* source={source}
* inputChange={inputChange}
* typography={typography}
* htmlStylesCss={htmlStylesCss}
* htmlAdjustedCss={htmlAdjustedCss}
* />
* </>
* );
* }
* );
* }
*
* @example <caption> Change the default renderer to htmlparser </caption>
*
* ...
*
* import HTML from "react-native-render-html";
*
* export const applyCustomCode = (externalCodeSetup) => {
*
* externalCodeSetup.quizAnswersApi.setQuestionClosedComponent(
* ({
* tagsStyles,
* baseFontStyle,
* questionText,
* computedWidth,
* alterChildren,
* onLinkPress,
* ignoredTags,
* renderers
* }) => {
* return (
* <>
* <Text>HTML generated using rn render-html</Text>
* <HTML
* tagsStyles={tagsStyles}
* baseFontStyle={baseFontStyle}
* html={questionText}
* staticContentMaxWidth={computedWidth}
* alterChildren={alterChildren}
* onLinkPress={onLinkPress}
* ignoredTags={ignoredTags}
* renderers={renderers}
* />
* </>
* );
* }
* );
* }
*/
setQuestionClosedComponent = (
QuestionClosedComponent: React.ComponentType<
QuestionClosedComponentProps
> | null
) => {
this.QuestionClosedComponent = QuestionClosedComponent;
};
QuestionSortItemComponent: React.ComponentType<
QuestionSortItemComponentProps
> | null = null;
/**
* You can use this hook to customize the sort item component which is rendered when answering a "sorting" choice question type.
* For example, you can change the component's color, icon, or text display.
* @method
* @param {React.ComponentType<QuestionSortItemComponentProps>} QuestionSortItemComponent
* @example <caption> Change the text color of the item component when dragging </caption>
*
* ...
*
* import Icon from "@src/components/Icon";
*
* export const applyCustomCode = externalCodeSetup => {
* externalCodeSetup.quizAnswersApi.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>
* <Icon
* tintColor={styles.iconColor}
* styles={styles.image}
* icon={{fontIconName: icon, weight: 400}}
* />
* </Component>
* );
* }
* );
* }
*/
setQuestionSortItemComponent = (
QuestionSortItemComponent: React.ComponentType<
QuestionSortItemComponentProps
> | null
) => {
this.QuestionSortItemComponent = QuestionSortItemComponent;
};
sortItemOnDragStartCallback:
| ((props: SortItemOnDragStartCallbackProps) => void)
| null = null;
/**
* You can use this hook to modify the `dragStart` event of the sort item component.
* @method
* @param {SortItemOnDragStartCallbackProps} sortItemOnDragStartCallback
* @example
*
* externalCodeSetup.quizAnswersApi.setSortItemOnDragStartCallback(
* ({index, data, dragStart}) => {
* if (index === 0) {
* console.log(`Drag start on ${data[0].title}`);
* }
* dragStart();
* }
* );
*/
setSortItemOnDragStartCallback = (
sortItemOnDragStartCallback:
| ((props: SortItemOnDragStartCallbackProps) => void)
| null
) => {
this.sortItemOnDragStartCallback = sortItemOnDragStartCallback;
};
sortItemOnDraggingCallback:
| ((props: SortItemOnDraggingCallbackProps) => void)
| null = null;
/**
* You can use this hook to modify the `dragging` event of the sort item component.
* @method
* @param {SortItemOnDraggingCallbackProps} sortItemOnDraggingCallback
* @example
* externalCodeSetup.quizAnswersApi.setSortItemOnDraggingCallback(
* ({dragging}) => {
* dragging();
* }
* );
*/
setSortItemOnDraggingCallback = (
sortItemOnDraggingCallback:
| ((props: SortItemOnDraggingCallbackProps) => void)
| null
) => {
this.sortItemOnDraggingCallback = sortItemOnDraggingCallback;
};
sortItemOnDragEndCallback:
| ((props: SortItemOnDragEndCallbackProps) => void)
| null = null;
/**
* You can use this hook to modify the `dragEnd` event of the sort item component.
* @method
* @param {SortItemOnDragEndCallbackProps} sortItemOnDragEndCallback
* @example
*
* externalCodeSetup.quizAnswersApi.setSortItemOnDragEndCallback(
* ({index, data, dragEnd}) => {
* if (index === 0) {
* console.log(`Drag end on ${data[0].title}`);
* }
* dragEnd();
* }
* );
*/
setSortItemOnDragEndCallback = (
sortItemOnDragEndCallback:
| ((props: SortItemOnDragEndCallbackProps) => void)
| null
) => {
this.sortItemOnDragEndCallback = sortItemOnDragEndCallback;
};
QuestionAssessmentHTML: React.ComponentType<
QuestionAssessmentHTMLProps
> | null = null;
/**
* You can use this hook to customize the "Less true" or "More true" components in an "Assessment" type of question.
* @method
* @param {QuestionAssessmentHTMLProps} QuestionAssessmentHTML
* @example
*
* ...
*
* import HTML from "react-native-render-html";
*
* export const applyCustomCode = (externalCodeSetup) => {
* externalCodeSetup.quizAnswersApi.setQuestionAssessmentHTML(
* ({item, index, styles, global, tagsStyles}) => (
* <View key={"html" + item.value + index.toString()}>
* <HTML
* html={item.value}
* containerStyle={styles.containerStyle}
* baseFontStyle={global.content}
* tagsStyles={tagsStyles}
* onLinkPress={() => {}}
* />
* </View>
* )
* );
* }
*/
setQuestionAssessmentHTML = (
QuestionAssessmentHTML: React.ComponentType<
QuestionAssessmentHTMLProps
> | null
) => {
this.QuestionAssessmentHTML = QuestionAssessmentHTML;
};
matrixItemOnDragStartCallback:
| ((props: MatrixItemOnDragStartCallbackProps) => void)
| null = null;
/**
* You can use this hook to modify the `dragStart` event of the matrix sort item component.
* @method
* @param {MatrixItemOnDragStartCallbackProps} matrixItemOnDragStartCallback
* @example
*
* externalCodeSetup.quizAnswersApi.setMatrixItemOnDragStartCallback(props => {
* props.dragStart()
* })
*/
setMatrixItemOnDragStartCallback = (
matrixItemOnDragStartCallback:
| ((props: MatrixItemOnDragStartCallbackProps) => void)
| null
) => {
this.matrixItemOnDragStartCallback = matrixItemOnDragStartCallback;
};
matrixItemOnDraggingCallback:
| ((props: MatrixItemOnDraggingCallbackProps) => void)
| null = null;
/**
* You can use this hook to modify the `dragging` event of the matrix sort item component.
* @method
* @param {MatrixItemOnDraggingCallbackProps} matrixItemOnDraggingCallback
* @example
*
* externalCodeSetup.quizAnswersApi.setMatrixItemOnDraggingCallback(props => {
* props.dragging()
* })
*/
setMatrixItemOnDraggingCallback = (
matrixItemOnDraggingCallback:
| ((props: MatrixItemOnDraggingCallbackProps) => void)
| null
) => {
this.matrixItemOnDraggingCallback = matrixItemOnDraggingCallback;
};
matrixItemOnDragEndCallback:
| ((props: MatrixItemOnDragEndCallbackProps) => void)
| null = null;
/**
* You can use this hook to modify the `dragEnd` event of the matrix sort item component.
* @method
* @param {MatrixItemOnDragEndCallbackProps} matrixItemOnDragEndCallback
* @example
*
* externalCodeSetup.quizAnswersApi.setMatrixItemOnDragEndCallback(props => {
* props.dragEnd()
* })
*/
setMatrixItemOnDragEndCallback = (
matrixItemOnDragEndCallback:
| ((props: MatrixItemOnDragEndCallbackProps) => void)
| null
) => {
this.matrixItemOnDragEndCallback = matrixItemOnDragEndCallback;
};
}
Source