fastcomments-react-native-sdk
Version:
React Native FastComments Components. Add live commenting to any React Native application.
94 lines (93 loc) • 6.8 kB
JavaScript
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 }) }) }) });
}