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;
};
}
Source