Source

externalCode/profileScreen.js

import * as React from "react";

/**
 * @typedef {Object} User Logged-in user's data
 */

/**
 * @typedef {"xprofile" | "courses" | "certificates" | "gamipress_points" | "gamipress_achievements" | "gamipress_ranks" | "badgeos_points" | "badgeos_achievements" | "badgeos_ranks" | "results" | "favourites" | "subscribed" | "replies" | "topics" | "activities" | "forums" | "friends" | "blocked_users" | "groups" | "documents"} ProfileTab
 */

/**
 * @typedef { "just-me" | "friends" | "groups" | "favorites" | "mentions" | "following" } ActivitiesFilter
 */

/**
 * @typedef { "-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"} ActivitiesSubFilter
 */

/**
 * Image resource (via request('...src'))
 * @typedef {number} LocalImageSource
 */

/**
 * @typedef {Object} RemoteImageSource
 */

/**
 * @typedef {LocalImageSource | RemoteImageSource} ImageSource
 */

/**
 * @typedef {Object} SubscreenObject
 * @param {LocalImageSource} icon
 * @param {String} label
 * @param {?Number} count
 * @param {Function} onPress
 */

/**
 * @typedef {Function} TransformProfileIgnoredSubscreensCallback
 * @param {Array<ProfileTab>} list Ignored subscreens list
 * @param {Boolean} isOwnAccount Returns `true` if profile displayed in screen is logged-in user's own account
 * @return {Array<string>} New list of ignored subscreens
 */

/**
 * @typedef {Function} TransformProfileActivityFilters
 * @param {Array<ActivitiesFilter>} list
 * @return {Array<string>} - New list
 */

/**
 * @typedef {Function} TransformProfileSubscreensListCallback
 * @param {Array<SubscreenObject>} list Subscreens list
 * @param {NavigationService} navigation
 * @param {User} user
 * @param {Boolean} isOwnAccount Returns `true` if profile displayed in screen is logged-in user's own account
 * @return {Array<SubscreenObject>} New subscreens list
 */

/**
 * @typedef {Object} BeforeProfileDetailsComponentProps
 * @property { Object }  colors App colors
 * @property { Object }  global App global style
 * @property { MemberViewModel }  user
 */

/**
 * @typedef {Object} AfterProfileDetailsComponentProps
 * @property { MemberViewModel }  user
 */

/**
 * @typedef {Object} UserFullNameComponentProps
 * @property { MemberViewModel }  user
 * @property { Object }  global App global style
 * @property { Object }  textStyle
 * @property { ?Object }  topicLoading
 */

/**
 * @typedef {Object} UserTypeComponentProps
 * @property { Boolean }  isUserProfile
 * @property { MemberViewModel }  user
 * @property { Object }  global App global style
 * @property { Object }  textStyle
 */

/**
 * @typedef {Object} UserHandleComponentProps
 * @property { MemberViewModel } user
 * @property { Object } global App global style
 * @property { Object } textStyle
 * @property { Boolean } hideHandle Returns `true` if a setting to hide the handle was set
 */

/**
 * @typedef {Object} UserRegisteredComponentProps
 * @property { MemberViewModel } user
 * @property { Object } global App global style
 * @property { TranslationFunction } t
 * @property {Function} formatDateFunc Helper function for parsing dates
 */

/**
 * @typedef {Object} UserFollowingComponentProps
 * @property { MemberViewModel } user
 * @property { Object } global App global style
 * @property { Object } colors App colors
 * @property { TranslationFunction } t
 */

/**
 * @typedef {Object} UserAvatarProps
 * @property { Boolean }  isOwnAccount Returns `true` if the logged-in user is viewing their own account
 * @property { TranslationFunction }  t
 * @property { Object }  global
 * @property { MemberViewModel }  user
 */

/**
 * @typedef {Object} AfterProfileHeaderProps
 * @property { MemberViewModel }  user
 */

/**
 * @typedef {Object} ActionButtonProps
 * @property {Object} global App global style
 * @property {Object} button Default actions when button is pressed
 * @property {Object} color Color for icon
 * @property {Object} style
 * @property {TranslationFunction} t
 * @property {Boolean} withLabel Returns `true` if button has label
 * @property {Object} labelStyle
 * @property {Boolean} loading Returns `true` if component is still loading
 * @property {Boolean} first Returns `true` if button is first in the list
 * @property {Boolean} last Returns `true` if button is last in the list
 * @property {Boolean} highlight Returns `true` if button is highlighted
 */

/**
 * @typedef {Function} OnChangeEventListenerCallback
 * @param {Number} id Field id
 * @param {Number} groupKey Group key
 * @param {Boolean} required Returns `true` if value for field is required
 * @param {Boolean} isDate Returns `true` if input is date
 * @param {String} newValue Returns value of input
 */

/**
 * @typedef {Function} TransformEditProfileFieldSetsFilterCallback
 * @param {Array<Object>} list List of filters
 * @return {Array<Object>} New list of filters
 */

/**
 * @typedef {Object} FieldSetObject
 * @property {Number} id id of field set
 * @property {String} name
 * @property {Object} description
 * @property {Number} group_order
 * @property {Boolean} can_delete Returns `true` if field set can be deleted
 * @property {Boolean} repeater_enabled Returns `true` if repeater is enabled
 * @property {Array<Object>} fields Fields in a field set
 */

/**
 * @typedef {Function} TransformEditProfileFieldSetsCallback
 * @param {Array<FieldSetObject>} fieldSets List of field sets
 * @return {Array<FieldSetObject>} New list of field sets
 */

/**
 * @typedef {Function} TransformViewProfileFieldSetsCallback
 * @param {Array<FieldSetObject>} fieldSets List of field sets
 * @return {Array<FieldSetObject>} New list of field sets
 */

/**
 * @typedef {Function} EditProfileComponentDidUpdateCallback
 * @param {Object} prevProps
 * @param {Object} prevState
 * @param {Object} props
 * @param {Object} state
 * @param {Function} updateStoreValues Helper function which you can use to update the Edit Profile screen's field values
 */

/**
 * @class
 * ProfileScreen Hooks.
 * Instance name: profileScreenHooksApi
 
   You can use this hook to personalize the profile screen by adding components before/after profile headers, blog details, custom header backgrounds and more.
 * @example
 * externalCodeSetup.profileScreenHooksApi.METHOD_NAME
 */
export class ProfileScreenHooksApi {
	/**
	 * @deprecated
	 */
	activityFiltersSubFilter = list => list;
	setActivityFiltersSubFilter = activityFiltersSubFilter => {
		this.activityFiltersSubFilter = activityFiltersSubFilter;
	};

	/**
	 * Sets a default cover
	 * @private
	 */
	baseCover;
	/**
	 * @ignore
	 * Reason for ignore: Function is not used anywhere in the app
	 * Sets a default cover image. It will override Platform settings.
	 * @param {LocalImageSource} baseCover
	 */
	setBaseCover = baseCover => {
		this.baseCover = baseCover;
	};

	/**
	 * @private
	 */
	headerBgSource = null;
	/**
	 * @ignore
	 * Reason for ignore: Hook not being used to replace header background.
	 * There are some instances where `headerBgSource` is used to check for a condition but it should be replaced by `customHeaderBackground`.
	 * Set image for Profile Screen header background
	 * @param {ImageSource}
	 */
	setHeaderBgSource = source => {
		this.headerBgSource = source;
	};

	profileActivityFiltersFilter = list => list;
	/**
	 * @ignore
	 * Reason for ignore: Variable assignment is incorrect and filter is not being used in profile activities screen
	 * Sets the function that can change filters array
	 * @param {TransformProfileActivityFilters} activityFiltersFilter
	 * @example
	 * externalCodeSetup.profileScreenHooksApi.setProfileActivityFiltersFilter((
	 * 	list,
	 * ) => ([
	 * 	...list,
	 * 	"followers",
	 * ]))
	 */
	setProfileActivityFiltersFilter = activityFiltersFilter => {
		this.activityFiltersFilter = activityFiltersFilter;
	};

	customHeaderBackground = null;

	/**
	 * Replaces cover image for all profiles in the profile screen
	 * @method
	 * @param {String} customHeaderBackground Resource to replace cover image
	 * @example
	 * externalCodeSetup.profileScreenHooksApi.setCustomHeaderBackground('https://link-to-image.png')
	 */
	setCustomHeaderBackground = customHeaderBackground => {
		this.customHeaderBackground = customHeaderBackground;
	};

	tabsList = list => list;

	/**
	 * You can use this hook to add or modify existing tabs in the profile screen.
	 * For example, you can add a new route in profile screen tab list
	 * @method
	 * @param {TransformProfileSubscreensListCallback} tabsList
	 * @example <caption> Add a new route in profile screen tab list </caption>
	 * ...
	 * import { CommonActions } from "@react-navigation/native";
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  //Register a new route
	 *  externalCodeSetup.navigationApi.addNavigationRoute(
	 *    "book",
	 *    "BookScreen",
	 *    () => <Text>Custom Book Screen</Text>,
	 *    "All"
	 *  );
	 *
	 *  //Add new menu item to profile screen tab list
	 *  externalCodeSetup.profileScreenHooksApi.setTabsList((
	 *    list,
	 *    navigation,
	 *    user,
	 *    isOwnAccount
	 *  ) => {
	 *    return [
	 *      ...list,
	 *      {
	 *        icon: require("@src/assets/img/about.png"), //Set icon
	 *        label: "Book", //Set label of menu
	 *        onPress: () => navigation.navigate(
	 *          CommonActions.navigate({
	 *            name: "book",
	 *            params: { //Pass params if needed
	 *              user,
	 *              isOwnAccount
	 *            },
	 *            key: user.id
	 *          })
	 *        )
	 *      }
	 *    ]
	 *  })
	 * }
	 */
	setTabsList = tabsList => {
		this.tabsList = tabsList;
	};

	/**
	 * Hides user handle in profile header
	 * @private
	 */
	hideHandle = false;

	/**
	 * Hides user handle in profile header by passing it as a `true` value.
	 * @method
	 * @param {Boolean} hideHandle
	 * @example
	 * externalCodeSetup.profileScreenHooksApi.setHideHandle(true)
	 */
	setHideHandle = hideHandle => {
		this.hideHandle = hideHandle;
	};

	/**
	 * filter ignored tabs on profile
	 * @private
	 */
	ignoreTabsFilter = (tabs, own) => tabs;
	/**
	 * You can use this to set a function that is capable of hiding specific profile menu items.
	 * @method
	 * @param {TransformProfileIgnoredSubscreensCallback} ignoreTabsFilter
	 * @example
	 * externalCodeSetup.profileScreenHooksApi.setIgnoreTabsFilter((
	 *   list,
	 *   isOwnAccount
	 * ) => [
	 *     ...list,
	 *     "activities",
	 *     "friends"
	 *   ])
	 */
	setIgnoreTabsFilter = ignoreTabsFilter => {
		this.ignoreTabsFilter = ignoreTabsFilter;
	};

	BeforeDetailsComponent = null;

	/**
	 * You can use it to add a component before the profile details.
	 * @method
	 * @param {React.ComponentType<BeforeProfileDetailsComponentProps>} BeforeDetailsComponent
	 * @example
	 * const BeforeDetailsComponent = ({user}) => (
	 *    <Text>User Type: {user.type}</Text>
	 * )
	 *
	 *  externalCodeSetup.profileScreenHooksApi.setBeforeDetailsComponent(BeforeDetailsComponent)
	 */
	setBeforeDetailsComponent = BeforeDetailsComponent => {
		this.BeforeDetailsComponent = BeforeDetailsComponent;
	};

	AfterDetailsComponent = null;

	/**
	 * You can use this to add a component after the profile details. For example, you can add more information about your profile in the custom component.
	 * @method
	 * @param {React.ComponentType<AfterProfileDetailsComponentProps>} AfterDetailsComponent
	 * @example
	 * const AfterDetailsComponent = ({ user }) => (
	 *  <Text>Last activity: {user.lastActivity}</Text>
	 * )
	 *
	 * externalCodeSetup.profileScreenHooksApi.setAfterDetailsComponent(AfterDetailsComponent)
	 */
	setAfterDetailsComponent = AfterDetailsComponent => {
		this.AfterDetailsComponent = AfterDetailsComponent;
	};

	UserFullNameComponent = null;

	/**
	 * You can use this to replace the user full name component and customize the name display according to your app preferences.
	 * @method
	 * @param {React.ComponentType<UserFullNameComponentProps>} UserFullNameComponent
	 * @example
	 * const UserFullNameComponent = (props) => (
	 *     <View>
	 *       <Text style={{fontSize: 20, color: "red"}}>
	 *        {props.user.fullname}
	 *       </Text>
	 *     </View>
	 * )
	 *
	 * externalCodeSetup.profileScreenHooksApi.setUserFullNameComponent(UserFullNameComponent)
	 */

	setUserFullNameComponent = UserFullNameComponent => {
		this.UserFullNameComponent = UserFullNameComponent;
	};

	UserTypeComponent = null;

	/**
	 * You can use this to replace the user type component for the various app users.
	 * @method
	 * @param {React.ComponentType<UserTypeComponentProps>} UserTypeComponent
	 * @example
	 *
	 * const UserTypeComponent = (props) => (
	 *  <View>
	 *    <Text>
	 *      User type: {props.user.type}
	 *    </Text>
	 *  </View>
	 * )
	 * externalCodeSetup.profileScreenHooksApi.setUserTypeComponent(UserTypeComponent);
	 */
	setUserTypeComponent = UserTypeComponent => {
		this.UserTypeComponent = UserTypeComponent;
	};

	UserHandleComponent = null;

	/**
	 * It is used to replace the default user handle component.
	 * @method
	 * @param {React.ComponentType<UserHandleComponentProps>} UserHandleComponent
	 * @example
	 *
	 * const UserHandleComponent = (props) => (
	 *  <Text style={{color: "blue", fontSize: 30}}> @{props.user.nicename} </Text>
	 * )
	 *
	 * externalCodeSetup.profileScreenHooksApi.setUserHandleComponent(UserHandleComponent)
	 */
	setUserHandleComponent = UserHandleComponent => {
		this.UserHandleComponent = UserHandleComponent;
	};

	UserRegisteredComponent = null;

	/**
	 * It is used to replace user registration details component.
	 * @method
	 * @param {React.ComponentType<UserRegisteredComponentProps>} UserRegisteredComponent
	 * @example
	 *
	 * const UserRegisteredComponent = (props) => (
	 *  <View style={{ marginVertical: 5 }}>
	 *    <Text>Date registered: {props.formatDateFunc(props.user.registeredDate)}</Text>
	 *  </View>
	 * )
	 *
	 * externalCodeSetup.profileScreenHooksApi.setUserRegisteredComponent(UserRegisteredComponent)
	 */
	setUserRegisteredComponent = UserRegisteredComponent => {
		this.UserRegisteredComponent = UserRegisteredComponent;
	};

	UserFollowingComponent = null;

	/**
	 * You can use this to replace the user's following and/or follower details component.
	 * @param {React.ComponentType<UserFollowingComponentProps>} UserFollowingComponent
	 * @example
	 *
	 * const UserFollowingComponent = (props) => (
	 *  <View style={{ flexDirection: "row" }}>
	 *    <Text> {props.user.followers} Followers </Text>
	 *    <Text> {props.user.following} Following </Text>
	 *  </View>
	 * )
	 *
	 * externalCodeSetup.profileScreenHooksApi.setUserFollowingComponent(UserFollowingComponent)
	 */

	setUserFollowingComponent = UserFollowingComponent => {
		this.UserFollowingComponent = UserFollowingComponent;
	};

	UserAvatar = null;

	/**
	 * You can use it to replace the user avatar component.
	 * @method
	 * @param {React.ComponentType<UserAvatarProps>} UserAvatar
	 * @example
	 * ...
	 * import AvatarImageUpload from "@src/components/AvatarImageUpload"
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  const UserAvatar = (props) => {
	 *    return (
	 *      <>
	 *        <Text>Tap avatar to edit</Text>
	 *        <AvatarImageUpload
	 *          isOwnAccount={props.isOwnAccount}
	 *          user={props.user}
	 *          size={100}
	 *          imagePickerProps={{ cropping: true, cropperCircleOverlay: true }}
	 *        />
	 *      </>
	 *    )
	 *  }
	 *
	 *  externalCodeSetup.profileScreenHooksApi.setUserAvatar(UserAvatar)
	 *
	 */
	setUserAvatar = UserAvatar => {
		this.UserAvatar = UserAvatar;
	};

	AfterProfileHeader = null;

	/**
	 * It adds a component after the profile header.
	 * @method
	 * @param {React.ComponentType<AfterProfileHeaderProps>} AfterProfileHeader
	 * @example
	 *
	 *  const AfterProfileHeader = (props) => (
	 *    <View style={{ marginLeft: 20 }}>
	 *      <Text> User Points: {props.user.points} </Text>
	 *    </View>
	 *  )
	 *
	 *  externalCodeSetup.profileScreenHooksApi.setAfterProfileHeader(AfterProfileHeader)
	 *
	 */
	setAfterProfileHeader = AfterProfileHeader => {
		this.AfterProfileHeader = AfterProfileHeader;
	};

	HeaderRightComponent = null;

	/**
	 * You can use it to add a component on the top right corner of the profile screen for users.
	 * @method
	 * @param {React.ComponentType<HeaderRightComponent>} HeaderRightComponent
	 * @example
	 *
	 * //In custom_code/components/ProfileHeaderButton.js
	 *
	 * ...
	 *
	 * import { Alert } from "react-native";
	 * import IconButton from "@src/components/IconButton";
	 * import { globalStyle } from "@src/styles/global";
	 * import { useSelector } from "react-redux"; //use useSelector to get state from redux
	 *
	 * export const ProfileHeaderButton = () => {
	 *
	 *    const globalStyles = useSelector((state) => globalStyle(state.config.styles)) // Get style from redux
	 *    const user = useSelector((state) => state.user.userObject); // Get user from redux
	 *    const { colors } = globalStyles;
	 *    return (
	 *        <IconButton
	 *            icon={require("@src/assets/img/plus-circle.png")}
	 *            pressHandler={() => Alert.alert(`Hello ${user.nicename}!`) }// Do something here such as call api requests
	 *            tintColor={colors.headerIconColor}
	 *            style={{
	 *                height: 28
	 *            }}
	 *        />
	 *    )
	 *
	 * }
	 *
	 *
	 * //In custom_code/index.js
	 *
	 * ...
	 *
	 * import { ProfileHeaderButton } from "./components/ProfileHeaderButton";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.profileScreenHooksApi.setHeaderRightComponent(() => <ProfileHeaderButton />)
	 * };
	 */
	setHeaderRightComponent = HeaderRightComponent => {
		this.HeaderRightComponent = HeaderRightComponent;
	};

	ActionButton = null;

	/**
	 * You can use this hook to replace the action button in the profile header component.
	 * @method
	 * @param {React.ComponentType<ActionButtonProps>} ActionButton
	 * @example
	 * ...
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *   const RoundIconButton = ({
	 *     global,
	 *     button,
	 *     color,
	 *     style,
	 *     t,
	 *     withLabel,
	 *     labelStyle,
	 *     loading,
	 *     first,
	 *     last,
	 *     highlight
	 *   }) => (
	 *  <>
	 *    <View
	 *      style={[
	 *        {justifyContent: "center", alignItems: "center"},
	 *        highlight
	 *          ? global.wrappedIconButtonHighlight
	 *          : styles.roundActionButton,
	 *        !first && !withLabel && {marginLeft: 10},
	 *        !last && !withLabel && {marginRight: 10},
	 *        style
	 *      ]}
	 *      activeOpacity={1}
	 *    >
	 *      {!loading &&
	 *        button.icon && (
	 *          <Icon
	 *            tintColor={highlight ? "#fff" : color || "#000"}
	 *            icon={button.icon}
	 *            styles={{height: 26, width: 26}}
	 *          />
	 *        )}
	 *      {loading && (
	 *        <ActivityIndicator
	 *          animating={true}
	 *          style={styles.indicator}
	 *          color={color}
	 *          size="small"
	 *        />
	 *      )}
	 *    </View>
	 *    {withLabel && (
	 *      <View style={{height: 40, paddingTop: 10}}>
	 *        <Text
	 *          ellipsizeMode="tail"
	 *          numberOfLines={2}
	 *          style={
	 *            [global.actionIconText, {textAlign: "center"}, labelStyle]
	 *          }
	 *        >
	 *          {t(button.label)}
	 *        </Text>
	 *      </View>
	 *    )}
	 *   </>
	 *  );
	 *
	 * const styles = StyleSheet.create({
	 *   indicator: {opacity: 0.45},
	 *   roundActionButton: {
	 *   backgroundColor: "#EDEEF2",
	 *   borderRadius: 24,
	 *   width: 48,
	 *   height: 48,
	 *   justifyContent: "center",
	 *   alignItems: "center",
	 *   marginHorizontal: 5
	 *  }
	 * });
	 *
	 *  externalCodeSetup.profileScreenHooksApi.setActionButton((props) => <RoundIconButton {...props} />)
	 * }
	 */
	setActionButton = ActionButton => {
		this.ActionButton = ActionButton;
	};

	editProfileFieldSetsFilter = list => list;
	/**
	 * Sets the filters available on the Edit Profile screen as the filter tabs.
	 * For example, you can use this hook to remove a specific filter. However, this does not remove the corresponding field set of the removed filter.
	 * @method
	 * @param {TransformEditProfileFieldSetsFilterCallback} editProfileFieldSetsFilter
	 * @example <caption> Change name of filter with id 1 </caption>
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.profileScreenHooksApi.setEditProfileFieldSetsFilter(props => {
	 *    if (Array.isArray(props.filters)){
	 *
	 *      const modifiedFilters = props.filters.map(obj => {
	 *
	 *        if (obj.id === 1){
	 *          return {
	 *            ...obj,
	 *            name: "New name"
	 *          }
	 *        }
	 *
	 *        return obj;
	 *      })
	 *
	 *      return {
	 *        ...props,
	 *        filters: modifiedFilters
	 *      };
	 *
	 *    }
	 *
	 *    return props;
	 *
	 *  });
	 * }
	 */
	setEditProfileFieldSetsFilter = editProfileFieldSetsFilter => {
		this.editProfileFieldSetsFilter = editProfileFieldSetsFilter;
	};

	handleInputFieldCallback = null;
	/**
	 * You can use this hook to add a callback to a function when an input field on the profile Edit screen is changed.
	 * For example, you can add a function to display a prompt whenever the word 'Bar' is typed in a specific profile field.
	 * @method
	 * @param {OnChangeEventListenerCallback} onHandledInput
	 * @example <caption> If "Food" is selected when editing the value in a profile field, change the available field sets in the edit profile screen </caption>
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.profileScreenHooksApi.addHandleInputFieldCallback(props => {
	 *
	 *    const { id, newValue } = props;
	 *
	 *    if (id === 24) {
	 *
	 *      if (newValue.includes("Food")) {
	 *
	 *        //If "Food" is selected, display the first field set only
	 *        externalCodeSetup.profileScreenHooksApi.setEditProfileFieldSets(fieldSets => {
	 *          return [...fieldSets].splice(0,1);
	 *        });
	 *
	 *      } else {
	 *
	 *        //Reset field sets
	 *        externalCodeSetup.profileScreenHooksApi.setEditProfileFieldSets(fieldSets => fieldSets);
	 *      }
	 *
	 *    }
	 *  })
	 * }
	 */
	addHandleInputFieldCallback = onHandledInput => {
		this.handleInputFieldCallback = onHandledInput;
	};

	editProfileFieldSets = fieldSets => fieldSets;
	/**
	 * Sets the field sets and the filters available on the Edit Profile screen.
	 * @method
	 * @param {TransformEditProfileFieldSetsCallback} editProfileFieldSets
	 * @example <caption>Delete a field from a field set</caption>
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.profileScreenHooksApi.setEditProfileFieldSets(fieldSets => {
	 *
	 *    const modifiedFieldSets = fieldSets.map(obj => {
	 *
	 *      if (obj.id === 1){
	 *
	 *        //Delete a field from the field set
	 *        const fields = obj.fields.slice(1);
	 *
	 *        return {
	 *          ...obj,
	 *          fields: fields
	 *        }
	 *      }
	 *      return obj;
	 *    });
	 *
	 *    return modifiedFieldSets;
	 *  });
	 * }
	 */
	setEditProfileFieldSets = editProfileFieldSets => {
		this.editProfileFieldSets = editProfileFieldSets;
	};

	viewProfileFieldSets = fieldSets => fieldSets;

	/**
	 * Used to set and modify the field sets in the View Profile screen.
	 * You can show/hide the field sets in the View Profile screen.
	 * @method
	 * @param {TransformViewProfileFieldSetsCallback} viewProfileFieldSets
	 * @example
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.profileScreenHooksApi.setViewProfileFieldSets(fieldSets => {
	 *
	 *    if (Array.isArray(fieldSets)){
	 *      const modifiedFieldSets = [...fieldSets].slice(1);
	 *
	 *      return modifiedFieldSets;
	 *    }
	 *
	 *    return fieldSets;
	 *
	 *  })
	 * }
	 */
	setViewProfileFieldSets = viewProfileFieldSets => {
		this.viewProfileFieldSets = viewProfileFieldSets;
	};

	editProfileComponentDidUpdateCallback = null;
	/**
	 * You can use this hook to set a callback function in the Edit Profile screen's componentDidUpdate function.
	 * For example, you can use this to make a network request (or call an API) if a state's value is changed.
	 * @method
	 * @param {EditProfileComponentDidUpdateCallback} onComponentDidUpdate
	 * @example <caption>Change edit profile field values based on WebView's message</caption>
	 *
	 * //In custom_code/MyCustomScreen.js...
	 *
	 * import React, { useState } from 'react';
	 * import { View, Text, StyleSheet, Button, Modal, TouchableOpacity } from "react-native";
	 * import isEqual from 'lodash.isequal';
	 * import { WebView } from 'react-native-webview';
	 * import EditScreen from "@src/containers/Custom/Profile/Xprofile/Edit";
	 * import { backButton } from "@src/utils";
	 * import { getExternalCodeSetup } from '../../src/externalCode/externalRepo';
	 *
	 * const MyHTML = require('./../html/sample.html');
	 *
	 * const MyModal = ({ modalVisible, setModalVisible, updateStoreValues }) => {
	 *
	 *     //You can change this according to the message sent by the webview's source
	 *     const matchedMessage = "Clicked!";
	 *
	 *     return <View style={styles.centeredView}>
	 *         <Modal
	 *             animationType="slide"
	 *             transparent={true}
	 *             visible={modalVisible}
	 *             onRequestClose={() => {
	 *                 setModalVisible(!modalVisible);
	 *             }}
	 *             style={{
	 *                 margin: 15
	 *             }}
	 *         >
	 *             <WebView
	 *                 source={MyHTML}
	 *                 onMessage={event => {
	 *
	 *                     const message = event.nativeEvent.data;
	 *
	 *                     if (message == matchedMessage) {
	 *                         updateStoreValues()
	 *                     }
	 *                 }}
	 *
	 *             />
	 *             <TouchableOpacity
	 *                 style={[styles.button, styles.buttonClose]}
	 *                 onPress={() => setModalVisible(!modalVisible)}
	 *             >
	 *                 <Text style={styles.textStyle}>Hide Modal</Text>
	 *             </TouchableOpacity>
	 *         </Modal>
	 *     </View>
	 * }
	 *
	 * const MyCustomScreen = (props) => {
	 *
	 *     const matchedValue = "gmap";
	 *
	 *     const [modalVisible, setModalVisible] = useState(false);
	 *     const [callbackUpdateStoreValues, setCallbackUpdateStoreValues] = useState(null);
	 *
	 *
	 *     //Set condition when to open modal. If the field matches the value of matchedValue, then it will open the modal.
	 *     getExternalCodeSetup().profileScreenHooksApi.addHandleInputFieldCallback(props => {
	 *         const { id, newValue, groupKey } = props;
	 *         if (groupKey === 1 && id === 3) {
	 *             if (newValue === matchedValue) {
	 *                 setModalVisible(true)
	 *             }
	 *         }
	 *     })
	 *
	 *     getExternalCodeSetup().profileScreenHooksApi.setEditProfileComponentDidUpdateCallback(paramProps => {
	 *
	 *         const {
	 *             prevProps,
	 *             prevState,
	 *             props,
	 *             state,
	 *             updateStoreValues } = paramProps;
	 *
	 *         //Update callbackUpdateStoreValues only when there are updates in the EditProfile component
	 *         if (!isEqual(state.updates, prevState.updates) && Object.keys(prevState.updates).length !== 0) {
	 *
	 *             const updateValues = () => {
	 *
	 *                 //You can get the appropriate groupKey and id by doing a console.log for state and/or prevState.
	 *                 //In this case, we're updating the store values of groupKey = 1 and id = 1 with a the webViewInput value.
	 *                 const groupKey = 1,
	 *                     id = 1,
	 *                     property = "value",
	 *                     webViewInput = "Updated from web view";
	 *
	 *                 updateStoreValues(groupKey, id, property, webViewInput);
	 *
	 *             }
	 *
	 *             setCallbackUpdateStoreValues(() => () => updateValues());
	 *         }
	 *
	 *     });
	 *
	 *     return <>
	 *         <EditScreen />
	 *         <MyModal
	 *             modalVisible={modalVisible}
	 *             setModalVisible={setModalVisible}
	 *             updateStoreValues={callbackUpdateStoreValues}
	 *         />
	 *     </>
	 * }
	 *
	 * MyCustomScreen.navigationOptions = ({ navigation, screenProps }) => {
	 *     const { t, colors, calcFontSize, global } = screenProps;
	 *     const { borderColor } = colors;
	 *     const { params = {} } = navigation.state;
	 *
	 *     const hideBackButton = true;
	 *
	 *     let headerLeft = params.renderHeaderLeft
	 *         ? params.renderHeaderLeft()
	 *         : backButton({
	 *             navigation,
	 *             headerColor: colors.headerIconColor,
	 *             text: t("common:back"),
	 *             textStyle: global.headerText,
	 *             colors
	 *         });
	 *
	 *     if (hideBackButton) {
	 *         headerLeft = null;
	 *     }
	 *
	 *     return {
	 *         headerTitle: (
	 *             <Text
	 *                 ellipsizeMode="tail"
	 *                 numberOfLines={1}
	 *                 style={global.appHeaderTitle}
	 *             >
	 *                 {t("profile:editXprofile")}
	 *             </Text>
	 *         ),
	 *         tabBarVisible: false,
	 *         headerLeft: headerLeft,
	 *         headerRight: params.renderHeaderRight ? params.renderHeaderRight() : null,
	 *         headerStyle: {
	 *             ...StyleSheet.flatten(global.header),
	 *             borderBottomColor: borderColor,
	 *             borderBottomWidth: StyleSheet.hairlineWidth
	 *         }
	 *     };
	 * };
	 *
	 * export default MyCustomScreen;
	 *
	 * const styles = StyleSheet.create({
	 *     centeredView: {
	 *         justifyContent: "center",
	 *         alignItems: "center",
	 *     },
	 *     button: {
	 *         position: "absolute",
	 *         bottom: 80,
	 *         width: "50%",
	 *         borderRadius: 20,
	 *         padding: 10,
	 *         elevation: 2,
	 *         alignSelf: "center"
	 *     },
	 *     buttonClose: {
	 *         backgroundColor: "#2196F3",
	 *     },
	 *     textStyle: {
	 *         color: "white",
	 *         fontWeight: "bold",
	 *         textAlign: "center"
	 *     }
	 * });
	 *
	 * //In custom_code/html/sample.html...
	 * <!DOCTYPE html>
	 * <html>
	 * <meta name="viewport" content="width=device-width, initial-scale=1">
	 *
	 * <head>
	 *     <style>
	 *         body {
	 *             background-color: #18222d;
	 *             height: 100vh;
	 *             display: flex;
	 *             justify-content: center;
	 *             align-items: center;
	 *         }
	 *     </style>
	 * </head>
	 * <body>
	 *     <div>
	 *         <button type="button" onclick="clicked()">Click Me!</button>
	 *     </div>
	 *     <script>
	 *         const OS = "ios";
	 *         const sendMessageToRN = (message) => {
	 *             if (OS === "ios") {
	 *                 if (window.ReactNativeWebView.postMessage.length !== 1) {
	 *                     setTimeout(sendMessageToRN(message), 200);
	 *                 } else {
	 *                     window.ReactNativeWebView.postMessage(message);
	 *                 }
	 *             } else {
	 *                 window.ReactNativeWebView.postMessage(message);
	 *                 setTimeout(() => window.ReactNativeWebView.postMessage(message), 50);
	 *             }
	 *         }
	 *         const clicked = () => {
	 *             sendMessageToRN("Clicked!")
	 *         }
	 *     </script>
	 * </body>
	 *
	 * </html>
	 *
	 *  //In custom_code/index.js...
	 *
	 *  ...
	 *
	 * import MyCustomScreen from "./components/MyCustomScreen";
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.navigationApi.replaceScreenComponent("EditXprofile", MyCustomScreen);
	 * }
	 *
	 *
	 */
	setEditProfileComponentDidUpdateCallback = onComponentDidUpdate => {
		this.editProfileComponentDidUpdateCallback = onComponentDidUpdate;
	};
}