Source

externalCode/appPages.js

import * as React from "react";

/**
 * @typedef {Object} CourseBlock
 * @property {String} title
 * @property {String} tint_color
 * @property {Object} data_source Object with fields such as course ids, type, any other data added via custom work
 */

/**
 * @typedef {Object} CoursesWidgetComponentProps
 * @property {String} bgColor Background color of the widgets container
 * @property {String} title Title for the widgets container
 * @property {Array<Object>} courses Contains courses object with fields such as title, date, has_course_access, slug etc.
 * @property {Function} onCourseClick Function that will redirect to the selected course
 * @property {Function} onCourseSeeAllClick Function that will redirect to the courses list
 * @property {CourseBlock} block
 * @property {TranslationFunction} t
 * @property {NavigationService} navigation
 */

/**
 * @typedef {Object} ActivitiesWidgetComponentProps
 * @property {String} bgColor Background color of the widgets container
 * @property {String} title Title for the widgets container
 * @property {Array<Object>} activities Contains activities object with fields such as name, date, media, title etc.
 * @property {Function} onActivitiesSeeAllClick Function that will redirect to the activities list
 * @property {TranslationFunction} t
 * @property {NavigationService} navigation
 */

/**
 * @typedef {Object} ActivitiesItemWidgetComponentProps
 * @property {User} user
 * @property {ActivityViewModel} item
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {Object} tagsStyles Tag default styles
 * @property {Object} contentWrapperStyle Default content wrapper for activity item
 * @property {Object} style Default style for activity item wrapper
 * @property {Function} attemptDeepLink Helper function which is used for deeplinking
 * @property {Number} avatarSize Returns default size of avatar
 * @property {Boolean} hidePrivacy Returns `true` if privacy button should be hidden
 *
 */

/**
 * @typedef {Object} TopicsWidgetComponentProps
 * @property {String} title Title for the widgets container
 * @property {Array<Object>} topics Contains topics object with fields such as title, slug, id etc.
 * @property {Function} onTopicSeeAllClick Function that will redirect to the topics list
 * @property {Function} onTopicClick Function that will redirect to the topic
 * @property {Function} onAvatarClick Function that will redirect to the profile of the author of the topic
 * @property {TranslationFunction} t
 */

/**
 * @typedef {Object} TopicItemWidgetComponentProps
 * @property {Array<Object>} topic Contains topic object with fields such as title, shortContent, id etc.
 * @property {Boolean} isLast Returns `true` if current item is last in the list
 * @property {Object} global App global style
 * @property {Object} colors App colors
 */

/**
 * @typedef {Object} CoursesWidgetTitleProps
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {Object} style
 * @property {String} icon
 * @property {String} title Title of the widget
 * @property {String} textColor
 * @property {?Boolean} seeMoreHidden Returns `true` if "See More" button should be hidden
 * @property {Function} seeMoreHandler Helper function that redirects to appropriate screen
 * @property {String} seeMoreLabel Default label of "See More" button
 * @property {Object} block Object which contains block data such as the source, params, colors etc
 * @property {Array<CourseViewModel>} courses
 * @property {TranslationFunction} t
 * @property {NavigationService} navigation
 * @property {CourseBlock} block
 */

/**
 * @typedef {Object} TopicsWidgetTitleProps
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {String} icon
 * @property {String} title Title of the widget
 * @property {String} textColor
 * @property {Boolean} seeMoreHidden Returns `false` by default
 * @property {Function} seeMoreHandler Helper function that redirects to appropriate screen
 * @property {String} seeMoreLabel Default label of "See More" button
 * @property {Array<TopicViewModel>} topics
 * @property {TranslationFunction} t
 * @property {NavigationService} navigation
 */

/**
 * @typedef {Object} ForumsWidgetTitleProps
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {String} icon
 * @property {String} title Title of the widget
 * @property {String} textColor
 * @property {Boolean} seeMoreHidden Returns `false` by default
 * @property {Function} seeMoreHandler Helper function that redirects to appropriate screen
 * @property {String} seeMoreLabel Default label of "See More" button
 * @property {Array<ForumViewModel>} forums
 * @property {TranslationFunction} t
 * @property {NavigationService} navigation
 */

/**
 * @typedef {Object} GroupsWidgetTitleProps
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {String} icon
 * @property {String} title Title of the widget
 * @property {String} textColor
 * @property {Boolean} seeMoreHidden Returns `false` by default
 * @property {Function} seeMoreHandler Helper function that redirects to appropriate screen
 * @property {String} seeMoreLabel Default label of "See More" button
 * @property {Array<GroupViewModel>} groups
 * @property {TranslationFunction} t
 * @property {NavigationService} navigation
 */

/**
 * @typedef {Object} ActivitiesWidgetTitleProps
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {String} icon
 * @property {String} title Title of the widget
 * @property {String} textColor
 * @property {Boolean} seeMoreHidden Returns `false` by default
 * @property {Function} seeMoreHandler Helper function that redirects to appropriate screen
 * @property {String} seeMoreLabel Default label of "See More" button
 * @property {Array<ActivityViewModel>} activities
 * @property {TranslationFunction} t
 * @property {NavigationService} navigation
 */

/**
 * @typedef {Object} MembersWidgetTitleProps
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {String} icon
 * @property {String} title Title of the widget
 * @property {Boolean} seeMoreHidden Returns `false` by default
 * @property {Function} seeMoreHandler Helper function that redirects to appropriate screen
 * @property {String} seeMoreLabel Default label of "See More" button
 * @property {Array<MemberViewModel>} users
 * @property {TranslationFunction} t
 * @property {NavigationService} navigation
 */

/**
 * @typedef {Object} NotificationsWidgetTitleProps
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {String} icon
 * @property {String} title Title of the widget
 * @property {String} textColor
 * @property {Boolean} seeMoreHidden Returns `false` by default
 * @property {Function} seeMoreHandler Helper function that redirects to appropriate screen
 * @property {String} seeMoreLabel Default label of "See More" button
 * @property {Array<Object>} notifications Notification object
 * @property {TranslationFunction} t
 * @property {NavigationService} navigation
 */

/**
 * @typedef {Object} LinksWidgetTitleProps
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {String} textColor
 * @property {String} icon
 * @property {String} title Title of the widget
 * @property {Boolean} seeMoreHidden Returns `false` by default
 * @property {Array<Object>} quickLinks Quick links object
 * @property {TranslationFunction} t
 * @property {NavigationService} navigation
 */

/**
 * @typedef {Object} TopicsItemWidgetDetailsComponentProps
 * @property {Object} styles Default styles
 * @property {Object} global App global style
 * @property {TopicViewModel} topic
 */

/**
 * @typedef {Object} CoursesItemWidgetDetailsComponentProps
 * @property {Object} styles Default styles
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {Boolean} hideAuthor Returns `true` if course author should be hidden
 * @property {CourseViewModel} course
 */

/**
 * @typedef {Object} BlogItemWidgetDetailsComponentProps
 * @property {Object} styles Default styles
 * @property {Object} global App global style
 * @property {BlogViewModel} blog
 */

/**
 * @typedef {Object} BlogWidgetTitleProps
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {String} textColor
 * @property {String} icon
 * @property {String} title Title of the widget
 * @property {Boolean} seeMoreHidden Returns `false` by default
 * @property {Function} seeMoreHandler Helper function that redirects to appropriate screen
 * @property {TranslationFunction} t
 */

/**
 * @class
 * App Page Hooks
 * Instance name: appPagesHooksApi.
 
   Modifies the appearance and functionality of the app pages.
 * @example
 * externalCodeSetup.appPagesHooksApi.METHOD_NAME
 */
export class AppPagesApi {
	CoursesWidgetComponent = null;
	/**
	 * You can use this filter to set a component that displays course widgets in other app pages such as in a home screen.
	 * Do keep in mind that this hook overrides the components you use in the Course Categories screen and enables you to have more design flexibility to the courses section.
	 * So if you want to change only the widget in any app page course options, you refer to our documentation on `coursesHooksApi.WidgetItemCourseComponent`.
	 * @method
	 * @param {?React.ComponentType<CoursesWidgetComponentProps>} CoursesWidgetComponent
	 * @example <caption>Display a promotional banner in place of the widget items</caption>
	 * //In custom_code/components/CoursesWidget.js
	 * import React from 'react';
	 * import { View, Alert } from 'react-native';
	 * import { globalStyle } from "@src/styles/global";
	 * import { useSelector } from "react-redux"; //use useSelector to get state from redux
	 * import WidgetTitle from "@src/components/Widgets/WidgetTitle"; //Use BuddyBoss WidgetTitle component
	 * import { TouchableOpacity } from 'react-native-gesture-handler';
	 * import FastImage from 'react-native-fast-image';
	 * const CoursesWidget = (props) => {
	 *    const globalStyles = useSelector((state) => globalStyle(state.config.styles)) // Get style from redux
	 *    const { colors, global } = globalStyles;
	 *
	 *    return (<View
	 *        style={[
	 *            global.widget,
	 *            {
	 *                backgroundColor: props.bgColor,
	 *                borderBottomColor: colors.borderColor
	 *            }
	 *            ]}
	 *         >
	 *        <View style={global.widgetInner}>
	 *
	 *            //Use BB component that can display Courses title and a See all link
	 *            <WidgetTitle
	 *                colors={colors}
	 *                global={global}
	 *                style={{ marginTop: 5 }}
	 *                title={props.title}
	 *                seeMoreHidden={false}
	 *                seeMoreHandler={props.onCourseSeeAllClick} //Use props passed to redirect to all courses screen
	 *                seeMoreLabel={props.t("home:seeAllCourses")}
	 *            />
	 *
	 *             //Display a promotional banner here
	 *             <View>
	 *                 <TouchableOpacity onPress={() => Alert.alert("Redirecting you to our best selling courses...")}>
	 *                     <FastImage
	 *                         style={{ width: "auto", height: 200 }}
	 *                         source={{ uri: "https://link-to-image.png" }} />
	 *                 </TouchableOpacity>
	 *             </View>
	 *         </View>
	 *      </View>)
	 * }
	 *
	 * export default CoursesWidget;
	 *
	 *
	 * //In custom_code/index.js...
	 *
	 *  ...
	 *
	 *  import CoursesWidget from "./components/CoursesWidget";
	 *  export const applyCustomCode = externalCodeSetup => {
	 *    externalCodeSetup.appPagesHooksApi.setCoursesWidgetComponent((props) => <CoursesWidget {...props} />);
	 *  };
	 *
	 */
	setCoursesWidgetComponent = CoursesWidgetComponent => {
		this.CoursesWidgetComponent = CoursesWidgetComponent;
	};

	ActivitiesWidgetComponent = null;
	/**
	 * It is used to modify the appearance and structure of the activities block of an app page.
	 * You can set a component to display various activities widgets in your app pages similar to the ones you have in your home screen.
	 * @method
	 * @param {?React.ComponentType<ActivitiesWidgetComponentProps>} ActivitiesWidgetComponent
	 * @example <caption>Feature an activity</caption>
	 * //In custom_code/components/ActivitiesWidget.js
	 *
	 * import React from 'react';
	 * import { View } from 'react-native';
	 * import { globalStyle } from "@src/styles/global";
	 * import { useSelector } from "react-redux"; //use useSelector to get state from redux
	 * import WidgetTitle from "@src/components/Widgets/WidgetTitle"; //Use BuddyBoss WidgetTitle component
	 * import FastImage from 'react-native-fast-image';
	 * import { ItemTitle } from "@src/components/TextComponents"; //Use BuddyBoss ItemTitle component
	 * const ActivitiesWidget = (props) => {
	 *    const globalStyles = useSelector((state) => globalStyle(state.config.styles)) // Get style from redux
	 *    const { colors, global } = globalStyles;
	 *
	 *    const featuredActivity = props.activities[0];
	 *
	 *    return (<View
	 *        style={[
	 *            global.widget,
	 *            {
	 *                backgroundColor: props.bgColor,
	 *                borderBottomColor: colors.borderColor
	 *            }
	 *        ]}
	 *    >
	 *        <View style={global.widgetInner}>
	 *
	 *            <WidgetTitle
	 *                colors={colors}
	 *                global={global}
	 *                style={{ marginTop: 5 }}
	 *                title={"Featured Activity"}
	 *                seeMoreHidden={false}
	 *                seeMoreHandler={props.onActivitiesSeeAllClick} //Use props passed to redirect to "all activities" screen
	 *                seeMoreLabel={"See all activities"}
	 *            />
	 *
	 *            <View>
	 *                    <FastImage
	 *                        style={{ width: "auto", height: 200 }}
	 *                        source={{ uri: featuredActivity.bp_media_ids[0].url }} />
	 *
	 *                    <View style={{marginTop: 10, marginLeft: 20}}>
	 *                      <ItemTitle global={global}>Author: {featuredActivity.name} </ItemTitle>
	 *                    </View>
	 *            </View>
	 *        </View>
	 *    </View>)
	 * }
	 *
	 * export default ActivitiesWidget;
	 *
	 * //In custom_code/index.js
	 *
	 * ...
	 *
	 * import ActivitiesWidget from "./components/ActivitiesWidget";
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.appPagesHooksApi.setActivitiesWidgetComponent( (props) => <ActivitiesWidget {...props} />);
	 * };
	 */
	setActivitiesWidgetComponent = ActivitiesWidgetComponent => {
		this.ActivitiesWidgetComponent = ActivitiesWidgetComponent;
	};

	ActivitiesItemWidgetComponent = null;
	/**
	 * It is used to modify the appearance and structure of the activities widget item of an app page.
	 * @method
	 * @param {?React.ComponentType<ActivitiesItemWidgetComponentProps>} ActivitiesItemWidgetComponent
	 * @example <caption>Use the default widget component and also modify the content display</caption>
	 *
	 * //In custom_code/components/ActivitiesItemWidget.js...
	 *
	 * import React from "react";
	 * import { View, StyleSheet, Text } from "react-native";
	 * import AppAvatar from "@src/components/AppAvatar";
	 * import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
	 * import { getAvatar } from "@src/utils";
	 * import { dateRenderer, spanRenderer } from "@src/utils/htmlRender";
	 * import { FontWeights } from "@src/styles/global";
	 * import { stripActivityTags } from "@src/utils/buddypress";
	 * import HTML from "react-native-render-html";
	 * import ActivityPrivacyButton from "@src/components/Activity/Privacy/ActivityPrivacyButton";
	 *
	 * const ActivityHeader = (props) => {
	 *
	 *    const {
	 *        user,
	 *        item,
	 *        global,
	 *        colors,
	 *        tagsStyles,
	 *        attemptDeepLink,
	 *        showAvatar,
	 *        style,
	 *        textColor,
	 *        setItemHeight = () => { },
	 *        onChangePrivacy,
	 *        privacyModalVisible,
	 *        contentWrapperStyle,
	 *        avatarSize,
	 *        hidePrivacy
	 *    } = props;
	 *
	 *    const lightText = colors.descLightTextColor;
	 *
	 *    let activityContent = item.action;
	 *
	 *    //(The following codes are examples only and can be safely removed from the component)
	 *    //Change the display content of the activity item.
	 *    const status = `<span>(User status: verified)</span>`; //Create html element for displaying verified status
	 *    activityContent += status;
	 *    //End
	 *
	 *    let avatarName = item?.user?.name || "";
	 *    if (item?.user?.id === user?.id) avatarName = user.name; // user is unavailable during guest login
	 *
	 *    const showPrivacy =
	 *        !hidePrivacy &&
	 *        item.can_edit &&
	 *        (item.type === "activity_update" || item.type === "activity_comment") &&
	 *        item.component !== "groups";
	 *
	 *    const onLayout = ({
	 *        nativeEvent: {
	 *            layout: { height }
	 *        }
	 *    }) => {
	 *        setItemHeight(height);
	 *    };
	 *
	 *    const tColor = textColor || colors.textColor;
	 *
	 *    return (
	 *        <View style={[global.row, styles.header, style]}>
	 *            {showAvatar && (
	 *                <AppTouchableOpacity onPress={item.authorClick}>
	 *                    <AppAvatar
	 *                        userId={item.user.user_id}
	 *                        size={avatarSize || 40}
	 *                        name={avatarName}
	 *                        source={
	 *                            item.avatarUrl
	 *                                ? { uri: getAvatar(item.avatarUrl, 96) }
	 *                                : {fontIconName: "user", weight: 300}
	 *                        }
	 *                    />
	 *                </AppTouchableOpacity>
	 *            )}
	 *            <View
	 *                onLayout={onLayout}
	 *                style={[
	 *                    styles.text,
	 *                    { marginLeft: showAvatar ? 10 : 0 },
	 *                    contentWrapperStyle
	 *                ]}
	 *            >
	 *                <HTML
	 *                    classesStyles={{ "activity-to": { marginHorizontal: 3 } }}
	 *                    tagsStyles={{
	 *                        ...tagsStyles,
	 *                        rawtext: {
	 *                            ...global.activityHtmlrawtext,
	 *                            color: tColor
	 *                        },
	 *                        p: { ...global.activityHtmlp, color: tColor },
	 *                        a: {
	 *                            ...global.activityHtmla,
	 *                            color: tColor,
	 *                            textDecorationLine: "none"
	 *                        }
	 *                    }}
	 *                    baseFontStyle={Object.assign(
	 *                        {},
	 *                        global.activityHtml,
	 *                        textColor ? { color: textColor } : {}
	 *                    )}
	 *                    html={stripActivityTags(activityContent)}
	 *                    onLinkPress={attemptDeepLink(false)}
	 *                    renderers={{
	 *                        a: dateRenderer,
	 *                        span: spanRenderer
	 *                    }}
	 *                />
	 *
	 *                <Text style={[global.activityDate, { color: lightText, marginTop: 3 }]}>
	 *                    {item.dateRecorded}
	 *                </Text>
	 *            </View>
	 *            {showPrivacy &&
	 *                !!item.privacy &&
	 *                item.privacy !== "media" && (
	 *                    <ActivityPrivacyButton
	 *                        privacyModalVisible={privacyModalVisible}
	 *                        privacy={item.privacy}
	 *                        onPress={onChangePrivacy}
	 *                        colors={colors}
	 *                        global={global}
	 *                        style={{ width: 18, height: 13 }}
	 *                    />
	 *                )}
	 *        </View>
	 *    );
	 * };
	 *
	 * const styles = StyleSheet.create({
	 *    item: {},
	 *    header: {
	 *        alignItems: "flex-start",
	 *        justifyContent: "space-between",
	 *        marginBottom: 11
	 *    },
	 *    text: {
	 *        flex: 1
	 *    }
	 * });
	 *
	 * export default ActivityHeader;
	 *
	 * //In custom_code/index.js..
	 *
	 * ...
	 * import ActivitiesItemWidget from "./components/ActivitiesItemWidget";
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.appPagesHooksApi.setActivitiesItemWidgetComponent( (props) => <ActivitiesItemWidget {...props} />);
	 * }
	 */
	setActivitiesItemWidgetComponent = ActivitiesItemWidgetComponent => {
		this.ActivitiesItemWidgetComponent = ActivitiesItemWidgetComponent;
	};

	TopicsWidgetComponent = null;
	/**
	 * It is used to modify the appearance and structure of the topics/discussions block of an app page.
	 * @method
	 * @param {?React.ComponentType<TopicsWidgetComponentProps>} TopicsWidgetComponentProps
	 * @example <caption>Use the default topics widget component but without the "See all" link</caption>
	 *
	 * //In custom_code/components/TopicWidget.js
	 *
	 * import React from "react";
	 * import {View} from "react-native";
	 * import WidgetItemTopic from "@src/components/Widgets/WidgetItemTopic";
	 * import {topicToViewModel} from "@src/utils/index";
	 * import withGlobalStyles from "@src/components/hocs/withGlobalStyles";
	 * import WidgetTitleIcon from "@src/components/Widgets/WidgetTitleIcon";
	 * import WidgetTitle from "@src/components/Widgets/WidgetTitle";
	 * import {compose} from "recompose";
	 * import {bindActionCreators} from "redux";
	 * import * as TopicActions from "@src/actions/topics";
	 * import withProfileNavigation from "@src/components/hocs/withProfileNavigation";
	 * import {useDispatch} from "react-redux";
	 *
	 * const TopicWidget = (props) => {
	 *
	 *    const dispatch = useDispatch();
	 *
	 *    const topicActions = bindActionCreators(TopicActions, dispatch);
	 *
	 *    const {
	 *        global,
	 *        colors,
	 *        t,
	 *        bgColor,
	 *        icon,
	 *        toUserBasedOnSettings,
	 *        lastItem,
	 *        onTopicSeeAllClick,
	 *        title,
	 *        topics
	 *    } = props;
	 *
	 *    const textColor = props.parentStyle?.textColor;
	 *
	 *    if (!topics || !Array.isArray(topics) || topics.length === 0) return null;
	 *
	 *    const WidgetIcon = <WidgetTitleIcon icon={icon} color={colors.textColor} />;
	 *
	 *    return (
	 *        <View style={[global.widget, {backgroundColor: bgColor}]}>
	 *            <View style={global.widgetInner}>
	 *                <WidgetTitle
	 *                    colors={colors}
	 *                    global={global}
	 *                    WidgetIcon={WidgetIcon}
	 *                    textColor={textColor}
	 *                    title={title}
	 *                    seeMoreHidden={true}
	 *                    seeMoreHandler={onTopicSeeAllClick}
	 *                    seeMoreLabel={t("home:seeAllTopics")}
	 *                />
	 *                <View style={global.widgetContent}>
	 *                    {topics.map((topic, index) => {
	 *                        const viewModel = topicToViewModel(topic, {
	 *                            topicActions,
	 *                            toUserBasedOnSettings,
	 *                            t
	 *                        });
	 *                        return (
	 *                            <WidgetItemTopic
	 *                                isLast={index + 1 === topics.length}
	 *                                key={topic.id}
	 *                                topic={viewModel}
	 *                                colors={colors}
	 *                                global={global}
	 *                                textColor={textColor}
	 *                            />
	 *                        );
	 *                    })}
	 *                </View>
	 *            </View>
	 *
	 *            {!lastItem && <View style={global.widgetBorder} />}
	 *        </View>
	 *    );
	 * }
	 *
	 * export default compose(
	 *	withProfileNavigation,
	 *	withGlobalStyles
	 * )(TopicWidget);
	 *
	 * //In custom_code/index.js...
	 *
	 * import TopicWidget from "./components/TopicWidget";
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.appPagesHooksApi.setTopicsWidgetComponent( (props) => <TopicWidget {...props} />);
	 * }
	 *
	 *
	 */
	setTopicsWidgetComponent = TopicsWidgetComponent => {
		this.TopicsWidgetComponent = TopicsWidgetComponent;
	};

	TopicItemWidgetComponent = null;
	/**
	 * It is used to modify the appearance and structure of the topics/discussions widget item of an app page.
	 * @method
	 * @param {?React.ComponentType<TopicItemWidgetComponentProps>} TopicItemWidgetComponent
	 * @example <caption>Add more details to the topic item</caption>
	 *
	 * //In custom_code/components/TopicItemWidget.js...
	 * import React from "react";
	 * import {View, Text, Image, StyleSheet, Platform} from "react-native";
	 * import {getAvatar} from "@src/utils";
	 * import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
	 * import AppAvatar from "@src/components//AppAvatar";
	 * import {titleTrim} from "@src/utils";
	 * const margin = Platform.OS === "ios" ? 16 : 14;
	 *
	 * const TopicItemWidget = ({topic, global, colors, isLast, textColor}) => {
	 *
	 * return (
	 *   <AppTouchableOpacity onPress={topic.toSingle}>
	 *    <View
	 *      style={[
	 *        styles.itemInner,
	 *        styles.border,
	 *        {
	 *           borderBottomColor: isLast ? "transparent" : colors.borderColor,
	 *           marginBottom: isLast ? 0 : margin - 1
	 *        }
	 *      ]}
	 *    >
	 *      <AppTouchableOpacity
	 *        onPress={topic.navigateToProfile ? topic.navigateToProfile : () => {}}
	 *        style={styles.itemAvatarWrap}
	 *      >
	 *        <AppAvatar
	 *          size={40}
	 *          name={topic.author.name}
	 *          source={{
	 *            uri: getAvatar(topic.author.avatar, 78)
	 *          }}
	 *        />
	 *          </AppTouchableOpacity>
	 *            <View
	 *              style={{
	 *                flex: 1
	 *              }}
	 *            >
	 *              <Text
	 *                style={[
	 *                  global.itemTitle,
	 *                  textColor && {color: textColor},
	 *                  {marginBottom: 5, marginTop: 2}
	 *                ]}
	 *              >
	 *                {titleTrim(topic.title)}
	 *              </Text>
	 *              <Text
	 *                style={[
	 *                  textColor && {color: textColor},
	 *                  {marginBottom: 5, marginTop: 2}
	 *                ]}
	 *              >
	 *                {topic.shortContent}
	 *              </Text>
	 *              <View style={global.row}>
	 *                <Text style={global.itemMeta}>{topic.author.name}</Text>
	 *                <View style={global.dotSep} />
	 *                <Text style={global.itemMeta}>{topic.voiceCount}</Text>
	 *                <View style={global.dotSep} />
	 *                <Text style={[global.itemMeta, {flexShrink: 1}]} numberOfLines={1}>
	 *                  {topic.replyCount}
	 *                </Text>
	 *              </View>
	 *            </View>
	 *          </View>
	 *        </AppTouchableOpacity>
	 *   );
	 * };
	 *
	 * export default TopicItemWidget;
	 *
	 * const styles = StyleSheet.create({
	 * 	itemInner: {
	 * 	  alignItems: "flex-start",
	 *    flexDirection: "row"
	 *  },
	 *  itemAvatarWrap: {
	 *    marginRight: 10,
	 *    marginTop: 3
	 *  },
	 *  border: {
	 *    paddingBottom: margin,
	 *    borderBottomWidth: StyleSheet.hairlineWidth
	 *  }
	 * });
	 *
	 * //In custom_code/index.js...
	 *
	 * import TopicItemWidget from "./components/TopicItemWidget"
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.appPagesHooksApi.setTopicItemWidgetComponent((props) => {
	 *    return <TopicItemWidget {...props} />
	 *  });
	 * }
	 */
	setTopicItemWidgetComponent = TopicItemWidgetComponent => {
		this.TopicItemWidgetComponent = TopicItemWidgetComponent;
	};

	homePageTitleIcon = null;
	/**
	 * Set an icon in any of the app pages if the app page is in the main navigation (or bottom navigation bar) at index 0.
	 * It can be used to automatically replace the default Home screen logo which can be found in the BuddyBoss WordPress admin > BuddyBoss App > Branding > Images.
	 * @method
	 * @param {LocalImageSource} icon
	 *
	 * @example
	 * externalCodeSetup.appPagesHooksApi.setHomePageTitleIcon("https://link-to-image.png");
	 */

	setHomePageTitleIcon = icon => {
		this.homePageTitleIcon = icon;
	};

	CoursesWidgetTitle = null;
	/**
	 * You can use this to change the courses widget's title.
	 * @method
	 * @param {?React.ComponentType<CoursesWidgetTitleProps>} CoursesWidgetTitle
	 * @example <caption> Create your own widget title and change how See All button is handled</caption>
	 *
	 * ...
	 *
	 * import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
	 * import Icon from "@src/components/Icon";
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.appPagesHooksApi.setCoursesWidgetTitle((props) => {
	 *
	 *    const {
	 *      colors,
	 *      global,
	 *      style,
	 *      icon,
	 *      title,
	 *      textColor,
	 *      seeMoreHidden,
	 *      seeMoreHandler,
	 *      seeMoreLabel,
	 *      courses,
	 *      t,
	 *      navigation
	 *    } = props;
	 *
	 *    const goToCoursesTab = () => {
	 *      const routeName = "CoursesScreenTabRoute3"; //You can check the name of tab routes by doing a console.log inside the setFilterBottomTabsRoutes hook
	 *      const action = navigation.navigate(routeName);
	 *      navigation.dispatch(action);
	 *    }
	 *
	 *    return <View style={[global.row, global.widgetHeader, style]}>
	 *      <View style={[global.row, { flex: 1 }]}>
	 *
	 *        {icon && typeof icon === "string" ? (
	 *          <Icon
	 *            icon={{ uri: icon }}
	 *            tintColor={colors.textColor}
	 *            styles={{
	 *              marginLeft: 2,
	 *              marginRight: 11,
	 *              height: 19,
	 *              width: 19,
	 *              opacity: 0.45
	 *            }}
	 *          />
	 *        ) : null}
	 *
	 *        <Text
	 *          style={[
	 *            global.widgetTitle,
	 *            textColor && { color: textColor },
	 *            { marginRight: "auto" }
	 *          ]}
	 *        >
	 *          {title}
	 *        </Text>
	 *      </View>
	 *      {!seeMoreHidden && (
	 *        <AppTouchableOpacity
	 *          style={global.widgetSeeLink}
	 *          onPress={() => goToCoursesTab()}
	 *        >
	 *          <Text style={global.seeLink}>{seeMoreLabel}</Text>
	 *        </AppTouchableOpacity>
	 *      )}
	 *    </View>
	 *
	 *  })
	 * }
	 *
	 */
	setCoursesWidgetTitle = CoursesWidgetTitle => {
		this.CoursesWidgetTitle = CoursesWidgetTitle;
	};

	TopicsWidgetTitle = null;
	/**
	 * You can use this to change the topics widget's title.
	 * @method
	 * @param {?React.ComponentType<TopicsWidgetTitleProps>} TopicsWidgetTitle
	 * @example <caption> Use BB WidgetTitle component in a container while modifying some of its props </caption>
	 *
	 * ...
	 *
	 * import WidgetTitle from "@src/components/Widgets/WidgetTitle";
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.appPagesHooksApi.setTopicsWidgetTitle((props) => {
	 *
	 *    const newProps = {
	 *      ...props,
	 *      title: "See all Discussions",
	 *      textColor: "white"
	 *    }
	 *
	 *    return <View style={{backgroundColor: "gray", padding: 10}}>
	 *        <WidgetTitle {...newProps} />
	 *    </View>
	 *
	 *  })
	 * }
	 */
	setTopicsWidgetTitle = TopicsWidgetTitle => {
		this.TopicsWidgetTitle = TopicsWidgetTitle;
	};

	ForumsWidgetTitle = null;
	/**
	 * You can use this to change the forums widget's title.
	 * @method
	 * @param {?React.ComponentType<ForumsWidgetTitleProps>} ForumsWidgetTitle
	 * @example
	 *
	 * ...
	 *
	 * import WidgetTitle from "@src/components/Widgets/WidgetTitle";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.appPagesHooksApi.setForumsWidgetTitle((props) => {
	 *
	 *    const newProps = {
	 *      ...props,
	 *      seeMoreHandler: () => console.log("Change handler function")
	 *    }
	 *
	 *    return <View style={{ backgroundColor: "gray", padding: 10 }}>
	 *      <WidgetTitle {...newProps} />
	 *    </View>
	 *
	 *  })
	 * }
	 */
	setForumsWidgetTitle = ForumsWidgetTitle => {
		this.ForumsWidgetTitle = ForumsWidgetTitle;
	};

	GroupsWidgetTitle = null;
	/**
	 * You can use this to change the groups widget's title.
	 * @method
	 * @param {?React.ComponentType<GroupsWidgetTitleProps>} GroupsWidgetTitle
	 * @example <caption> Display total number of groups from redux state </caption>
	 *
	 * ...
	 *
	 * import {useSelector} from "react-redux";
	 * import WidgetTitle from "@src/components/Widgets/WidgetTitle";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.appPagesHooksApi.setGroupsWidgetTitle((props) => {
	 *
	 *    const count = useSelector(state => state.socialGroups.all.count);
	 *
	 *    const newProps = {
	 *      ...props,
	 *      seeMoreLabel: (count) ? `See all ${count} groups` : `See all`
	 *    }
	 *
	 *    return <WidgetTitle {...newProps} />;
	 *
	 *  })
	 * }
	 */
	setGroupsWidgetTitle = GroupsWidgetTitle => {
		this.GroupsWidgetTitle = GroupsWidgetTitle;
	};

	MembersWidgetTitle = null;
	/**
	 * You can use this to change the members widget's title.
	 * @method
	 * @param {?React.ComponentType<MembersWidgetTitleProps>} MembersWidgetTitle
	 * @example <caption> Hide See All button </caption>
	 *
	 * ...
	 * import WidgetTitle from "@src/components/Widgets/WidgetTitle";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.appPagesHooksApi.setMembersWidgetTitle((props) => {
	 *
	 *    const newProps = {
	 *      ...props,
	 *      seeMoreHidden: true
	 *    }
	 *
	 *    return <WidgetTitle {...newProps} />;
	 *
	 *  })
	 * }
	 */
	setMembersWidgetTitle = MembersWidgetTitle => {
		this.MembersWidgetTitle = MembersWidgetTitle;
	};

	ActivitiesWidgetTitle = null;
	/**
	 * You can use this to change the activities widget's title.
	 * @method
	 * @param {?React.ComponentType<ActivitiesWidgetTitleProps>} ActivitiesWidgetTitle
	 * @example <caption>Add Icon to WidgetTitle</caption>
	 *
	 * ...
	 *
	 * import Icon from "@src/components/Icon";
	 * import WidgetTitle from "@src/components/Widgets/WidgetTitle";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.appPagesHooksApi.setActivitiesWidgetTitle((props) => {
	 *
	 *    const WidgetIconComp = (
	 *      <Icon
	 *        icon={{fontIconName: "thumbs-up", weight: 200}}
	 *        tintColor={props.colors.textColor}
	 *        styles={{
	 *          marginLeft: 2,
	 *          marginRight: 11,
	 *          height: 19,
	 *          width: 19,
	 *          opacity: 0.45
	 *        }}
	 *      />
	 *    );
	 *
	 *    const newProps = {
	 *      ...props,
	 *      WidgetIcon: WidgetIconComp
	 *    }
	 *
	 *    return <WidgetTitle {...newProps} />;
	 *
	 *  })
	 * }
	 */
	setActivitiesWidgetTitle = ActivitiesWidgetTitle => {
		this.ActivitiesWidgetTitle = ActivitiesWidgetTitle;
	};

	NotificationsWidgetTitle = null;
	/**
	 * You can use this to change the notifications widget's title.
	 * @method
	 * @param {?React.ComponentType<NotificationsWidgetTitleProps>} NotificationsWidgetTitle
	 * @example
	 *
	 * ...
	 * import WidgetTitle from "@src/components/Widgets/WidgetTitle";
	 * export const applyCustomCode = externalCodeSetup => {
	 *  externalCodeSetup.appPagesHooksApi.setNotificationsWidgetTitle((props) => {
	 *   return <View style={{backgroundColor: "cyan"}}><WidgetTitle {...props} /></View>;
	 *  })
	 * }
	 *
	 */
	setNotificationsWidgetTitle = NotificationsWidgetTitle => {
		this.NotificationsWidgetTitle = NotificationsWidgetTitle;
	};

	LinksWidgetTitle = null;
	/**
	 * You can use this to change the quick links widget's title.
	 * @method
	 * @param {?React.ComponentType<LinksWidgetTitleProps>} LinksWidgetTitle
	 * @example <caption> Add a Go To Link button which can use deep link handler with the help of HOCs</caption>
	 *
	 * ...
	 *
	 * import { compose } from "recompose";
	 * import {withNavigation} from "@src/components/hocs/withNavigation";
	 * import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
	 * import WidgetTitle from "@src/components/Widgets/WidgetTitle";
	 * import withDeeplinkClickHandler from "@src/components/hocs/withDeeplinkClickHandler";
	 * import withGlobalStyles from "@src/components/hocs/withGlobalStyles"
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  const TouchComponent = (props) => (
	 *    <AppTouchableOpacity
	 *      style={props.global.widgetSeeLink}
	 *      onPress={() => props.attemptDeepLink(false)(null, "https://buddyboss.com")}
	 *    >
	 *      <Text style={props.global.seeLink}>Go To Link</Text>
	 *    </AppTouchableOpacity>
	 *  )
	 *
	 *  const TouchWithHOC = compose(
	 *    withNavigation,
	 *    withDeeplinkClickHandler,
	 *    withGlobalStyles
	 *  )(TouchComponent);
	 *
	 *  externalCodeSetup.appPagesHooksApi.setLinksWidgetTitle((props) => {
	 *
	 *    const {
	 *      global,
	 *      quickLinks,
	 *      textColor,
	 *      title
	 *    } = props;
	 *
	 *    return <View style={[global.row, global.widgetHeader]}>
	 *      <View style={[global.row, { flex: 1 }]}>
	 *
	 *        <Text
	 *          style={[
	 *            global.widgetTitle,
	 *            textColor && { color: textColor },
	 *            { marginRight: "auto" }
	 *          ]}
	 *        >
	 *          {title}
	 *        </Text>
	 *      </View>
	 *      <TouchWithHOC />
	 *    </View>
	 *
	 *  })
	 * }
	 *
	 */
	setLinksWidgetTitle = LinksWidgetTitle => {
		this.LinksWidgetTitle = LinksWidgetTitle;
	};

	TopicsItemWidgetDetailsComponent = null;

	/**
	 * You can use this to change the topic item widget's details.
	 * For example, you can use this to change the title, author, or member count in the widget.
	 * @method
	 * @param {?React.ComponentType<TopicsItemWidgetDetailsComponentProps>} TopicsItemWidgetDetailsComponent
	 * @example
	 *
	 * externalCodeSetup.appPagesHooksApi.setTopicsItemWidgetDetailsComponent(
	 *   props => {
	 *       const {global, styles, topic} = props;
	 *
	 *       return (
	 *           <>
	 *               <Text style={styles.title}>{topic.title}</Text>
	 *               <View style={global.row}>
	 *                   <Text style={global.itemMeta}>{topic.author.name}</Text>
	 *                   <View style={global.dotSep} />
	 *                   <Text style={global.itemMeta}>{topic.voiceCount}</Text>
	 *                   <View style={global.dotSep} />
	 *                   <Text style={styles.replyCount} numberOfLines={1}>
	 *                       {topic.replyCount}
	 *                   </Text>
	 *               </View>
	 *           </>
	 *       );
	 *   }
	 * );
	 *
	 */
	setTopicsItemWidgetDetailsComponent = TopicsItemWidgetDetailsComponent => {
		this.TopicsItemWidgetDetailsComponent = TopicsItemWidgetDetailsComponent;
	};

	CoursesItemWidgetDetailsComponent = null;

	/**
	 * You can use this to change the course item widget's details.
	 * For example, you can use this to change the title or author in the widget.
	 * @method
	 * @param {?React.ComponentType<CoursesItemWidgetDetailsComponentProps>} CoursesItemWidgetDetailsComponent
	 * @example
	 *
	 * import {WidgetItemCourseUserConnected} from "@src/components/Widgets/WidgetItemCourseUser";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *     externalCodeSetup.appPagesHooksApi.setCoursesItemWidgetDetailsComponent(
	 *         props => {
	 *             const {global, colors, styles, course, hideAuthor} = props;
	 *
	 *             return (
	 *                 <View style={global.courseItemContent}>
	 *                     <Text style={styles.title} numberOfLines={1} ellipsizeMode={"tail"}>
	 *                         {course.title}
	 *                     </Text>
	 *                     {!hideAuthor && (
	 *                         <WidgetItemCourseUserConnected
	 *                             lightText={true}
	 *                             global={global}
	 *                             userId={course.authorId}
	 *                             colors={colors}
	 *                         />
	 *                     )}
	 *                 </View>
	 *             );
	 *         }
	 *     );
	 * }
	 *
	 */
	setCoursesItemWidgetDetailsComponent = CoursesItemWidgetDetailsComponent => {
		this.CoursesItemWidgetDetailsComponent = CoursesItemWidgetDetailsComponent;
	};

	BlogItemWidgetDetailsComponent = null;

	/**
	 * You can use this to change the blog item widget's details.
	 * For example, you can use this to change the title or author in the widget.
	 * @method
	 * @param {?React.ComponentType<BlogItemWidgetDetailsComponentProps>} BlogItemWidgetDetailsComponent
	 * @example
	 *
	 * externalCodeSetup.appPagesHooksApi.setBlogItemWidgetDetailsComponent(
	 *   props => {
	 *       const {global, styles, blog} = props;
	 *
	 *       return (
	 *           <View style={global.courseItemContent}>
	 *               <Text style={styles.title} numberOfLines={1} ellipsizeMode={"tail"}>
	 *                   {blog.title}
	 *               </Text>
	 *               <Text style={styles.author} numberOfLines={1} ellipsizeMode={"tail"}>
	 *                   {blog.authorName}
	 *               </Text>
	 *           </View>
	 *       );
	 *   }
	 * );
	 *
	 */
	setBlogItemWidgetDetailsComponent = BlogItemWidgetDetailsComponent => {
		this.BlogItemWidgetDetailsComponent = BlogItemWidgetDetailsComponent;
	};

	BlogWidgetTitle = null;
	/**
	 * You can use this to change the blog widget's title.
	 * @method
	 * @param {React.ComponentType<BlogWidgetTitleProps>} BlogWidgetTitle
	 * @example <caption> Replace the See all text with an icon </caption>
	 *
	 * ...
	 *
	 * import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
	 * import Icon from "@src/components/Icon";
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *
	 *     externalCodeSetup.appPagesHooksApi.setBlogWidgetTitle(props => {
	 *         const {global, title, seeMoreHandler} = props;
	 *
	 *         return (
	 *             <View style={[global.row, global.widgetHeader]}>
	 *                 <View style={[global.row, {flex: 1}]}>
	 *                     <Text style={[global.widgetTitle, {marginRight: "auto"}]}>
	 *                         {title}
	 *                     </Text>
	 *                 </View>
	 *                 <AppTouchableOpacity style={global.widgetSeeLink} onPress={seeMoreHandler}>
	 *                     <Icon
	 *                         icon={{
	 *                             fontIconName: "plus",
	 *                             weight: "300"
	 *                         }}
	 *                         foregroundColor="#fff"
	 *                     />
	 *                 </AppTouchableOpacity>
	 *             </View>
	 *         );
	 *     });
	 * }
	 */
	setBlogWidgetTitle = BlogWidgetTitle => {
		this.BlogWidgetTitle = BlogWidgetTitle;
	};
}