@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
226 lines (218 loc) • 11.5 kB
JavaScript
"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;