Source

externalCode/courseSingle.ts

import * as React from "react";
import {TCourseViewModel, TTranslationFunction, TQuizViewModel} from "./types";
import {NavigationService} from "./types";
import {NavigationProp} from "@react-navigation/native";
export const API_NAME = "courseSingleApi";

/**
 * CoursePropsFilterCallback
 */
type CoursePropsFilterCallback = {
	/**
	 * Course props
	 */
	oldProps: Record<any, any>
};
/**
 * CourseStatusHiddenCallback
 */
type CourseStatusHiddenCallback = {
	course: TCourseViewModel,
	/**
	 * Returns `true` if course progress has started
	 */
	hasStarted: boolean,
	/**
	 * Course structure
	 */
	courseTree: Record<any, any>
};
/**
 * CourseDescriptionHiddenCallback
 */
type CourseDescriptionHiddenCallback = {
	course: TCourseViewModel
};

/**
 * CategoryTagsHiddenCallback
 */
type CategoryTagsHiddenCallback = {
	course: TCourseViewModel
};

/**
 * TransformCourseActionButtonsCallback
 */
type TransformCourseActionButtonsCallback = {
	CourseActionBtn: JSX.Element,
	course: TCourseViewModel,
	t: Function,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Products associated to the course
	 */
	products: Record<any, any>[],
	navigation: NavigationService,

	/**
	 * Starts the course when called
	 */
	startCourse: Function,
	/**
	 * Continues the course when called for a course in progress
	 */
	continueCourse: Function,
	/**
	 * Renders the price component when called
	 */
	priceComponentRender: Function
};

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

	t: TTranslationFunction,

	/**
	 * Contents of course materials field
	 */
	materials: string,
	/**
	 * Default styles for different tags
	 */
	tagsStyles: Record<any, any>,
	/**
	 * Default styles for course materials
	 */
	materialsStyles: Record<any, any>,
	/**
	 * Function to set a font style
	 */
	baseFontStyle: Function,

	navigation: NavigationProp<any, any>,
	/**
	 * Helper function that handles link press for the HTML component
	 */
	onLinkPress: Function
};

/**
 * HeaderAuthorComponentProps
 */
type HeaderAuthorComponentProps = {
	/**
	 * Author details
	 */
	user: Record<any, any>,
	/**
	 * Returns `true` if course is using cover image
	 */
	lightStyle: boolean,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * User id of course author
	 */
	userId: number,
	onUserProfilePress: Function,
	loadingInProgress: Function,
	t: TTranslationFunction
};

/**
 * CourseTitleProps
 */
type CourseTitleProps = {
	course: TCourseViewModel,
	/**
	 * App global style
	 */
	_globalStyles: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Returns `true` if course is using cover image
	 */
	lightStyle: boolean,

	/**
	 * Default title styles
	 */
	styles: Record<any, any>,

	/**
	 * Returns an object generated by React Native Animated
	 */
	animatedOpacity: Record<any, any>
};

/**
 * CourseHeaderDetailsProps
 */
type CourseHeaderDetailsProps = {
	courseVM: TCourseViewModel,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,

	labels: Record<any, any>,

	t: TTranslationFunction,

	/**
	 * Lessons count
	 */
	lCount: number,
	/**
	 * Topics count
	 */
	tCount: number,
	/**
	 * Quizzes count
	 */
	qCount: number,

	/**
	 * Can be used to determine if participants should be shown in the component
	 */
	learndashCourseParticipants: number,

	navigation: NavigationProp<any, any>,

	/**
	 * Returns `true` if participants should be shown
	 */
	shouldShowParticipants: Boolean,

	/**
	 * Returns `true` if course image should be shown
	 */
	shouldShowImageBackground: Boolean,

	/**
	 * Returns `true` if course video should be shown
	 */
	shouldShowVideo: Boolean,
	/**
	 * Returns `true` if "Course Includes" label should be shown
	 */
	shouldShowCourseIncludesTitle: Boolean,
	/**
	 * Returns `true` if lessons label should be shown
	 */
	shouldShowLessonsText: Boolean,
	/**
	 * Returns `true` if topics label should be shown
	 */
	shouldShowTopicsText: Boolean,
	/**
	 * Returns `true` if quizzes label should be shown
	 */
	shouldShowQuizzesText: Boolean,
	/**
	 * Returns `true` if course certificate label should be shown
	 */
	shouldShowCertificatesText: Boolean,

	/**
	 * Returns the lessons label
	 */
	lessonsText: String,
	/**
	 * Returns the topics label
	 */
	topicsText: String,
	/**
	 * Returns the quizzes label
	 */
	quizzesText: String,
	/**
	 * Returns the enrolled label
	 */
	enrolledText: String,
	/**
	 * Default styles
	 */
	styles: Record<any, any>
};
/**
 * DownloadProgressComponentProps
 */
type DownloadProgressComponentProps = {
	/**
	 * Cancels the download progress
	 */
	onPress: Function,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Current progress of download
	 */
	progress: number,
	/**
	 * Size of progress circle
	 */
	size: number,
	/**
	 * Returns `true` if component should use lightStyle
	 */
	lightStyle: boolean,
	/**
	 * Default hitSlop for component
	 */
	hitSlop: Record<string, number>,
	/**
	 * Default container style
	 */
	containerStyle: Record<any, any>
};

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

	t: TTranslationFunction,
	courseVM: TCourseViewModel,

	/**
	 * Returns `true` if course should be open for guest user
	 */
	isShowingOpenCourseForGuestUser: boolean,

	/**
	 * Can be used to indicate what DownloadStatusIndicator component style should use
	 */
	contentStyle: Record<any, any>
};

/*
 *
 * DownloadIconProps
 */
type DownloadIconProps = {
	/**
	 * Returns the status of the course being downloaded. Status includes `Complete`, `Pending`, `Failed`, etc.
	 */
	status: string,
	/**
	 * Starts the download process
	 */
	start: Function,
	/**
	 * Cancels the download process
	 */
	cancel: Function,
	/**
	 * Opens a modal that contains actions available for the downloaded
	 */
	openOptions: Function,
	/**
	 * Icon size
	 */
	size: number,
	/**
	 * Returns `true` if component should use lightStyle
	 */
	lightStyle: boolean,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Default color of icon
	 */
	idleIconColor: string,
	/**
	 * Default hitSlop for component
	 */
	hitSlop: Record<string, number>
};

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

	t: TTranslationFunction,

	courseVM: TCourseViewModel,

	/**
	 * Default styles for the header component
	 */
	styles: Record<any, any>,

	/**
	 * Helper function for parsing dates
	 */
	formatDateFunc: Function
};

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

	t: TTranslationFunction,

	labels: Record<any, any>,

	/**
	 * Returns `true` if course content is collapsable
	 */
	isCollapsable: boolean,

	/**
	 * Returns `true` if collapsable items are already expanded
	 */
	expanded: boolean,

	/**
	 * Hides all the collapsable items
	 */
	hideAll: Function,

	/**
	 * Expands all the collapsable items
	 */
	expand: Function
};

/**
 * CourseSectionItemProps
 */
type CourseSectionItemProps = {
	/**
	 * Data about item to be rendered
	 */
	item: Record<any, any>,
	/**
	 * Returns progression of the item
	 */
	progression: number,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Returns `true` if navigation to the item is allowed
	 */
	allowNavigation: boolean,
	/**
	 * Navigates to the lesson; topic or quiz
	 */
	onItemPress: Function,
	/**
	 * Returns number of topics and quizzes for the top-level item.
	 * This can be used when determining if the lesson should be expandable or not.
	 */
	count: number,
	/**
	 * Result of using require() when fetching the appropriate icon for each item
	 */
	icon: number,
	/**
	 * Toggle or expand the item. This can be called when creating a custom IconComponent
	 */
	toggleExpand: Function,
	/**
	 * Returs the type of section item
	 */
	blockType: string | undefined,
	/**
	 * Calls an alert component which shows an error message
	 */
	showAlertMessage: Function,
	/**
	 * Default component for displaying the steps label in the item
	 */
	StepsComponent: JSX.Element,
	/**
	 * Default component for displaying the left-most icon in the item
	 */
	IconComponent: JSX.Element
};
/**
 * QuizSectionTitleProps
 */
type QuizSectionTitleProps = {
	/**
	 * App global style
	 */
	global: Record<any, any>,

	t: TTranslationFunction
};

/**
 * CourseDescriptionSectionTitleProps
 */
type CourseDescriptionSectionTitleProps = {
	/**
	 * Returns `true` if there are blocks to be rendered natively
	 */
	shouldRenderBlocks: boolean,
	courseVM: TCourseViewModel,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	t: TTranslationFunction,
	labels: Record<any, any>
};

/**
 * CourseMaterialsSectionTitleProps
 */
type CourseMaterialsSectionTitleProps = {
	/**
	 * App global style
	 */
	global: Record<any, any>,
	t: TTranslationFunction,
	labels: Record<any, any>
};

/**
 * CourseDescriptionReadMoreComponentProps
 */
type CourseDescriptionReadMoreComponentProps = {
	courseVM: TCourseViewModel,
	/**
	 * Opens the desription modal
	 */
	openDescriptionModal: Function,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	t: TTranslationFunction
};

/**
 * WebViewOfflineComponentProps
 */
type WebViewOfflineComponentProps = {
	/**
	 * App global style
	 */
	global: Record<any, any>,
	t: TTranslationFunction,

	/**
	 * Default container style
	 */
	containerStyle: Record<any, any>,

	/**
	 * Default style of EmptyList component
	 */
	emptyListStyle: Record<any, any>
};

/**
 * WebViewDescriptionComponentProps
 */
type WebViewDescriptionComponentProps = {
	/**
	 * Returns `true` if device is connected to an internet network
	 */
	online: boolean,
	t: TTranslationFunction,
	/**
	 * The default function used for determining how to handle webview requests.
	 */
	onShouldStartLoadWithRequest: Function,
	/**
	 * Default height limit
	 */
	heightLimit: number,
	/**
	 * Contains data of the web site to be loaded in the webview
	 */
	source: Record<any, any>,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Modal which shows up when the "Read More" component is pressed
	 */
	ModalHeaderComponent: React.FC
};
/**
 * CourseQuizItemProps
 */
type CourseQuizItemProps = {
	item: TQuizViewModel,
	style: Record<any, any>,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Can be used to determine if actual progress should be shown or if item should be indicated as completed
	 */
	skipProgress: boolean,
	/**
	 * Navigates to the quiz
	 */
	onPress: Function,
	/**
	 * Returns `true` if navigation to the item is allowed
	 */
	allowNavigation: boolean,
	/**
	 * Default component for displaying the left-most icon in the item
	 */
	IconComponent: JSX.Element
};

/**
 * LessonProgressStepsProps
 */
type LessonProgressStepsProps = {
	t: TTranslationFunction,
	/**
	 * Item details
	 */
	item: Record<any, any>,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,

	/**
	 * Number of items inside the item
	 */
	count: number,
	course: TCourseViewModel,
	/**
	 * Describes the type of item being generated
	 */
	blockType: string,
	/**
	 * Number of completed steps inside the lesson
	 */
	completedSteps: number
};

/**
 * @class
 * Single Course Screen Hooks.
 * Instance name: courseSingleApi
  
   Hooks to modify the individual courses’ pages.
 * @example
 * externalCodeSetup.courseSingleApi.METHOD_NAME
 */
export class CourseSingleApi {
	/**
	 * @deprecated
	 */
	// show number of lessons on course single screen beside the lesson title
	setShowLessonsCount = () => (this.showLessonsCount = true);
	/**
	 * @deprecated
	 */
	// show number of quizzes on course single screen beside the quizzes title
	setShowQuizzesCount = () => (this.showQuizzesCount = true);

	/**
	 * @deprecated
	 * @private
	 * @property {boolean} showLessonsCount
	 */
	showLessonsCount = true;
	/**
	 * @deprecated
	 * @private
	 * @property {boolean} showQuizzesCount
	 */
	showQuizzesCount = true;

	headerAuthorRenderer: React.ComponentType<
		HeaderAuthorComponentProps
	> | null = null;

	/**
	 * Sets component for overriding the default course author component.
	 * @method
	 * @param {React.ComponentType<HeaderAuthorComponentProps>} renderer
	 * @example <caption>Add more details besides the author name</caption>
	 *
	 * //In custom_code/components/CourseAuthor.js
	 *
	 * import React from 'react';
	 * import { View, Text } from 'react-native';
	 * import AppAvatar from "@src/components/AppAvatar";
	 * import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
	 * import { getBestImageVariant } from "@src/utils/CCDataUtil";
	 * import { withUserClickHandler } from "@src/components/hocs/withUserClickHandler"; //Use BuddyBoss HOC for easier navigation
	 *
	 * const CourseAuthor = (props) => {
	 *
	 *    const { user, global, lightStyle, toUserBasedOnSettings } = props;
	 *
	 *    //Able navigate to profile of `user` because of wrapping component with HOC
	 *    const boundCallback = React.useMemo(
	 *	        () => toUserBasedOnSettings.bind(null, null, user),
	 *        [user]
	 *    );
	 *
	 *    //Use BuddyBoss getBestImageVariant helper function to get best image size for the component
	 *    const userAvatarUrl = React.useMemo(
	 *        () =>
	 *            !!user
	 *                ? user.avatar_urls
	 *                    ? getBestImageVariant(user.avatar_urls, 96)
	 *                    : user?.avatar?.thumb
	 *                : "",
	 *        [user]
	 *    );
	 *
	 *    return <View style={[global.row]}>
	 *        <AppTouchableOpacity onPress={boundCallback}>
	 *            <View>
	 *                {user && (
	 *                    <AppAvatar
	 *                        size={26}
	 *                        name={user.name}
	 *                        source={{
	 *                            uri: userAvatarUrl
	 *                        }}
	 *                    />
	 *                )}
	 *            </View>
	 *        </AppTouchableOpacity>
	 *        <View style={{ marginLeft: 8 }}>
	 *            {user && (
	 *
	 *                <>
	 *                    <Text
	 *                        style={[
	 *                            global.itemAuthorName,
	 *                            { marginBottom: 1 },
	 *                            lightStyle ? { color: "white" } : {}
	 *                        ]}
	 *                    >
	 *                        {user?.name}
	 *                    </Text>
	 *
	 *                    <Text> {user?.member_rest.user_email} </Text>
	 *                </>
	 *
	 *            )}
	 *        </View>
	 *    </View>
	 * }
	 *
	 * export default withUserClickHandler(CourseAuthor);
	 *
	 * //In custom_code/index.js
	 *
	 * ...
	 *
	 * import CourseAuthor from "./components/CourseAuthor";
	 * export const applyCustomCode = externalCodeSetup => {
	 *    externalCodeSetup.courseSingleApi.setHeaderAuthorRenderer((props) => <CourseAuthor {...props} />)
	 * }
	 */
	setHeaderAuthorRenderer = (
		renderer: React.ComponentType<HeaderAuthorComponentProps> | null
	) => {
		this.headerAuthorRenderer = renderer;
	};

	filterIncomingCourseProps = (props: Record<any, any>) => props;

	/**
	 * Sets the callback function `filterIncomingCourseProps` used for filtering props that are coming into Courses Single Screen component
	 * @param {CoursePropsFilterCallback} filterIncomingCourseProps
	 * @method
	 * @example <caption>Add a date object to incoming course props</caption>
	 * externalCodeSetup.courseSingleApi.setFilterIncomingCourseProps((props) => {
	 *   return {
	 *     ...props,
	 *     date: new Date()
	 *   }
	 * });
	 */
	setFilterIncomingCourseProps = (
		filterIncomingCourseProps: (
			filterIncomingCourseProps: Record<any, any>
		) => Record<any, any>
	) => {
		this.filterIncomingCourseProps = filterIncomingCourseProps;
	};

	isCategoryTagsHidden = (course: TCourseViewModel) => false;

	/**
	 * You can use this to show or hide the category tags in the course single screen.
	 * @param {CategoryTagsHiddenCallback} CategoryTagsHiddenCallback
	 * @method
	 * @example
	 *
	 * externalCodeSetup.courseSingleApi.setIsCategoryTagsHidden((course) => {
	 *  return false;
	 * })
	 */
	setIsCategoryTagsHidden = (
		isCategoryTagsHidden: (course: TCourseViewModel) => boolean
	) => {
		this.isCategoryTagsHidden = isCategoryTagsHidden;
	};

	CourseMaterialsComponent: React.ComponentType<
		CourseMaterialsProps
	> | null = null;

	/**
	 * Sets a component that overrides the content added in course materials field found in BuddyBoss site > Learndash LMS > Courses > [Selected Course] > Settings.
	 * @method
	 * @param {React.ComponentType<CourseMaterialsProps>} CourseMaterialsComponent
	 * @example <caption>Use a different component depending on the logged-in user</caption>
	 *
	 * ...
	 *
	 * const DEVICE_WIDTH = Dimensions.get("window").width;
	 * import { useSelector } from "react-redux";
	 * import WebView from "react-native-webview";
	 * const ent = require("ent");
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *
	 *   externalCodeSetup.courseSingleApi.setCourseMaterialsComponent(({
	 *     tagsStyles,
	 *     materialsStyles,
	 *     baseFontStyle,
	 *     materials,
	 *     onLinkPress,
	 *     global
	 *   }) => {
	 *
	 *     const CourseMaterial = () => {
	 *       const user = useSelector((state) => state.user.userObject);
	 *
	 *       return user.id === 1 ?
	 *         <>
	 *           <Text style={{ marginBottom: 20 }}> Welcome back {user.name}! We prepared the materials for you. </Text>
	 *           <WebView source={{ uri: 'https://buddyboss.com' }} style={{ width: "auto", height: 300 }} />
	 *         </>
	 *         :
	 *         <View style={global.courseRoundBox}>
	 *           {typeof materials === "string" && (
	 *             <View style={{ paddingHorizontal: 15 }}>
	 *               <HTML
	 *                 tagsStyles={{ ...tagsStyles, ...materialsStyles }}
	 *                 baseFontStyle={baseFontStyle(15)}
	 *                 html={ent.decode(materials)}
	 *                 imagesMaxWidth={DEVICE_WIDTH - 32}
	 *                 onLinkPress={onLinkPress}
	 *               />
	 *             </View>
	 *           )}
	 *         </View>
	 *
	 *     }
	 *
	 *     return <CourseMaterial />
	 *
	 *   })
	 * }
	 */
	setCourseMaterialsComponent = (
		CourseMaterialsComponent: React.ComponentType<CourseMaterialsProps> | null
	) => {
		this.CourseMaterialsComponent = CourseMaterialsComponent;
	};

	transformCourseActionButtons: (
		CourseActionBtn: JSX.Element,
		course: TCourseViewModel,
		t: Function,
		colors: Record<any, any>,
		global: Record<any, any>,
		products: Record<any, any>[],
		navigation: NavigationService,
		startCourse: Function,
		continueCourse: Function,
		priceComponentRender: Function
	) => JSX.Element = CourseActionBtn => CourseActionBtn;

	/**
	 * You can transform the default course action buttons which are starting, buying or continuing a course by replacing it with your preferred action buttons.
	 * @param {TransformCourseActionButtonsCallback} transformCourseActionButtons
	 * @method
	 * @example <caption> Add more components for course action </caption>
	 *
	 * import CourseActionButton from "@src/components/Course/CourseActionButton";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *   externalCodeSetup.courseSingleApi.setTransformCourseActionButtons((
	 *     CourseActionBtn,
	 *     course,
	 *     t,
	 *     colors,
	 *     global,
	 *     products,
	 *     navigation,
	 *     startCourse,
	 *     continueCourse,
	 *     priceComponentRender) => {
	 *
	 *     return <>
	 *       <View style={{ paddingHorizontal: 20, paddingVertical: 10 }}>
	 *         <Text>To continue the course, tap the button below++</Text>
	 *       </View>
	 *
	 *       <View style={{
	 *         paddingHorizontal: 20,
	 *         paddingVertical: 16,
	 *         flexDirection: "row",
	 *         alignItems: "center",
	 *         justifyContent: "space-between"
	 *       }}>
	 *         {CourseActionBtn}
	 *         <CourseActionButton
	 *           title={"Go to Courses screen"}
	 *           onPress={() => navigation.navigate("CoursesScreen")}
	 *           style={{ backgroundColor: "cyan" }}
	 *         />
	 *       </View>
	 *     </>
	 *   })
	 *
	 * }
	 */

	setTransformCourseActionButtons = (
		transformCourseActionButtons: (
			CourseActionBtn: JSX.Element,
			course: TCourseViewModel,
			t: Function,
			colors: Record<any, any>,
			global: Record<any, any>,
			products: Record<any, any>[],
			navigation: NavigationService,
			startCourse: Function,
			continueCourse: Function,
			priceComponentRender: Function
		) => JSX.Element
	) => {
		this.transformCourseActionButtons = transformCourseActionButtons;
	};

	isCourseStatusHidden = (
		course: TCourseViewModel,
		hasStarted: boolean,
		courseTree: Record<any, any>
	) => false;

	/**
	 * You can use this hook to show or hide the course status component.
	 * @param {CourseStatusHiddenCallback} CourseStatusHiddenCallback
	 * @method
	 * @example <caption> Hide the course status component depending on the course title </caption>
	 *  externalCodeSetup.courseSingleApi.setIsCourseStatusHidden((course, hasStarted, courseTree) => {
	 *    if (course.title == "React Native"){
	 *      return true;
	 *    }
	 *    return false;
	 *  })
	 */
	setIsCourseStatusHidden = (
		isCourseStatusHidden: (
			course: TCourseViewModel,
			hasStarted: boolean,
			courseTree: Record<any, any>
		) => boolean
	) => {
		this.isCourseStatusHidden = isCourseStatusHidden;
	};

	isCourseDescriptionHidden = (course: TCourseViewModel) => false;

	/**
	 * You can use this hook to show or hide the course description component.
	 * @param {CourseDescriptionHiddenCallback} CourseDescriptionHiddenCallback
	 * @method
	 * @example <caption> Hide the course description depending on the course title </caption>
	 *  externalCodeSetup.courseSingleApi.setIsCourseDescriptionHidden((course) => {
	 *    if (course.title == "React Native"){
	 *      return true;
	 *    }
	 *    return false;
	 *  })
	 */
	setIsCourseDescriptionHidden = (
		isCourseDescriptionHidden: (course: TCourseViewModel) => boolean
	) => {
		this.isCourseDescriptionHidden = isCourseDescriptionHidden;
	};

	CourseTitleComponent: React.ComponentType<CourseTitleProps> | null = null;

	/**
	 * You can use this to replace the course title component.
	 * For example, you can use this to change the title's font size.
	 * @method
	 * @param {React.ComponentType<CourseTitleProps>} CourseTitleComponent
	 * @example
	 *
	 * import React from "react";
	 * import Animated from "react-native-reanimated";
	 * import {View} from "react-native";
	 * 
	 * export const applyCustomCode = externalCodeSetup => {
	 *     externalCodeSetup.courseSingleApi.setCourseTitleComponent(props => {
	 *         const {
	 *             course,
	 *             _globalStyles,
	 *             colors,
	 *             styles,
	 *             lightStyle,
	 *             animatedOpacity
	 *         } = props;
	 * 
	 *         return (
	 *             <View>
	 *                 <Animated.Text
	 *                     style={[
	 *                         _globalStyles.iosStyleScreenTitle,
	 *                         styles.title,
	 *                         lightStyle ? {color: "white"} : {color: colors.textColor},
	 *                         animatedOpacity
	 *                     ]}
	 *                 >
	 *                     {course.title}
	 *                 </Animated.Text>
	 *             </View>
	 *         );
	 *     });
	 * };

	 */
	setCourseTitleComponent = (
		CourseTitleComponent: React.ComponentType<CourseTitleProps> | null
	) => {
		this.CourseTitleComponent = CourseTitleComponent;
	};

	CourseHeaderDetails: React.ComponentType<
		CourseHeaderDetailsProps
	> | null = null;

	/**
	 * You can use this hook to customize the Course Status component of the LearnDash course details if a course is not yet in progress.
	 * For example, you can use this to change the course's preview video, featured image or the "Course Includes" details.
	 * @method
	 * @param {React.ComponentType<CourseHeaderDetailsProps>} CourseHeaderDetails
	 * @example
	 *
	 * import Icon from "@src/components/Icon";
	 * import AppImageBackground from "@src/components/AppImageBackground";
	 * import {CourseVideo} from "@src/components/Course/CourseStatus";
	 * import AppAvatar from "@src/components/AppAvatar";
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.courseSingleApi.setCourseHeaderDetails(props => {
	 *         const {
	 *             courseVM,
	 *             global,
	 *             labels,
	 *             colors,
	 *             t,
	 *             navigation,
	 *             shouldShowParticipants,
	 *             shouldShowImageBackground,
	 *             shouldShowVideo,
	 *             shouldShowCourseIncludesTitle,
	 *             shouldShowLessonsText,
	 *             shouldShowTopicsText,
	 *             shouldShowQuizzesText,
	 *             shouldShowCertificatesText,
	 *             lessonsText,
	 *             topicsText,
	 *             quizzesText,
	 *             enrolledText,
	 *             styles
	 *         } = props;
	 *
	 *         const size = 26;
	 *
	 *         return (
	 *             <>
	 *                 <View style={styles.mediaContainer}>
	 *                     {shouldShowImageBackground && (
	 *                         <AppImageBackground
	 *                             source={{uri: courseVM.featuredUrl}}
	 *                             style={{width: "100%", height: 200}}
	 *                         />
	 *                     )}
	 *                     {shouldShowVideo && (
	 *                         <CourseVideo
	 *                             url={courseVM.videoUrl}
	 *                             feature={courseVM.featuredUrl}
	 *                             global={global}
	 *                             colors={colors}
	 *                             navigation={navigation}
	 *                         />
	 *                     )}
	 *                 </View>
	 *
	 *                 <View style={styles.container}>
	 *                     {shouldShowParticipants && (
	 *                         <View style={{...global.row}}>
	 *                             {courseVM.members
	 *                                 .map(x => x.member_rest?.avatar?.thumb || "")
	 *                                 .map((url, index) => (
	 *                                     <AppAvatar
	 *                                         key={url}
	 *                                         style={[
	 *                                             styles.avatar,
	 *                                             {
	 *                                                 left: index === 0 ? 0 : -10 	 *  index,
	 *                                                 zIndex: index
	 *                                             }
	 *                                         ]}
	 *                                         borderRadius={size / 2}
	 *                                         size={size}
	 *                                         source={{
	 *                                             uri: url
	 *                                         }}
	 *                                     />
	 *                                 ))}
	 *                             <Text style={styles.enrolledText}>{enrolledText}</Text>
	 *                         </View>
	 *                     )}
	 *                     {shouldShowCourseIncludesTitle && (
	 *                         <Text style={styles.courseIncludesTitle}>
	 *                             {t("course:includesTitle", {label: labels.course})}
	 *                         </Text>
	 *                     )}
	 *                     {shouldShowLessonsText && (
	 *                         <View style={{flexDirection: "row", marginBottom: 5}}>
	 *                             <Icon
	 *                                 size={30}
	 *                                 webIcon={"IconAndroidGroup"}
	 *                                 tintColor={colors.descLightTextColor}
	 *                                 icon={{fontIconName: "book", weight: 400}}
	 *                             />
	 *                             <Text style={styles.courseIncludesText}>{lessonsText}</Text>
	 *                         </View>
	 *                     )}
	 *                     {shouldShowTopicsText && (
	 *                         <View style={{flexDirection: "row", marginBottom: 5, marginLeft: 5}}>
	 *                             <Icon
	 *                                 size={24}
	 *                                 webIcon={"IconAndroidGroup"}
	 *                                 tintColor={colors.descLightTextColor}
	 *                                 icon={{fontIconName: "text", weight: 500}}
	 *                             />
	 *                             <Text style={styles.courseIncludesText}>{topicsText}</Text>
	 *                         </View>
	 *                     )}
	 *                     {shouldShowQuizzesText && (
	 *                         <View style={{flexDirection: "row", marginLeft: 5, marginBottom: 5}}>
	 *                             <Icon
	 *                                 size={24}
	 *                                 webIcon={"IconAndroidGroup"}
	 *                                 tintColor={colors.descLightTextColor}
	 *                                 icon={{fontIconName: "question", weight: 100}}
	 *                             />
	 *                             <Text style={styles.courseIncludesText}>{quizzesText}</Text>
	 *                         </View>
	 *                     )}
	 *                     {shouldShowCertificatesText && (
	 *                         <View style={{flexDirection: "row", marginLeft: 5}}>
	 *                             <Icon
	 *                                 size={26}
	 *                                 webIcon={"IconAndroidGroup"}
	 *                                 tintColor={colors.descLightTextColor}
	 *                                 icon={{fontIconName: "certificate", weight: 400}}
	 *                             />
	 *                             <Text style={styles.courseIncludesText}>
	 *                                 {t("course:certificate", {label: labels.course})} asdfasdf
	 *                             </Text>
	 *                         </View>
	 *                     )}
	 *                 </View>
	 *             </>
	 *         );
	 *     });
	 * }
	 *
	 */
	setCourseHeaderDetails = (
		CourseHeaderDetails: React.ComponentType<CourseHeaderDetailsProps> | null
	) => {
		this.CourseHeaderDetails = CourseHeaderDetails;
	};

	HeaderRightComponent: React.ComponentType<
		CourseHeaderRightProps
	> | null = null;

	/**
	 * You can use this hook to customize the component on the top right corner of the CourseSingleScreen which the download icon usually occupies.
	 * @method
	 * @param {React.ComponentType<CourseHeaderRightProps>} HeaderRightComponent
	 * @example
	 * ...
	 *
	 * import AuthWrapper from "@src/components/AuthWrapper";
	 * import DownloadStatusIndicator from "@src/components/Downloader/DownloadStatusIndicator";
	 * import StatusBarWrapper from "@src/utils/StatusBarWrapper";
	 * import { DownloadTypes } from "@src/services/enums/downloads";
	 *
	 * export const applyCustomCode = (externalCodeSetup: any) => {
	 *
	 *     externalCodeSetup.courseSingleApi.setHeaderRightComponent(({
	 *         global,
	 *         colors,
	 *         t,
	 *         courseVM,
	 *         isShowingOpenCourseForGuestUser,
	 *         contentStyle
	 *     }) => (
	 *         courseVM.hasAccess &&
	 *         !courseVM.offlineDisabled && (
	 *             <AuthWrapper
	 *                 actionOnGuestLogin={
	 *                     isShowingOpenCourseForGuestUser
	 *                         ? null
	 *                         : "showAuthScreen"
	 *                 }
	 *             >
	 *                 <DownloadStatusIndicator
	 *                     lightStyle={
	 *                         contentStyle === StatusBarWrapper.lightStyle
	 *                     }
	 *                     postId={courseVM.id}
	 *                     postType={DownloadTypes.course}
	 *                     colors={colors}
	 *                     global={global}
	 *                     size={30}
	 *                     t={t}
	 *                     iconColor={colors.linkColor}
	 *                     containerStyle={{
	 *                         marginLeft: 15
	 *                     }}
	 *                 />
	 *             </AuthWrapper>
	 *         )
	 *
	 *     ))
	 * }
	 */
	setHeaderRightComponent = (
		HeaderRightComponent: React.ComponentType<CourseHeaderRightProps> | null
	) => {
		this.HeaderRightComponent = HeaderRightComponent;
	};

	DownloadProgressComponent: React.ComponentType<
		DownloadProgressComponentProps
	> | null = null;

	/**
	 * You can use this hook to customize the DownloadProgressComponent which shows up when the course is currently downloading.
	 * @param {React.ComponentType<DownloadProgressComponentProps>} DownloadProgressComponent
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * import ProgressCircle from "react-native-progress/Circle";
	 * import {TouchableWithoutFeedback} from "react-native";
	 * import Icon from "@src/components/Icon";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *
	 *     externalCodeSetup.courseSingleApi.setDownloadProgressComponent(({
	 *         size,
	 *         lightStyle,
	 *         colors,
	 *         onPress,
	 *         hitSlop,
	 *         containerStyle,
	 *         progress
	 *     }) => {
	 *         const iconSize = size - 10;
	 *         const color = lightStyle ? "#fff" : colors.highlightColor;
	 *         const unfilledColor = lightStyle
	 *             ? "rgba(255, 255, 255, 0.24)"
	 *             : "rgba(0, 0, 0, 0.24)";
	 *         return (
	 *             <TouchableWithoutFeedback onPress={onPress} hitSlop={hitSlop}>
	 *                 <View style={containerStyle}>
	 *                     <ProgressCircle
	 *                         size={size}
	 *                         progress={progress}
	 *                         thickness={2}
	 *                         unfilledColor={unfilledColor}
	 *                         animated={true}
	 *                         borderWidth={0}
	 *                         color={color}
	 *                     />
	 *                     <Icon
	 *                         icon={{fontIconName: "stop", weight: 300}}
	 *                         tintColor={color}
	 *                         styles={{height: iconSize, width: iconSize, position: "absolute"}}
	 *                     />
	 *                 </View>
	 *             </TouchableWithoutFeedback>
	 *         );
	 *     })
	 * }
	 */
	setDownloadProgressComponent = (
		DownloadProgressComponent: React.ComponentType<
			DownloadProgressComponentProps
		> | null
	) => {
		this.DownloadProgressComponent = DownloadProgressComponent;
	};

	DownloadIcon: React.ComponentType<DownloadIconProps> | null = null;

	/**
	 * You can use this hook to customize the DownloadIcon which can be used to download a course, delete a course, or indicate if a course has already been downloaded.
	 *
	 * @param {React.ComponentType<DownloadIconProps>} DownloadIcon
	 * @method
	 * @example
	 *
	 * import React from "react";
	 * import Animated from "react-native-reanimated";
	 * import AppTouchableWithoutFeedback from "@src/components/AppTouchableWithoutFeedback";
	 * import Icon from "@src/components/Icon";
	 * export const applyCustomCode = externalCodeSetup => {
	 *     externalCodeSetup.courseSingleApi.setDownloadIcon(
	 *         ({colors, idleIconColor, lightStyle, start, size, hitSlop}) => {
	 *             const iconColor =
	 *                 idleIconColor ?? (lightStyle ? "#fff" : colors.linkColor);
	 *             const action = start;
	 *             return (
	 *                 <AppTouchableWithoutFeedback
	 *                     onPress={action}
	 *                     debounce={500}
	 *                     hitSlop={hitSlop}
	 *                 >
	 *
	 *                     <Animated.View>
	 *                         <Icon
	 *                             icon={{fontIconName: "cloud-download", weight: 400}}
	 *                             styles={{height: size, width: size}}
	 *                             tintColor={iconColor}
	 *                         />
	 *                     </Animated.View>
	 *                 </AppTouchableWithoutFeedback>
	 *             );
	 *         }
	 *     );
	 * };
	 *
	 */
	setDownloadIcon = (
		DownloadIcon: React.ComponentType<DownloadIconProps> | null
	) => {
		this.DownloadIcon = DownloadIcon;
	};

	CourseStartedHeaderDetails: React.ComponentType<
		CourseStartedHeaderDetailsProps
	> | null = null;

	/**
	 * You can use this hook to customize the Course Status component of the LearnDash course details if a course is in progress or is already complete.
	 * @param {React.ComponentType<CourseStartedHeaderDetailsProps>} CourseStartedHeaderDetails
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * import Icon from "@src/components/Icon";
	 * import Progress from "@src/components/Progress";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *
	 *     externalCodeSetup.courseSingleApi.setCourseStartedHeaderDetails(({
	 *         global,
	 *         colors,
	 *         t,
	 *         courseVM,
	 *         styles,
	 *         formatDateFunc
	 *     }) =>  <View
	 *                 style={[
	 *                     global.row,
	 *                     {
	 *                         paddingHorizontal: 20,
	 *                         paddingVertical: 16,
	 *                         flex: 1
	 *                     }
	 *                 ]}
	 *             >
	 *                 <View style={{flex: 1, marginRight: 8}}>
	 *                     {courseVM.hasAccess ? (
	 *                         <Text style={[global.title, styles.title]}>
	 *                             {!!!courseVM.completed
	 *                                 ? t("course:inProgress")
	 *                                 : t("course:completed")}
	 *                         </Text>
	 *                     ) : (
	 *                         <Text style={[global.title, styles.title]}>
	 *                             {t("course:enrolled")}
	 *                         </Text>
	 *                     )}
	 *                     {courseVM.modifiedDate && (
	 *                         <Text style={[global.courseDate, {marginTop: 5}]}>
	 *                             {`${t("course:lastActivity")} ${formatDateFunc(
	 *                                 courseVM.modifiedDate
	 *                             )}`}
	 *                         </Text>
	 *                     )}
	 *                 </View>
	 *                 <Text style={[global.progressLargeText, styles.progressText]}>
	 *                     {courseVM.progression + "%"}
	 *                 </Text>
	 *                 <Progress
	 *                     size={32}
	 *                     checkIcon={
	 *                         <Icon
	 *                             styles={{width: 36, height: 36}}
	 *                             icon={{fontIconName: "check", weight: 200}}
	 *                             tintColor={colors.successColor}
	 *                         />
	 *                     }
	 *                     isCompleted={!!courseVM.completed}
	 *                     progress={courseVM.progression}
	 *                     colors={{
	 *                         highlightColor: colors.highlightColor,
	 *                         bodyBg: "#e7e9ec"
	 *                     }}
	 *                 />
	 *             </View>
	 *     );
	 * }
	 *
	 *
	 */
	setCourseStartedHeaderDetails = (
		CourseStartedHeaderDetails: React.ComponentType<
			CourseStartedHeaderDetailsProps
		> | null
	) => {
		this.CourseStartedHeaderDetails = CourseStartedHeaderDetails;
	};

	CourseContentTitle: React.ComponentType<
		CourseContentTitleProps
	> | null = null;

	/**
	 * You can use this hook to customize the "Course Content" title and the "Expand All" function.
	 * @param {React.ComponentType<CourseContentTitleProps>} CourseContentTitle
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *   externalCodeSetup.courseSingleApi.setCourseContentTitle(({
	 *       global,
	 *       labels,
	 *       isCollapsable,
	 *       expanded,
	 *       hideAll,
	 *       expand,
	 *       t
	 *   }) => (
	 *       <View
	 *           style={[
	 *               global.row,
	 *               {flex: 1, justifyContent: "space-between", marginBottom: 9}
	 *           ]}
	 *       >
	 *           <Text style={[global.courseRoundBoxTitleAbove, {marginBottom: 0}]}>
	 *               {t("course:contentTitle", {label: labels.course})}
	 *           </Text>
	 *           {isCollapsable && (
	 *               <TouchableWithoutFeedback
	 *                   hitSlop={{top: 20, right: 20, bottom: 20, left: 20}}
	 *                   onPress={() => {
	 *                       if (expanded) {
	 *                           hideAll();
	 *                       } else {
	 *                           expand();
	 *                       }
	 *                   }}
	 *               >
	 *                   <Text style={[global.link, {fontSize: 17}]}>
	 *                       {expanded ? t("courses:collapseAll") : t("courses:expandAll")}
	 *                   </Text>
	 *               </TouchableWithoutFeedback>
	 *           )}
	 *       </View>
	 *   ));
	 * }
	 *
	 */
	setCourseContentTitle = (
		CourseContentTitle: React.ComponentType<CourseContentTitleProps> | null
	) => {
		this.CourseContentTitle = CourseContentTitle;
	};

	CourseSectionItem: React.ComponentType<CourseSectionItemProps> | null = null;

	/**
	 * You can use this hook to customize the Item components that are displayed as course content.
	 * @param {React.ComponentType<CourseSectionItemProps>} CourseSectionItem
	 * @method
	 * @example <caption> Use your own icon component instead of the default IconComponent of lessons with children</caption>
	 *
	 * ...
	 *
	 * import Icon from "@src/components/Icon";
	 * import LearnItem from "@src/components/Course/LearnItem";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *
	 *     externalCodeSetup.courseSingleApi.setCourseSectionItem(props => {
	 *         const {
	 *             item,
	 *             progression,
	 *             global,
	 *             colors,
	 *             allowNavigation,
	 *             onItemPress,
	 *             StepsComponent,
	 *             IconComponent,
	 *             blockType,
	 *             toggleExpand,
	 *             count,
	 *             showAlertMessage
	 *         } = props;
	 *
	 *         let CustomIcon = IconComponent;
	 *         if (blockType === "lesson" && count > 0) {
	 *             CustomIcon = (
	 *                 <TouchableOpacity onPress={toggleExpand}>
	 *                     <Icon
	 *                         tintColor={colors.descLightTextColor}
	 *                         icon={{fontIconName: "heart", weight: 400}}
	 *                         styles={{
	 *                             opacity: !allowNavigation ? 0.45 : 1,
	 *                             marginRight: 10,
	 *                             width: 25,
	 *                             height: 25
	 *                         }}
	 *                     />
	 *                 </TouchableOpacity>
	 *             );
	 *         }
	 *
	 *         return (
	 *             <LearnItem
	 *                 key={item.id}
	 *                 style={{
	 *                     paddingLeft: 0
	 *                 }}
	 *                 item={{
	 *                     id: item.id,
	 *                     completed: item.completed,
	 *                     title: item.title,
	 *                     progression
	 *                 }}
	 *                 global={global}
	 *                 colors={colors}
	 *                 onPress={() => {
	 *                     if (allowNavigation) {
	 *                         showAlertMessage();
	 *                         return false;
	 *                     }
	 *                     onItemPress();
	 *                 }}
	 *                 allowNavigation={allowNavigation}
	 *                 beforeProgress={StepsComponent}
	 *                 beforeLabel={CustomIcon}
	 *             />
	 *         );
	 *     });
	 * }
	 */
	setCourseSectionItem = (
		CourseSectionItem: React.ComponentType<CourseSectionItemProps> | null
	) => {
		this.CourseSectionItem = CourseSectionItem;
	};

	QuizSectionTitle: React.ComponentType<QuizSectionTitleProps> | null = null;

	/**
	 * You can use this hook to customize the component that displays the "Final Quizzes" text.
	 * @method
	 * @param {React.ComponentType<QuizSectionTitleProps>} QuizSectionTitle
	 * @example
	 *
	 * ...
	 *
	 * externalCodeSetup.courseSingleApi.setQuizSectionTitle(({global, t}) => (
	 *   <Text style={global.courseRoundBoxSectionTitle}>
	 *       {t("course:finalQuizzes")}
	 *   </Text>
	 * ));
	 */
	setQuizSectionTitle = (
		QuizSectionTitle: React.ComponentType<QuizSectionTitleProps> | null
	) => {
		this.QuizSectionTitle = QuizSectionTitle;
	};

	CourseDescriptionSectionTitle: React.ComponentType<
		CourseDescriptionSectionTitleProps
	> | null = null;

	/**
	 * You can use this hook to customize the component that displays the "Course Description" text.
	 * @method
	 * @param {React.ComponentType<CourseDescriptionSectionTitleProps>} CourseDescriptionSectionTitle
	 * @example
	 *
	 * ...
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.courseSingleApi.setCourseDescriptionSectionTitle(
	 *         ({shouldRenderBlocks, courseVM, global, labels, t}) => {
	 *             if (shouldRenderBlocks || courseVM.content) {
	 *                 return (
	 *                     <Text style={[global.courseRoundBoxTitleAbove]}>
	 *                         {t("course:descriptionTitle", {
	 *                             label: labels.course
	 *                         })}
	 *                     </Text>
	 *                 );
	 *             }
	 *
	 *             return null;
	 *         }
	 *     );
	 * }
	 */
	setCourseDescriptionSectionTitle = (
		CourseDescriptionSectionTitle: React.ComponentType<
			CourseDescriptionSectionTitleProps
		> | null
	) => {
		this.CourseDescriptionSectionTitle = CourseDescriptionSectionTitle;
	};

	CourseMaterialsSectionTitle: React.ComponentType<
		CourseMaterialsSectionTitleProps
	> | null = null;

	/**
	 * You can use this hook to customize the component that displays the "Course Materials" text.
	 * @method
	 * @param {React.ComponentType<CourseMaterialsSectionTitleProps>} CourseMaterialsSectionTitle
	 * @example
	 *
	 * ...
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *  externalCodeSetup.courseSingleApi.setCourseMaterialsSectionTitle(
	 *    ({global, t, labels}) => (
	 *        <Text style={[global.courseRoundBoxTitleAbove, {marginBottom: 20}]}>
	 *            {t("course:courseMaterials", {label: labels.course})}
	 *        </Text>
	 *    )
	 *  );
	 * }
	 */
	setCourseMaterialsSectionTitle = (
		CourseMaterialsSectionTitle: React.ComponentType<
			CourseMaterialsSectionTitleProps
		> | null
	) => {
		this.CourseMaterialsSectionTitle = CourseMaterialsSectionTitle;
	};

	CourseDescriptionReadMoreComponent: React.ComponentType<
		CourseDescriptionReadMoreComponentProps
	> | null = null;

	/**
	 * You can use this hook to customize the "Read More" text that shows the course description in a modal when pressed.
	 * @method
	 * @param {React.ComponentType<CourseDescriptionReadMoreComponentProps>} CourseDescriptionReadMoreComponent
	 * @example
	 *
	 * ...
	 * import AppTouchableWithoutFeedback from "@src/components/AppTouchableWithoutFeedback";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.courseSingleApi.setCourseDescriptionReadMoreComponent(({
	 *         courseVM,
	 *         openDescriptionModal,
	 *         global,
	 *         t
	 *     }) => {
	 *         if (courseVM.contentNative.length > 1) {
	 *             return <View style={{alignItems: "center"}}>
	 *                 <AppTouchableWithoutFeedback
	 *                     onPress={openDescriptionModal}
	 *                 >
	 *                     <Text
	 *                         style={[
	 *                             global.linkRegular,
	 *                             {
	 *                                 paddingHorizontal: 20,
	 *                                 paddingVertical: 10
	 *                             }
	 *                         ]}
	 *                     >
	 *                         {t("courses:readMore")}
	 *                     </Text>
	 *                 </AppTouchableWithoutFeedback>
	 *             </View>
	 *         }
	 *         return null
	 *     })
	 * }
	 */
	setCourseDescriptionReadMoreComponent = (
		CourseDescriptionReadMoreComponent: React.ComponentType<
			CourseDescriptionReadMoreComponentProps
		> | null
	) => {
		this.CourseDescriptionReadMoreComponent = CourseDescriptionReadMoreComponent;
	};

	WebViewOfflineComponent: React.ComponentType<
		WebViewOfflineComponentProps
	> | null = null;

	/**
	 * You can use this hook to customize the component that displays a "This content is not available offline" message if a webview is used for rendering the course description while the device is offline.
	 * @method
	 * @param {React.ComponentType<WebViewOfflineComponentProps>} WebViewOfflineComponent
	 * @example
	 *
	 * ...
	 *
	 * import EmptyList from "@src/components/EmptyList";
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.courseSingleApi.setWebViewOfflineComponent(
	 *         ({containerStyle, t, global, emptyListStyle}) => (
	 *             <View style={containerStyle}>
	 *                 <Text>Please connect to an internet network</Text>
	 *                 <EmptyList
	 *                     emptyText={{
	 *                         title: t("common:contentOfflineMessage"),
	 *                         icon: {fontIconName: "wifi-slash", weight: 400}
	 *                     }}
	 *                     global={global}
	 *                     style={emptyListStyle}
	 *                 />
	 *             </View>
	 *         )
	 *     );
	 * }
	 */
	setWebViewOfflineComponent = (
		WebViewOfflineComponent: React.ComponentType<
			WebViewOfflineComponentProps
		> | null
	) => {
		this.WebViewOfflineComponent = WebViewOfflineComponent;
	};

	WebViewDescriptionComponent: React.ComponentType<
		WebViewDescriptionComponentProps
	> | null = null;

	/**
	 * You can use this hook to replace the webview being used in the course description.
	 * For example, you can choose to replace it with the default react-native webview.
	 * @method
	 * @param {React.ComponentType<WebViewDescriptionComponentProps>} WebViewDescriptionComponent
	 * @example
	 *
	 * ...
	 *
	 * import WebViewWithMore from "@src/components/WebViewWithMore";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.courseSingleApi.setWebViewDescriptionComponent(
	 *         ({
	 *             online,
	 *             t,
	 *             onShouldStartLoadWithRequest,
	 *             heightLimit,
	 *             source,
	 *             global,
	 *             colors,
	 *             ModalHeaderComponent
	 *         }) => (
	 *             <WebViewWithMore
	 *                 online={online}
	 *                 t={t}
	 *                 onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
	 *                 disableLoadingPadding={true}
	 *                 height={heightLimit}
	 *                 source={source}
	 *                 global={global}
	 *                 colors={colors}
	 *                 ModalHeaderComponent={ModalHeaderComponent}
	 *             />
	 *         )
	 *     );
	 * }
	 */
	setWebViewDescriptionComponent = (
		WebViewDescriptionComponent: React.ComponentType<
			WebViewDescriptionComponentProps
		> | null
	) => {
		this.WebViewDescriptionComponent = WebViewDescriptionComponent;
	};

	CourseQuizItem: React.ComponentType<CourseQuizItemProps> | null = null;

	/**
	 * You can use this hook to customize the Item components that are displayed as final quizzes.
	 * @param {React.ComponentType<CourseQuizItemProps>} CourseQuizItem
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * import LearnItem from "@src/components/Course/LearnItem";
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.courseSingleApi.setCourseQuizItem(
	 *         ({
	 *             item,
	 *             style,
	 *             global,
	 *             colors,
	 *             skipProgress,
	 *             onPress,
	 *             allowNavigation,
	 *             IconComponent
	 *         }) => (
	 *             <LearnItem
	 *                 key={item.id}
	 *                 style={style}
	 *                 item={item}
	 *                 global={global}
	 *                 colors={colors}
	 *                 skipProgress={skipProgress}
	 *                 onPress={onPress}
	 *                 allowNavigation={allowNavigation}
	 *                 beforeLabel={IconComponent}
	 *             />
	 *         )
	 *     );
	 * }
	 *
	 */
	setCourseQuizItem = (
		CourseQuizItem: React.ComponentType<CourseQuizItemProps> | null
	) => {
		this.CourseQuizItem = CourseQuizItem;
	};

	LessonProgressStepsComponent: React.ComponentType<
		LessonProgressStepsProps
	> | null = null;
	/**
	 * You can use this to replace the course lesson progress step component.
	 * @method
	 * @param {React.ComponentType<LessonProgressStepsProps>} LessonProgressStepsComponent
	 * @example <caption>Replace the course lesson progress steps component</caption>
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.courseSingleApi.setLessonProgressStepsComponent(props => {
	 *         const {count, completedSteps, blockType, global, t} = props;
	 *
	 *         return (
	 *             !!count &&
	 *             count > 0 &&
	 *             blockType === "lesson" ? (
	 *                 <Text style={[global.caption]}>
	 *                     {`${t("courses:stepsOutOf", {completedSteps, count})}`}
	 *                 </Text>
	 *             ) : <></>
	 *         );
	 *     });
	 * }
	 */
	setLessonProgressStepsComponent = (
		LessonProgressStepsComponent: React.ComponentType<
			LessonProgressStepsProps
		> | null
	) => {
		this.LessonProgressStepsComponent = LessonProgressStepsComponent;
	};
}