UNPKG

fastcomments-react-native-sdk

Version:

React Native FastComments Components. Add live commenting to any React Native application.

94 lines (93 loc) 6.8 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import RenderHtml, { defaultHTMLElementModels, HTMLContentModel, RenderHTMLConfigProvider, TRenderEngineProvider } from "react-native-render-html"; import { ActivityIndicator, FlatList, useWindowDimensions, View, Text } from "react-native"; import { useHookstate, useHookstateEffect } from "@hookstate/core"; import React, { useState } from 'react'; import { PaginationNext } from "./pagination-next"; import { PaginationPrev } from "./pagination-prev"; import { canPaginateNext, paginateNext, paginatePrev } from "../services/pagination"; import { FastCommentsCommentView } from "./comment"; import { arePropsEqual, incChangeCounter } from "../services/comment-render-determination"; import { LiveCommentingTopArea } from "./live-commenting-top-area"; import { iterateCommentsTreeWithDepth } from "../services/comment-trees"; const CommentViewMemo = React.memo(props => FastCommentsCommentView(props), (prevProps, nextProps) => arePropsEqual(prevProps, nextProps)); // makes reacts show inline const customHTMLElementModels = { img: defaultHTMLElementModels.img.extend({ contentModel: HTMLContentModel.mixed }) }; export function LiveCommentingList(props) { const { callbacks, callbackObserver, config, imageAssets, onReplySuccess, openCommentMenu, requestSetReplyingTo, styles, service } = props; const state = useHookstate(props.state); // OPTIMIZATION creating local state const [isFetchingNextPage, setFetchingNextPage] = useState(false); const { width } = useWindowDimensions(); const [viewableComments, setViewableComments] = useState([]); // It could be possible to switch to a flat list as the backing store, but not sure worth it yet as a tree is nice to work with. function createList() { const list = []; const byId = state.commentsById.get({ noproxy: true }); const start = Date.now(); // Re-creating the whole list generally takes 1-2ms. console.log('...Re-creating view list from tree...'); iterateCommentsTreeWithDepth(state.commentsTree.get({ noproxy: true, stealth: true }), 0, (comment, depth) => { if (!comment) { return; } const parentId = comment.parentId ? comment.parentId : undefined; if (parentId) { const parent = byId[parentId]; if (parent && !parent.hidden && !parent.repliesHidden) { comment.depth = depth; list.push(comment); } } else { comment.depth = depth; list.push(comment); } }); console.log('...Re-created view list from tree with', list.length, 'comments.', Number(Date.now() - start).toLocaleString() + 'ms'); setViewableComments(list); } // Re-recreating this list all the time and rendering the tree as a flat list is more efficient than trying to render a tree // due to state management/re-rendering of deep elements in the tree. useHookstateEffect(() => { createList(); }, [state.commentsTree]); const setRepliesHidden = (parentComment, repliesHidden) => { parentComment.repliesHidden = repliesHidden; incChangeCounter(parentComment); createList(); }; const isInfiniteScroll = state.config.enableInfiniteScrolling.get(); const doPaginateNext = async (isAll) => { setFetchingNextPage(true); await paginateNext(state, service.current, isAll ? -1 : undefined); setFetchingNextPage(false); }; const doPaginatePrev = async () => { setFetchingNextPage(true); await paginatePrev(state, service.current); setFetchingNextPage(false); }; const paginationBeforeComments = isInfiniteScroll ? null : (state.commentsVisible.get() && state.config.paginationBeforeComments.get() ? _jsx(PaginationNext, { state: state, styles: styles, doPaginate: doPaginateNext }) : _jsx(PaginationPrev, { state: state, styles: styles, doPaginate: doPaginatePrev })); const paginationAfterComments = isInfiniteScroll ? null : (state.commentsVisible.get() && !state.config.paginationBeforeComments.get() ? _jsx(PaginationNext, { state: state, styles: styles, doPaginate: doPaginateNext }) : null); const onEndReached = async () => { if (state.config.enableInfiniteScrolling.get() && canPaginateNext(state)) { await doPaginateNext(false); } }; // Note: we do not support changing image assets or translations without a complete reload, as a (reasonable) optimization. const renderItem = (info) => _jsx(CommentViewMemo, { comment: info.item, config: config, setRepliesHidden: setRepliesHidden, imageAssets: imageAssets, translations: state.translations.get({ stealth: true }), state: state, styles: styles, onAuthenticationChange: callbacks?.onAuthenticationChange, onReplySuccess: onReplySuccess, onVoteSuccess: callbacks?.onVoteSuccess, openCommentMenu: openCommentMenu, pickImage: callbacks?.pickImage, requestSetReplyingTo: requestSetReplyingTo, width: width }); const header = _jsxs(View, { children: [state.hasBillingIssue.get() && state.isSiteAdmin.get() && _jsx(Text, { style: styles.red, children: state.translations.BILLING_INFO_INV.get() }), state.isDemo.get() && _jsx(Text, { style: styles.red, children: _jsx(RenderHtml, { source: { html: state.translations.DEMO_CREATE_ACCT.get() }, contentWidth: width }) }), _jsx(LiveCommentingTopArea, { callbackObserver: callbackObserver, config: config, imageAssets: imageAssets, onAuthenticationChange: callbacks?.onAuthenticationChange, onNotificationSelected: callbacks?.onNotificationSelected, onReplySuccess: callbacks?.onReplySuccess, pickGIF: callbacks?.pickGIF, pickImage: callbacks?.pickImage, state: state, styles: styles, translations: state.translations.get() }), paginationBeforeComments] }); console.log('!!!! ************** list re-rendered ************** !!!!'); return _jsx(TRenderEngineProvider, { baseStyle: styles.comment?.text, classesStyles: styles.comment?.HTMLNodeStyleByClass, customHTMLElementModels: customHTMLElementModels, children: _jsx(RenderHTMLConfigProvider, { children: _jsx(FlatList, { style: styles.commentsWrapper, data: viewableComments, keyExtractor: item => item && item._id !== undefined ? item._id : '???', maxToRenderPerBatch: state.PAGE_SIZE.get(), onEndReachedThreshold: 0.3, onEndReached: onEndReached, renderItem: renderItem, ListHeaderComponent: header, ListFooterComponent: _jsx(View, { children: isFetchingNextPage ? _jsx(ActivityIndicator, { size: "small" }) : paginationAfterComments }) }) }) }); }