import * as React from "react";
/**
* @typedef {Object} Member
*/
/**
* @typedef {Object} FeatureValues
*/
/**
* @typedef {Function} TransformMemberViewModelCallback
* @param {MemberViewModel} viewModel
* @param {Object} item Member data from API
* @param {ToUserBasedOnSettings} toUserBasedOnSettings
* @param {Boolean} isOwnAccount Returns `true` if item is logged in user's own account
* @param {Boolean} isProfile
* @return {Object}
*/
/**
* @typedef {Function} TransformMemberActionsCallback
* @param {Array<ButtonConfig>}
* @return {Array<ButtonConfig>}
*/
/**
* @typedef {Object} ButtonConfig
* @property {?String} permissionField
* @property {String} statusField
* @property {Array<ButtonFlow>} flow
*/
/**
* @typedef {Function} CheckProperty
* @param {Object} object View model
* @return {Boolean}
*/
/**
* Redux action to dispatch or simple function to execute
* @typedef {Function} DoFunction
* @param {Object} item - View model
* @param {?String} value - Value from prompt popup input
* @return {Function}
* @example
* doFunction: (item, value) => () => { navigateToReport(item.id) } // `navigateToReport` is function that we dont want to dispatch on redux
* doFunction: (item, value) =>
documentUpdateRequest(item, {
title: value,
group_id: item.groupId,
folder_id: item.folderId
}) // `documentUpdateRequest` is redux action to dispatch
*/
/**
* Get error from redux state
* @typedef {Function} GetError
* @param {Object} store - Whole redux store
* @return {any}
* @example
* state => state.forums.unsubscribe.error
*/
/**
* @typedef {Object} ActionButton
* @property {?Number} icon - Image loaded via "require"
* @property {String} label - Translatable string
* @property {DoFunction} doFunction - Redux action to dispatch or simple function to execute
* @property {?GetError} getError - Redux action to dispatch or simple function to execute
* @property {?Boolean} isNavigation - If true button will not show spinner when changing state
* @property {?String} promptMessage - If set prompt popup with input will show on action executed
* @property {Function} promptDefaultValue
*/
/**
* @typedef {Object} ButtonFlow
* @property {CheckProperty} check Checks for a view model property and checks if it should show the button
* @property {Array} buttons Buttons to show if check passes
*/
/**
* @typedef {Function} ToUserBasedOnSettings
* @param {?String} selectedTabId - Profile subscreen idenitifier
* @param {User} User - User to navigate to
* @param {Object} params - Params to send through route
*/
/**
* @typedef {Object} MemberItemComponentProps
* @property { ?Number } groupId Group Id
* @property { ?Boolean } groupMember Returns `true` if user is a member of the group
* @property { Object } colors App colors
* @property { Object } global App global style
* @property { MemberViewModel } item
* @property { Number } index Index of the item in the list
* @property { TranslationFunction } t
* @property { Array } actions Member actions
* @property { Object } settings App settings
* @property { Boolean } lastItem Returns `true` if it is the last element in the list
* @property { String } locale
* @property { Object } rawData Member data from API
*/
/**
* @typedef {Function} TransformMembersParams
* @param {FetchMembersParams}
* @return {Object}
*/
/**
* @typedef {Object} FetchMembersParams
* @see {@link https://www.buddyboss.com/resources/api/#api-Members-GetBBMembers}
* @property {Number} per_page Maximum number of items to be returned in result set.
* @property {Number} page Current page of the collection.
* @property {String} scope Limit result set to items with a specific scope.
* @property {String} search Limit results to those matching a string.
* @property {String} type Shorthand for certain orderby/order combinations.
*/
/**
* @typedef {Function} TransformMembersSubFiltersFilterCallback
* @param {Object}
* @return {Object}
*/
/**
* @class
* Members Screen Hooks.
* Instance name: membersListHooksApi
You can customize how the members list screen such as replacing item components, modifying call to action buttons and more.
* @example
* externalCodeSetup.membersListHooksApi.METHOD_NAME
*/
export class MembersListHooksApi {
// filters and changes screen navigationOptions
memberViewModelFilter = (
viewModel,
item,
toUserBasedOnSettings,
currentUserId,
isProfile
) => viewModel;
/**
* Sets the callback function that can change an existing member view model object.
* @method
* @param {TransformMemberViewModelCallback} memberViewModelFilter
* @example
* externalCodeSetup.membersListHooksApi.setMemberViewModelFilter((props) => {
* return {...props, date: new Date()}
* })
*/
setMemberViewModelFilter = memberViewModelFilter => {
this.memberViewModelFilter = memberViewModelFilter;
};
// filters and changes action buttons list
actionsFilter = membersActions => membersActions;
/**
* It sets the filter function to modify the member action buttons array such as removing an action button from the list.
* @method
* @param {TransformMemberActionsCallback} actionsFilter
* @example <caption>The following example shows how to remove a button from the members list.</caption>
* externalCodeSetup.membersListHooksApi.setActionsFilter((buttonConfig) => {
* return buttonConfig.splice(0, 1);
* })
*/
setActionsFilter = actionsFilter => {
this.actionsFilter = actionsFilter;
};
/**
* @deprecated
* hides the BuddyPressListFilters bellow header in MembersList
*/
shouldHideFilterComponent = false;
hideFilterComponent = () => {
this.shouldHideFilterComponent = true;
};
MemberItemComponent = null;
/**
* Replaces a member item component in the members list.
* For example, you can add more information about the members as shown in the example below.
* @method
* @param {?React.ComponentType<MemberItemComponentProps>} MemberItemComponent
* @example <caption> Use default member item structure and add more information about the member </caption>
*
* //In custom_code/components/MemberItem.js
*
* import React, { useMemo } from "react";
* import { View, StyleSheet, Text, ActivityIndicator } from "react-native";
*
* //Load BuddyBoss components and helper functions
* import AppAvatar from "@src/components/AppAvatar";
* import { ItemTitle } from "@src/components//TextComponents";
* import Icon from "@src/components/Icon";
* import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
* import { Settings } from "@src/reducers/config";
* import AuthWrapper from "@src/components/AuthWrapper";
* import { withSettings } from "@src/components/hocs/withSettings";
* import ActionSheetButton from "@src/components/ActionButtons/ActionSheetButton";
* import { formatDate, displayUserName } from "@src/utils";
* import { GUTTER } from "@src/styles/global";
*
* const MemberItem = props => {
* const {
* item,
* global,
* actions,
* index,
* colors,
* settings,
* lastItem,
* groupId,
* locale,
* t,
* showLoader = false,
* rawData
* } = props;
*
* const userMeta = useMemo(() => {
* if (!!groupId && item.groupJoiningDate) {
* return `${t("members:joined")} ${formatDate(locale)(
* item.groupJoiningDate
* )}`;
* } else if (settings[Settings.ENABLE_MEMBER_TYPE_DISPLAY] && item.type) {
* return item.type;
* } else if (item.nicename) {
* return displayUserName(item.nicename);
* }
* });
*
* return (
* <AppTouchableOpacity
* onPress={item.onClick}
* style={[styles.item, index === 0 ? { paddingTop: 0 } : {}]}
* >
* <View style={[global.row, styles.itemInner]}>
* <AppAvatar
* size={64}
* name={item.fullname}
* source={{
* uri: item.avatarUrl
* }}
* />
* <View
* style={[global.row, !lastItem && global.bottomBorder, styles.text]}
* >
* <View style={{ flex: 1 }}>
* <ItemTitle global={global} style={{ marginBottom: 3 }}>
* {item.fullname}
* </ItemTitle>
* {!!userMeta && <Text style={global.itemMeta}>{userMeta}</Text>}
*
* //Add more data for member...
* <Text>Link to user profile: {rawData?.link}</Text>
* <Text>Last Activity: {rawData?.last_activity}</Text>
* <Text>Friendship status: {rawData?.friendship_status}</Text>
* </View>
* {showLoader ? (
* <ActivityIndicator size={"small"} color={colors.highlightColor} />
* ) : (
* <ActionSheetButton
* headerProps={{
* id: item.id,
* title: item.fullname,
* avatarSource: { uri: item.avatarUrl },
* onClick: item.onClick
* }}
* object={item}
* actionButtons={actions}
* global={global}
* colors={colors}
* t={t}
* renderButton={() => (
* <AuthWrapper actionOnGuestLogin={"hide"}>
* <Icon
* icon={{fontIconName: "ellipsis-h", weight: 300}}
* tintColor={colors.textIconColor}
* styles={{
* margin: 5,
* height: 16
* }}
* />
* </AuthWrapper>
* )}
* />
* )}
* </View>
* </View>
* </AppTouchableOpacity>
* );
* };
*
* const styles = StyleSheet.create({
* item: {
* flex: 1,
* paddingHorizontal: GUTTER
* },
* itemInner: {
* flex: 1,
* justifyContent: "space-between"
* },
* text: {
* paddingVertical: 24,
* marginLeft: 14,
* justifyContent: "space-between",
* flex: 1
* },
* buttonsWrap: {}
* });
*
* export default withSettings(MemberItem);
*
* //In custom_code/index.js
*
* ...
*
* import MemberItem from "./components/MemberItem";
* export const applyCustomCode = externalCodeSetup => {
* externalCodeSetup.membersListHooksApi.setMemberItemComponent(props => {
* return <MemberItem {...props} />
* })
* }
*/
setMemberItemComponent = MemberItemComponent => {
this.MemberItemComponent = MemberItemComponent;
};
fetchParamsFilter = params => params;
/**
* It overrides the parameters that are used to fetch members in the Members screen so that you can make it as customizable as possible when calling its API.
* @method
* @param {TransformMembersParams} fetchParamsFilter
*
* @example <caption> Create a custom filter in members screen </caption>
*
* //In components/MembersBeforeList.js...
*
* import React, { useState } from "react";
* import { TextInput, View, Button } from 'react-native'
* import { useDispatch } from "react-redux";
* import { membersRequested } from "@src/actions/members";
* import { getExternalCodeSetup } from "@src/externalCode/externalRepo";
* import withGlobalStyles from "@src/components/hocs/withGlobalStyles";
*
* const hook = getExternalCodeSetup().membersListHooksApi;
*
* const screenName = "book";
*
* const filter = "all"; //"all", "friends", "following", "followers", "requests"
* const subfilters = {
* type: "active" // "active", "newest", "alphabetical", "random", "online", "popular"
* };
*
* const refresh = true; //Set to true to refresh list
* const searchTerm = ""
*
* const MembersBeforeList = (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 [experience, setExperience] = useState('');
* const [coursesCompleted, setCoursesCompleted] = useState('')
*
* const handleSubmit = () => {
*
* //Set custom parameters before fetching documents
* hook.setFetchParamsFilter((props) => {
*
* //You can add more parameters such as "subject", "keyword" etc...
* return {
* ...props,
* experience,
* coursesCompleted
* }
* })
*
* //Dispatch redux action to call api using customized filters
* dispatch(membersRequested(filter, subfilters, refresh, searchTerm));
*
* }
*
* return <View style={{ backgroundColor: colors.whiteColor}}>
*
* <TextInput
* style={{paddingHorizontal: 20, marginTop: 10, fontSize: 20}}
* autoFocus
* keyboardType="number-pad"
* value={experience}
* onChangeText={experience => setExperience(experience)}
* placeholder="Experience (Cumulative Years)"
* />
*
* <TextInput
* style={{paddingHorizontal: 20, marginTop: 10, fontSize: 20}}
* value={coursesCompleted}
* onChangeText={coursesCompleted => setCoursesCompleted(coursesCompleted)}
* placeholder="Courses completed (Enter keyword...)"
* />
*
* <Button
* onPress={() => handleSubmit()}
* title="Filter"
* />
* </View>
* }
*
* return null;
*
* }
*
* export default withGlobalStyles(MembersBeforeList);
*
* //In components/MyCustomScreen.js...
* import React from 'react';
* import MembersScreen from "@src/containers/Custom/MembersScreen";
*
* const MyCustomScreen = props => (<MembersScreen {...props} showSearch={false} hideFilters={true} headerHeight={250} />)
*
*
* export default MyCustomScreen;
*
* //In custom_code/index.js...
*
* ...
*
* import MembersBeforeList from "./components/MembersBeforeList";
* export const applyCustomCode = externalCodeSetup => {
*
* externalCodeSetup.filterScreenApiHooks.setAfterFilterComponent(MembersBeforeList);
*
* externalCodeSetup.navigationApi.addNavigationRoute(
* "book",
* "BookScreen",
* MyCustomScreen,
* "All"
* );
* externalCodeSetup.navigationApi.addNavigationRoute(
* "book",
* "BookScreen",
* MyCustomScreen,
* "Main"
* );
* }
*/
setFetchParamsFilter = fetchParamsFilter => {
this.fetchParamsFilter = fetchParamsFilter;
};
subFiltersFilter = filters => filters;
/**
* You can use this to set the sub filter function to rearrange the order of the filters in the Members screen.
* For example, you can rearrange the labels to set "Alphabetical" as the default filter on the members list screen under the search bar.
* @method
* @param {TransformMembersSubFiltersFilterCallback} subFiltersFilter
* @example <caption>User would like to set "Alphabetical" as the first filter</caption>
* externalCodeSetup.membersListHooksApi.setSubFiltersFilter(filter => {
* return {
* type: [
* {
* value: "alphabetical",
* label: "Alphabetical"
* },
* {
* value: "active",
* label: "Recently Active"
* },
* {
* value: "newest",
* label: "Newest Members"
* }
* ],
* member_type: filter.member_type
* };
* });
*/
setSubFiltersFilter = subFiltersFilter => {
this.subFiltersFilter = subFiltersFilter;
};
}
Source