Source

externalCode/forumSingleScreen.js

/**
 * @typedef {Object} Forum
 */

/**
 * @typedef {Object} ForumViewModel
 * @property {Number} id Forum id
 * @property {String} title Forum title
 * @property {String} shortContent Html for displaying forum's description
 * @property {Boolean} can_report Returns true if forum can be reported
 * @property {Boolean} reported Returns true if forum is already reported
 * @property {Object} author Details of forum author
 * @property {String} date Date of when forum was created
 * @property {String} modified Date of when forum was last modified
 * @property {String} lastActive Date of when last activity in forum
 * @property {Object} actionStates contains `subscribed` field which returns `true` if user is subscribed to forum
 * @property {String} replyCount Number of replies
 * @property {String} topicCount Number of discussions
 * @property {Object} group Group associated with the forum
 * @property {String} content Html for displaying forum's description
 * @property {String} coverImage Link to forum's cover image
 * @property {String} coverImageThumbnail Link to forum's thumbnail cover image
 * @property {Boolean} canCreateTopic Returns true if user can create a topic in the forum
 * @property {Boolean} canSeeTopics Returns true if user can create a topic in the forum
 * @property {Boolean} canSeeSubForums Returns true if user can see sub forums in the forum
 * @property {Array} subForums Sub forums associated to forum
 * @property {Function} subscribe Function to subscribe to forum
 * @property {Function} toSingle Function navigate to forum item
 * @property {Function} navigateToProfile Function to navigate to a user's profile
 */

/**
 * @typedef {Object} ForumHeaderProps
 * @property { Boolean }  hideShortContent Returns true if forum short content is hidden
 * @property { Object }  colors App colors
 * @property { Object }  global App global style
 * @property { ForumViewModel }  forum
 * @property {Function} formatDateFunc Helper function which can be used to format dates
 * @property {Number} HEADER_HEIGHT Default height of header used for ForumHeader component
 * @property {Boolean} disableActionButtons Returns true if actions buttons are disabled
 * @property {Array<Object>} actionButtons Default action buttons such as creating a discussion or toggling subscription to a forum
 * @property {TranslationFunction} t
 * @property {Function} navigateToGroup Function to navigate to associated group
 */

/**
 * @typedef {Function} TransformForumActionButtonsCallback
 * @property {Array.<Object>} action Contains objects for default action buttons
 */

/**
 * @typedef {Object} BeforeForumDetailsComponentProps
 * @property {ForumViewModel} forum
 */

/**
 * @typedef {Object} ForumDetailsComponentProps
 * @property {String} contentStyle Suggested content style
 * @property {Boolean} hideShortContent Returns true if a hook was used to indicate that short content should be hidden
 * @property {Object} global App global style
 * @property {ForumViewModel} forum
 * @property {String} forumShortContent Formatted forum short content
 * @property {React.ComponentType} ForumBottomSheetWrapper Reusable component derived from src/components/ActionButtons/ActionSheetButtonWrapper
 */

/**
 * @typedef {Object} AfterForumDetailsComponentProps
 * @property {ForumViewModel} forum
 */

/**
 * @typedef {Object} AfterForumProfileHeaderProps
 * @property {ForumViewModel} forum
 */

/**
 * @typedef {Object} HeaderRightComponentProps
 * @property {TranslationFunction} t
 * @property {ForumViewModel} forum
 * @property {Object} colors App colors
 * @property {Object} global App global style
 * @property {String} headerColor Header color used in app
 * @property {Array<Object>} actionButtons Contains objects for forum actions such as Create Discussion and Subscribe
 */

/**
 * @typedef {Object} AssociatedGroupComponentProps
 * @property {TranslationFunction} t
 * @property {Object} colors App colors
 * @property {Object} global App global style
 * @property {NavigationService} navigate
 * @property {String} uri Contains link to group's image
 * @property {String} name Group name
 * @property {String} subtitle Outputs the value of `forums:associatedGroup` translation
 *
 */

/**
 * @class
 * Forum Single Screen Hooks.
 * Instance name: forumSingleHooksApi
 
   You can use this hook to customize the different aspects of the forum such as adding components after forum details, hiding short content on the forum and so on.
 * @example
 * externalCodeSetup.forumSingleHooksApi.METHOD_NAME
 */
export class ForumSingleHooksApi {
	ForumHeaderRenderer = null;
	/**
	 * Adds a component below a forum's cover image and replaces components for displaying associated groups and components generated by hooks such as `forumSingleHooksApi.BeforeDetailsComponent`.
	 * @method
	 * @param {?React.ComponentType<ForumHeaderProps>} ForumHeaderRenderer
	 * @example <caption>Header component with more information display</caption>
	 * ...
	 *
	 * import HTML from "react-native-render-html";
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.forumSingleHooksApi.setForumHeaderRenderer((props) => {
	 *    const { forum, formatDateFunc } = props
	 *    return <View style={{ padding: 10 }}>
	 *
	 *      <Text> {forum.title}  </Text>
	 *      <HTML html={forum.content} />
	 *      <Text> Created {formatDateFunc(forum.date)}  </Text>
	 *      <Text> Last modified {formatDateFunc(forum.modified)}  </Text>
	 *    </View>
	 *  })
	 * }
	 *
	 */
	setForumHeaderRenderer = ForumHeaderRenderer => {
		this.ForumHeaderRenderer = ForumHeaderRenderer;
	};

	forumSingleHideShortContent = false;
	/**
	 * Hides forum short content text located below the forum title and is overlaid on top of forum cover image
	 * @method
	 * @example
	 * externalCodeSetup.forumSingleHooksApi.hideForumSingleShortContent();
	 */
	hideForumSingleShortContent = () => {
		this.forumSingleHideShortContent = true;
	};

	forumSingleHeaderHeight = null;
	/**
	 * You can use it to set the height of the forum header.
	 * Please keep in mind that the cover image, title and short content might be affected depending on height set.
	 * @method
	 * @param {Number} height
	 * @example
	 * externalCodeSetup.forumSingleHooksApi.setForumSingleHeaderHeight(100);
	 */
	setForumSingleHeaderHeight = height => {
		this.forumSingleHeaderHeight = height;
	};

	customHeaderBackground = null;

	/**
	 * It is used to replace the forum's cover image with your preferred image for the header background.
	 * @method
	 * @param {String} customHeaderBackground
	 * @example
	 * externalCodeSetup.forumSingleHooksApi.setCustomHeaderBackground('https://link-to-image.png')
	 */
	setCustomHeaderBackground = customHeaderBackground => {
		this.customHeaderBackground = customHeaderBackground;
	};

	filteredForumActionButtons = actions => actions;

	/**
	 * Append or prepend action buttons inside the forum action sheet.
	 * By default, only Create Discussion and Subscribe buttons are inside. Use this function to add more buttons.
	 * @method
	 * @param {TransformForumActionButtonsCallback} filteredForumActionButtons
	 * @example
	 *
	 * externalCodeSetup.forumSingleHooksApi.setFilteredForumActionButtons((action) => {
	 *
	 *    const share = () => {
	 *      //Create share function
	 *    }
	 *
	 *    const btnA = {
	 *      label: 'Share link',
	 *      doFunction: () => () => share(),
	 *      icon: {fontIconName: "hand-pointer", weight: "400"}
	 *    }
	 *
	 *    return [...action, btnA];
	 *
	 * })
	 */
	setFilteredForumActionButtons = filteredForumActionButtons => {
		this.filteredForumActionButtons = filteredForumActionButtons;
	};

	BeforeDetailsComponent = null;

	/**
	 * It used to add a component before the forum details.
	 * For example you can add a component before the forum short content description, title and other details.
	 * @method
	 * @param {React.ComponentType<BeforeForumDetailsComponentProps>} BeforeDetailsComponent
	 * @example <caption>Add a component before forum title, short content and other details</caption>
	 *
	 * externalCodeSetup.forumSingleHooksApi.setBeforeDetailsComponent((props) => {
	 *   const { forum } = props;
	 *   return <View style={{ padding: 10 }}>
	 *     <Text style={{color: "#fff"}}> Forum created by: {forum.author.name}  </Text>
	 *   </View>
	 * })
	 */
	setBeforeDetailsComponent = BeforeDetailsComponent => {
		this.BeforeDetailsComponent = BeforeDetailsComponent;
	};

	ForumDetailsComponent = null;

	/**
	 * Replaces the forum details component
	 * @method
	 * @param {React.ComponentType<ForumDetailsComponentProps>} ForumDetailsComponent
	 * @example <caption>Instead of short content, include the forum author</caption>
	 * ...
	 *
	 * const {width: DEVICE_WIDTH, height: DEVICE_HEIGHT} = Dimensions.get("window");
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  const ForumDetailsComponent = ({ contentStyle, hideShortContent, global, forum, forumShortContent, ForumBottomSheetWrapper, textStyle }) => {
	 *    return (
	 *      <View style={[styles.coverImage]}>
	 *        <Text
	 *          numberOfLines={2}
	 *          ellipsizeMode="tail"
	 *          style={[
	 *            global.textHeaderTitle,
	 *            {
	 *              textAlign: "center",
	 *              marginTop: 0
	 *            },
	 *            textStyle
	 *          ]}
	 *        >
	 *          {forum.title}
	 *        </Text>
	 *
	 *          <ForumBottomSheetWrapper>
	 *            <Text
	 *              ellipsizeMode="tail"
	 *              numberOfLines={DEVICE_HEIGHT < 700 ? 1 : 2}
	 *              style={[
	 *                global.textSmall,
	 *                {
	 *                  textAlign: "center",
	 *                  marginTop: 12
	 *                },
	 *                textStyle
	 *              ]}
	 *            >
	 *              This forum is moderated by {forum.author.name}
	 *            </Text>
	 *          </ForumBottomSheetWrapper>
	 *
	 *      </View>
	 *    )
	 *  }
	 *
	 *  externalCodeSetup.forumSingleHooksApi.setForumDetailsComponent((props) => <ForumDetailsComponent {...props} />)
	 * };
	 *
	 * const styles = StyleSheet.create({
	 *	coverImage: {
	 *		paddingBottom: 14,
	 *		paddingHorizontal: GUTTER * 2,
	 *		flex: 1,
	 *		width: "100%",
	 *		justifyContent: "flex-end",
	 *		marginBottom: 20
	 *	}
	 * });
	 *
	 */

	setForumDetailsComponent = ForumDetailsComponent => {
		this.ForumDetailsComponent = ForumDetailsComponent;
	};

	AfterDetailsComponent = null;

	/**
	 * It is used to add a component after the forum details.
	 * For example you can add a component after the forum title, short content description and more to display further details of the forum.
	 * @method
	 * @param {React.ComponentType<AfterForumDetailsComponentProps>} AfterDetailsComponent
	 * @example <caption>Add a component after forum title, short content and other details</caption>
	 *  externalCodeSetup.forumSingleHooksApi.setAfterDetailsComponent((props) => {
	 *   const { forum } = props;
	 *    return <View style={{ padding: 10 }}>
	 *     <Text style={{color: "#fff"}}> Forum created by: {forum.author.name}  </Text>
	 *    </View>
	 *  })
	 */
	setAfterDetailsComponent = AfterDetailsComponent => {
		this.AfterDetailsComponent = AfterDetailsComponent;
	};

	AfterProfileHeader = null;

	/**
	 * It used to add a component after the header.
	 * @method
	 * @param {React.ComponentType<AfterForumProfileHeaderProps>} AfterProfileHeader
	 * @example <caption>Add a touchable component after the forum header consisting of cover image and associated group components</caption>
	 * ...
	 *
	 * import FastImage from "react-native-fast-image";
	 * export const applyCustomCode = externalCodeSetup => {
	 *  const AfterForumProfileHeader = ({ forum }) => {
	 *   const goToAuthorProfile = () => {
	 *     //Redirect to author profile
	 *   }
	 *   return (
	 *     <TouchableOpacity onPress={ goToAuthorProfile }>
	 *       <FastImage style={{ width: "auto", height: 100 }} source={{ uri: "https://link-to-image.png" }} />
	 *     </TouchableOpacity>
	 *   )
	 *  }
	 *
	 *  externalCodeSetup.forumSingleHooksApi.setAfterProfileHeader(AfterForumProfileHeader)
	 * }
	 */
	setAfterProfileHeader = AfterProfileHeader => {
		this.AfterProfileHeader = AfterProfileHeader;
	};

	HeaderRightComponent = null;

	/**
	 * Replaces the headerRightComponent in forumSingleScreen.
	 * By default, headerRightComponent contains actions such as "Create Discussion" and "Subscribe"
	 * @method
	 * @param {React.ComponentType<HeaderRightComponentProps>} HeaderRightComponent
	 * @example <caption>Users would like to use Create Discussion and Subscribe buttons outside of an action sheet.</caption>
	 *  //(In custom_code/components/ForumHeaderButtons.js)
	 *
	 *  import React from 'react';
	 *  import { Button } from 'react-native';
	 *  import {useDispatch} from "react-redux";
	 *
	 *  export const ForumHeaderButtons = ({actionButtons, forum, t}) => {
	 *
	 *      //Use redux's dispatch to call actionButtons' functions.
	 *      //actionButtons[0] = create discussion, actionButtons[1] = subscribe/unsubscribe
	 *
	 *  	const dispatch = useDispatch();
	 *      return <>
	 *        <Button onPress={() => dispatch(actionButtons[0].doFunction(forum))} title={t(actionButtons[0].label)} />
	 *        <Button onPress={() => dispatch(actionButtons[1].doFunction(forum))} title={t(actionButtons[1].label)} />
	 *      </>
	 *  }
	 *  export default ForumHeaderButtons;
	 *
	 *  //(In custom_code/index.js)
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.forumSingleHooksApi.setHeaderRightComponent(({ t, forum, colors, global, headerColor, actionButtons, ...rest }) => {
	 *      //Pass the necessary props to the custom component
	 *      return <ForumHeaderButtons forum={forum} actionButtons={actionButtons} t={t}/>
	 *   })
	 * }
	 *
	 */
	setHeaderRightComponent = HeaderRightComponent => {
		this.HeaderRightComponent = HeaderRightComponent;
	};

	AssociatedGroupComponent = null;

	/**
	 * Replaces the Associated Group section in forumSingleScreen.
	 * For example, you can use this to remove the image and label "Associated Group" in the Associated Group component.
	 * @method
	 * @param {React.ComponentType<AssociatedGroupComponentProps>} AssociatedGroupComponent
	 * @example <caption>User would like to remove the image and label "Associated Group" in the Associated Group component</caption>
	 * ...
	 *
	 * import { FontWeights } from "@src/styles/global";
	 * import Icon from "@src/components/Icon";
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *    externalCodeSetup.forumSingleHooksApi.setAssociatedGroupComponent(({ t,
	 *        colors,
	 *        global,
	 *        navigate,
	 *        uri,
	 *        name,
	 *        subtitle }) => {
	 *
	 *        return <View
	 *            style={{
	 *                ...global.bottomBorder,
	 *                borderTopWidth: StyleSheet.hairlineWidth,
	 *                borderTopColor: colors.borderColor,
	 *                paddingHorizontal: 20,
	 *                paddingVertical: 12,
	 *                backgroundColor: colors.bodyBg
	 *            }}>
	 *            <TouchableWithoutFeedback onPress={navigate}>
	 *
	 *                <View style={global.row}>
	 *                    <View style={{ marginLeft: 10, flex: 1 }}>
	 *                        <Text
	 *                            style={[
	 *                                global.textAlt,
	 *                                {
	 *                                    fontSize: 15,
	 *                                    fontWeight: FontWeights.medium,
	 *                                    maxWidth: "95%"
	 *                                }
	 *                            ]}
	 *                            numberOfLines={1}
	 *                            ellipsizeMode={"tail"}
	 *                        >
	 *                            {name}
	 *                        </Text>
	 *                    </View>
	 *                    <Icon
	 *                        icon={{fontIconName: "u-turn-left", weight: 400}}
	 *                        webIcon={"IconArrowBack"}
	 *                        tintColor={colors.textIconColor}
	 *                        styles={{
	 *                            width: 20,
	 *                            height: 20
	 *                        }}
	 *                    />
	 *                </View>
	 *            </TouchableWithoutFeedback>
	 *        </View>
	 *    })
	 *
	 * };
	 *
	 *
	 * @example <caption>User would like to remove the Associated Group Component</caption>
	 * externalCodeSetup.forumSingleHooksApi.setAssociatedGroupComponent(() => {
	 *   return null
	 * })
	 */
	setAssociatedGroupComponent = AssociatedGroupComponent => {
		this.AssociatedGroupComponent = AssociatedGroupComponent;
	};
}