Source

externalCode/moreScreen.js

/**
 * @typedef {Function} MoreScreenNavigationCallback
 * @param {NavigationService} navigation
 * @param {String} routeName
 * @param {Object} menuItem Information about the menu item such as label, icon, type
 * @param {number} userId Logged-in user's id
 */

/**
 * @typedef {Function} TransformMoreScreenListCallback
 * @param {Array<Object>} section Menu item information
 * @param {Function} dispatch Redux dispatch function
 * @param {NavigationService} navigation
 * @param {Function} toUserBasedOnSettings Navigate to user function
 * @param {Function} attemptDeepLink Attempt deep linking
 * @param {Object} auth User details
 * @return {Array<Object>} Modified section
 */

/**
 * @typedef {Function} TransformContainerPaddingTopCallback
 * @param {Number} containerPaddingTop
 * @return {Number} New padding top value
 */

/**
 * @typedef {Function} TransformContentInsetTopCallback
 * @param {Number} contentInsetTop
 * @return {Number} New content inset value
 */

/**
 * @typedef {Function} TransformContentOffsetYCallback
 * @param {Number} contentOffsetY
 * @return {Number} New content offset value
 */
/**
 * @typedef {Function} TransformSearchContainerPaddingTopCallback
 * @param {Number} listTopMargin
 * @param {Number} navHeight
 * @return {Number} New padding top value. Note: aside from the result of add(), you can also return a number as the new value.
 */

/**
 * @typedef {Object} MoreScreenProfileItemProps
 * @property {Object} user Object containing user details
 * @property {Object} global App global style
 * @property {Object} colors App colors
 * @property {Object} styles Default Component style
 * @property {Function} navigateToUserProfile function which navigates to user's profile
 * @property {Boolean} hideHandle Boolean specifying whether to show or hide handles
 * @property {Boolean} showProfile Boolean specifying whether to show or hide Profile Component set via custom code
 */
/**

/**
 * @class
 * More Screen (Screen with additional navigation links) Hooks.
 * Instance name: moreScreenApi
  
   You can use this hook to customize how the "More Screen" will behave when the user taps on it and override the default functionality based on your preferences. 
 * @example
 * externalCodeSetup.moreScreenApi.METHOD_NAME
 */

export class MoreScreenHooksApi {
	navigationHandler = null;

	/**
	 * Sets the function that overrides the default "More Screen" navigation functionality.
	 * This hook is called whenever a menu item in More Screen is clicked.
	 * For example, you can configure how a menu item will behave after a user taps on it.
	 * @method
	 * @param {MoreScreenNavigationCallback} navigationHandler
	 * @example
	 * ...
	 * import {Linking} from "react-native";
	 * import {CommonActions} from "@react-navigation/native";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *    const defaultNavigateTo = (navigation, routeName, menuItem, userId) => {
	 *
	 *    //Attempt to open using React Native's Linking function based on different conditions...
	 * 	  if (
	 * 		(menuItem.type === "page" ||
	 * 			menuItem.type === "custom" ||
	 * 			(menuItem.type === "post_type" && menuItem.object === "page")) &&
	 * 		menuItem.data &&
	 * 		menuItem.data.open_external
	 *     ) {
	 * 		Linking.canOpenURL(menuItem.data.link)
	 * 			.then(canOpen => {
	 * 				if (canOpen) {
	 * 					Linking.openURL(menuItem.data.link);
	 * 				}
	 * 			})
	 * 			.catch(error => {
	 * 				Alert.alert("There was a problem", "This page cannot be opened.");
	 * 			});
	 * 	    }
	 *      //Otherwise, navigate to appropriate screen
	 *      else {
	 * 		 navigation.dispatch(
	 * 			CommonActions.navigate({
	 * 				name: menuItem.label === "Photos" ? "GlobalPhotos" : routeName,
	 * 				params: {
	 * 					item: menuItem,
	 * 					userId
	 * 				}
	 * 			})
	 * 		 );
	 * 	    }
	 *    }
	 * }
	 *
	 * externalCodeSetup.moreScreenApi.setNavigationHandler(defaultNavigateTo);
	 */
	setNavigationHandler = navigationHandler => {
		this.navigationHandler = navigationHandler;
	};

	tabsList = list => list;

	/**
	 * You can use this hook to add or modify existing tabs in the More screen.
	 * @method
	 * @param {TransformMoreScreenListCallback} tabsList
	 * @example <caption> Add a new item in More Screen items that calls the logout action </caption>
	 * ...
	 * import { logout } from "@src/actions/auth"
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.moreScreenApi.setTabsList((section, dispatch) => {
	 *
	 *    return [
	 *      ...section,
	 *      {
	 *        label: "AUTH",
	 *        screens: [
	 *          {
	 *            item: {
	 *              label: "Logout",
	 *              icon: {
	 *                id: 'power-on',
	 *                type: 'buddyboss',
	 *                box_style: 'round', //"", "none", "round", "box"
	 *                tint_color: `#000000`,
	 *                monochrome: true,
	 *                icon_style: `outlined`,
	 *              },
	 *              onPress: () => dispatch(logout()),
	 *              hasNavArrow: false
	 *            },
	 *            routeName: "Logout"
	 *          }
	 *        ]
	 *      }
	 *    ]
	 *  })
	 * }
	 *
	 * @example <caption> Create your own item component </caption>
	 * import { logout } from "@src/actions/auth"
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  const CustomComponent = (dispatch) => {
	 *    return <View style={{padding: 10, backgroundColor: "white", borderRadius: 5}}>
	 *    <TouchableOpacity onPress={() => dispatch(logout())}>
	 *      <Text>Logout</Text>
	 *    </TouchableOpacity>
	 *  </View>
	 *  }
	 *
	 *  externalCodeSetup.moreScreenApi.setTabsList((section, dispatch) => {
	 *
	 *    return [
	 *      ...section,
	 *      {
	 *        screens: [
	 *          {
	 *            item: {
	 *              component: () => CustomComponent(dispatch)
	 *            }
	 *          }
	 *        ]
	 *      }
	 *    ]
	 *  })
	 * }
	 */
	setTabsList = tabsList => {
		this.tabsList = tabsList;
	};

	replaceMenuItemRoutes = [];

	/**
	 * You can use this to substitute the default routeName of the menu item in the More Screen.
	 * For example, instead of redirecting to the `DocumentsScreenMoreMenu3`, you can redirect them to a custom screen such as `ConfidentialDocsScreen`.
	 * Note: More Screen items are composed as: [ScreenName] + "MoreMenu" + [index of the MoreScreen tab in the bottom bar component].
	 * For example, if the MoreScreen tab is the 4th item in the bottom bar component, the routes names of the menu items would be: `ActivitiesScreenMoreMenu3`, `SettingsScreenMoreMenu3`
	 * @method
	 * @example <caption> Change route of menu item depending on the user </caption>
	 *
	 * ...
	 *
	 * import { getNavigationService } from "@src/utils/NavigationService";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.reduxApi.addOnStoreCreateListener((props) => {
	 *
	 *    let shouldUnsubscribe = false;
	 *
	 *    const unsubscribe = props.subscribe(() => {
	 *
	 *      const currentRoute = getNavigationService().getCurrentRoute();
	 *
	 *      //If navigating in the MoreScreen...
	 *      if (currentRoute?.params?.item?.object === "more") {
	 *
	 *        const state = props.getState();
	 *        const userId = 1;
	 *
	 *        //Show a different route depending on the logged-in user
	 *        if (state.user?.userObject.id === userId){
	 *          externalCodeSetup.moreScreenApi.setReplaceMenuItemRoutes([
	 *            {
	 *              "originalRoute": "DocumentsScreenMoreMenu3",
	 *              "replaceWith": "SettingsScreenMoreMenu3"
	 *            }
	 *          ])
	 *        }
	 *        shouldUnsubscribe = true;
	 *      }
	 *      if (shouldUnsubscribe) {
	 *        unsubscribe()
	 *      }
	 *
	 *    });
	 *
	 *  });
	 * }
	 */
	setReplaceMenuItemRoutes = replaceMenuItemRoutes => {
		this.replaceMenuItemRoutes = replaceMenuItemRoutes;
	};

	useOriginalRouteNames = false;
	/**
	 * Menu items inside the More Screen are constructed such as: DocumentsScreenMoreMenu3, ActivityScreenMoreMenu3.
	 * Set this to `true` if you'd like to use the original route name such as: DocumentsScreen or ActivitiesScreen.
	 * This is especially useful if you'd like to remove the More Screen using setFilterBottomTabsRoutes while "Tab bar Visibility" is set to "Show on All Screens"
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *   //Remove the default MoreScreen from the bottom tab component
	 *   externalCodeSetup.navigationApi.setFilterBottomTabsRoutes(routes => {
	 *     delete routes["MoreScreen"]
	 *     return routes;
	 *   });
	 *
	 *   //Add a button which navigates to a custom More Screen
	 *   externalCodeSetup.indexScreenApiHooks.enableAlwaysShowHeaderRight();
	 *   externalCodeSetup.indexScreenApiHooks.setRenderHeaderRight(<HomeHeaderRight />);
	 *
	 *   //Since a bottom tab route might not have the More Screen's menu items, navigate to "DocumentsScreen" instead of the inaccessible "DocumentsScreenMoreMenu1"
	 *   externalCodeSetup.moreScreenApi.enableUseOriginalRouteNames();
	 * }
	 */
	enableUseOriginalRouteNames = () => {
		this.useOriginalRouteNames = true;
	};

	containerPaddingTop = ({containerPaddingTop}) => containerPaddingTop;
	/**
	 * You can use this hook to adjust the amount of padding top used by the more screen container.
	 * @method
	 * @param {TransformContainerPaddingTopCallback} containerPaddingTop
	 * @example
	 * externalCodeSetup.moreScreenApi.setContainerPaddingTop(props => props.containerPaddingTop);
	 *
	 */
	setContainerPaddingTop = containerPaddingTop => {
		this.containerPaddingTop = containerPaddingTop;
	};

	contentInsetTop = ({contentInsetTop}) => contentInsetTop;
	/**
	 * You can use this hook amount by which the scroll view content is inset from the edges of the scroll view.
	 * @method
	 * @param {TransformContentInsetTopCallback} contentInsetTop
	 * @example
	 * externalCodeSetup.moreScreenApi.setContentInsetTop(props => props.contentInsetTop);
	 */
	setContentInsetTop = contentInsetTop => {
		this.contentInsetTop = contentInsetTop;
	};

	contentOffsetY = ({contentOffsetY}) => contentOffsetY;
	/**
	 * You can use this hook to set the starting scroll offset.
	 * @method
	 * @param {TransformContentOffsetYCallback} contentOffsetY
	 * @example
	 * externalCodeSetup.moreScreenApi.setContentOffsetY(props => props.contentOffsetY);
	 */
	setContentOffsetY = contentOffsetY => {
		this.contentOffsetY = contentOffsetY;
	};

	searchContainerPaddingTop = ({
		listTopMargin,
		navHeight,
		searchContainerPaddingTop
	}) => searchContainerPaddingTop;
	/**
	 * You can use this hook to adjust the amount of padding top used by the container which the search and list components occupy.
	 * Note: aside from the result of add() which returns an animated value, you can also return a number as the new value.
	 * @method
	 * @param {TransformSearchContainerPaddingTopCallback} searchContainerPaddingTop
	 * @example
	 *
	 * ...
	 *
	 * import {add} from "react-native-reanimated";
	 * export const applyCustomCode = (externalCodeSetup: any) => {
	 *     externalCodeSetup.moreScreenApi.setSearchContainerPaddingTop(props => {
	 *         return add(props.listTopMargin, props.navHeight + 17);
	 *     })
	 * }
	 */
	setSearchContainerPaddingTop = searchContainerPaddingTop => {
		this.searchContainerPaddingTop = searchContainerPaddingTop;
	};

	MoreScreenProfileItem = null;
	/**
	 * @ignore
	 * You can use this hook to modify the Profile Item Component on MoreScreen.
	 * @method
	 * @param {React.ComponentType<MoreScreenProfileItemProps>} MoreScreenProfileItem
	 * @example
	 * import { Text, Image, TouchableOpacity} from "react-native";
	 *
	 * externalCodeSetup.moreScreenApi.setMoreScreenProfileItem( props => {
	 *  const {global, colors} = props;
	 *  return (
	 *    <TouchableOpacity
	 *      activeOpacity={0.5}
	 *      onPress={() => props.navigateToUserProfile()}
	 *      style={{
	 *        flexDirection: "row",
	 *        alignItems: "center",
	 *        marginTop: 15,
	 *        padding: 15,
	 *        borderRadius: 10,
	 *        backgroundColor: colors.bodyFrontBg
	 *     }}
	 *    >
	 *    <Image
	 *      source={{uri: props.user.avatar_urls.full}}
	 *      style={{width: 60, height: 60, borderRadius: 30, marginRight: 10}}
	 *    />
	 *      <Text style={{fontSize: 34}}>Hi, {props.user.fullname}</Text>
	 *    </TouchableOpacity>
	 *  )
	 *});
	 */

	setMoreScreenProfileItem = MoreScreenProfileItem => {
		this.MoreScreenProfileItem = MoreScreenProfileItem;
	};
}