Source

externalCode/blogSingle.ts

import * as React from "react";
import {
	BlogViewModel,
	NavigationService,
	TTranslationFunction,
	WebSource
} from "./types";
export const API_NAME = "blogSingleApi";
/**
 * Blog comment
 */
type BlogComment = {
	/**
	 * Id of comment
	 */
	id: number,
	/**
	 * Id of post where comment was written
	 */
	post: number,
	/**
	 *  Id of the parent entity if the comment is a child of it
	 */
	parent: number,
	/**
	 * Id of the author of the comment
	 */
	author: number,
	/**
	 * Author name
	 */
	author_name: string,
	/**
	 * Date when the comment was posted
	 */
	date: string,
	/**
	 * Content of the comment
	 */
	content: Record<any, any>,
	/**
	 * Url to the comment
	 */
	link: string,
	/**
	 * Comment status
	 */
	status: string,
	/**
	 * Returns `true` if comment can be reported
	 */
	can_report: boolean,
	/**
	 * Returns `true` if comment was reported
	 */
	reported: boolean,
	/**
	 * Text of the report button
	 */
	report_button_text: string,
	/**
	 * Type of report
	 */
	report_type: string,
	/**
	 * Returns `true` if comment can be deleted
	 */
	can_delete: boolean
};

/**
 * BeforeDetailsComponentProps
 */
type BeforeDetailsComponentProps = {
	blog: BlogViewModel
};

/**
 * AfterDetailsComponentProps
 */
type AfterDetailsComponentProps = {
	blog: BlogViewModel
};

/**
 * BlogHeaderAvatarProps
 */
type BlogHeaderAvatarProps = {
	blog: BlogViewModel,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * Returns a defined style object if blog is using a featured image
	 */
	textStyle: Record<any, any>
};

/**
 * BlogDetailsComponentProps
 */
type BlogDetailsComponentProps = {
	blog: BlogViewModel,
	/**
	 * App global style
	 */
	globalStyle: Record<any, any>,
	/**
	 * Uses useMemo() hook and returns `animatedOpacity`
	 */
	animatedOpacity: Function,
	/**
	 * Returns a defined style object if blog is using a featured image
	 */
	textStyle: Record<any, any>
};
/**
 * BlogSingleBodyProps
 */
type BlogSingleBodyProps = {
	blog: BlogViewModel,
	/**
	 * Return `true` if online
	 */
	online: boolean,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	navigation: NavigationService,
	/**
	 * App configuration object
	 */
	config: Record<any, any>,
	/**
	 * Tag default styles
	 */
	tagsStyles: Record<any, any>,
	/**
	 * Function to set a font style
	 */
	baseFontStyle: Function,
	/**
	 * Default computed width of component to render
	 */
	computedWidth: number,
	/**
	 * Helper function which is used for deep linking when a link is pressed
	 */
	linkClickHandler: Function,
	/**
	 * Helper function which can be passed to a webview to start a request by attempting to deep link
	 */
	onShouldStartLoadWithRequest: Function
};

/**
 * AfterBlogProfileHeaderProps
 */
type AfterBlogProfileHeaderProps = {
	blog: BlogViewModel
};

/**
 * BeforeBlogSingleBodyProps
 */
type BeforeBlogSingleBodyProps = {
	blog: BlogViewModel,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Helper function which is used for deep linking when a link is pressed
	 */
	linkClickHandler: Function,
	t: TTranslationFunction,
	navigation: NavigationService
};
/**
 * AfterBlogSingleBodyProps
 */
type AfterBlogSingleBodyProps = {
	blog: BlogViewModel,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Helper function which is used for deep linking when a link is pressed
	 */
	linkClickHandler: Function,
	t: TTranslationFunction,
	navigation: NavigationService
};

/**
 * CommentsModalHeaderProps
 */
type CommentsModalHeaderProps = {
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	t: TTranslationFunction,
	/**
	 * Default style of modal header
	 */
	modalHeaderContainerStyle: Record<any, any>,
	/**
	 * Closes the modal
	 */
	closeCommentsModal: Function,
	/**
	 * Returns `true` if comments are allowed in the post
	 */
	allowComments: boolean
};
/**
 * TransformBlogButtonsCallback
 */
type TransformBlogButtonsCallback = {
	/**
	 * Buttons for comment, facebook and twitter share
	 */
	buttons: JSX.Element[],
	blog: BlogViewModel
};

/**
 * CommentAvatarProps
 */
type CommentAvatarProps = {
	/**
	 * Url of avatar
	 */
	avatarUrl: string
};

/**
 * CommentHeaderProps
 */
type CommentHeaderProps = {
	/**
	 * App global style
	 */
	global: Record<any, any>,
	commentVM: BlogComment,
	/**
	 * Default style for container
	 */
	nameDateContainerStyle: Record<any, any>
};

/**
 * CommentContentProps
 */
type CommentContentProps = {
	commentVM: BlogComment,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * Default styles for blog comments
	 */
	blogCommentTagStyles: Record<any, any>,
	/**
	 * Helper function which is used for deep linking
	 */
	onLinkPress: Function
};

/**
 * CommentButtonsProps
 */
type CommentButtonsProps = {
	comment: BlogComment,
	t: TTranslationFunction,
	/**
	 * Links the reply to the comment being added in the input component
	 */
	onComment: Function,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Opens a modal for reporting the comment
	 */
	navigateToReport: Function
};

/**
 * CommentReplyButtonsProps
 */
type CommentReplyButtonsProps = {
	item: BlogComment,
	t: TTranslationFunction,
	/**
	 * Links the reply to the comment being added in the input component
	 */
	replyPress: Function,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	/**
	 * Opens a modal for reporting the comment
	 */
	navigateToReport: Function
};

/**
 * BlogWebViewProps
 */
type BlogWebViewProps = {
	blog: BlogViewModel,
	/**
	 * `true` if device is online
	 */
	online: boolean,
	t: TTranslationFunction,
	/**
	 * Default height for the web view
	 */
	webViewHeight: number,
	/**
	 * App global style
	 */
	global: Record<any, any>,
	/**
	 * App colors
	 */
	colors: Record<any, any>,
	source: WebSource,
	/**
	 * function which can be used by the web view's `onShouldStartLoadWithRequest` prop
	 */
	onShouldStartLoadWithRequest: Function,
	/**
	 * Modal which shows up when the "Read More" component is pressed
	 */
	ModalHeaderComponent: React.Component<any>
};

/**
 * BookmarkComponentProps
 */
type BookmarkComponentProps = {
	/**
	 * App global style
	 */
	global: Record<any, any>,

	/**
	 * Default styles
	 */
	styles: Record<any, any>,

	/**
	 * Toggles bookmark function
	 */
	onPress: () => void,

	/**
	 * Default hit slop assigned to the button
	 */
	hitSlop: Record<any, any>,

	/**
	 * Bookmark animation
	 */
	animatedStyle: Record<any, any>,

	/**
	 * Returns `true` if fix for alignRight should be added
	 */
	fixAlignRight: boolean,

	/**
	 * Returns `true` item is bookmarked
	 */
	bookmarked: boolean,

	/**
	 * Default icon name
	 */
	fontIconName: string,

	/**
	 * Default icon variant
	 */
	fontIconVariant: string,

	/**
	 * Tint color of bookmark
	 */
	tintColor: string,

	/**
	 * Returns `true` if underlay style should be used
	 */
	withUnderlay: boolean,

	/**
	 * Underlay theme to be used
	 */
	underlayTheme: string,

	/**
	 * Navigation service
	 */
	navigation: NavigationService
};

/**
 * @class
 * Blog Single Hooks.
 * Instance name: blogSingleApi
  
   You can utilize this to add details to your blog page and modify its structure.
 * @example
 * externalCodeSetup.blogSingleApi.METHOD_NAME
 */
export class BlogSingleApi {
	customHeaderBackground: string | null = null;

	/**
	 * You can add a custom cover image or banner for all your blogs to replace the default blog cover image.
	 * (If you want to change the image header background for a particular blog, then you would have to specify the blog in your function.)
	 * @param {String} customHeaderBackground Resource to replace a blog's cover image
	 * @method
	 * @example
	 *
	 * externalCodeSetup.blogSingleApi.setCustomHeaderBackground('https://link-to-image.png');
	 */
	setCustomHeaderBackground = (customHeaderBackground: string | null) => {
		this.customHeaderBackground = customHeaderBackground;
	};

	BeforeDetailsComponent: React.ComponentType<
		BeforeDetailsComponentProps
	> | null = null;

	/**
	 * You can use this to add a component displaying information such as title and author before the blog details.
	 * @param {React.ComponentType<BeforeDetailsComponentProps>} BeforeDetailsComponent
	 * @method
	 * @example
	 * //In custom_code/components/BeforeDetails.js
	 *
	 * import React from 'react';
	 * import { View, Text } from 'react-native';
	 * import moment from 'moment';
	 * const BeforeDetails = (props) => {
	 *
	 *    const {blog} = props;
	 *
	 *    const lastModified = moment(blog.modified).startOf('day').fromNow();
	 *
	 *    return <View style={{padding: 20}}>
	 *        <Text> This blog was last modified {lastModified} </Text>
	 *    </View>
	 * }
	 *
	 * export default BeforeDetails;
	 *
	 * //In custom_code/index.js
	 *
	 * import BeforeDetails from "./components/BeforeDetails";
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.blogSingleApi.setBeforeDetailsComponent((props) => <BeforeDetails {...props} />)
	 * }
	 *
	 */
	setBeforeDetailsComponent = (
		BeforeDetailsComponent: React.ComponentType<
			BeforeDetailsComponentProps
		> | null
	) => {
		this.BeforeDetailsComponent = BeforeDetailsComponent;
	};

	AfterDetailsComponent: React.ComponentType<
		AfterDetailsComponentProps
	> | null = null;

	/**
	 * You can use this to add a component that displays details of the blogs such as author name and blog title within the header.
	 * @param {React.ComponentType<AfterDetailsComponentProps>} AfterDetailsComponent
	 * @method
	 * @example
	 * //In custom_code/components/AfterDetails.js
	 *
	 * import React from 'react';
	 * import { View, Text } from 'react-native';
	 * import moment from 'moment';
	 * const AfterDetails = (props) => {
	 *
	 *    const {blog} = props;
	 *
	 *    const lastModified = moment(blog.modified).startOf('day').fromNow();
	 *
	 *    return <View style={{padding: 20}}>
	 *        <Text> This blog was last modified {lastModified} </Text>
	 *    </View>
	 * }
	 *
	 * export default AfterDetails;
	 *
	 * //In custom_code/index.js
	 *
	 * ...
	 *
	 * import AfterDetails from "./components/AfterDetails";
	 * export const applyCustomCode = externalCodeSetup => {
	 *   externalCodeSetup.blogSingleApi.setAfterDetailsComponent((props) => <AfterDetails {...props} />)
	 * }
	 *
	 */
	setAfterDetailsComponent = (
		AfterDetailsComponent: React.ComponentType<
			AfterDetailsComponentProps
		> | null
	) => {
		this.AfterDetailsComponent = AfterDetailsComponent;
	};

	BlogDetailsComponent: React.ComponentType<
		BlogDetailsComponentProps
	> | null = null;

	/**
	 * It replaces the blog details component in the header.
	 * @param {React.ComponentType<BlogDetailsComponentProps>} BlogDetailsComponent
	 * @method
	 * @example
	 *
	 * import React from "react";
	 * import Animated from "react-native-reanimated";
	 * export const applyCustomCode = externalCodeSetup => {
	 *     const BlogDetailsComponent = ({
	 *         blog,
	 *         globalStyle,
	 *         animatedOpacity,
	 *         textStyle
	 *     }) => {
	 *         return (
	 *             <Animated.Text
	 *                 numberOfLines={4}
	 *                 style={[
	 *                     globalStyle.textHeaderTitle,
	 *                     {alignSelf: "flex-start"},
	 *                     textStyle,
	 *                     animatedOpacity
	 *                 ]}
	 *             >
	 *                 {blog.title}
	 *             </Animated.Text>
	 *         );
	 *     };
	 *     externalCodeSetup.blogSingleApi.setBlogDetailsComponent(BlogDetailsComponent);
	 * };
	 */
	setBlogDetailsComponent = (
		BlogDetailsComponent: React.ComponentType<BlogDetailsComponentProps> | null
	) => {
		this.BlogDetailsComponent = BlogDetailsComponent;
	};

	BlogHeaderAvatar: React.ComponentType<BlogHeaderAvatarProps> | null = null;

	/**
	 * You can replace the blog header avatar instead of using the default settings that includes displays of avatar, author name and publishing date.
	 * @param {React.ComponentType<BlogHeaderAvatarProps>} BlogHeaderAvatar
	 * @method
	 * @example <caption>User would like to add more info in the BlogHeaderAvatar component</caption>
	 *
	 * ...
	 *
	 * import AppAvatar from "@src/components/AppAvatar";
	 * import {FontWeights} from "@src/styles/global";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *  const BlogHeaderAvatar = ({  blog, global, textStyle }) => {
	 *   return (
	 *     <View style={[global.row, { flex: 1 }]}>
	 *        <AppAvatar
	 *            size={35}
	 *            source={{ uri: blog.avatar }}
	 *            style={{ marginRight: 10 }}
	 *        />
	 *        <View>
	 *            <Text
	 *                style={[global.text, { fontWeight: FontWeights.semiBold }, textStyle]}>
	 *                {blog.authorName}
	 *            </Text>
	 *            <Text style={[global.text, { fontWeight: FontWeights.semiBold }, textStyle]}>{blog.link}</Text>
	 *            <Text style={[global.textMeta, textStyle]}>{blog.date}</Text>
	 *        </View>
	 *     </View>
	 *    );
	 *
	 *  }
	 *  externalCodeSetup.blogSingleApi.setBlogHeaderAvatar(BlogHeaderAvatar);
	 * }
	 */
	setBlogHeaderAvatar = (
		BlogHeaderAvatar: React.ComponentType<BlogHeaderAvatarProps> | null
	) => {
		this.BlogHeaderAvatar = BlogHeaderAvatar;
	};

	// transformBlogHeaderButtons = (
	// 	buttons: Array<JSX.Element>,
	// 	blog: BlogViewModel
	// ) => buttons;
	transformBlogHeaderButtons = (buttons: JSX.Element[], blog: BlogViewModel) =>
		buttons;

	/**
	 * You can transform default blog buttons for commenting, Facebook and Twitter sharing and replace it with your preferred ones.
	 * @param {TransformBlogButtonsCallback} transformBlogHeaderButtons
	 * @method
	 * @example <caption>Add an email share button</caption>
	 *
	 * ...
	 *
	 * import Share from "react-native-share";
	 * import IconButton from "@src/components/IconButton";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *    externalCodeSetup.blogSingleApi.setTransformBlogHeaderButtons((buttons, blog) => {
	 *
	 *        const social = Share.Social.EMAIL;
	 *
	 *        const hasCover = !!blog.featuredImage;
	 *        const iconBackgroundColor = hasCover ? "#fff" : "#A6ADB5";
	 *        const iconTintColor = hasCover ? "#000" : "#fff";
	 *
	 *        const Email = <IconButton
	 *            pressHandler={() =>
	 *                Share.shareSingle({
	 *                        message: blog.excerpt.rendered,
	 *                        url: blog.link,
	 *                        title: blog.title,
	 *                        subject: blog.title,
	 *                        email: "[email protected]",
	 *                        social: social
	 *                    })
	 *            }
	 *            icon={{uri: "https://link-to-image.png"}}
	 *            touchableStyle={{
	 *                backgroundColor: iconBackgroundColor,
	 *                alignItems: "center",
	 *                borderRadius: 18,
	 *                padding: 0,
	 *                marginRight: 8
	 *            }}
	 *            tintColor={iconTintColor}
	 *            style={{ height: 28, width: 28 }}
	 *            rtlStyleFix={"handled"}
	 *        />
	 *
	 *        return [...buttons, Email];
	 *
	 *    })
	 * }
	 */
	setTransformBlogHeaderButtons = (
		transformBlogHeaderButtons: (
			buttons: JSX.Element[],
			blog: BlogViewModel
		) => JSX.Element[]
	) => {
		this.transformBlogHeaderButtons = transformBlogHeaderButtons;
	};

	AfterProfileHeader: React.ComponentType<
		AfterBlogProfileHeaderProps
	> | null = null;

	/**
	 * Used to add a component below the header if you want to include an abstract, image or any other information.
	 * @param {React.ComponentType<AfterBlogProfileHeaderProps>} AfterProfileHeader
	 * @method
	 * @example <caption>Add a banner image after blog profile header component</caption>
	 *
	 * ...
	 *
	 * import FastImage from "react-native-fast-image";
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *    const AfterProfileHeader = ({ blog }) => {
	 *        return (<FastImage style={{width: "auto", height: 100}} source={{uri: "https://link-to-image.png"}} />)
	 *    }
	 *
	 *    externalCodeSetup.blogSingleApi.setAfterProfileHeader(AfterProfileHeader)
	 * }
	 */
	setAfterProfileHeader = (
		AfterProfileHeader: React.ComponentType<AfterBlogProfileHeaderProps> | null
	) => {
		this.AfterProfileHeader = AfterProfileHeader;
	};

	BeforeBlogSingleBody: React.ComponentType<
		BeforeBlogSingleBodyProps
	> | null = null;

	/**
	 * You can use this to add a component before the blog's body component.
	 * @param {React.ComponentType<BeforeBlogSingleBodyProps>} BeforeBlogSingleBody
	 * @method
	 * @example <caption> Add HTML with redirect function </caption>
	 *
	 * ...
	 *
	 * import HTML from "react-native-render-html";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.blogSingleApi.setBeforeBlogSingleBody((props) => {
	 *
	 *    const html = `Go to link: <a href="https://buddyboss.com">BuddyBoss</a>`;
	 *
	 *    return <View style={{ flex: 1, borderRadius: 10, borderWidth: 1, padding: 10, alignItems: "center" }}>
	 *      <HTML
	 *        containerStyle={{
	 *          paddingTop: 2,
	 *          paddingBottom: 1,
	 *          flex: 1
	 *        }}
	 *        html={html}
	 *        onLinkPress={props.linkClickHandler}
	 *      />
	 *    </View>
	 *
	 *  })
	 * }
	 *
	 */
	setBeforeBlogSingleBody = (
		BeforeBlogSingleBody: React.ComponentType<BeforeBlogSingleBodyProps> | null
	) => {
		this.BeforeBlogSingleBody = BeforeBlogSingleBody;
	};

	AfterBlogSingleBody: React.ComponentType<
		AfterBlogSingleBodyProps
	> | null = null;

	/**
	 * You can use this to add a component after the blog's body component.
	 * @param {React.ComponentType<AfterBlogSingleBodyProps>} AfterBlogSingleBody
	 * @method
	 * @example <caption> Display other blogs from redux state </caption>
	 *
	 * ...
	 *
	 * import { useSelector } from "react-redux";
	 * export const applyCustomCode = externalCodeSetup => {
	 *
	 *  externalCodeSetup.blogSingleApi.setAfterBlogSingleBody((props) => {
	 *
	 *    const blogIds = useSelector(state => state.blog.all.ids);
	 *    const blogCache = useSelector(state => state.blogCache);
	 *
	 *    if (blogIds.size > 0) {
	 *
	 *      const goToBlog = (blog) => {
	 *        props.navigation.dispatch(
	 *          props.navigation.navigate({
	 *            routeName: "BlogSingleScreen",
	 *            params: {
	 *              blog
	 *            },
	 *	            key: `BlogSingleScreen-${blog.id.toString()}`
	 *          })
	 *        );
	 *      }
	 *
	 *      return <>
	 *        {blogIds.map((id) => {
	 *
	 *          if (props.blog.id == id) {
	 *            return null;
	 *          }
	 *
	 *          const details = blogCache.byId.get(id.toString());
	 *
	 *          return <TouchableOpacity style={{margin: 30}} onPress={() => goToBlog(details)}>
	 *            <View style={{flex: 1, borderRadius: 10, borderWidth: 1, padding: 10, alignItems: "center"}}>
	 *              <Text>
	 *                {details.title.rendered}
	 *              </Text>
	 *            </View>
	 *          </TouchableOpacity>
	 *
	 *        })}
	 *      </>
	 *
	 *    }
	 *
	 *    return null;
	 *
	 *  });
	 * }
	 */
	setAfterBlogSingleBody = (
		AfterBlogSingleBody: React.ComponentType<AfterBlogSingleBodyProps> | null
	) => {
		this.AfterBlogSingleBody = AfterBlogSingleBody;
	};

	BlogSingleBody: React.ComponentType<BlogSingleBodyProps> | null = null;

	/**
	 *
	 * You can use this hook to customize the body/content of the blog.
	 *
	 * @param {React.ComponentType<BlogSingleBodyProps>} BlogSingleBody
	 * @method
	 * @example <caption> Generate the content using the react-native-render-html library </caption>
	 *
	 * ...
	 *
	 * import HTML from 'react-native-render-html';
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *   externalCodeSetup.blogSingleApi.setBlogSingleBody(({blog}) => <HTML html={blog.content} />);
	 * }
	 */
	setBlogSingleBody = (
		BlogSingleBody: React.ComponentType<BlogSingleBodyProps> | null
	) => {
		this.BlogSingleBody = BlogSingleBody;
	};

	CommentsModalHeader: React.ComponentType<
		CommentsModalHeaderProps
	> | null = null;

	/**
	 *
	 * You can use this hook to customize the modal's header.
	 *
	 * @param {React.ComponentType<CommentsModalHeaderProps>} CommentsModalHeader
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * import IconButton from "@src/components/IconButton";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *
	 *   externalCodeSetup.blogSingleApi.setCommentsModalHeader(({
	 *     global,
	 *     modalHeaderContainerStyle,
	 *     closeCommentsModal,
	 *     colors,
	 *     t
	 *   }) => {
	 *
	 *     return <View style={[global.row, modalHeaderContainerStyle]}>
	 *       <IconButton
	 *         icon={{fontIconName: "angle-left", weight: 400}}
	 *         pressHandler={closeCommentsModal}
	 *         tintColor={colors.linkColor}
	 *         style={{height: 20, width: 20, alignSelf: "center"}}
	 *         touchableStyle={{alignItems: "center", justifyContent: "center"}}
	 *         renderText={() => (
	 *           <Text style={[global.seeLink]}>{t("common:back")}</Text>
	 *         )}
	 *       />
	 *
	 *       <Text style={[global.filterTitle, { flex: 1, textAlign: "center" }]}>
	 *         {t("blog:comments")}
	 *       </Text>
	 *
	 *       <View style={{ width: 44 }} />
	 *     </View>
	 *
	 *   })
	 * }
	 */
	setCommentsModalHeader = (
		CommentsModalHeader: React.ComponentType<CommentsModalHeaderProps> | null
	) => {
		this.CommentsModalHeader = CommentsModalHeader;
	};

	CommentAvatar: React.ComponentType<CommentAvatarProps> | null = null;

	/**
	 *
	 * You can use this hook to customize the avatar of the user who added the comment.
	 *
	 * @param {React.ComponentType<CommentAvatarProps>} CommentAvatar
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * import AppAvatar from "@src/components/AppAvatar";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *   externalCodeSetup.blogSingleApi.setCommentAvatar(({ avatarUrl }) =>
	 *     <AppAvatar
	 *       size={48}
	 *       source={{ uri: avatarUrl }}
	 *       style={{ marginRight: 10 }}
	 *     />)
	 * }
	 */
	setCommentAvatar = (
		CommentAvatar: React.ComponentType<CommentAvatarProps> | null
	) => {
		this.CommentAvatar = CommentAvatar;
	};

	CommentHeader: React.ComponentType<CommentHeaderProps> | null = null;

	/**
	 *
	 * You can use this hook to customize the component which displays the name of the user who added the comment and the comment's date.
	 *
	 * @param {React.ComponentType<CommentHeaderProps>} CommentHeader
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * import { ItemTitle } from "@src/components/TextComponents";
	 * export const applyCustomCode = (externalCodeSetup: ExternalCodeSetup) => {
	 *
	 *   externalCodeSetup.blogSingleApi.setCommentHeader(({
	 *     nameDateContainerStyle,
	 *     commentVM,
	 *     global
	 *   }) => <View style={nameDateContainerStyle}>
	 *       <ItemTitle global={global}>{commentVM.author_name}</ItemTitle>
	 *       <View style={{ width: 8 }} />
	 *       <Text style={global.textItemSubtitle}>{commentVM.date}</Text>
	 *     </View>
	 *   )
	 * }
	 *
	 */
	setCommentHeader = (
		CommentHeader: React.ComponentType<CommentHeaderProps> | null
	) => {
		this.CommentHeader = CommentHeader;
	};

	CommentContent: React.ComponentType<CommentContentProps> | null = null;

	/**
	 * You can use this hook to customize the content of the comment.
	 *
	 * @param {React.ComponentType<CommentContentProps>} CommentContent
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * import HTML from 'react-native-render-html';
	 * export const applyCustomCode = (externalCodeSetup: ExternalCodeSetup) => {
	 *
	 *   externalCodeSetup.blogSingleApi.setCommentContent(({
	 *     commentVM,
	 *     global,
	 *     blogCommentTagStyles,
	 *     onLinkPress
	 *   }) =>
	 *     <HTML
	 *       html={commentVM.content}
	 *       baseFontStyle={global.text}
	 *       tagsStyles={blogCommentTagStyles}
	 *       onLinkPress={onLinkPress()}
	 *     />
	 *   )
	 * }
	 */
	setCommentContent = (
		CommentContent: React.ComponentType<CommentContentProps> | null
	) => {
		this.CommentContent = CommentContent;
	};

	CommentButtons: React.ComponentType<CommentButtonsProps> | null = null;

	/**
	 * You can use this hook to customize the buttons that are displayed below the comment.
	 *
	 * @param {React.ComponentType<CommentButtonsProps>} CommentButtons
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * import BlogCommentButtons from "@src/components/Common/Buttons/BlogCommentButtons";
	 * export const applyCustomCode = (externalCodeSetup: ExternalCodeSetup) => {
	 *
	 *   externalCodeSetup.blogSingleApi.setCommentButtons(({
	 *     comment,
	 *     onComment,
	 *     t,
	 *     global,
	 *     colors,
	 *     navigateToReport
	 *   }) => <BlogCommentButtons
	 *       {...{
	 *         item: comment,
	 *         t,
	 *         replyPress: onComment,
	 *         global,
	 *         colors,
	 *         navigateToReport
	 *       }}
	 *     />
	 *   )
	 * }
	 *
	 */
	setCommentButtons = (
		CommentButtons: React.ComponentType<CommentButtonsProps> | null
	) => {
		this.CommentButtons = CommentButtons;
	};

	CommentReplyAvatar: React.ComponentType<CommentAvatarProps> | null = null;

	/**
	 *
	 * You can use this hook to customize the avatar of the user who added a reply to a comment.
	 *
	 * @param {React.ComponentType<CommentAvatarProps>} CommentReplyAvatar
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * import AppAvatar from "@src/components/AppAvatar";
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *   externalCodeSetup.blogSingleApi.setCommentReplyAvatar(({ avatarUrl }) =>
	 *     <AppAvatar
	 *       size={36}
	 *       source={{ uri: avatarUrl }}
	 *       style={{ marginRight: 10 }}
	 *     />)
	 * }
	 */
	setCommentReplyAvatar = (
		CommentReplyAvatar: React.ComponentType<CommentAvatarProps> | null
	) => {
		this.CommentReplyAvatar = CommentReplyAvatar;
	};

	CommentReplyHeader: React.ComponentType<CommentHeaderProps> | null = null;

	/**
	 *
	 * You can use this hook to customize the component which displays a reply to the comment.
	 * This can modify the name of the user who added the comment and the comment's date.
	 *
	 * @param {React.ComponentType<CommentHeaderProps>} CommentReplyHeader
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * import { ItemTitle } from "@src/components/TextComponents";
	 * export const applyCustomCode = (externalCodeSetup: ExternalCodeSetup) => {
	 *
	 *   externalCodeSetup.blogSingleApi.setCommentReplyHeader(({
	 *     nameDateContainerStyle,
	 *     commentVM,
	 *     global
	 *   }) => <View style={nameDateContainerStyle}>
	 *       <ItemTitle global={global}>{commentVM.author_name}</ItemTitle>
	 *       <View style={{ width: 8 }} />
	 *       <Text style={global.textItemSubtitle}>{commentVM.date}</Text>
	 *     </View>
	 *   )
	 * }
	 *
	 */
	setCommentReplyHeader = (
		CommentReplyHeader: React.ComponentType<CommentHeaderProps> | null
	) => {
		this.CommentReplyHeader = CommentReplyHeader;
	};

	CommentReplyContent: React.ComponentType<CommentContentProps> | null = null;

	/**
	 * You can use this hook to customize the reply content to a comment.
	 * @param {React.ComponentType<CommentContentProps>} CommentReplyContent
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * import HTML from 'react-native-render-html';
	 * export const applyCustomCode = (externalCodeSetup: ExternalCodeSetup) => {
	 *
	 *   externalCodeSetup.blogSingleApi.setCommentReplyContent(({
	 *     commentVM,
	 *     global,
	 *     blogCommentTagStyles,
	 *     attemptDeepLink
	 *   }) =>
	 *     <HTML
	 *       html={commentVM.content}
	 *       baseFontStyle={global.text}
	 *       tagsStyles={blogCommentTagStyles}
	 *       onLinkPress={attemptDeepLink(false)}
	 *     />
	 *   )
	 * }
	 */
	setCommentReplyContent = (
		CommentReplyContent: React.ComponentType<CommentContentProps> | null
	) => {
		this.CommentReplyContent = CommentReplyContent;
	};

	CommentReplyButtons: React.ComponentType<
		CommentReplyButtonsProps
	> | null = null;

	/**
	 * You can use this hook to customize the buttons that are displayed below a reply comment.
	 *
	 * @param {React.ComponentType<CommentReplyButtonsProps>} CommentReplyButtons
	 * @method
	 * @example
	 *
	 * ...
	 *
	 * import BlogCommentButtons from "@src/components/Common/Buttons/BlogCommentButtons";
	 * export const applyCustomCode = (externalCodeSetup: ExternalCodeSetup) => {
	 *
	 *   externalCodeSetup.blogSingleApi.setCommentReplyButtons(({
	 *     item,
	 *     t,
	 *     replyPress,
	 *     colors,
	 *     global,
	 *     navigateToReport
	 *   }) => <BlogCommentButtons
	 *       {...{
	 *         item,
	 *         t,
	 *         replyPress,
	 *         global,
	 *         colors,
	 *         navigateToReport
	 *       }}
	 *     />
	 *   )
	 * }
	 *
	 */
	setCommentReplyButtons = (
		CommentReplyButtons: React.ComponentType<CommentReplyButtonsProps> | null
	) => {
		this.CommentReplyButtons = CommentReplyButtons;
	};

	BlogWebView: React.ComponentType<BlogWebViewProps> | null = null;
	/**
	 * You can use this to hook to replace the webview component that shows a "Read more" button when rendering a post as a web fallback.
	 * For example, you can use this hook to render the full content without the use of a "Read more" button.
	 * @param {React.ComponentType<BlogWebViewProps>} BlogWebView
	 * @method
	 * @example
	 *
	 * import WebViewWithMore from "@src/components/WebViewWithMore";
	 *
	 * export const applyCustomCode = (externalCodeSetup) => {
	 *     externalCodeSetup.blogSingleApi.setBlogWebView(
	 *         ({
	 *             blog,
	 *             online,
	 *             t,
	 *             webViewHeight,
	 *             source,
	 *             global,
	 *             colors,
	 *             onShouldStartLoadWithRequest,
	 *             ModalHeaderComponent
	 *         }) => {
	 *             return (
	 *                 <View style={{paddingTop: 10}}>
	 *                     <WebViewWithMore
	 *                         online={online}
	 *                         t={t}
	 *                         height={webViewHeight}
	 *                         source={source}
	 *                         global={global}
	 *                         colors={colors}
	 *                         onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
	 *                         ModalHeaderComponent={ModalHeaderComponent}
	 *                     />
	 *                 </View>
	 *             );
	 *         }
	 *     );
	 * }
	 */
	setBlogWebView = (
		BlogWebView: React.ComponentType<BlogWebViewProps> | null
	) => {
		this.BlogWebView = BlogWebView;
	};

	BookmarkComponent: React.ComponentType<BookmarkComponentProps> | null = null;

	/**
	 * You can use this hook to modify the bookmark component.
	 * @method
	 * @param {?React.ComponentType<BookmarkComponentProps>} BookmarkComponent
	 * @example
	 *
	 *
	 * import React from "react";
	 * import {View, TouchableOpacity, Animated} from "react-native";
	 * import IconButton from "@src/components/IconButton";
	 *
	 * export const applyCustomCode = externalCodeSetup => {
	 *    externalCodeSetup.blogSingleApi.setBookmarkComponent(props => {
	 *        const {
	 *            global,
	 *            styles,
	 *            onPress,
	 *            hitSlop,
	 *            animatedStyle,
	 *            fixAlignRight,
	 *            bookmarked,
	 *            fontIconName,
	 *            fontIconVariant,
	 *            tintColor,
	 *            withUnderlay,
	 *            underlayTheme
	 *        } = props;
	 *        return (
	 *            <View style={[global.column, styles.bookmarkContainer]}>
	 *                <TouchableOpacity
	 *                    onPress={onPress}
	 *                    activeOpacity={0.5}
	 *                    hitSlop={hitSlop}
	 *                >
	 *                    <Animated.View style={animatedStyle}>
	 *                        <IconButton
	 *                            fixAlignRight={fixAlignRight}
	 *                            withUnderlay={withUnderlay}
	 *                            underlayTheme={underlayTheme}
	 *                            icon={{
	 *                                fontIconName: fontIconName,
	 *                                fontIconVariant: fontIconVariant
	 *                            }}
	 *                            tintColor={tintColor}
	 *                            size={20}
	 *                        />
	 *                    </Animated.View>
	 *                </TouchableOpacity>
	 *            </View>
	 *        );
	 *    });
	 * }
	 */
	setBookmarkComponent = (
		BookmarkComponent: React.ComponentType<BookmarkComponentProps> | null
	) => {
		this.BookmarkComponent = BookmarkComponent;
	};
}