Source

externalCode/coursesScreen.js

/**
 * @typedef {Object} FetchCourseParams
 * @see {@link http://www.buddyboss.com/resources/api/app/#api-LD_Courses-GetLDCourses}
 * @property {?Number} page Page to fetch
 * @property {?Number} per_page Maximum number of items to be returned in result set
 * @property {String} order Sort result set by given order. Allowed values: `asc` or `desc`
 * @property {String} orderby Sort result set by given field. Allowed values: `date`, `id`, `title`, `menu_order`
 * @property {Array<Number>} categories Limit results to those assigned to specific categories.
 * @property {Array<Number>} include Ensure result set includes specific IDs.
 * @property {boolean} _embed
 */

/**
 * @typedef {Object} ItemCourseComponentProps
 * @property {Number} key Index of the item
 * @property {CourseViewModel} viewModel
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {string} textColor Text color used in the component item
 * @property {string} locale App locale
 * @property {boolean} inList Returns true if the item is in vertical self-loading list
 * @property {Object} wStyles Defined styles for `container` and `item`
 * @property {boolean} online Returns true if user is online
 * @property {Object} labels Dynamic names for Leandash CPTs; set on site
 */

/**
 * @typedef {Object} CourseViewModel
 * @property {Boolean} canEnroll Returns true if user can enroll to the course
 * @property {?String} incompletePrerequisiteMessage Returns a message if incomplete prerequisite
 * @property {Number} id Course id
 * @property {String} featuredUrl Url to featured image
 * @property {String} coveredUrl Url to cover image
 * @property {String} title Course title
 * @property {Number} progression Returns course progression by the user
 * @property {String} date Date of when course was created
 * @property {Number} lessonsCount  Number of lessons in the course
 * @property {Number} lessonsCompleted Number of lessons completed in the course
 * @property {Function} onClick Default function when a course widget is clicked
 * @property {Boolean} isClosed Returns true if course is closed
 * @property {Boolean} hasAccess Returns true if user has access
 * @property {Boolean} hasContentAccess Returns true if has content access
 * @property {Boolean} hidecontentTable Returns true if content table is hidden
 * @property {Boolean} paidCourse Returns true if course can only be accessed if user has paid for it
 * @property {Boolean} completed Returns true if course has been completed by the logged-in user
 * @property {String} link Link to the course
 * @property {Boolean} puchasable Returns true if course can be purchased
 * @property {Boolean} offlineDisabled Returns true if offline disabled
 * @property {String|undefined} videoUrl Course video
 * @property {?Object} price Course price and currency
 * @property {Object} error Error message encountered
 * @property {Number} authorId Id of course's author
 * @property {?Object} author Author details
 * @property {?String} modifiedDate Date of when course was last modified
 * @property {Object} certificate Certificate details
 * @property {Number} enrolledMembers Number of enrolled members in the course
 *
 */

/**
 * @typedef {Function} TransformParams
 * @param {FetchCourseParams}
 * @return {Object}
 */

/**
 * @typedef {Function} TransformCourseCategoriesParams
 * @param {FetchCourseCategoriesParams}
 * @return {Object}
 */

/**
 * @typedef {Object} FetchCourseCategoriesParams
 * @see {@link http://www.buddyboss.com/resources/api/app/#api-LD_Courses-GetLDCourseCategories}
 * @property {Number} page Page to fetch
 * @property {Number} per_page Maximum number of items to be returned in result set
 * @property {Number} courses_limit Number of courses to fetch
 * @property {Number} mycourses Limit results to current user courses
 * @property {String} order Sort result set by given order. Allowed values: `asc` or `desc`.
 * @property {String} orderby Sort result set by given field. Allowed values: `date`, `term_id`, `name`, `slug`.
 *
 */

/**
 * @typedef {Function} TransformCourseViewModelCallback
 * @property {CourseViewModel} viewModel
 * @property {Object} course Course raw data from API
 * @property {Object} params - Additional data passed by component
 * @property {NavigationService} navigation
 * @return {Object} New view model
 */

/**
 * @typedef {Function} TransformSubFiltersFilterCallback
 * @param {Array<string>} filters Available filters: `title`, `recent`, `my_progress`
 * @return {Array<string>}
 */

/**
 * @typedef {Function} TransformCategoriesSubFiltersFilterCallback
 * @param {Array<string>} filters Available filters: `title`, `date`
 * @return {Array<string>}
 */

/**
 * @typedef {Object} CourseTitleComponentProps
 * @property {Object} styles Default styles
 * @property {String} title Course title
 */

/**
 * @typedef {Object} CourseAuthorComponentProps
 * @property {Boolean} hideAuthor Returns `true` if author of the course should be hidden
 * @property {Number} userId User id of the course's author
 * @property {Object}  global App global style
 * @property {Object} colors App colors
 */

/**
 * @typedef {Object} CourseDateComponentProps
 * @property {Boolean} showDate Returns `true` if date of the course should be visible
 * @property {Object} styles Default styles
 * @property {String} date Course date
 */

/**
 * @class
 * Courses Index Screen Hooks.
 * Instance name: coursesHooksApi
  
   Offers modification option to the courses screen.
 * @example
 * externalCodeSetup.coursesHooksApi.METHOD_NAME
 */
export class CoursesHooksApi {
	/**
	 * @private
	 * @property {TransformParams} fetchParamsFilter
	 */
	fetchParamsFilter = params => params;
	/**
	 * It overrides the parameters that are used to fetch courses in the Courses screen so that you can make it as customizable as possible when calling its API.
	 * @method
	 * @param {TransformParams} fetchParamsFilter
	 *
	 * @example <caption> Create a custom filter in courses screen </caption>
	 *
	 * //In components/MyCustomScreen.js...
	 *
	 * import React from 'react';
	 *
	 * import { View, Text } from "react-native"
	 * import CoursesScreen from "@src/containers/Custom/CoursesScreen";
	 * import withGlobalStyles from "@src/components/hocs/withGlobalStyles";
	 * import CoursesFilter from "./CoursesFilter"
	 *
	 * const MyCustomHeader = (props) => {
	 *
	 * const {colors, title} = props
	 *
	 * return <View style={{
	 *    backgroundColor: colors.headerBg,
	 *    height: 116}}>
	 *    <Text style={{
	 *      position: "absolute",
	 *      color: colors.whiteColor,
	 *      top: 60,
	 *      left: 10,
	 *      fontSize: 30
	 *    }}> {title} </Text>
	 *   </View>
	 * }
	 *
	 * const MyCustomScreen = props => {
	 *
	 *  const { global, colors } = props;
	 *  const title = "My Courses";
	 *
	 *  return <>
	 *    <MyCustomHeader {...props} title={title} />
	 *      <CoursesFilter {...props} />
	 *      <CoursesScreen {...props} showSearch={false} hideFilters={true} headerHeight={0} hideNavigationHeader={true}/>
	 *  </>
	 *
	 * }
	 *
	 * export default withGlobalStyles(MyCustomScreen);
	 *
	 * //In components/CoursesFilter.js...
	 *
	 * import React, { useState } from "react";
	 * import { TextInput, View, Button } from 'react-native'
	 * import { useDispatch } from "react-redux";
	 * import { requestCourses } from "@src/actions/courses";
	 * import { getExternalCodeSetup } from "@src/externalCode/externalRepo";
	 * import {withNavigation} from "@src/components/hocs/withNavigation";
	 * const hook = getExternalCodeSetup().coursesHooksApi;
	 * const requestAction = requestCourses;
	 * const screenName = "book";
	 *
	 * const filter = "my-courses"; // "all", "my-courses"
	 * const subfilters = "title" // "title", "recent", "my_progress";
	 * const refresh = true; //Set to true to refresh list
	 *
	 * const CoursesFilter = (props) => {
	 *
	 *    const { navigation, route, colors } = props;
	 *
	 *    const dispatch = useDispatch();
	 *
	 *    //If showing the matched screen, show custom filter before displaying list component
	 *    if (route?.params?.item?.object === screenName) {
	 *
	 *        const [author, setAuthor] = useState('');
	 *
	 *        const handleSubmit = () => {
	 *
	 *            //Set custom parameters before fetching
	 *            hook.setFetchParamsFilter((props) => {
	 *
	 *                //You can add more parameters such as "subject", "keyword" etc...
	 *                return {
	 *                    ...props,
	 *                    author
	 *                }
	 *            })
	 *
	 *            //Dispatch redux action to call api using customized filters
	 *            dispatch(requestAction(filter, subfilters, refresh));
	 *
	 *        }
	 *
	 *        return <View style={{ backgroundColor: colors.whiteColor}}>
	 *
	 *            <TextInput
	 *                style={{paddingHorizontal: 20, marginTop: 10, fontSize: 20}}
	 *                autoFocus
	 *                value={author}
	 *                onChangeText={author => setAuthor(author)}
	 *                placeholder="Author"
	 *            />
	 *
	 *            <Button
	 *                onPress={() => handleSubmit()}
	 *                title="Filter"
	 *            />
	 *        </View>
	 *    }
	 *
	 *    return null;
	 *
	 * }
	 *
	 * export default withNavigation(CoursesFilter);
	 *
	 * //In custom_code/index.js...
	 *
	 * ...
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *    externalCodeSetup.navigationApi.addNavigationRoute(
	 *       "book",
	 *       "BookScreen",
	 *       MyCustomScreen,
	 *       "All"
	 *    );
	 *    externalCodeSetup.navigationApi.addNavigationRoute(
	 *       "book",
	 *       "BookScreen",
	 *       MyCustomScreen,
	 *       "Main"
	 *    );
	 * }
	 *
	 * @example <caption>Set sort order</caption>
	 * externalCodeSetup.coursesHooksApi.setFetchParamsFilter(props => {
	 *   return {...props, order: "desc"}
	 * });
	 */
	setFetchParamsFilter = fetchParamsFilter => {
		this.fetchParamsFilter = fetchParamsFilter;
	};

	/**
	 * @private
	 * @property {TransformCourseCategoriesParams} fetchCategoriesParamsFilter
	 */
	fetchCategoriesParamsFilter = params => params;

	/**
	 * It overrides the parameters that are used to fetch courses categories in the Courses Categories screen so that you can make it as customizable as possible when calling its API.
	 * @method
	 * @param {TransformCourseCategoriesParams} fetchParamsFilter
	 * @example <caption>Define how many course items to be displayed in course categories screen</caption>
	 * externalCodeSetup.coursesHooksApi.setFetchCategoriesParamsFilter(props => {
	 *   return {...props, courses_limit: 1}
	 * });
	 */
	setFetchCategoriesParamsFilter = fetchCategoriesParamsFilter => {
		this.fetchCategoriesParamsFilter = fetchCategoriesParamsFilter;
	};

	/**
	 * @private
	 * @property {TransformCourseViewModelCallback} courseViewModelFilter
	 */
	courseViewModelFilter = (viewModel, item, params, navigation) => viewModel;

	/**
	 * Sets the callback function that can change an existing course view model object.
	 * @method
	 * @param {TransformCourseViewModelCallback} courseViewModelFilter
	 * @example <caption>Add date to course view model</caption>
	 * externalCodeSetup.coursesHooksApi.setCourseViewModelFilter((viewModel, course, params, navigation) => {
	 *   return {...viewModel, date: new Date()}
	 * });
	 */
	setCourseViewModelFilter = courseViewModelFilter => {
		this.courseViewModelFilter = courseViewModelFilter;
	};

	WidgetItemCourseComponent = null;
	/**
	 * Renders custom components for course items in a list of courses.
	 * This affects components used for widget items in courses screen and courses block in the home screen.
	 * @method
	 * @param {React.ComponentType<ItemCourseComponentProps>} WidgetItemCourseComponent
	 * @example <caption>Courses widget to be displayed as text list with additional details</caption>
	 *
	 * ...
	 *
	 * import { WidgetItemCourseUserConnected } from "@src/components/Widgets/WidgetItemCourseUser"; //Use BuddyBoss component that can display author name using author id
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  const NewWidgetItemCourseComponent = (props) => {
	 *
	 *    const { viewModel, global, colors } = props;
	 *
	 *    return <View style={{ margin: 20 }}>
	 *
	 *      <TouchableOpacity onPress={viewModel.onClick}>
	 *        <Text>
	 *          {viewModel.title}
	 *        </Text>
	 *
	 *        <WidgetItemCourseUserConnected
	 *          lightText={true}
	 *          global={global}
	 *          userId={viewModel.authorId}
	 *          colors={colors}
	 *        />
	 *
	 *        <Text>
	 *          Enrolled members: {viewModel.enrolledMembers}
	 *        </Text>
	 *      </TouchableOpacity>
	 *
	 *     </View>
	 *   }
	 *   externalCodeSetup.coursesHooksApi.setWidgetItemCourseComponent(NewWidgetItemCourseComponent)
	 * }
	 */
	setWidgetItemCourseComponent = WidgetItemCourseComponent =>
		(this.WidgetItemCourseComponent = WidgetItemCourseComponent);

	subFiltersFilter = filters => filters;

	/**
	 * Sets the available sub filter function for courses such as Alphabetical, Newly Created and so on.
	 * @method
	 * @param {TransformSubFiltersFilterCallback} subFiltersFilter
	 * @example <caption>User would like to have "Alphabetical" filter only</caption>
	 * externalCodeSetup.coursesHooksApi.setSubFiltersFilter((filters) => {
	 *   return ["title"]; //available filters include "title", "recent", "my_progress"
	 * })
	 */
	setSubFiltersFilter = subFiltersFilter => {
		this.subFiltersFilter = subFiltersFilter;
	};

	categoriesSubFiltersFilter = filters => filters;

	/**
	 * Sets the available sub filter function for course categories such as Alphabetical and Newly Created.
	 * @method
	 * @param {TransformCategoriesSubFiltersFilterCallback} subFiltersFilter
	 * @example <caption>User would like to have "Newly Created" as the default selected filter</caption>
	 * externalCodeSetup.coursesHooksApi.setCategoriesSubFiltersFilter((filters) => {
	 *   return ["date", "title"]; //available filters include "title", "date"
	 * })
	 */
	setCategoriesSubFiltersFilter = subFiltersFilter => {
		this.categoriesSubFiltersFilter = subFiltersFilter;
	};

	CourseTitleComponent = null;

	/**
	 * You can use this hook to customize the title of the course.
	 * For example, you can change its color, size, or font.
	 * @method
	 * @param {React.ComponentType<CourseTitleComponentProps>} CourseTitleComponent
	 * @example <caption>Allow 3 lines of text instead of the default 2 lines</caption>
	 *
	 * externalCodeSetup.coursesHooksApi.setCourseTitleComponent(({
	 *   styles,
	 *   title
	 * }) => {
	 *     return (
	 *         <Text style={styles.title} numberOfLines={3} ellipsizeMode={"tail"}>
	 *             {title}
	 *         </Text>
	 *     );
	 * });
	 */
	setCourseTitleComponent = CourseTitleComponent => {
		this.CourseTitleComponent = CourseTitleComponent;
	};

	CourseAuthorComponent = null;

	/**
	 * You can use this hook to customize the author of the course.
	 * @method
	 * @param {React.ComponentType<CourseAuthorComponentProps>} CourseAuthorComponent
	 * @example
	 *
	 * ...
	 *
	 * import {WidgetItemCourseUserConnected} from "@src/components/Widgets/WidgetItemCourseUser";
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *
	 *     externalCodeSetup.coursesHooksApi.setCourseAuthorComponent(({
	 *         hideAuthor,
	 *         global,
	 *         userId,
	 *         colors
	 *     }) => {
	 *         return !hideAuthor ? (
	 *             <WidgetItemCourseUserConnected
	 *                 global={global}
	 *                 userId={userId}
	 *                 colors={colors}
	 *             />
	 *         ) : null;
	 *     });
	 * }
	 */
	setCourseAuthorComponent = CourseAuthorComponent => {
		this.CourseAuthorComponent = CourseAuthorComponent;
	};

	CourseDateComponent = null;

	/**
	 * You can use this hook to customize the date of the course.
	 * @method
	 * @param {React.ComponentType<CourseDateComponentProps>} CourseDateComponent
	 * @example
	 *
	 * externalCodeSetup.coursesHooksApi.setCourseDateComponent(
	 *  ({showDate, styles, date}) => {
	 *    return showDate ? <Text style={styles.date}>{date}</Text> : null;
	 *  }
	 * );
	 */
	setCourseDateComponent = CourseDateComponent => {
		this.CourseDateComponent = CourseDateComponent;
	};
}