Class

ActivitiesScreenHooksApi

ActivitiesScreenHooksApi()

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.

Constructor

# new ActivitiesScreenHooksApi()

Example
externalCodeSetup.activitiesScreenApi.METHOD_NAME

Methods

# setActivityButtonsFilter(activityButtonsFilter)

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.

Parameters:
Name Type Description
activityButtonsFilter ActivityButtonsFilterCallback

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>
       )
     }]
  })
}

# setActivityCommentAvatar(ActivityCommentAvatar)

You can use this to customize the author avatar of the activity comments.

Parameters:
Name Type Description
ActivityCommentAvatar React.ComponentType.<ActivityCommentAvatarProps>
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>
        )
    );
}

# setActivityCommentButtonsFilter(activityCommentButtonsFilter)

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.

Parameters:
Name Type Description
activityCommentButtonsFilter TransformActivityCommentButtons
Example

Add new buttons in the main activity post and comment activity post

...

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'
        ]
    })
}

# setActivityCommentHeaderComponent(ActivityCommentHeaderComponentnullable)

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.

Parameters:
Name Type Attributes Description
ActivityCommentHeaderComponent React.ComponentType.<ActivityCommentHeaderComponentProps> <nullable>
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>
      );
  }
);

# setActivityHeaderComponent(ActivityHeaderComponentnullable)

It is used to modify the appearance and structure of the activities header component in the activities list screen.

Parameters:
Name Type Attributes Description
ActivityHeaderComponent React.ComponentType.<ActivityHeaderComponentProps> <nullable>
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} />)
}

# setActivityImageComponent(ActivityImageComponentnullable)

You can use this hook to replace an activity image. For example, you can use this to change the component's dimensions.

Parameters:
Name Type Attributes Description
ActivityImageComponent React.ComponentType.<ActivityImageComponentProps> <nullable>
Example

Allow image to occupy entire image container

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'
            />
        );
    });
}

# setActivityLikeComponent(ActivityLikeComponentnullable)

You can use this hook to replace the default "Like"/"Thumbs up" button to any of your preferred buttons in the Activities List screen.

Parameters:
Name Type Attributes Description
ActivityLikeComponent React.ComponentType.<ActivityLikeComponentProps> <nullable>
Example

Like button changes icon and color when pressed

//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} />)
}

# setActivityToViewModelFilter(activityToViewModelFilter)

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.

Parameters:
Name Type Description
activityToViewModelFilter ActivityViewModelFilterCallback

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

# setAfterActivityContentComponent(AfterActivityContentComponent)

You can use this hook to add a component after each ActivityContent component.

Parameters:
Name Type Description
AfterActivityContentComponent React.ComponentType.<AfterActivityContentComponentProps>
Example
...

 externalCodeSetup.activitiesScreenApi.setAfterActivityContentComponent(
  props => (
      <TouchableOpacity>
          <View style={{marginVertical: 5}}>
              <Text style={{fontSize: 13}}>John and 35 others liked this post</Text>
          </View>
      </TouchableOpacity>
  )
);

# setAfterActivitySingleComponent(AfterActivitySingleComponentnullable)

You can use this hook to add a component after each ActivitySingle component.

Parameters:
Name Type Attributes Description
AfterActivitySingleComponent React.ComponentType.<AfterActivitySingleComponentProps> <nullable>
Example
...

externalCodeSetup.activitiesScreenApi.setAfterActivitySingleComponent(props => <Text>Hello World</Text>)

# setBeforeActivitySingleComponent(BeforeActivitySingleComponentnullable)

You can use this hook to add a component before each ActivitySingle component.

Parameters:
Name Type Attributes Description
BeforeActivitySingleComponent React.ComponentType.<BeforeActivitySingleComponentProps> <nullable>
Example

Add a text before the ActivitySingle component for x page

...

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;

   })
}

# setFetchParamsFilter(fetchParamsFilter)

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.

Parameters:
Name Type Description
fetchParamsFilter TransformActivitiesParams
Example

Create a custom filter in activities screen

//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"
   );
}

# setHeaderActionComponent(HeaderActionComponent)

You can use this hook to customize the "create post" button located at the upper right section of the activities screen.

Parameters:
Name Type Description
HeaderActionComponent React.ComponentType.<HeaderActionComponentProps>
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;
        }
    );
}