Source

externalCode/learnTopicSingleScreen.js

import * as React from "react";

/**
 * @typedef {Object} LearnTopicAfterContentRenderProps
 * @property {LearnTopicViewModel} topic
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {NavigationService} navigation
 */

/**
 * @typedef {Object} LearnTopicViewModel
 * @property {Number} id Topic id
 * @property {Object} title Topic title
 * @property {Object} content Content of topic
 * @property {String} date Date created
 * @property {String} date_gmt Date created
 * @property {String} modified Date modified
 * @property {String} modified_gmt Date modified
 * @property {String} link Url to topic
 * @property {String} slug Slug used for topic
 * @property {Number} author Author's id
 * @property {Number} featured_media Featured media of topic
 * @property {Number} course Course id of topic's parent
 * @property {Number} lesson Lesson id of topic's parent
 * @property {String} materials Topic materials
 * @property {String} video Url for video progression
 */

/**
 * @typedef {Function} LearnTopicAfterContentRendererFunction
 * @param {LearnTopicAfterContentRenderProps} props
 * @return {?React.ComponentType<any>}
 */

/**
 * @typedef {Function} TransformTopicActionButtonsCallback
 * @property {React.ComponentType} topicButton Topic action button
 * @property {Boolean} showComplete Returns `true` if "Mark Complete" button should be shown
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {TopicViewModel} topic
 * @property {Boolean} completing Returns `true` if topic is being completed
 * @property {Object} labels Labels in the topic
 * @property {Function} handleComplete Function that marks the topic as complete
 */

/**
 * @typedef {Object} LearnTopicHeaderProps
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {LearnTopicViewModel} topic
 * @property {Number} lessonOrder Order of lesson where topic belongs to
 * @property {Function} setHeaderHeight Helper function which can be called to set header height
 * @property {Object} labels Learndash labels
 * @property {TranslationFunction} t
 * @property {Number} paddingTop Default padding top applied to component
 * @property {Function} onQuizClick Function to execute if previous or next button is a quiz
 * @property {Function} onLessonClick Function to execute if previous or next button is a lesson
 * @property {Function} onTopicClick Function to execute if previous or next button is a topic
 * @property {?Object} prevObject Information about previous lesson/topic/quiz
 * @property {?Object} nextObject Information about next lesson/topic/quiz
 * @property {Number} courseId Course id of lesson/topic/quiz
 * @property {Function} nextLockedAlert Shows an alert with information that next object is locked
 * @property {React.ComponentType} backToCourse Returns default back button component
 * @property {Boolean} loading Returns `true` if screen is still loading
 * @property {CourseViewModel} course
 * @property {Boolean | React.ComponentType} renderTimer Returns `false` if topic doesn't have a timer set. Will return a component if timer for the topic is set.
 * @property {Function} onTimePassed Function which updates the seconds passed in the topic screen container
 * @property {NavigationService} navigation
 * @property {Boolean} hidePrevNext Returns `true` if prev/next buttons should be hidden
 * @property {Boolean | React.ComponentType} prevNext Returns `false` if hidePrevNext is `true`. Will return buttons which can navigate through previous and next screens if hidePrevNext is `false`
 */

/**
 * @typedef {Object} LearnTopicProps
 * @property {LearnTopicViewModel} topic
 * @return {Boolean}
 */

/**
 * @typedef {Object} LearnTopicPrevNextComponentProps
 * @property {Function} onQuizClick Function to execute if previous or next button is a quiz
 * @property {Function} onLessonClick Function to execute if previous or next button is a lesson
 * @property {Function} onTopicClick Function to execute if previous or next button is a topic
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {TranslationFunction} t
 * @property {?Object} prevObject Information about previous lesson/topic/quiz
 * @property {?Object} nextObject Information about next lesson/topic/quiz
 * @property {Number} courseId Course id of lesson/topic/quiz
 * @property {Function} nextLockedAlert Shows an alert with information that next object is locked
 */

/**
 * @typedef {Object} LearnTopicTitleComponentProps
 * @property {LearnTopicHeaderProps} LearnTopicHeaderProps
 */

/**
 * @typedef {Object} LearnTopicScreenHeaderProps
 * @property {LearnTopicHeaderProps} LearnTopicHeaderProps
 * @property {Object} headerLeftStyle Default styling for left section of the header
 * @property {Object} style Default styling of lesson header
 * @property {Object} headerRightAuthWrapperProps Props which can be passed to an AuthWrapper
 */

/**
 * @typedef {Object} LearnTopicVideoProgressionComponentProps
 * @property {Object} topicVideoStyle Default styling applied to topic video
 * @property {Boolean} controls Returns `true` if controls should be displayed
 * @property {Boolean} autoplay Returns `true` if auto play should be enabled
 * @property {Function} videoCallback Helper function which can be called when the video has finished playing
 * @property {String} url Video url
 * @property {Number} width Player width
 * @property {Number} height Player height
 * @property {Object} global App global style
 * @property {Boolean} isNavActive Returns `true` if screen is active
 * @property {LearnTopicViewModel} topic
 * @property {Boolean} showVideo Returns `true` if video should be shown
 * @property {Boolean} videoWatched Returns `true` if video has already been watched
 * @property {Function} setVideoWatched Helper function which dispatches an action and marks the video as watched
 * @property {Function} completeTopic Helper function which dispatches an action to mark the topic as complete
 * @property {Function} onCompleteTopicClick Helper function which considers different conditions (such as if quizzes inside a topic are already completed) before calling the `completeTopic` function
 */

/**
 * @typedef {Object} LearnTopicAfterMaterialsComponentProps
 * @property {LearnTopicViewModel} topic
 * @property {Number} lessonOrder Order of lesson where topic belongs to
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {LessonViewModel} lesson
 * @property {Object} labels Learndash labels
 * @property {TranslationFunction} t
 * @property {Function} onQuizClick Function to execute if previous or next button is a quiz
 * @property {Function} onLessonClick Function to execute if previous or next button is a lesson
 * @property {Function} onTopicClick Function to execute if previous or next button is a topic
 * @property {?Object} prevObject Information about previous lesson/topic/quiz
 * @property {?Object} nextObject Information about next lesson/topic/quiz
 * @property {Function} nextLockedAlert Shows an alert with information that next object is locked
 * @property {Boolean} loading Returns `true` if screen is still loading
 * @property {CourseViewModel} course
 * @property {NavigationService} navigation
 * @property {String} materials Lesson materials
 */

/**
 * @typedef {Object} LearnTopicActionComponentProps
 * @property {LearnTopicViewModel} topicVM
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {TranslationFunction} t
 * @property {Boolean} showComplete Returns `true` if "Mark Complete" button should be shown
 * @property {Function} onCompleteTopicClick Helper function which considers different conditions (such as if quizzes inside a topic are already completed) before calling the `completeTopic` function
 * @property {Boolean} completing Returns `true` if topic is being completed
 * @property {Boolean} completeDisabled Returns `true` if "Mark Complete" button should be disabled
 *
 */

/**
 * @class
 * Learn Topic Screen Hooks.
 * Instance name: learnTopicSingleScreenApi
 
   You can use this hook to customize the learn topic screen such as by adding a component by the topic content.
 * @example
 * externalCodeSetup.learnTopicSingleScreenApi.METHOD_NAME
 */
export class LearnTopicSingleScreenHooksApi {
	afterContentRenderer = renderProps => null;

	/**
	 * It adds a component after the topic content so you can customize the information to be displayed.
	 * @method
	 * @param {LearnTopicAfterContentRendererFunction} renderFunction
	 * @example
	 *  externalCodeSetup.learnTopicSingleScreenApi.setAfterContentRenderer((topicObject, global, colors, navigation) => (
	 *    <TouchableOpacity onPress={() => navigation.navigate("CoursesScreen")}>
	 *     <Text style={{fontSize: 12}}> Tap to go back to courses list</Text>
	 *    </TouchableOpacity>
	 *  ))
	 */
	setAfterContentRenderer = renderFunction => {
		this.afterContentRenderer = renderFunction;
	};

	transformTopicActionButtons = (
		topicButton,
		showComplete,
		global,
		colors,
		lesson,
		completing,
		labels,
		handleComplete
	) => topicButton;

	/**
	 * You can transform the default lesson action button by replacing it with your preferred action buttons.
	 * For example, you can add an inline button to the topic screen for marking topic completion.
	 * @param {TransformTopicActionButtonsCallback} transformTopicActionButtons
	 * @method
	 * @example <caption> Add more components for topic action </caption>
	 *
	 * externalCodeSetup.learnTopicSingleScreenApi.setTransformTopicActionButtons((
	 *   topicButton,
	 *   showComplete,
	 *   global,
	 *   colors,
	 *   topic,
	 *   completing,
	 *   labels,
	 *   handleComplete) => {
	 *
	 *   const Buttons =
	 *     <View style={[global.row, { backgroundColor: "#fff" }]}>
	 *
	 *       <View style={{ width: "45%", backgroundColor: "#fff", paddingHorizontal: 20, paddingVertical: 15 }}>
	 *         <AppTouchableOpacity
	 *           style={[
	 *             global.completeTopicButtonW,
	 *             { flex: 1, backgroundColor: colors.primaryButtonBg }
	 *           ]}
	 *           onPress={() => {
	 *             //Do function...
	 *           }}
	 *         >
	 *           <View style={global.row}>
	 *             <View style={global.linkWithArrow}>
	 *               <Text
	 *                 style={{ color: "#fff", fontWeight: "bold" }}
	 *               >
	 *                 Questions?
	 *               </Text>
	 *             </View>
	 *           </View>
	 *         </AppTouchableOpacity>
	 *       </View>
	 *       <View style={{ width: "45%", marginLeft: "auto" }}>
	 *         {topicButton}
	 *       </View>
	 *     </View>
	 *
	 *   return Buttons;
	 * })
	 */

	setTransformTopicActionButtons = transformTopicActionButtons => {
		this.transformTopicActionButtons = transformTopicActionButtons;
	};

	showMarkAsComplete = topic => true;

	/**
	 * Use this to hide or show the mark as complete component.
	 * @method
	 * @param {LearnTopicProps} topic
	 * @example
	 * externalCodeSetup.learnTopicSingleScreenApi.setShowMarkAsComplete((topic) => false);
	 */
	setShowMarkAsComplete = showMarkAsComplete => {
		this.showMarkAsComplete = showMarkAsComplete;
	};

	PrevNextComponent = null;

	/**
	 * You can use this to replace the previous and next buttons on the learn topic single screen if you want to change the default option which always displays the prev/next buttons.
	 * @method
	 * @param {?React.ComponentType<LearnTopicPrevNextComponentProps>} PrevNextComponent
	 * @example <caption> Remove previous and next buttons if there is no previous and next objects. Otherwise, return the default previous and next buttons </caption>
	 *
	 * //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
	 * }) => {
	 *
	 *    if (!nextObject && !prevObject) {
	 *        return null;
	 *    }
	 *
	 *    return (
	 *        <View style={[global.row]}>
	 *            <AppTouchableOpacity
	 *                style={[
	 *                    global.wrappedButton,
	 *                    global.wrappedTextButton,
	 *                    { marginRight: 4 }
	 *                ]}
	 *                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)
	 *                                            : colors.headerIconColor
	 *                                }
	 *                            ]}
	 *                        >
	 *                            {t("lesson:prevButtonText")}
	 *                        </Text>
	 *                    </View>
	 *                </View>
	 *            </AppTouchableOpacity>
	 *
	 *            <AppTouchableOpacity
	 *                style={[global.wrappedButton, global.wrappedTextButton]}
	 *                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)
	 *                                            : colors.headerIconColor
	 *                                }
	 *                            ]}
	 *                        >
	 *                            {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.learnTopicSingleScreenApi.setPrevNextComponent((props) => <PrevNextComponent {...props} />);
	 * }
	 *
	 */
	setPrevNextComponent = PrevNextComponent => {
		this.PrevNextComponent = PrevNextComponent;
	};

	LearnTopicTitleComponent = null;

	/**
	 * You can use this to replace the topic's title component.
	 * For example, you can use this to change the subtitle's color.
	 * @method
	 * @param {React.ComponentType<LearnTopicTitleComponentProps>} LearnTopicTitleComponent
	 * @example <caption> Change subtitle colors </caption>
	 *
	 * //In custom_code/components/TopicTitle.js...
	 * import React from "react";
	 * import {View, Text} from "react-native";
	 * import Animated from "react-native-reanimated";
	 *
	 * const TopicTitle = ({
	 *  topic,
	 *  global,
	 *  colors,
	 *  paddingTop,
	 *  setHeaderHeight,
	 *  t,
	 *  labels,
	 *  lessonOrder
	 * }) => {
	 *
	 *   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}
	 *           ]}
	 *         >
	 *           {topic.title}
	 *         </Animated.Text>
	 *
	 *         <View style={global.row}>
	 *           <Text style={[global.courseHeaderSubTitle, {color: "red"}]}>
	 *             {t("lessonTopic:lessoncount", {
	 *               lesson: labels.lesson,
	 *               current: lessonOrder + 1
	 *             })}
	 *           </Text>
	 *           <View
	 *             style={{
	 *               width: 3,
	 *               height: 3,
	 *               marginTop: 2,
	 *               marginLeft: 5,
	 *               marginRight: 4,
	 *               backgroundColor: "#8D8F97",
	 *               borderRadius: 2,
	 *               opacity: 0.45
	 *             }}
	 *           />
	 *             <Text style={[global.courseHeaderSubTitle, {color: "blue"}]}>
	 *               {t("lessonTopic:count", {
	 *                 topic: labels.topic,
	 *                 current: topic.order
	 *               })}
	 *             </Text>
	 *           </View>
	 *         </Animated.View>
	 *       </View>
	 *     </Animated.View>
	 *   );
	 * };
	 *
	 * export default TopicTitle;
	 *
	 *
	 * //In custom_code/index.js...
	 *
	 * ...
	 *
	 * import TopicTitle from "./components/TopicTitle";
	 * export const applyCustomCode = externalCodeSetup => {
	 *  externalCodeSetup.learnTopicSingleScreenApi.setLearnTopicTitleComponent(props => <TopicTitle {...props} />)
	 * }
	 */
	setLearnTopicTitleComponent = LearnTopicTitleComponent => {
		this.LearnTopicTitleComponent = LearnTopicTitleComponent;
	};

	LearnTopicScreenHeader = null;
	/**
	 * You can use this hook to customize the header of the Learn Topic Single Screen which by default, contains the back-to-course button and the previous/next buttons.
	 * @method
	 * @param {React.ComponentType<LearnTopicScreenHeaderProps>} LearnTopicScreenHeader
	 * @example
	 *
	 * //In custom_code/components/LearnTopicHeader.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,
	 *     backToCourse,
	 *     renderTimer,
	 *     headerRightAuthWrapperProps,
	 *     prevNext,
	 *     topic
	 * }) => {
	 *   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: "cyan",
	 *             borderRadius: 20
	 *           }
	 *         ]}
	 *       >
	 *         <View style={[global.headerButtonLeft, headerLeftStyle]}>
	 *           {backToCourse}
	 *         </View>
	 *
	 *         <View>
	 *           <Text>
	 *             {topic.title}
	 *           </Text>
	 *         </View>
	 *
	 *         <View style={[global.headerCustomTitle]}>
	 *           {renderTimer}
	 *         </View>
	 *         <View style={[global.headerButtonRight]}>
	 *           <AuthWrapper
	 *             actionOnGuestLogin={"hide"}
	 *             {...headerRightAuthWrapperProps}
	 *           >
	 *             {prevNext}
	 *           </AuthWrapper>
	 *         </View>
	 *       </View>
	 *     </Animated.View>
	 *   );
	 * };
	 *
	 * export default Header;
	 *
	 * //In custom_code/index.js...
	 *
	 * import LearnTopicHeader from "./components/LearnTopicHeader"
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.learnTopicSingleScreenApi.LearnTopicScreenHeader(props => <LearnTopicHeader {...props} />)
	 * }
	 */
	setLearnTopicScreenHeader = LearnTopicScreenHeader => {
		this.LearnTopicScreenHeader = LearnTopicScreenHeader;
	};

	VideoProgressionComponent = null;
	/**
	 * You can use this hook to customize the Video Progression component in the single topic screen.
	 * For example, you can use this to change the size of the video player or add a custom function when the video finishes playing on a topic
	 * @method
	 * @param {React.ComponentType<LearnTopicVideoProgressionComponentProps>} VideoProgressionComponent
	 * @example <caption> Execute a custom callback when video has finished playing </caption>
	 *
	 * ...
	 * import AppVideo from "@src/components/Video/AppVideo";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *   externalCodeSetup.learnTopicSingleScreenApi.setVideoProgressionComponent(props => {
	 *     const {
	 *       topicVideoStyle,
	 *       controls,
	 *       autoPlay,
	 *       videoCallback,
	 *       url,
	 *       width,
	 *       height,
	 *       global,
	 *       isNavActive,
	 *       topic,
	 *       videoWatched,
	 *       setVideoWatched,
	 *       onCompleteTopicClick
	 *     } = props;
	 *
	 *     const customCallback = settings => event => {
	 *
	 *       if (event.nativeEvent.data === "ENDED") {
	 *
	 *         if (!videoWatched)
	 *           setVideoWatched();
	 *
	 *         Alert.alert(
	 *           "Video Complete",
	 *           "You have finished watching the video. Do you want to mark the topic as complete?",
	 *           [
	 *             {
	 *               text: "Cancel",
	 *               onPress: () => console.log("Cancel Pressed"),
	 *               style: "cancel"
	 *             },
	 *             { text: "OK", onPress: () => onCompleteTopicClick() }
	 *           ]
	 *         );
	 *       }
	 *
	 *     }
	 *
	 *     return <View style={topicVideoStyle}>
	 *       <AppVideo
	 *         controls={controls}
	 *         autoPlay={autoPlay}
	 *         // videoCallback={videoCallback()}
	 *         videoCallback={customCallback(topic.settings)}
	 *         url={url}
	 *         width={width}
	 *         height={height}
	 *         global={global}
	 *         isNavActive={isNavActive}
	 *       />
	 *     </View>
	 *   })
	 * }
	 *
	 */
	setVideoProgressionComponent = VideoProgressionComponent => {
		this.VideoProgressionComponent = VideoProgressionComponent;
	};

	AfterMaterialsComponent = null;
	/**
	 * You can use this hook to add a component at the bottom of the topic single screen just after the component that displays the materials.
	 * @method
	 * @param {React.ComponentType<LearnTopicAfterMaterialsComponentProps>} AfterMaterialsComponent
	 * @example
	 *
	 * //In custom_code/components/TopicBottomComponent.js...
	 *
	 * import React from "react";
	 * import { View, Text, TouchableOpacity } from "react-native";
	 *
	 * const TopicBottomComponent = props => {
	 *
	 *     const {
	 *         colors,
	 *         course,
	 *         materials,
	 *         navigation
	 *     } = props;
	 *
	 *     const back = () => {
	 *         navigation.navigate({
	 *             routeName: "CoursesSingleScreen",
	 *             params: {
	 *                 id: course.id,
	 *                 course
	 *             },
	 *             key: course.id.toString()
	 *         })
	 *     }
	 *     return <View style={{
	 *         backgroundColor: colors.bodyFrontBg,
	 *         paddingHorizontal: 20,
	 *         paddingBottom: 20,
	 *         minHeight: 100,
	 *     }}>
	 *         <Text>This lesson is part of the {course.title.rendered} course </Text>
	 *         <TouchableOpacity onPress={back}>
	 *             <Text>
	 *                 Back To Course
	 *             </Text>
	 *         </TouchableOpacity>
	 *     </View>
	 * }
	 *
	 * export default TopicBottomComponent;
	 *
	 *  //In custom_code/index.js...
	 *
	 *  ...
	 *
	 * import TopicBottomComponent from "./components/TopicBottomComponent";
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.learnTopicSingleScreenApi.setAfterMaterialsComponent(props => <TopicBottomComponent {...props}/>)
	 * }
	 */
	setAfterMaterialsComponent = AfterMaterialsComponent => {
		this.AfterMaterialsComponent = AfterMaterialsComponent;
	};

	LearnTopicActionComponent = null;
	/**
	 * You can use this hook to customize the "Mark Complete" / "Completed" button.
	 * For example, you can add your own loading animation when the "Mark Complete" button is pressed.
	 * @method
	 * @param {React.ComponentType<LearnTopicActionComponentProps>} LearnTopicActionComponent
	 * @example
	 *
	 * //In custom_code/components/LearnTopicActionComponent.js...
	 *
	 * import React from "react";
	 * import { View, Text, ActivityIndicator } from "react-native";
	 *
	 * import AuthWrapper from "@src/components/AuthWrapper";
	 * import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
	 * import Icon from "@src/components/Icon";
	 * import { isColorDark } from "@src/utils";
	 *
	 * const LearnTopicActionComponent = ({
	 *   showComplete,
	 *   global,
	 *   colors,
	 *   t,
	 *   topicVM,
	 *   onCompleteTopicClick,
	 *   completing,
	 *   completeDisabled
	 * }) => (
	 *   <AuthWrapper actionOnGuestLogin={"hide"}>
	 *     {showComplete && (
	 *       <View
	 *         style={[
	 *           global.row,
	 *           {
	 *             backgroundColor: colors.bodyFrontBg,
	 *             borderTopColor: colors.borderColor
	 *           },
	 *           global.learnTopicActionButtonContainer
	 *         ]}
	 *       >
	 *         <AppTouchableOpacity
	 *           style={[
	 *             {flex: 1},
	 *             {
	 *               opacity: !topicVM.completed && completeDisabled ? 0.5 : 1,
	 *               backgroundColor: !topicVM.completed
	 *                 ? colors.primaryButtonBg
	 *                 : colors.bodyFrontBg
	 *             },
	 *             global.completeTopicButtonW
	 *           ]}
	 *           disabled={topicVM.completed || completeDisabled}
	 *           onPress={onCompleteTopicClick}
	 *         >
	 *           <View style={global.row}>
	 *             <View style={global.linkWithArrow}>
	 *               {!topicVM.completed ? (
	 *                 completing && (
	 *                   <ActivityIndicator
	 *                     animating={true}
	 *                     color={colors.primaryButtonColor}
	 *                     size="small"
	 *                     style={global.learnTopicButtonLoadingIcon}
	 *                   />
	 *                 )
	 *               ) : (
	 *                 <Icon
	 *                   webIcon={""}
	 *                   icon={require("@src/assets/img/completed-course.png")}
	 *                   styles={global.learnTopicActionCompleteIcon}
	 *                 />
	 *               )}
	 *               <Text
	 *                 style={[
	 *                   {
	 *                     marginLeft: 10,
	 *                     color: !topicVM.completed
	 *                       ? colors.primaryButtonColor
	 *                       : isColorDark(colors.bodyFrontBg)
	 *                         ? "white"
	 *                         : "black"
	 *                   },
	 *                   global.completeTopicButton
	 *                 ]}
	 *               >
	 *                 {t(
	 *                   topicVM.completed
	 *                     ? "lessonTopic:completed"
	 *                     : "lessonTopic:markAsComplete"
	 *                 )}
	 *               </Text>
	 *             </View>
	 *           </View>
	 *         </AppTouchableOpacity>
	 *       </View>
	 *     )}
	 *   </AuthWrapper>
	 * );
	 *
	 * export default LearnTopicActionComponent;
	 *
	 * //In custom_code/index.js...
	 *
	 * ...
	 *
	 * import LearnTopicActionComponent from "./components/LearnTopicActionComponent";
	 * export const applyCustomCode = (externalCodeSetup: any) => {
	 *     externalCodeSetup.learnTopicSingleScreenApi.setLearnTopicActionComponent(props => <LearnTopicActionComponent {...props} />)
	 * }
	 */
	setLearnTopicActionComponent = LearnTopicActionComponent => {
		this.LearnTopicActionComponent = LearnTopicActionComponent;
	};
}