import * as React from "react";
import {User, TMemberViewModel, TTranslationFunction} from "./types";
import {NavigationService} from "./navigation";
/**
* @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
*/
type TransformProfileIgnoredSubscreensCallback = {
list:
| "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",
/**
* Returns `true` if profile displayed in screen is logged-in user's own account
*/
isOwnAcccount: boolean
};
/**
* @typedef {Function} TransformProfileActivityFilters
* @param {Array<ActivitiesFilter>} list
* @return {Array<string>} - New list
*/
/**
* SubscreenObject
*/
type SubscreenObject = {
icon: number | Record<any, any>,
label: string,
count?: number,
onPress: () => void
};
/**
* TransformProfileSubscreensListCallback
*/
type TransformProfileSubscreensListCallback = {
list: SubscreenObject[],
navigation: NavigationService,
user: User,
/**
* Returns `true` if profile displayed in screen is logged-in user's own account
*/
isOwnAccount: boolean
};
/**
* BeforeProfileDetailsComponentProps
*/
type BeforeProfileDetailsComponentProps = {
/**
* App global style
*/
global: Record<any, any>,
/**
* App colors
*/
colors: Record<any, any>,
user: TMemberViewModel
};
/**
* AfterProfileDetailsComponentProps
*/
type AfterProfileDetailsComponentProps = {
user: TMemberViewModel
};
/**
* UserFullNameComponentProps
*/
type UserFullNameComponentProps = {
user: TMemberViewModel,
/**
* App global style
*/
global: Record<any, any>,
textStyle: Record<any, any>,
topicLoading: Record<any, any>
};
/**
* UserTypeComponentProps
*/
type UserTypeComponentProps = {
isUserProfile: boolean,
user: TMemberViewModel,
/**
* App global style
*/
global: Record<any, any>,
textStyle: Record<any, any>
};
/**
* UserHandleComponentProps
*/
type UserHandleComponentProps = {
user: TMemberViewModel,
/**
* App global style
*/
global: Record<any, any>,
textStyle: Record<any, any>,
/**
* Returns `true` if a setting to hide the handle was set
*/
hideHandle: boolean
};
/**
* UserRegisteredComponentProps
*/
type UserRegisteredComponentProps = {
user: TMemberViewModel,
/**
* App global style
*/
global: Record<any, any>,
t: TTranslationFunction,
/**
* Helper function for parsing dates
*/
formatDateFunc: Function
};
/**
* UserFollowingComponentProps
*/
type UserFollowingComponentProps = {
user: TMemberViewModel,
/**
* App global style
*/
global: Record<any, any>,
/**
* App colors
*/
colors: Record<any, any>,
t: TTranslationFunction
};
/**
* UserAvatarContainerProps
*/
type UserAvatarContainerProps = {
/**
* Default styles
*/
styles: Record<any, any>
};
/**
* UserAvatarProps
*/
type UserAvatarProps = {
/**
* Returns `true` if profile displayed in screen is logged-in user's own account
*/
isOwnAccount: boolean,
t: TTranslationFunction,
/**
* App global style
*/
global: Record<any, any>,
user: TMemberViewModel
};
/**
* AfterProfileHeaderProps
*/
type AfterProfileHeaderProps = {
user: TMemberViewModel
};
/**
* ActionButtonProps
*/
type ActionButtonProps = {
/** App global style */
global: Record<any, any>,
/** Default actions when button is pressed */
button: Record<any, any>,
/** Color for icon */
color: Record<any, any>,
/** Style for the button */
style: Record<any, any>,
/** Translation function */
t: TTranslationFunction,
/** Returns `true` if button has label */
withLabel: boolean,
/** Style for the label */
labelStyle: Record<any, any>,
/** Returns `true` if component is still loading */
loading: boolean,
/** Returns `true` if button is first in the list */
first: boolean,
/** Returns `true` if button is last in the list */
last: boolean,
/** Returns `true` if button is highlighted */
highlight: boolean
};
/**
* OnChangeEventListenerCallback
*/
type OnChangeEventListenerCallback = {
/** Field id */
id: number,
/** Group key */
groupKey: number,
/** Returns `true` if value for field is required */
required: boolean,
/** Returns `true` if input is date */
isDate: boolean,
/** Returns value of input */
newValue: string
};
/**
* TransformEditProfileFieldSetsCallback
*/
type TransformEditProfileFieldSetsCallback = {
/** id of field set */
id: number,
/** Name of the field set */
name: string,
/** Description of the field set */
description: Record<any, any>,
/** Order of the group */
group_order: number,
/** Returns `true` if field set can be deleted */
can_delete: boolean,
/** Returns `true` if repeater is enabled */
repeater_enabled: boolean,
/** Fields in a field set */
fields: Record<any, any>[]
};
/**
* TransformViewProfileFieldSetsCallback
*/
type TransformViewProfileFieldSetsCallback = {
/** id of field set */
id: number,
/** Name of the field set */
name: string,
/** Description of the field set */
description: Record<any, any>,
/** Order of the group */
group_order: number,
/** Returns `true` if field set can be deleted */
can_delete: boolean,
/** Returns `true` if repeater is enabled */
repeater_enabled: boolean,
/** Fields in a field set */
fields: Record<any, any>[]
};
/**
* EditProfileComponentDidUpdateCallback
*/
type EditProfileComponentDidUpdateCallback = {
prevProps: Record<any, any>,
prevState: Record<any, any>,
props: Record<any, any>,
state: Record<any, any>,
/**
* Helper function which you can use to update the Edit Profile screen's field values
*/
updateStoreValues: Function
};
/**
* ProfileHeaderWrapperProps
*/
type ProfileHeaderWrapperProps = {
styles: Record<any, any>,
children: React.ComponentType
};
/**
* ProfileItemValueProps
*/
type ProfileItemValueProps = {
/** App global style */
global: Record<any, any>,
/**
* Field details
*/
data: Record<any, any>,
/**
* Field type
*/
type: string,
/**
* Field options
*/
options: Record<any, any>[],
/**
* Helper function which can be used to format dates
*/
formatDateFunc: Function,
/**
* Helper function which is used for deep linking
*/
attemptDeepLink: Function,
/**
* Default component used for rendering the values
*/
ProfileItemValue: React.ComponentType<any>
};
/**
* ProfileItemProps
*/
type ProfileItemProps = {
/**
* Returns `true` if item to be rendered is last in the list
*/
isLast: boolean,
/** App global style */
global: Record<any, any>,
/**
* App colors
*/
colors: Record<any, any>,
/**
* Helper function which can be used to format dates
*/
formatDateFunc: Function,
/**
* Helper function which is used for deep linking
*/
attemptDeepLink: Function,
/**
* Default styles
*/
styles: Record<any, any>,
/**
* Field details
*/
field: Record<any, any>
};
/**
* EditProfileItemProps
*/
type EditProfileItemProps = {
/**
* Form item details
*/
formItem: Record<any, any>,
/**
* Profile component details
*/
values: Record<any, any>,
/**
* Function to handle input changes to the component
*/
handleInput: Function,
/**
* Function to handle visibility changes to the component
*/
handleVisibility: Function,
config: Record<any, any>,
/** App global style */
global: Record<any, any>,
/**
* App colors
*/
colors: Record<any, any>,
t: TTranslationFunction,
/**
* Error details
*/
errors: Record<any, any>,
/**
* Default styles
*/
styles: Record<any, any>
};
/**
* XProfileUserAvatarProps
*/
type XProfileUserAvatarProps = {
/**
* Returns `true` if profile displayed in screen is logged-in user's own account
*/
isOwnAccount: boolean,
t: TTranslationFunction,
/** App global style */
global: Record<any, any>,
user: TMemberViewModel,
/**
* Default avatar size
*/
size: number,
/**
* Default settings for image picker
*/
imagePickerProps: Record<any, any>
};
/**
* XProfileUserTypeComponentProps
*/
type XProfileUserTypeComponentProps = {
user: TMemberViewModel,
/**
* Default styles
*/
styles: Record<any, any>
};
/**
* XProfileUserFullNameComponentProps
*/
type XProfileUserFullNameComponentProps = {
user: TMemberViewModel,
/**
* Default styles
*/
styles: Record<any, any>
};
/**
* XProfileUserHandleComponentProps
*/
type XProfileUserHandleComponentProps = {
/**
* Returns `true` if user handle should be hidden
*/
hideHandle: boolean,
/**
* User nickname
*/
name: string,
/**
* App colors
*/
colors: Record<any, any>,
/**
* Default styles
*/
styles: Record<any, any>
};
/**
* XProfileUserRegisteredComponentProps
*/
type XProfileUserRegisteredComponentProps = {
user: TMemberViewModel,
/**
* App global style
*/
global: Record<any, any>,
t: TTranslationFunction,
/**
* Helper function for parsing dates
*/
formatDateFunc: Function
};
/**
* XProfileUserFollowingComponentProps
*/
type XProfileUserFollowingComponentProps = {
/**
* App global style
*/
global: Record<any, any>,
/**
* Default styles
*/
styles: Record<any, any>,
t: TTranslationFunction,
user: TMemberViewModel
};
/**
* GroupFieldsTitleProps
*/
type GroupFieldsTitleProps = {
/**
* Fieldset details
*/
group: Record<any, any>,
/**
* Default styles
*/
styles: Record<any, any>
};
/**
* ProfileHeaderButtonObject
*/
type ProfileHeaderButtonObject = {
/**
* Button icon
*/
icon: number,
/**
* Button label
*/
label: string,
/**
* Function to call
*/
doFunction: Function,
/**
* Callback if an error occured
*/
getError: Function
};
/**
* EditProfileInputComponentProps
*/
type EditProfileInputComponentProps = {
/**
* Profile component details
*/
values: Record<any, any>,
/**
* Function to handle input changes to the component
*/
handleInput: Function,
config: Record<any, any>,
/**
* App global style
*/
global: Record<any, any>,
/**
* App colors
*/
colors: Record<any, any>,
t: TTranslationFunction,
/**
* Error details
*/
errors: undefined | Record<any, any>,
/**
* Current form component
*/
formItem: Record<any, any>
};
/**
* AchievementsComponentProps
*/
type AchievementsComponentProps = {
/**
* Default styles
*/
styles: Record<any, any>,
/**
* Returns the default container component
*/
ContainerComponent: React.ComponentType<any>,
/**
* Achievement data
*/
achievements: Record<any, any>,
/**
* Navigates to the achievements screen
*/
navigateToAchievements: Function
};
/**
* @typedef {Function} TransformProfileHeaderButtonsCallback
* @param {Array<ProfileHeaderButtonObject>} profileHeaderButtons Array of objects that renders the header buttons
* @return {Array<ProfileHeaderButtonObject>} New Array of objects
*/
/**
* @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
*/
//@ts-ignore
activityFiltersSubFilter = list => list;
//@ts-ignore
setActivityFiltersSubFilter = activityFiltersSubFilter => {
this.activityFiltersSubFilter = activityFiltersSubFilter;
};
/**
* Sets a default cover
* @private
*/
//@ts-ignore
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
*/
//@ts-ignore
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}
*/
//@ts-ignore
setHeaderBgSource = source => {
this.headerBgSource = source;
};
//@ts-ignore
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",
* ]))
*/
//@ts-ignore
setProfileActivityFiltersFilter = activityFiltersFilter => {
//@ts-ignore
this.activityFiltersFilter = activityFiltersFilter;
};
customHeaderBackground: string | null = 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: string | null) => {
this.customHeaderBackground = customHeaderBackground;
};
tabsList = (
list: SubscreenObject[],
navigation: NavigationService,
user: User,
isOwnAccount: boolean
) => 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: {fontIconName: 'book', weight: 100}, //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: (
list: SubscreenObject[],
navigation: NavigationService,
user: User,
isOwnAccount: boolean
) => SubscreenObject[]
) => {
this.tabsList = tabsList;
};
hideHandle: boolean = 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: boolean) => {
this.hideHandle = hideHandle;
};
hideAchievementPoints: boolean = false;
/**
* Hides the points under each badge on the Achievements screen.
* @method
* @param {Boolean} hideAchievementPoints
* @example
* externalCodeSetup.profileScreenHooksApi.sethideAchievementPoints(true)
*/
setHideAchievementPoints = (hideAchievementPoints: boolean) => {
this.hideAchievementPoints = hideAchievementPoints;
};
ignoreTabsFilter = (tabs: string[], own: boolean) => 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: (tabs: string[], own: boolean) => string[]
) => {
this.ignoreTabsFilter = ignoreTabsFilter;
};
BeforeDetailsComponent: React.ComponentType<
BeforeProfileDetailsComponentProps
> | null = 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: React.ComponentType<
BeforeProfileDetailsComponentProps
> | null
) => {
this.BeforeDetailsComponent = BeforeDetailsComponent;
};
AfterDetailsComponent: React.ComponentType<
AfterProfileDetailsComponentProps
> | null = 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: React.ComponentType<
AfterProfileDetailsComponentProps
> | null
) => {
this.AfterDetailsComponent = AfterDetailsComponent;
};
UserFullNameComponent: React.ComponentType<
UserFullNameComponentProps
> | null = 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: React.ComponentType<
UserFullNameComponentProps
> | null
) => {
this.UserFullNameComponent = UserFullNameComponent;
};
UserTypeComponent: React.ComponentType<UserTypeComponentProps> | null = 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: React.ComponentType<UserTypeComponentProps> | null
) => {
this.UserTypeComponent = UserTypeComponent;
};
UserHandleComponent: React.ComponentType<
UserHandleComponentProps
> | null = 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: React.ComponentType<UserHandleComponentProps> | null
) => {
this.UserHandleComponent = UserHandleComponent;
};
UserRegisteredComponent: React.ComponentType<
UserRegisteredComponentProps
> | null = 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: React.ComponentType<
UserRegisteredComponentProps
> | null
) => {
this.UserRegisteredComponent = UserRegisteredComponent;
};
UserFollowingComponent: React.ComponentType<
UserFollowingComponentProps
> | null = null;
/**
* You can use this to replace the user's following and/or follower details component.
* @param {React.ComponentType<UserFollowingComponentProps>} UserFollowingComponent
* @method
* @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: React.ComponentType<
UserFollowingComponentProps
> | null
) => {
this.UserFollowingComponent = UserFollowingComponent;
};
UserAvatarContainer: React.ComponentType<
UserAvatarContainerProps
> | null = null;
/**
* You can use it to replace the user avatar container component.
* @method
* @param {React.ComponentType<UserAvatarContainerProps>} UserAvatarContainer
* @example <caption> Overwrite default container styles </caption>
* externalCodeSetup.profileScreenHooksApi.setUserAvatarContainer(({styles, children}) => (
* <View
* style={[
* styles.container,
* {
* borderRadius: 30,
* top: styles.height + 10 - styles.headerTopOffset - styles.avatarContainerSize / 2,
* height: styles.avatarContainerSize - 20,
* width: styles.avatarContainerSize - 20
* }
* ]}
* >
* {children}
* </View>
* ));
*/
setUserAvatarContainer = (
UserAvatarContainer: React.ComponentType<UserAvatarContainerProps> | null
) => {
this.UserAvatarContainer = UserAvatarContainer;
};
UserAvatar: React.ComponentType<UserAvatarProps> | null = 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: React.ComponentType<UserAvatarProps> | null) => {
this.UserAvatar = UserAvatar;
};
AfterProfileHeader: React.ComponentType<
AfterProfileHeaderProps
> | null = 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: React.ComponentType<AfterProfileHeaderProps> | null
) => {
this.AfterProfileHeader = AfterProfileHeader;
};
HeaderRightComponent: React.ComponentType | null = 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
* @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={{fontIconName: "plus", weight: 200}}
* 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: React.ComponentType | null
) => {
this.HeaderRightComponent = HeaderRightComponent;
};
ActionButton: React.ComponentType<ActionButtonProps> | null = 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: React.ComponentType<ActionButtonProps> | null
) => {
this.ActionButton = ActionButton;
};
editProfileFieldSetsFilter = (list: Record<any, any>) => 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 {Record<any,any>} 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: (props: Record<any, any>) => Record<any, any>
) => {
this.editProfileFieldSetsFilter = editProfileFieldSetsFilter;
};
handleInputFieldCallback:
| null
| ((props: OnChangeEventListenerCallback) => void) = 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: null | ((props: OnChangeEventListenerCallback) => void)
) => {
this.handleInputFieldCallback = onHandledInput;
};
editProfileFieldSets = (fieldSets: TransformEditProfileFieldSetsCallback[]) =>
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: (
fieldSets: TransformEditProfileFieldSetsCallback[]
) => TransformEditProfileFieldSetsCallback[]
) => {
this.editProfileFieldSets = editProfileFieldSets;
};
viewProfileFieldSets = (fieldSets: TransformViewProfileFieldSetsCallback[]) =>
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: (
fieldSets: TransformViewProfileFieldSetsCallback[]
) => TransformViewProfileFieldSetsCallback[]
) => {
this.viewProfileFieldSets = viewProfileFieldSets;
};
editProfileComponentDidUpdateCallback:
| null
| ((props: EditProfileComponentDidUpdateCallback) => void) = 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:
| null
| ((props: EditProfileComponentDidUpdateCallback) => void)
) => {
this.editProfileComponentDidUpdateCallback = onComponentDidUpdate;
};
profileHeaderButtonsFilter = (
profileHeaderButtons: ProfileHeaderButtonObject[]
) => profileHeaderButtons;
/**
* You can use this hook to filter the buttons rendered in the header component of the Profile screen.
* For example, you can add or remove buttons according to your preference.
* @method
* @param {ProfileHeaderButtonObject[]} profileHeaderButtons
* @example <caption> Add an "Announcement" button </caption>
*
* externalCodeSetup.profileScreenHooksApi.setProfileHeaderButtonsFilter(
* buttons => {
* const modifiedButtons = [
*
* {
* icon: {fontIconName: 'globe', weight: 300},
* label: "Announcements",
* isNavigation: true, //If set to true, the button will not be set to a "loading" state
* useDispatch: false, //If this is not set, `doFunction` will be wrapped in a `dispatch` function which is used to call a redux function
* doFunction: () => Alert.alert("This user is an admin"),
* getError: (err) => console.log('Error', err)
* },
* ...buttons
* ];
*
* return modifiedButtons;
* }
* );
*/
setProfileHeaderButtonsFilter = (
profileHeaderButtons: (
profileHeaderButtons: ProfileHeaderButtonObject[]
) => ProfileHeaderButtonObject[]
) => {
this.profileHeaderButtonsFilter = profileHeaderButtons;
};
ProfileHeaderWrapper: React.ComponentType<
ProfileHeaderWrapperProps
> | null = null;
/**
* You can use this hook to customize the ProfileHeaderWrapper component when viewing the XProfile Screen.
* For example, you can use this to change the appearance of the component.
* @method
* @param {ProfileHeaderWrapperProps} ProfileHeaderWrapper
* @example <caption> Change style of the wrapper </caption>
*
* externalCodeSetup.profileScreenHooksApi.setProfileHeaderWrapper(props => (
* <View style={[props.styles.wrapper, {borderRadius: 0}]}>
* {props.children}
* </View>
* ));
*/
setProfileHeaderWrapper = (
ProfileHeaderWrapper: React.ComponentType<ProfileHeaderWrapperProps> | null
) => {
this.ProfileHeaderWrapper = ProfileHeaderWrapper;
};
ProfileItemValue: React.ComponentType<ProfileItemValueProps> | null = null;
/**
* You can use this hook to customize the component that displays the value of each fields when viewing the XProfile Screen.
* @method
* @param {ProfileItemValueProps} ProfileItemValue
* @example <caption> Use an image when displaying a certain type of field </caption>
*
* ...
*
* import AppImage from "@src/components/AppImage";
*
* export const applyCustomCode = async (externalCodeSetup) => {
* externalCodeSetup.profileScreenHooksApi.setProfileItemValue(props => {
* const {
* global,
* data,
* type,
* options,
* formatDateFunc,
* attemptDeepLink,
* ProfileItemValue
* } = props;
*
* return (
* <>
* {type === "country" ? (
* <View>
* <AppImage
* source={require("./assets/images/country.png")}
* style={{
* width: "auto",
* height: 50
* }}
* />
* </View>
* ) : (
* <ProfileItemValue
* {...{
* global,
* data,
* type,
* options,
* formatDateFunc,
* attemptDeepLink
* }}
* />
* )}
* </>
* );
* });
* }
*
*/
setProfileItemValue = (
ProfileItemValue: React.ComponentType<ProfileItemValueProps> | null
) => {
this.ProfileItemValue = ProfileItemValue;
};
ProfileItem: React.ComponentType<ProfileItemProps> | null = null;
/**
* You can use this hook to customize the component that displays the title and value of each fields when viewing the XProfile Screen.
* @method
* @param {ProfileItemProps} ProfileItem
* @example
*
* ...
*
* import {Text, View, StyleSheet} from "react-native";
* import {ProfileItemValue} from "@src/components/Profile/Xprofile/View";
*
* export const applyCustomCode = async (externalCodeSetup) => {
* externalCodeSetup.profileScreenHooksApi.setProfileItem(
* ({
* styles,
* isLast,
* global,
* colors,
* field,
* formatDateFunc,
* attemptDeepLink
* }) => (
* <View
* style={[
* styles.xProfileItemNew,
* !isLast
* ? {
* borderBottomColor: colors.borderColor,
* borderBottomWidth: StyleSheet.hairlineWidth
* }
* : {paddingBottom: 0}
* ]}
* >
* <View style={{flex: 1.5, marginBottom: 2}}>
* <Text style={[global.xProfileItemTitle]}>{field.name}</Text>
* </View>
* <View style={{flex: 2}}>
* <ProfileItemValue
* {...{
* global,
* data: field.data,
* type: field.type,
* options: field.options,
* formatDateFunc,
* attemptDeepLink,
* ProfileItemValue
* }}
* />
* </View>
* </View>
* )
* );
* }
*
*/
setProfileItem = (
ProfileItem: React.ComponentType<ProfileItemProps> | null
) => {
this.ProfileItem = ProfileItem;
};
EditProfileItem: React.ComponentType<EditProfileItemProps> | null = null;
/**
* You can use this hook to customize the component that displays the title and input fields when viewing the Edit XProfile Screen.
* @method
* @param {EditProfileItemProps} EditProfileItem
* @example
*
*
* //In custom_code/index.js...
*
* ...
*
* import XEditProfileItem from "./components/XEditProfileItem";
*
* export const applyCustomCode = externalCodeSetup => {
* externalCodeSetup.profileScreenHooksApi.setEditProfileItem(props => <XEditProfileItem {...props} />);
* }
*
* //In custom_code/components/XEditProfileItem.js...
*
* import React from 'react';
* import {View, Text} from 'react-native';
* import ent from "ent";
*
* import {ProfileItemVisibility, ProfileItemField, ProfileItemError} from '@src/components/Profile/Xprofile/Edit';
*
* const XEditProfileItem = (props) => {
*
* const {styles, global, formItem, errors} = props;
*
* return (
* <View style={styles.container}>
* <View style={global.row}>
* <Text style={styles.title}>
* {formItem.alternate_name !== ""
* ? formItem.alternate_name
* : formItem.name}
* </Text>
* {formItem.allow_custom_visibility !== "disabled" && (
* <ProfileItemVisibility {...props} />
* )}
* </View>
* <View style={styles.fieldContainer}>
* <ProfileItemField {...props}/>
* </View>
* {!!formItem.description?.rendered && (
* <Text
* style={styles.description}
* >
* {ent.decode(formItem.description.rendered || "")}
* </Text>
* )}
* {!!errors &&
* !!errors[formItem.id] && (
* <ProfileItemError {...props} error={errors[formItem.id]} />
* )}
* </View>
* );
* };
*
* export default XEditProfileItem;
*
*/
setEditProfileItem = (
EditProfileItem: React.ComponentType<EditProfileItemProps> | null
) => {
this.EditProfileItem = EditProfileItem;
};
GroupFieldsTitle: React.ComponentType<GroupFieldsTitleProps> | null = null;
/**
* You can use this hook to customize the component that displays the group title of the fields when viewing the XProfile Screen.
* @method
* @param {GroupFieldsTitleProps} GroupFieldsTitle
* @example
*
* externalCodeSetup.profileScreenHooksApi.setGroupFieldsTitle(
* ({styles, group}) => (
* <View style={styles.container}>
* <Text style={styles.text}>{group.name}</Text>
* </View>
* )
* );
*
*/
setGroupFieldsTitle = (
GroupFieldsTitle: React.ComponentType<GroupFieldsTitleProps> | null
) => {
this.GroupFieldsTitle = GroupFieldsTitle;
};
XProfileUserAvatar: React.ComponentType<
XProfileUserAvatarProps
> | null = null;
/**
* You can use this hook to customize the user avatar when viewing the XProfile Screen.
* @method
* @param {XProfileUserAvatarProps} XProfileUserAvatar
* @example
*
* ...
*
* import AvatarImageUpload from "@src/components/AvatarImageUpload";
*
* export const applyCustomCode = async (externalCodeSetup) => {
* externalCodeSetup.profileScreenHooksApi.setXProfileUserAvatar(
* ({isOwnAccount, t, global, user, size, imagePickerProps}) => (
* <AvatarImageUpload
* isOwnAccount={isOwnAccount}
* t={t}
* global={global}
* user={user}
* size={10}
* imagePickerProps={imagePickerProps}
* />
* )
* );
* }
*
*/
setXProfileUserAvatar = (
XProfileUserAvatar: React.ComponentType<XProfileUserAvatarProps> | null
) => {
this.XProfileUserAvatar = XProfileUserAvatar;
};
XProfileUserTypeComponent: React.ComponentType<
XProfileUserTypeComponentProps
> | null = null;
/**
* You can use this hook to customize the component that displays the user type when viewing the XProfile Screen.
* @method
* @param {XProfileUserTypeComponentProps} XProfileUserTypeComponent
* @example
*
* ...
*
* import AvatarImageUpload from "@src/components/AvatarImageUpload";
*
* export const applyCustomCode = async (externalCodeSetup) => {
* externalCodeSetup.profileScreenHooksApi.setXProfileUserTypeComponent(
* ({isOwnAccount, t, global, user, size, imagePickerProps}) => (
* <AvatarImageUpload
* isOwnAccount={isOwnAccount}
* t={t}
* global={global}
* user={user}
* size={10}
* imagePickerProps={imagePickerProps}
* />
* )
* );
* }
*
*/
setXProfileUserTypeComponent = (
XProfileUserTypeComponent: React.ComponentType<
XProfileUserTypeComponentProps
> | null
) => {
this.XProfileUserTypeComponent = XProfileUserTypeComponent;
};
XProfileUserFullNameComponent: React.ComponentType<
XProfileUserFullNameComponentProps
> | null = null;
/**
* You can use this hook to customize the component that displays the user's name in the header when viewing the XProfile Screen.
* @method
* @param {XProfileUserFullNameComponentProps} XProfileUserFullNameComponent
* @example
*
* ...
*
* import Animated from "react-native-reanimated";
*
* export const applyCustomCode = async (externalCodeSetup) => {
* externalCodeSetup.profileScreenHooksApi.setXProfileUserFullNameComponent(
* ({styles, user}) => (
* <Animated.View style={styles.container}>
* <Text style={styles.text}>{user.fullname}</Text>
* </Animated.View>
* )
* );
* }
*
*/
setXProfileUserFullNameComponent = (
XProfileUserFullNameComponent: React.ComponentType<
XProfileUserFullNameComponentProps
> | null
) => {
this.XProfileUserFullNameComponent = XProfileUserFullNameComponent;
};
XProfileUserHandleComponent: React.ComponentType<
XProfileUserHandleComponentProps
> | null = null;
/**
* It is used to replace the default user handle component when viewing the XProfile screen.
* @method
* @param {React.ComponentType<XProfileUserHandleComponentProps>} XProfileUserHandleComponent
* @example
*
* ...
*
* import {TextDot} from "@src/components/TextDot";
*
* export const applyCustomCode = async (externalCodeSetup) => {
* externalCodeSetup.profileScreenHooksApi.setXProfileUserHandleComponent(
* ({hideHandle, styles, name, colors}) => {
* return (
* <>
* {!hideHandle ? <Text style={styles.text}>{name}</Text> : null}
* <TextDot color={colors.descLightTextColor} style={styles.dot} />
* </>
* );
* }
* );
* }
*/
setXProfileUserHandleComponent = (
XProfileUserHandleComponent: React.ComponentType<
XProfileUserHandleComponentProps
> | null
) => {
this.XProfileUserHandleComponent = XProfileUserHandleComponent;
};
XProfileUserRegisteredComponent: React.ComponentType<
XProfileUserRegisteredComponentProps
> | null = null;
/**
* It is used to replace user registration details component when viewing the XProfile screen.
* @method
* @param {React.ComponentType<XProfileUserRegisteredComponentProps>} XProfileUserRegisteredComponent
* @example
*
* externalCodeSetup.profileScreenHooksApi.setXProfileUserRegisteredComponent(
* ({global, user, formatDateFunc, t}) => (
* <Text style={global.xProfileJoined}>{`${t("members:joined")} ${formatDateFunc(user.registeredDate)}`}</Text>
* )
* );
*/
setXProfileUserRegisteredComponent = (
XProfileUserRegisteredComponent: React.ComponentType<
XProfileUserRegisteredComponentProps
> | null
) => {
this.XProfileUserRegisteredComponent = XProfileUserRegisteredComponent;
};
XProfileUserFollowingComponent: React.ComponentType<
XProfileUserFollowingComponentProps
> | null = null;
/**
* You can use this to replace the user's following and/or follower details component when viewing the XProfile screen.
* @param {React.ComponentType<XProfileUserFollowingComponentProps>} XProfileUserFollowingComponent
* @method
* @example
*
* externalCodeSetup.profileScreenHooksApi.setXProfileUserFollowingComponent(
* ({global, styles, user, t}) => {
* return (
* <View style={[global.row, {marginTop: 20}]}>
* <View style={styles.metaBlock}>
* <Text style={[global.xProfileCount, styles.xProfileCount]}>
* {user.followers}
* </Text>
* <Text style={global.xProfileCountTitle}>
* {t(`members:followers`, {count: user.followers})}
* </Text>
* </View>
* <View style={styles.metaBlock}>
* <Text style={[global.xProfileCount, styles.xProfileCount]}>
* {user.following}
* </Text>
* <Text style={global.xProfileCountTitle}>
* {t("members:following")}
* </Text>
* </View>
* </View>
* );
* }
* );
*/
setXProfileUserFollowingComponent = (
XProfileUserFollowingComponent: React.ComponentType<
XProfileUserFollowingComponentProps
> | null
) => {
this.XProfileUserFollowingComponent = XProfileUserFollowingComponent;
};
EditProfileInputComponent: React.ComponentType<
EditProfileInputComponentProps
> | null = null;
/**
* You can use this hook to replace input components in the edit profile form.
* @param {React.ComponentType<EditProfileInputComponentProps>} EditProfileInputComponent
* @method
* @example
*
* //In custom_code/index.js...
*
* ...
*
* import MyEditInput from "./components/MyEditInput";
*
* export const applyCustomCode = (externalCodeSetup: any) => {
* externalCodeSetup.profileScreenHooksApi.setEditProfileInputComponent(
* props => {
* const {formItem, DefaultComponent} = props;
*
* if (formItem.name === "Nickname") {
* return <MyEditInput {...props} />;
* }
*
* return <DefaultComponent {...props} />;
* }
* );
* }
*
* //In custom_code/components/MyEditInput.js...
*
* import React, {useState} from "react";
* import {View, TextInput, ActivityIndicator, Text} from "react-native";
* import axios from "axios";
*
* const MyEditInput = props => {
* const {values, formItem, handleInput} = props;
*
* const [loading, setLoading] = useState(false);
* const [data, setData] = useState(null);
*
* const {value: oldValue} = values[formItem.id]
* ? values[formItem.id]
* : {};
*
* const fetchData = async text => {
* const search = text && text.toLowerCase();
*
* try {
* setLoading(true);
* const response = await axios.get(
* `https://example.api/${search}`
* );
* setData(response.data);
* setLoading(false);
* } catch (error) {
* console.error(error);
* }
* };
*
* const handleTextChange = (text, formItem) => {
* fetchData(text);
* handleInput(formItem.id, formItem.required)(text);
* };
*
* return (
* <View>
* <TextInput
* onChangeText={(text) => handleTextChange(text, formItem)}
* placeholder="Type something..."
* value={oldValue}
* />
* {loading && <ActivityIndicator />}
* {data && (
* <Text>
* Result: {data?.name} | {data?.abilities[0].ability.name}
* </Text>
* )}
* </View>
* );
* };
*
* export default MyEditInput;
*/
setEditProfileInputComponent = (
EditProfileInputComponent: React.ComponentType<
EditProfileInputComponentProps
> | null
) => {
this.EditProfileInputComponent = EditProfileInputComponent;
};
AchievementsComponent: React.ComponentType<
AchievementsComponentProps
> | null = null;
/**
* You can use this hook to modify the achievements component when viewing the XProfile Screen.
* @method
* @param {AchievementsComponentProps} AchievementsComponent
* @example
*
* ...
*
* import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
*
* export const applyCustomCode = (externalCodeSetup) => {
*
* externalCodeSetup.profileScreenHooksApi.setAchievementsComponent(({
* styles,
* ContainerComponent,
* achievements,
* navigateToAchievements
* }) => {
* return (
* <View style={styles.containerStyle}>
* <ContainerComponent>
* {achievements.map(achievementType =>
* achievementType.achievement.map(item => (
* <AppTouchableOpacity onPress={navigateToAchievements}>
* <View style={styles.badgeContainer}>
* {(!!item.thumbnail_url || !!achievementType.image) && (
* <Image
* source={{
* uri: item.thumbnail_url || achievementType.image
* }}
* style={styles.image}
* />
* )}
*
* <View style={styles.labelContainer} />
* <Text numberOfLines={2} style={styles.label}>
* {item.title}
* </Text>
* </View>
* </AppTouchableOpacity>
* ))
* )}
* </ContainerComponent>
* </View>
* );
* });
* }
*
*/
setAchievementsComponent = (
AchievementsComponent: React.ComponentType<
AchievementsComponentProps
> | null
) => {
this.AchievementsComponent = AchievementsComponent;
};
}
Source