Class

QuizApi

QuizApi()

Question Screen Hooks. Instance name: quizApi

You can use these hooks to customize the quiz questions for your app.

Constructor

# new QuizApi()

Example
externalCodeSetup.quizApi.METHOD_NAME

Methods

# setPrevNextComponent(PrevNextComponentnullable)

You can use this to replace the previous and next buttons on the quiz screen.

Parameters:
Name Type Attributes Description
PrevNextComponent React.ComponentType.<QuizPrevNextComponentProps> <nullable>
Example

Change colors of the default previous and next buttons

//In custom_code/components/PrevNext.js

import React from "react";
import { Text, View, StyleSheet } from "react-native";
import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
import Icon from "@src/components/Icon";
import { shadeColor } from "@src/utils";

export const onObjectClick = (
   object,
   onQuizClick,
   onTopicClick,
   onLessonClick
) => {
   if (!!!object) {
       return false;
   }
   switch (object.type) {
       case "quiz":
           onQuizClick(object.parentType, object.parent)(object);
           break;
       case "topic":
           onTopicClick(object, object.parent);
           break;
       case "lesson":
           onLessonClick(object);
           break;
   }
};

const PrevNext = ({
   global,
   colors,
   t,
   prevObject,
   nextObject,
   courseId,
   onQuizClick,
   onLessonClick,
   onTopicClick,
   nextLockedAlert
}) => {

   return (
       <View style={[global.row]}>
           <AppTouchableOpacity
               style={[
                   global.wrappedButton,
                   global.wrappedTextButton,
                   { marginRight: 4, backgroundColor: "purple" }
               ]}
               onPress={() => {
                   if (prevObject !== "disabled") {
                       onObjectClick(prevObject, onQuizClick, onTopicClick, onLessonClick);
                   }
               }}
           >
               <View style={global.row}>
                   <View style={global.linkWithArrow}>
                       <Text
                           style={[
                               global.wrappedTextButtonLabel,
                               {
                                   color:
                                       !!!prevObject || prevObject === "disabled"
                                           ? shadeColor(colors.headerIconColor, 0.4)
                                           : "red"
                               }
                           ]}
                       >
                           {t("lesson:prevButtonText")}
                       </Text>
                   </View>
               </View>
           </AppTouchableOpacity>

           <AppTouchableOpacity
               style={[global.wrappedButton, global.wrappedTextButton, {backgroundColor: "purple"}]}
               onPress={() => {
                   if (nextObject !== "disabled") {
                       onObjectClick(nextObject, onQuizClick, onTopicClick, onLessonClick);
                   } else if (typeof nextLockedAlert === "function") {
                       nextLockedAlert();
                   }
               }}
           >
               <View style={global.row}>
                   <View style={global.linkWithArrow}>
                       <Text
                           style={[
                               global.wrappedTextButtonLabel,
                               {
                                   color:
                                       !!!nextObject || nextObject === "disabled"
                                           ? shadeColor(colors.headerIconColor, 0.4)
                                           : "blue"
                               }
                           ]}
                       >
                           {t("lesson:nextButtonText")}
                       </Text>
                   </View>
               </View>
           </AppTouchableOpacity>
       </View>
   );
};

export default PrevNext;

//In custom_code/index.js...

...

import PrevNextComponent from './components/PrevNext';
export const applyCustomCode = externalCodeSetup => {
  externalCodeSetup.quizApi.setPrevNextComponent((props) => <PrevNextComponent {...props} />);
}

# setQuestionClosedRenderMode(questionClosedRenderMode)

It overrides the Closed Question type render mode. The default mode is webview. If the question is not rendering correctly, you can try setting it to htmlparser mode.

Parameters:
Name Type Description
questionClosedRenderMode QuestionClosedRenderMode
Example
externalCodeSetup.quizApi.setQuestionClosedRenderMode("htmlparser")

# setQuizScreenHeader(QuizScreenHeader)

You can use this hook to customize the header of the Quiz Single Screen which by default, contains the back-to-course button and the previous/next buttons.

Parameters:
Name Type Description
QuizScreenHeader React.ComponentType.<QuizScreenHeaderProps>
Example

Add a timer on the quiz screen header

//In custom_code/components/QuizScreenHeader.js...

import React from "react";
import {View, Text} from "react-native";
import Animated from "react-native-reanimated";
import {DEVICE_WIDTH} from "@src/styles/global";
import AuthWrapper from "@src/components/AuthWrapper";

const Header = ({
    headerLeftStyle,
    style,
    global,
    colors,
    backToCourse,
    headerRightAuthWrapperProps,
    prevNext,
    quiz,
    renderQuizTimer
}) => {
  return (
    <Animated.View
      style={[
        global.row,
        global.fakeHeader,
        {
          backgroundColor: "transparent",
          paddingHorizontal: 10,
          overflow: "hidden"
        },
        {
          width: DEVICE_WIDTH
        },
        style
      ]}
    >
      <View
        style={[
          {
            alignItems: "center",
            justifyContent: "center",
            flexDirection: "row",
            flex: 1,
            height: "100%",

                        backgroundColor: "gray",
                        borderRadius: 20
          }
        ]}
      >
        <View style={[global.headerButtonLeft, headerLeftStyle]}>
          {backToCourse}
        </View>

        <View style={[global.headerCustomTitle]}>
          {renderQuizTimer(quiz, global, colors)}
        </View>

        <View style={[global.headerButtonRight]}>
          <AuthWrapper
            actionOnGuestLogin={"hide"}
            {...headerRightAuthWrapperProps}
          >
            {prevNext}
          </AuthWrapper>
        </View>
      </View>
    </Animated.View>
  );
};

export default Header;

 //In custom_code/index.js...

import QuizScreenHeader from "./components/QuizScreenHeader";
export const applyCustomCode = externalCodeSetup => {
  externalCodeSetup.quizApi.setQuizScreenHeader(props => <QuizScreenHeader {...props} />)
}

# setQuizTitleComponent(QuizTitleComponent)

You can use this to replace the quiz's title component. For example, you can use this to add more details to the quiz's title.

Parameters:
Name Type Description
QuizTitleComponent React.ComponentType.<QuizTitleComponentProps>
Example

Add more quiz details to component

//In custom_code/components/QuizTitle.js...

import React from "react";
import {View, Text} from "react-native";
import Animated from "react-native-reanimated";
const QuizTitle = ({
	quiz,
	global,
	colors,
	paddingTop = 14,
	setHeaderHeight,
	t,
	labels,
	questions,
	currentSwiperPosition,
	quizOrder,
	quizTotalCount
}) => {

const paddingBottom = 14;

return (
  <Animated.View
    style={[
	   {
      backgroundColor: colors.bodyFrontBg,
      width: "100%",
      shadowOffset: {width: 0, height: 1},
      shadowRadius: 1,
      shadowColor: "#000",
      shadowOpacity: 0.05
    }
    ]}
  >
    <View
      style={[
       global.row,
       {
         justifyContent: "space-between",
         alignItems: "flex-start",
         paddingTop,
         paddingBottom
       }
      ]}
      onLayout={event => {
        const {height} = event.nativeEvent.layout;
        typeof setHeaderHeight === "function" && setHeaderHeight(height);
      }}
    >
    <Animated.View
      style={{
        flex: 1,
        paddingHorizontal: 20
      }}
    >
      <Animated.Text
        style={[
          global.courseHeaderTitle,
          {marginBottom: 5}
        ]}
      >
        {quiz.title}
      </Animated.Text>

      {
        !quiz.hideQuestionPositionOverview &&
        !quiz.hideQuestionNumbering &&
        currentSwiperPosition > 0 ? (
        <Text style={global.courseHeaderSubTitle}>
          {t("quiz:questionCount", {
            question: labels.question,
            current: currentSwiperPosition,
            total: questions
            ? questions.size
            : ""
          })}
        </Text>
        ) : (
        <Text style={global.courseHeaderSubTitle}>
          {`Quiz ${quizOrder + 1} of ${quizTotalCount}`}
        </Text>
        )
      }

      <Text style={global.courseHeaderSubTitle}>
        Author: {quiz.author.name}
      </Text>
      <Text style={global.courseHeaderSubTitle}>
        Completed: {quiz.completed.toString()}
      </Text>

    </Animated.View>
  </View>
 </Animated.View>
 );
};

export default QuizTitle;

//In custom_code/index.js...

...
import QuizTitle from "./components/QuizTitle";
export const applyCustomCode = externalCodeSetup => {
 externalCodeSetup.quizApi.setQuizTitleComponent(props => <QuizTitle {...props} />)
}

# setWrapQuestionHtmlFilter(wrapQuestionHtmlFilter)

We use an HTML wrapper for "Fill in the blank" questions to accept input answers. You can use this to change the HTML output.

Parameters:
Name Type Description
wrapQuestionHtmlFilter OverrideQuestionHTMLWrapperCallback
Example

Add additional details below the input field

externalCodeSetup.quizApi.setWrapQuestionHtmlFilter((HTMLWrapper, inputHtml, css) => {

   const disableZoom = true;
   const myNewHtml =
     `
  		<!DOCTYPE html>
  		<html>
   			<head>
  				<title>Topic Content</title>
  				<meta http-equiv="content-type" content="text/html; charset=utf-8">
  				<meta name="viewport" content="width=device-width, initial-scale=1 ${disableZoom ? "maximum-scale=1.0" : ""} ">
  				<style type="text/css">
  				${css}
  				.content {
  					width: 100%;
  					overflow: hidden;
  					padding-bottom: 4px;
  				}
  				</style>
  			</head>
  			<body>
  				<div class="content">
  				` +
       inputHtml +
     `
       <p> Please use UPPERCASE characters only</p>
  				</div>
  			</body>
  		</html>
  	`;
   return myNewHtml;
 })