Source

externalCode/activitiesScreen.js

import * as React from "react";

/**
 * @typedef {Object} ActivityViewModel
 * @property {Number} id  Activity id
 * @property {String} action  Description of activity update
 * @property {String} component  Info on where the activity came from such as "groups", "activity"
 * @property {Object} user  User's id and name
 * @property {String} content  Html content of activity to display
 * @property {String} contentStripped  Content of activity to display stripped of html tags
 * @property {Number} parentId  Used for activity relative id
 * @property {Number} firstParentId Used for activity relative id
 * @property {String} type Type of activity. Ex: "activity_update"
 * @property {String} avatarUrl Url to user's avatar
 * @property {Boolean} can_report True if user can report activity
 * @property {Boolean} reported True if user has already reported the activity
 * @property {Boolean} isMine True if activity is from user
 * @property {Boolean} can_comment True if user can comment
 * @property {Boolean} can_delete True if user can delete the activity
 * @property {Boolean} can_favorite True if user can mark activity as favorite
 * @property {Boolean} can_edit True if user can edit the activity
 * @property {Boolean} isFavorite True if activity is marked as favorite
 * @property {Object} activityData Contains more activity data such as groupName if post came from group activity
 * @property {Number} commentCount Number of people commented in the activity
 * @property {Function} authorClick Function that will navigate to profile of the user who posted the activity
 * @property {String} dateRecorded Ex: "a month ago"
 * @property {String} dateRecordedLong Ex: "3 weeks, 6 days ago"
 * @property {Array<Object>} children Activity data related to main activity such as if there are comments in the activity
 * @property {Array<Object>} media Media attached to activity
 * @property {Array} documents Documents attached to activity
 * @property {Array} platformMedia Platform media attached to activity
 * @property {Object} gif Gif information including preview_url, video_url and rendered html
 * @property {Object<Function>} actions Actions for `reply()` and `edit()`
 * @property {String} privacy Privacy setting of the activity
 *
 */

/**
 * @typedef {Object} Button
 * @param {boolean} permissionField Flag that tells should button show or not
 * @param {React.ComponentType<any>} jsx Contains components for Like, Comment and Delete buttons
 */

/**
 * @typedef {Function} ActivityButtonsFilterCallback
 * @param {Array<Button>} buttons Current buttons array
 * @param {ActivityViewModel} item Activity view model
 * @param {Array<string>} actionsList List of allowed actions
 * @param {Object} settings Settings object got from API
 * @return {Array<Button>} Changed array of buttons
 */

/**
 * @typedef {Function} ActivityViewModelFilterCallback
 * @property {ActivityViewModel} viewModel Activity view model
 * @property {Activity} activity Original activity object
 * @property {ActivityModelDependencies} depend Dependencies (functions used to create view model)
 * @return {Object} New view model
 */

/**
 * @typedef {Object} ActivityModelDependencies
 * @property {Object} config App configuration object
 * @property {TranslationFunction} t Translation function
 * @property {Object} actions Object with activity actions
 * @property {boolean} isProfileList Flag that tells if it's the current screen under profile
 * @property {User} currentUser Logged in user
 * @property {ToUserBasedOnSettings} toUserBasedOnSettings Navigate to user function
 */

/**
 * @typedef {Object} ActivityLikeComponentProps
 * @property {LocalImageSource} icon
 * @property {Function} pressHandler Mark activity as favorite
 * @property {String} tintColor Default tint color of activity like button. Changes value depending on if activity is liked or not.
 * @property {Array<Object>} touchableStyle Default styling of the like button container
 * @property {Object} style Default styling of the like button
 * @property {Function} renderText Returns JSX to display text beside the like button
 * @property {ActivityViewModel}
 *
 */

/**
 * @typedef {Object} ActivityHeaderComponentProps
 * @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 deep linking when activity is pressed
 * @property {Number} avatarSize Returns default size of avatar
 * @property {Boolean} hidePrivacy Returns `true` if privacy button should be hidden
 * @property {Function} onChangePrivacy Helper function which is used for changing the activity's privacy
 * @property {Boolean} privacyModalVisible Returns `true` if modal for setting privacy should be visible
 * @property {Object} contentWrapperStyle Returns the default styling for the content wrapper
 * @property {Number} avatarSize The default size of the avatar
 * @property {Boolean} hidePrivacy Returns `true` if privacy indicator should be shown
 * @property {String} profileAvatarType Avatar type to be displayed in the activitypost
 * @property {Boolean} enableProfileGravatar Returns `true` if profile gravatar is enabled
 * @property {String} defaultProfileAvatarType The default profile avatar type
 * @property {String} defaultCustomProfileAvatarImage The default custom profile avatar image
 * @property {String} activitiesFilter Active filter in the activities list
 * @property {Boolean} isGroupScreen Returns `true` if component is being rendered in a group screen
 * @property {Function} renderActivityOptions Function to render activity options
 *
 */

/**
 * @typedef {Function} TransformActivitiesParams
 * @param {FetchActivitiesParams}
 * @return {Object}
 */

/**
 * @typedef {Object} FetchActivitiesParams
 * @see {@link https://www.buddyboss.com/resources/api/#api-Activity-GetBBActivities}
 * @property {String} display_comments Allowed values: `stream`, `threaded`, `false`
 * @property {?String} search Limit results to those matching a string.
 *
 */

/**
 * @typedef {Object} TransformActivityCommentButtons
 * @property {Array<String>} params Default buttons allowed in the ActivityComment component
 */

/**
 * @typedef {Object} BeforeActivitySingleComponentProps
 * @property {ActivityViewModel} item
 * @property {Number} index
 * @property {User} currentUser
 */

/**
 * @typedef {Object} AfterActivitySingleComponentProps
 * @property {ActivityViewModel} item
 * @property {Number} index
 * @property {User} currentUser
 */

/**
 * @typedef {Object} HeaderActionComponentProps
 * @property {Boolean} canCreateActivity Returns `true` if create activity component should be visible
 * @property {Function} onPress Navigates user to the create activity post screen
 * @property {Object} colors App colors
 */

/**
 * @typedef {Object} ActivityImageComponentProps
 * @property {String} thumbnail Url to image's thumbnail
 * @property {String} source Url to image's source
 * @property {Object} styles Default styles
 * @property {String} resizeMode Default resize mode
 */

/**
 * @typedef {Object} AfterActivityContentComponentProps
 * @property {ActivityViewModel} item
 * @property {User} currentUser
 */

/**
 * @typedef {Object} ActivityCommentHeaderComponentProps
 * @property {Object} styles Default styles
 * @property {Function} handleAuthorClick Used for navigating to the author's profile
 * @property {String} username Author's name
 * @property {String} date Comment date
 * @property {Object} item Activity comment details
 */

/**
 * @typedef {Object} ActivityCommentAvatarProps
 * @property {Number} userId User id of the comment author
 * @property {Function} handleAuthorClick Navigates to the author's profile
 * @property {Number} size Default avatar size
 * @property {Object} source Default uri for author's image
 */

/**
 * @class
 * Activities Screen Hooks.
 * Instance name: activitiesScreenApi
 *
 
 * The ActivitiesScreenHooksApi() enables you to modify your activity options on the app activity list screen.
 
   The filters below have a range of options such as adding/changing the action button on or tweaking your ViewModel options in the app. 
 * @example
 * externalCodeSetup.activitiesScreenApi.METHOD_NAME
 */
export class ActivitiesScreenHooksApi {
	/**
	 * @private
	 * @property {ActivityButtonsFilterCallback} activityButtonsFilter
	 */
	activityButtonsFilter = (b, item, a, settings) => b;

	/**
	 * It sets the filter functions so that you can change the "Activity" action buttons/ call-to-action buttons.
	 * The activity buttons for this filter can be used to add or modify buttons include like, comment, or edit buttons in the activity list screen.
	 * @method
	 * @param {ActivityButtonsFilterCallback} activityButtonsFilter Function that changes call-to-action/activity buttons in the activity list screen
	 * @example
	 * ...
	 * import { Text, TouchableOpacity } from 'react-native'
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.activitiesScreenApi.setActivityButtonsFilter((buttons, item, actionsList, settings) => {
	 *
	 *     //Do something onPress
	 *       const onPress = () => {
	 *          //Call api...
	 *     }
	 *
	 *     return [
	 *     ...buttons,
	 *      {
	 *        // use false if it should be hidden.
	 *        // User can also use data from item. For example, instead of static boolean value, user can use `item.can_comment` if button should show if user can also comment
	 *        permissionField: true,
	 *        jsx: (
	 *          <TouchableOpacity onPress={onPress}>
	 *             <Text>Share</Text>
	 *          </TouchableOpacity>
	 *        )
	 *      }]
	 *   })
	 * }
	 */
	setActivityButtonsFilter = activityButtonsFilter => {
		this.activityButtonsFilter = activityButtonsFilter;
	};

	// @deprecated
	ActivityListHeaderComponent = null;
	setActivityListHeaderComponent = ActivityListHeaderComponent => {
		this.ActivityListHeaderComponent = ActivityListHeaderComponent;
	};

	/**
	 * @private
	 * @property {ActivityViewModelFilterCallback} activityToViewModelFilter
	 */
	activityToViewModelFilter = (viewModel, activity, depend) => viewModel;
	/**
	 * A ViewModel object contains a field that the app requires when viewing an activity.
	 * It helps UI-related data to be stored, managed, and configured in a conscious way.
	 * You can use the filter function below to change the current activity viewModel.
	 * For example, some of the fields you can change include `content`, `isMine`, `can_edit`, and `commentCount`.
	 * @method
	 * @param {ActivityViewModelFilterCallback} activityToViewModelFilter Function that changes activity ViewModel
	 * @example
	 *    externalCodeSetup.activitiesScreenApi.setActivityToViewModelFilter((viewModel, activity, depend) => {
	 *
	 *        return {
	 *            ...viewModel,
	 *            //Setting the following below as false will remove the buttons that allows a user to comment, delete, favorite and edit
	 *            can_comment: false,
	 *            can_delete: false,
	 *            can_favorite: false,
	 *            can_edit: false
	 *        }
	 *        return viewModel;
	 *    })
	 */
	setActivityToViewModelFilter = activityToViewModelFilter => {
		this.activityToViewModelFilter = activityToViewModelFilter;
	};

	ActivityLikeComponent = null;
	/**
	 * You can use this hook to replace the default "Like"/"Thumbs up" button to any of your preferred buttons in the Activities List screen.
	 * @method
	 * @param {?React.ComponentType<ActivityLikeComponentProps>} ActivityLikeComponent
	 * @example <caption> Like button changes icon and color when pressed</caption>
	 *
	 * //In custom_code/components/ActivityLikeButton.js...
	 *
	 * import React from "react";
	 * import IconButton from "@src/components/IconButton";
	 *
	 * const ActivityLikeButton = props => {
	 *
	 *    const {
	 *        pressHandler,
	 *        tintColor,
	 *        touchableStyle,
	 *        colors,
	 *        style,
	 *        renderText,
	 *        item } = props;
	 *
	 *    const likedIcon = {fontIconName: "thumbs-up", weight: 300}
	 *    const regularIcon = {fontIconName: "thumbs-up", weight: 400}
	 *
	 *    return (
	 *        <IconButton
	 *            icon={item.isFavorite ? likedIcon : regularIcon}
	 *            pressHandler={pressHandler}
	 *            tintColor={item.isFavorite ? "#A1DAD9" : tintColor}
	 *            touchableStyle={touchableStyle}
	 *            style={style}
	 *            renderText={renderText}
	 *        />
	 *    );
	 * };
	 * export default ActivityLikeButton;
	 *
	 * //In custom_code/index.js...
	 *
	 * ...
	 *
	 * import ActivityLikeButton from './components/ActivityLikeButton';
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.activitiesScreenApi.setActivityLikeComponent(props => <ActivityLikeButton {...props} />)
	 * }
	 *
	 */
	setActivityLikeComponent = ActivityLikeComponent => {
		this.ActivityLikeComponent = ActivityLikeComponent;
	};

	ActivityHeaderComponent = null;
	/**
	 * It is used to modify the appearance and structure of the activities header component in the activities list screen.
	 * @method
	 * @param {?React.ComponentType<ActivityHeaderComponentProps>} ActivityHeaderComponent
	 * @example
	 *
	 * //In custom_code/components/ActivityHeader.js...
	 *
	 * import React from "react";
	 * import {View, StyleSheet, Text, useWindowDimensions} from "react-native";
	 * import AppAvatar from "@src/components/AppAvatar";
	 * import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
	 * import {dateRenderer, spanRenderer} from "@src/utils/htmlRender";
	 * import {stripActivityTags} from "@src/utils/buddypress";
	 * import ActivityPrivacyButton from "@src/components/Activity/Privacy/ActivityPrivacyButton";
	 * import {getProfileImageSource} from "@src/components/Profile/Xprofile/utils";
	 * import {withDefaultProfileImageSettings} from "@src/components/hocs/withDefaultProfileImageSettings";
	 * import CustomHTML from "@src/components/HTML";
	 * import Icon from "@src/components/Icon";
	 * import {filters} from "@src/reducers/activities";
	 * import {BuddyPressScopes} from "@src/services/enums/buddyPress";
	 *
	 * const ActivityHeader = props => {
	 *     const {
	 *         t,
	 *         user,
	 *         item,
	 *         global,
	 *         colors,
	 *         tagsStyles,
	 *         attemptDeepLink,
	 *         showAvatar,
	 *         style,
	 *         textColor,
	 *         setItemHeight = () => {},
	 *         onChangePrivacy,
	 *         privacyModalVisible,
	 *         contentWrapperStyle,
	 *         avatarSize,
	 *         hidePrivacy,
	 *         profileAvatarType,
	 *         enableProfileGravatar,
	 *         defaultProfileAvatarType,
	 *         defaultCustomProfileAvatarImage,
	 *         activitiesFilter,
	 *         isGroupScreen,
	 *         renderActivityOptions
	 *     } = props;
	 *
	 *     const lightText = colors.descLightTextColor;
	 *
	 *     let avatarName = item.user?.name || "";
	 *     const {is_pinned} = item;
	 *     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 showPin = isGroupScreen
	 *         ? item.component === BuddyPressScopes.groups
	 *         : activitiesFilter === filters[0] && item.isGroupPost === false;
	 *
	 *     const onLayout = ({
	 *         nativeEvent: {
	 *             layout: {height}
	 *         }
	 *     }) => {
	 *         setItemHeight(height);
	 *     };
	 *
	 *     const {width} = useWindowDimensions();
	 *
	 *     const tColor = textColor || colors.textColor;
	 *
	 *     return (
	 *         <View style={[global.row, styles.header, style]}>
	 *             {showAvatar && (
	 *                 <AppTouchableOpacity onPress={item.authorClick}>
	 *                     <AppAvatar
	 *                         size={avatarSize || 40}
	 *                         name={avatarName}
	 *                         source={getProfileImageSource(item.user, {
	 *                             avatarType: profileAvatarType,
	 *                             enableGravatar: enableProfileGravatar,
	 *                             defaultAvatarType: defaultProfileAvatarType,
	 *                             defaultCustomAvatarImage: defaultCustomProfileAvatarImage
	 *                         })}
	 *                     />
	 *                 </AppTouchableOpacity>
	 *             )}
	 *             <View
	 *                 onLayout={onLayout}
	 *                 style={[
	 *                     styles.text,
	 *                     {marginLeft: showAvatar ? 10 : 0},
	 *                     contentWrapperStyle
	 *                 ]}
	 *             >
	 *                 <CustomHTML
	 *                     allowedAllTags
	 *                     classesStyles={{"activity-to": {marginHorizontal: 3}}}
	 *                     tagsStyles={{
	 *                         ...tagsStyles,
	 *                         rawtext: {
	 *                             ...global.activityHtmlrawtext,
	 *                             color: tColor
	 *                         },
	 *                         p: {...global.activityHtmlp, color: tColor},
	 *                         a: {
	 *                             ...global.activityHtmla,
	 *                             color: tColor,
	 *                             textDecorationLine: "none"
	 *                         }
	 *                     }}
	 *                     contentWidth={width}
	 *                     baseStyle={Object.assign(
	 *                         {},
	 *                         global.activityHtml,
	 *                         textColor ? {color: textColor} : {}
	 *                     )}
	 *                     renderersProps={{
	 *                         a: {onPress: attemptDeepLink(false)}
	 *                     }}
	 *                     source={{html: stripActivityTags(item.action)}}
	 *                     renderers={{
	 *                         a: dateRenderer,
	 *                         span: spanRenderer
	 *                     }}
	 *                 />
	 *
	 *                 <View style={[global.row, {marginTop: 3}]}>
	 *                     <Text style={[global.activityDate, {color: lightText}]}>
	 *                         {item.dateRecorded} {`${item.is_edited ? `(${t("edited")})` : ""}`}
	 *                     </Text>
	 *                     {showPrivacy &&
	 *                         !!item.privacy &&
	 *                         item.privacy !== "media" && (
	 *                             <ActivityPrivacyButton
	 *                                 hideBorder={true}
	 *                                 privacyModalVisible={privacyModalVisible}
	 *                                 privacy={item.privacy}
	 *                                 onPress={onChangePrivacy}
	 *                                 colors={colors}
	 *                                 global={global}
	 *                             />
	 *                         )}
	 *                 </View>
	 *             </View>
	 *             {showPin &&
	 *                 is_pinned && (
	 *                     <View style={styles.pinContainer}>
	 *                         <Icon
	 *                             icon={{fontIconName: "thumbtack", weight: "400"}}
	 *                             tintColor={colors.textIconColor}
	 *                             size={20}
	 *                         />
	 *                     </View>
	 *                 )}
	 *
	 *             {renderActivityOptions && renderActivityOptions()}
	 *         </View>
	 *     );
	 * };
	 *
	 * const styles = StyleSheet.create({
	 *     item: {},
	 *     header: {
	 *         alignItems: "flex-start",
	 *         justifyContent: "space-between",
	 *         marginBottom: 11
	 *     },
	 *     pinContainer: {
	 *         alignSelf: "flex-start",
	 *         marginTop: 2,
	 *         height: 26,
	 *         width: 26,
	 *         alignItems: "center",
	 *         justifyContent: "center"
	 *     },
	 *     text: {
	 *         flex: 1
	 *     }
	 * });
	 *
	 * export default withDefaultProfileImageSettings(ActivityHeader);
	 *
	 * //In custom_code/index.js..
	 *
	 * ...
	 * import ActivityHeader from "./components/ActivityHeader";
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.activitiesScreenApi.setActivityHeaderComponent(props => <ActivityHeader {...props} />)
	 * }
	 *
	 */
	setActivityHeaderComponent = ActivityHeaderComponent => {
		this.ActivityHeaderComponent = ActivityHeaderComponent;
	};

	fetchParamsFilter = params => params;

	/**
	 * It overrides the parameters that are used to fetch activities in the Activities screen and enables you to add more parameters when fetching an activity so that you can make it as customizable as possible when calling its API.
	 * @method
	 * @param {TransformActivitiesParams} fetchParamsFilter
	 *
	 * @example <caption> Create a custom filter in activities screen </caption>
	 *
	 * //In components/ActivitiesBeforeList.js...
	 *
	 * import React, { useState } from "react";
	 * import { TextInput, View, Button } from 'react-native'
	 * import { useDispatch } from "react-redux";
	 * import { activitiesRequested } from "@src/actions/activities";
	 * import { getExternalCodeSetup } from "@src/externalCode/externalRepo";
	 * import withGlobalStyles from "@src/components/hocs/withGlobalStyles";
	 *
	 * const hook = getExternalCodeSetup().activitiesScreenApi;
	 *
	 * const screenName = "book";
	 *
	 * const filter = "favorites"; //"just-me", "friends", "groups", "favorites", "mentions", "following"
	 * const subfilters = {type: "new_member"}; // "-1", "new_member", "new_avatar", "updated_profile", "activity_update", "activity_comment", "friendship_accepted", "friendship_created", "created_group", "joined_group", "group_details_updated", "bbp_topic_create", "bbp_reply_create"
	 *
	 * const refresh = true; //Set to true to refresh list
	 * const searchTerm = "Tony"
	 *
	 * const ActivitiesBeforeList = (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 [act, setAct] = useState('')
	 *
	 *        const handleSubmit = () => {
	 *
	 *            //Set custom parameters before fetching
	 *            hook.setFetchParamsFilter((props) => {
	 *
	 *                //You can add more parameters such as "subject", "keyword" etc...
	 *                return {
	 *                    ...props,
	 *                    display_comments: false,
	 *                    someActivities: act,
	 *                }
	 *            })
	 *
	 *            //Dispatch redux action to call api using customized filters
	 *            dispatch(activitiesRequested(filter, subfilters, refresh, searchTerm));
	 *
	 *        }
	 *
	 *        return <View style={{ backgroundColor: colors.whiteColor}}>
	 *
	 *            <TextInput
	 *                style={{paddingHorizontal: 20, marginTop: 10, fontSize: 20}}
	 *                autoFocus
	 *                value={act}
	 *                onChangeText={act => setAct(act)}
	 *                placeholder="Search for an Activity"
	 *            />
	 *
	 *            <Button
	 *                onPress={() => handleSubmit()}
	 *                title="Filter"
	 *            />
	 *        </View>
	 *    }
	 *
	 *    return null;
	 *
	 * }
	 *
	 * export default withGlobalStyles(ActivitiesBeforeList);
	 *
	 * //In components/MyCustomScreen.js...
	 * import React from 'react';
	 * import ActivitiesScreen from "@src/containers/Custom/ActivitiesScreen";
	 *
	 * const MyCustomScreen = props => (<ActivitiesScreen {...props} showSearch={false} hideFilters={true} headerHeight={250} />)
	 *
	 *
	 * export default MyCustomScreen;
	 *
	 * //In custom_code/index.js...
	 *
	 * ...
	 *
	 * import ActivitiesBeforeList from "./components/ActivitiesBeforeList";
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *    externalCodeSetup.filterScreenApiHooks.setAfterFilterComponent(ActivitiesBeforeList);
	 *
	 *    externalCodeSetup.navigationApi.addNavigationRoute(
	 *       "book",
	 *       "BookScreen",
	 *       MyCustomScreen,
	 *       "All"
	 *    );
	 *    externalCodeSetup.navigationApi.addNavigationRoute(
	 *       "book",
	 *       "BookScreen",
	 *       MyCustomScreen,
	 *       "Main"
	 *    );
	 * }
	 */
	setFetchParamsFilter = fetchParamsFilter => {
		this.fetchParamsFilter = fetchParamsFilter;
	};

	activityCommentButtonsFilter = params => params;

	/**
	 * It overrides the filters used in the ActivityComment component.
	 * You can use this together with `setActivityButtonsFilter` to add or remove buttons in the ActivityComment component.
	 * @method
	 * @param {TransformActivityCommentButtons} activityCommentButtonsFilter
	 *
	 * @example <caption> Add new buttons in the main activity post and comment activity post </caption>
	 *
	 * ...
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *     externalCodeSetup.activitiesScreenApi.setActivityButtonsFilter(
	 *         (buttons, item, actionsList, settings) => {
	 *
	 *             //Do something onPress
	 *             const onPress = () => {
	 *                 console.log(item);
	 *             };
	 *
	 *             //Add a share "Like" button
	 *             let newButtons = [
	 *                 {
	 *                     id: "reply",
	 *                     permissionField: true,
	 *                     jsx: (
	 *                         <TouchableOpacity onPress={onPress}>
	 *                             <Text>Share</Text>
	 *                         </TouchableOpacity>
	 *                     )
	 *                 },
	 *                 ...buttons
	 *             ];
	 *
	 *             //Replace the "Reply" button and add a new button
	 *             if (item.parentId){
	 *                 newButtons = [
	 *                     {
	 *                         id: "custom",
	 *                         permissionField: true,
	 *                         jsx: (
	 *                             <TouchableOpacity onPress={onPress}>
	 *                                 <Text>Custom | </Text>
	 *                             </TouchableOpacity>
	 *                         )
	 *                     },
	 *                     {
	 *                         id: "reply",
	 *                         permissionField: true,
	 *                         jsx: (
	 *                             <TouchableOpacity onPress={onPress}>
	 *                                 <Text>Reply</Text>
	 *                             </TouchableOpacity>
	 *                         )
	 *                     },
	 *                     buttons[1], //Delete button
	 *                     buttons[2] //Show more button
	 *                 ]
	 *             }
	 *
	 *             return newButtons;
	 *         }
	 *     );
	 *
	 *     //Allow ActivityComment to render the button with the 'custom' id
	 *     externalCodeSetup.activitiesScreenApi.setActivityCommentButtonsFilter(filters => {
	 *         return [
	 *             ...filters,
	 *             'custom'
	 *         ]
	 *     })
	 * }
	 */
	setActivityCommentButtonsFilter = activityCommentButtonsFilter => {
		this.activityCommentButtonsFilter = activityCommentButtonsFilter;
	};

	BeforeActivitySingleComponent = null;

	/**
	 * You can use this hook to add a component before each ActivitySingle component.
	 * @method
	 * @param {?React.ComponentType<BeforeActivitySingleComponentProps>} BeforeActivitySingleComponent
	 * @example <caption> Add a text before the ActivitySingle component for x page </caption>
	 *
	 * ...
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *    externalCodeSetup.activitiesScreenApi.setBeforeActivitySingleComponent(({
	 *        item,
	 *        index,
	 *        currentUser
	 *    }) => {
	 *
	 *        const numberPerPage = 10;
	 *        const page = Math.ceil(index / numberPerPage);
	 *
	 *        if (page < 2){
	 *            return <Text>Hi {currentUser?.name}!</Text>
	 *        }
	 *
	 *        return null;
	 *
	 *    })
	 * }
	 */
	setBeforeActivitySingleComponent = BeforeActivitySingleComponent => {
		this.BeforeActivitySingleComponent = BeforeActivitySingleComponent;
	};

	AfterActivitySingleComponent = null;

	/**
	 * You can use this hook to add a component after each ActivitySingle component.
	 * @method
	 * @param {?React.ComponentType<AfterActivitySingleComponentProps>} AfterActivitySingleComponent
	 * @example
	 *
	 * ...
	 *
	 * externalCodeSetup.activitiesScreenApi.setAfterActivitySingleComponent(props => <Text>Hello World</Text>)
	 */
	setAfterActivitySingleComponent = AfterActivitySingleComponent => {
		this.AfterActivitySingleComponent = AfterActivitySingleComponent;
	};

	HeaderActionComponent = null;

	/**
	 * You can use this hook to customize the "create post" button located at the upper right section of the activities screen.
	 * @method
	 * @param {React.ComponentType<HeaderActionComponentProps>} HeaderActionComponent
	 * @example
	 *
	 * ...
	 *
	 * import IconButton from "@src/components/IconButton";
	 * import AuthWrapper from "@src/components/AuthWrapper";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.activitiesScreenApi.setHeaderActionComponent(
	 *         ({canCreateActivity, onPress, colors}) => {
	 *             return canCreateActivity ? (
	 *                 <AuthWrapper>
	 *                     <IconButton
	 *                         icon={{fontIconName: "pencil", weight: 200}} //pencil, round-filled
	 *                         pressHandler={onPress}
	 *                         tintColor={colors.headerIconColor}
	 *                         style={{
	 *                             height: 28
	 *                         }}
	 *                     />
	 *                 </AuthWrapper>
	 *             ) : null;
	 *         }
	 *     );
	 * }
	 */

	setHeaderActionComponent = HeaderActionComponent => {
		this.HeaderActionComponent = HeaderActionComponent;
	};

	ActivityImageComponent = null;
	/**
	 * You can use this hook to replace an activity image.
	 * For example, you can use this to change the component's dimensions.
	 * @method
	 * @param {?React.ComponentType<ActivityImageComponentProps>} ActivityImageComponent
	 * @example <caption> Allow image to occupy entire image container</caption>
	 *
	 * import ProgressiveImage from "@src/components/ProgressiveImage";
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *
	 *     externalCodeSetup.activitiesScreenApi.setActivityImageComponent(({
	 *         thumbnail,
	 *         source,
	 *         styles,
	 *         resizeMode
	 *     }) => {
	 *
	 *         const customStyle = {
	 *             ...styles.container,
	 *             width: '100%'
	 *         }
	 *
	 *         return (
	 *             <ProgressiveImage
	 *                 thumbnailSource={{
	 *                     uri: thumbnail
	 *                 }}
	 *                 source={{
	 *                     uri: source
	 *                 }}
	 *                 style={styles.image}
	 *                 containerStyle={customStyle}
	 *                 resizeMode='cover'
	 *             />
	 *         );
	 *     });
	 * }
	 *
	 */
	setActivityImageComponent = ActivityImageComponent => {
		this.ActivityImageComponent = ActivityImageComponent;
	};

	AfterActivityContentComponent = null;
	/**
	 * You can use this hook to add a component after each ActivityContent component.
	 * @method
	 * @param {React.ComponentType<AfterActivityContentComponentProps>} AfterActivityContentComponent
	 * @example
	 *
	 * ...
	 *
	 *  externalCodeSetup.activitiesScreenApi.setAfterActivityContentComponent(
	 *   props => (
	 *       <TouchableOpacity>
	 *           <View style={{marginVertical: 5}}>
	 *               <Text style={{fontSize: 13}}>John and 35 others liked this post</Text>
	 *           </View>
	 *       </TouchableOpacity>
	 *   )
	 * );
	 *
	 */
	setAfterActivityContentComponent = AfterActivityContentComponent => {
		this.AfterActivityContentComponent = AfterActivityContentComponent;
	};

	ActivityCommentHeaderComponent = null;
	/**
	 * You can use this to customize the author name and post date of the activity comments.
	 * For example, you can add a "verified" badge beside the author's name using this hook.
	 * @method
	 * @param {?React.ComponentType<ActivityCommentHeaderComponentProps>} ActivityCommentHeaderComponent
	 * @example
	 *
	 * externalCodeSetup.activitiesScreenApi.setActivityCommentHeaderComponent(
	 *   props => {
	 *       const {styles, handleAuthorClick, username, date} = props;
	 *       return (
	 *           <View style={styles.textContainer}>
	 *               <Text style={styles.textInnerContainer}>
	 *                   <Text onPress={handleAuthorClick} style={styles.text}>
	 *                       {username}
	 *                   </Text>
	 *                   {"  "}
	 *                   {date}
	 *               </Text>
	 *           </View>
	 *       );
	 *   }
	 * );
	 *
	 */
	setActivityCommentHeaderComponent = ActivityCommentHeaderComponent => {
		this.ActivityCommentHeaderComponent = ActivityCommentHeaderComponent;
	};

	ActivityCommentAvatar = null;
	/**
	 * You can use this to customize the author avatar of the activity comments.
	 * @method
	 * @param {React.ComponentType<ActivityCommentAvatarProps>} ActivityCommentAvatar
	 * @example
	 *
	 * ...
	 *
	 * import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
	 * import AppAvatar from "@src/components/AppAvatar";
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *
	 *     externalCodeSetup.activitiesScreenApi.setActivityCommentAvatar(
	 *         ({handleAuthorClick, userId, size, source}) => (
	 *             <AppTouchableOpacity onPress={handleAuthorClick}>
	 *                 <AppAvatar
	 *                     userId={userId}
	 *                     size={size}
	 *                     source={source}
	 *                 />
	 *             </AppTouchableOpacity>
	 *         )
	 *     );
	 * }
	 *
	 */
	setActivityCommentAvatar = ActivityCommentAvatar => {
		this.ActivityCommentAvatar = ActivityCommentAvatar;
	};
}