UNPKG

@selfcommunity/react-ui

Version:

React UI Components to integrate a Community created with SelfCommunity Platform.

226 lines (218 loc) • 11.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const styles_1 = require("@mui/material/styles"); const react_intl_1 = require("react-intl"); const CommentObject_1 = tslib_1.__importDefault(require("../CommentObject")); const material_1 = require("@mui/material"); const comments_1 = require("../../types/comments"); const classnames_1 = tslib_1.__importDefault(require("classnames")); const system_1 = require("@mui/system"); const CommentsObject_1 = tslib_1.__importDefault(require("../CommentsObject")); const Errors_1 = require("../../constants/Errors"); const Typography_1 = tslib_1.__importDefault(require("@mui/material/Typography")); const contribution_1 = require("../../utils/contribution"); const api_services_1 = require("@selfcommunity/api-services"); const utils_1 = require("@selfcommunity/utils"); const react_core_1 = require("@selfcommunity/react-core"); const types_1 = require("@selfcommunity/types"); const Pagination_1 = require("../../constants/Pagination"); const constants_1 = require("./constants"); const classes = { root: `${constants_1.PREFIX}-root`, noComments: `${constants_1.PREFIX}-no-comments`, commentNotFound: `${constants_1.PREFIX}-comment-not-found` }; const Root = (0, styles_1.styled)(material_1.Box, { name: constants_1.PREFIX, slot: 'Root' })(() => ({})); /** * > API documentation for the Community-JS Comments Feed Object component. Learn about the available props and the CSS API. * * * This component renders a list of comment items. * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/CommentsFeedObject) #### Import ```jsx import {CommentsFeedObject} from '@selfcommunity/react-ui'; ``` #### Component Name The name `SCCommentsFeedObject` can be used when providing style overrides in the theme. #### CSS |Rule Name|Global class|Description| |---|---|---| |root|.SCCommentsFeedObject-root|Styles applied to the root element.| |noComments|.SCCommentsFeedObject-no-comments|Styles applied to the 'no comments' section.| |commentNotFound|.SCCommentsFeedObject-comment-not-found|Styles applied to the label 'Comment not found'.| * @param inProps */ function CommentsFeedObject(inProps) { const props = (0, system_1.useThemeProps)({ props: inProps, name: constants_1.PREFIX }); // PROPS const { id = `comments_object_${props.feedObjectType ? props.feedObjectType : props.feedObject ? props.feedObject.type : ''}_${props.feedObjectId ? props.feedObjectId : props.feedObject ? props.feedObject.id : ''}`, className, feedObjectId, feedObject, feedObjectType = types_1.SCContributionType.POST, commentObjectId, commentObject, CommentComponent = CommentObject_1.default, CommentComponentProps = { variant: 'outlined', linkableCommentDateTime: false }, CommentObjectSkeletonProps = { elevation: 0, WidgetProps: { variant: 'outlined' } }, renderNoComments, renderCommentNotFound, page = 1, commentsPageCount = Pagination_1.DEFAULT_PAGINATION_LIMIT, commentsOrderBy = comments_1.SCCommentsOrderBy.ADDED_AT_ASC, showTitle = false, infiniteScrolling = true, onChangePage, comments = [], cacheStrategy = utils_1.CacheStrategies.NETWORK_ONLY } = props, rest = tslib_1.__rest(props, ["id", "className", "feedObjectId", "feedObject", "feedObjectType", "commentObjectId", "commentObject", "CommentComponent", "CommentComponentProps", "CommentObjectSkeletonProps", "renderNoComments", "renderCommentNotFound", "page", "commentsPageCount", "commentsOrderBy", "showTitle", "infiniteScrolling", "onChangePage", "comments", "cacheStrategy"]); // STATE const commentsObject = (0, react_core_1.useSCFetchCommentObjects)({ id: feedObjectId, feedObject, feedObjectType, offset: (page - 1) * commentsPageCount, pageSize: commentsPageCount, orderBy: commentsOrderBy, onChangePage: onChangePage, cacheStrategy }); const [isLoading, setIsLoading] = (0, react_1.useState)(false); const [comment, setComment] = (0, react_1.useState)(null); const { obj: commentObj, error: errorCommentObj } = (0, react_core_1.useSCFetchCommentObject)({ id: commentObjectId, commentObject, cacheStrategy }); const [commentError, setCommentError] = (0, react_1.useState)(null); // CONST const objId = commentsObject.feedObject ? commentsObject.feedObject.id : null; const commentObjId = commentObj ? commentObj.id : null; // REFS const commentsContainerRef = (0, react_1.useRef)(); /** * Total number of comments */ const total = commentsObject.total + comments.length; /** * Render title */ const renderTitle = (0, react_1.useMemo)(() => () => { if (showTitle) { return ((0, jsx_runtime_1.jsx)(Typography_1.default, Object.assign({ variant: "h6", gutterBottom: true, color: 'inherit' }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.commentsObject.title", defaultMessage: "ui.commentsObject.title", values: { total: total } }) }))); } return null; }, [total, isLoading]); /** * Render no comments */ function renderNoCommentsFound() { return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: renderNoComments ? (renderNoComments()) : ((0, jsx_runtime_1.jsx)(material_1.Box, Object.assign({ className: classes.noComments }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.commentsObject.noComments", defaultMessage: "ui.commentsObject.noComments" }) }))) })); } /** * Render comment not found */ function renderCommentNotFoundError() { return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: renderCommentNotFound ? (renderCommentNotFound()) : ((0, jsx_runtime_1.jsx)(material_1.Box, Object.assign({ className: classes.commentNotFound }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.commentsObject.commentNotFound", defaultMessage: "ui.commentsObject.commentNotFound" }) }))) })); } /** * Get a single comment */ const performFetchComment = (0, react_1.useMemo)(() => (commentId) => { return api_services_1.http .request({ url: api_services_1.Endpoints.Comment.url({ id: commentId }), method: api_services_1.Endpoints.Comment.method }) .then((res) => { if (res.status >= 300) { return Promise.reject(res); } return Promise.resolve(res.data); }); }, [commentsObject.feedObject, commentObjectId, commentObj]); /** * Focus on comment * @param comment */ function scrollToComment(comment) { // Add (window.innerHeight / 2) to scroll // (usually >= (topBar + offset) and in center of the screen) setTimeout(() => { // Get the comment inside commentsContainer const el = commentsContainerRef.current ? commentsContainerRef.current.querySelector(`#comment_object_${comment.id}`) : null; if (el) { el.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' }); } }, 300); } /** * Fetch a single comment * and comment parent (if need it) */ function fetchComment() { if (commentObj) { if (commentObj.parent) { setIsLoading(true); performFetchComment(commentObj.parent) .then((parent) => { const _parent = Object.assign({}, parent); _parent.latest_comments = [commentObj]; if ((0, contribution_1.getContribution)(parent).id === commentsObject.feedObject.id) { setComment(_parent); scrollToComment(commentObj); } else { setCommentError(true); } setIsLoading(false); }) .catch((error) => { // Comment not found setIsLoading(false); utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error); }); } else { if ((0, contribution_1.getContribution)(commentObj).id === commentsObject.feedObject.id) { setComment(commentObj); scrollToComment(commentObj); } else { setCommentError(true); } setIsLoading(false); } } else if (errorCommentObj) { setIsLoading(false); } } /** * Prefetch comments only if obj exists */ (0, react_1.useEffect)(() => { if (objId !== null && !isLoading) { if (commentObjectId || commentObj) { fetchComment(); } else if (!isLoading) { commentsObject.getNextPage(); } } }, [objId, commentObjId]); /** * Render comments */ let commentsRendered = (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {}); if (commentsObject.componentLoaded && !total && !commentsObject.isLoadingNext && !isLoading) { /** * If comments were not found and loading is finished * and the component was not looking for a particular * comment render no comments message */ commentsRendered = renderNoCommentsFound(); } else { /** * Two modes available: * - infinite scroll * - load pagination with load more button * !IMPORTANT: * the component will switch to 'load more pagination' mode automatically * in case it needs to display a single comment */ commentsRendered = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [Boolean((commentError || errorCommentObj) && !isLoading && !total) && renderCommentNotFoundError(), (0, jsx_runtime_1.jsx)(CommentsObject_1.default, { feedObject: commentsObject.feedObject, comments: commentsObject.comments, endComments: [...(comment ? [comment] : []), ...(commentsOrderBy === comments_1.SCCommentsOrderBy.ADDED_AT_ASC ? comments : [])], startComments: [...(commentsOrderBy === comments_1.SCCommentsOrderBy.ADDED_AT_ASC ? [] : comments)], previous: commentsObject.previous, handlePrevious: commentsObject.getPreviousPage, isLoadingPrevious: commentsObject.isLoadingPrevious, next: commentsObject.next, isLoadingNext: commentsObject.isLoadingNext, handleNext: commentsObject.getNextPage, page: commentsObject.page, previousPage: commentsObject.previousPage, nextPage: commentsObject.nextPage, infiniteScrolling: infiniteScrolling && commentsObject.total > 0 && !comment && !comments.length, CommentComponent: CommentComponent, CommentComponentProps: CommentComponentProps, CommentObjectSkeletonProps: CommentObjectSkeletonProps })] })); } /** * Renders root object */ return ((0, jsx_runtime_1.jsxs)(Root, Object.assign({ id: id, className: (0, classnames_1.default)(classes.root, className) }, rest, { ref: commentsContainerRef }, { children: [renderTitle(), commentsRendered] }))); } exports.default = CommentsFeedObject;