UNPKG

@selfcommunity/react-ui

Version:

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

182 lines (174 loc) • 8.7 kB
import { __rest } from "tslib"; import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; import { useEffect, useRef, useState } from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import LessonCommentObject, { LessonCommentObjectSkeleton } from '../LessonCommentObject'; import { Box, List, ListItem, styled } from '@mui/material'; import classNames from 'classnames'; import { useThemeProps } from '@mui/system'; import { SCCommentsOrderBy } from '@selfcommunity/types'; import { CacheStrategies, Logger, LRUCache } from '@selfcommunity/utils'; import { SCCache, UserUtils, useSCFetchLessonCommentObjects, useSCUser } from '@selfcommunity/react-core'; import { PREFIX } from './constants'; import LessonCommentsObjectSkeleton from './Skeleton'; import CommentObjectReply from '../CommentObjectReply'; import { enqueueSnackbar } from 'notistack'; import { SCOPE_SC_UI } from '../../constants/Errors'; import { Endpoints, http } from '@selfcommunity/api-services'; import InfiniteScroll from '../../shared/InfiniteScroll'; import HiddenPlaceholder from '../../shared/HiddenPlaceholder'; const messages = defineMessages({ commentEditorPlaceholder: { id: 'ui.lessonCommentObjects.editor.placeholder', defaultMessage: 'ui.lessonCommentObjects.editor.placeholder' } }); const classes = { root: `${PREFIX}-root`, loadNextCommentsButton: `${PREFIX}-load-more-comments-button`, loadPreviousCommentsButton: `${PREFIX}-load-previous-comments-button`, paginationLink: `${PREFIX}-pagination-link`, pagination: `${PREFIX}-pagination`, commentsCounter: `${PREFIX}-comments-counter`, commentNotFound: `${PREFIX}-comment-not-found`, noOtherComments: `${PREFIX}-no-other-comment` }; const Root = styled(Box, { name: PREFIX, slot: 'Root' })(() => ({})); /** * > API documentation for the Community-JS Comments Object component. Learn about the available props and the CSS API. #### Import ```jsx import {LessonCommentObjects} from '@selfcommunity/react-ui'; ``` #### Component Name The name `SCLessonCommentObjects` can be used when providing style overrides in the theme. #### CSS |Rule Name|Global class|Description| |---|---|---| |root|.SCLessonCommentObjects-root|Styles applied to the root element.| |pagination|.SCLessonCommentObjects-pagination|Styles applied to the pagination controls.| |paginationLink|.SCLessonCommentObjects-pagination-link|Styles applied to the pagination link.| |loadNextCommentsButton|.SCLessonCommentObjects-load-next-comments-button|Styles applied to the load next comments button.| |loadPreviousCommentsButton|.SCLessonCommentObjects-load-previous-comments-button|Styles applied to the load previous comments button.| |commentsCounter|.SCLessonCommentObjects-comments-counter|Styles applied to the comments counter element.| * @param inProps */ export default function LessonCommentObjects(inProps) { const props = useThemeProps({ props: inProps, name: PREFIX }); // PROPS const { id = `lesson_comment_objects_lesson_${props.lessonObjectId ? props.lessonObjectId : props.lessonObject ? props.lessonObject.id : ''}`, className, lessonObjectId, lessonObject, CommentComponentProps = {}, CommentObjectSkeletonProps = { elevation: 0 }, CommentsObjectSkeletonProps = {}, cacheStrategy = CacheStrategies.STALE_WHILE_REVALIDATE } = props, rest = __rest(props, ["id", "className", "lessonObjectId", "lessonObject", "CommentComponentProps", "CommentObjectSkeletonProps", "CommentsObjectSkeletonProps", "cacheStrategy"]); //STATE const [commenting, setIsCommenting] = useState(false); const [editing, setIsEditing] = useState(false); const [replyKey, setReplyKey] = useState(0); // CONTEXT const scUserContext = useSCUser(); // INTL const intl = useIntl(); // REF const commentsEndRef = useRef(null); // STATE const commentsObject = useSCFetchLessonCommentObjects({ id: lessonObject.id, lessonObject: lessonObject, orderBy: SCCommentsOrderBy.ADDED_AT_ASC, cacheStrategy }); // EFFECTS useEffect(() => { if (commentsObject.lessonObject) { commentsObject.getNextPage(); } }, [commentsObject.lessonObject]); //HANDLERS function handleNext() { commentsObject.getNextPage(); } const scrollToBottom = () => { var _a; (_a = commentsEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ block: 'end', behavior: 'smooth' }); }; useEffect(() => { if (commentsObject.comments.length > 0) { scrollToBottom(); } }, [commentsObject.comments]); /** * Perform save/update comment */ const performComment = (comment, medias) => { const mediaIds = medias ? medias.map((media) => media.id) : []; return http .request({ url: Endpoints.CreateCourseComment.url({ id: lessonObject.course_id, section_id: lessonObject.section_id, lesson_id: lessonObject.id }), method: Endpoints.CreateCourseComment.method, data: { text: comment, medias: mediaIds } }) .then((res) => { if (res.status >= 300) { return Promise.reject(res); } return Promise.resolve(res.data); }); }; /** * Handle save comment */ function handleCommentAction(comment, medias) { if (UserUtils.isBlocked(scUserContext.user)) { enqueueSnackbar(_jsx(FormattedMessage, { id: "ui.common.userBlocked", defaultMessage: "ui.common.userBlocked" }), { variant: 'warning', autoHideDuration: 3000 }); } else { setIsCommenting(true); performComment(comment, medias) .then((data) => { handleCommentsUpdate(data); setReplyKey(comment.id); setIsCommenting(false); }) .catch((error) => { Logger.error(SCOPE_SC_UI, error); enqueueSnackbar(_jsx(FormattedMessage, { id: "ui.common.error.action", defaultMessage: "ui.common.error.action" }), { variant: 'error', autoHideDuration: 3000 }); }); } } const handleCommentsUpdate = (comment, forDeletion) => { let updated; if (forDeletion) { updated = commentsObject.comments.filter((c) => c.id !== comment.id); } else { updated = [...commentsObject.comments, comment]; } commentsObject.updateLessonComments([...updated]); LRUCache.set(SCCache.getLessonCommentCacheKey(lessonObject.id), updated); LRUCache.deleteKeysWithPrefix(SCCache.getLessonCommentsCachePrefixKeys(lessonObject.id)); }; /** * Renders root object(if obj) */ if (!commentsObject.lessonObject) { return _jsx(HiddenPlaceholder, {}); } if (!commentsObject.comments.length && commentsObject.isLoadingNext) { return _jsx(LessonCommentsObjectSkeleton, Object.assign({ count: 5 }, CommentsObjectSkeletonProps)); } return (_jsx(Root, Object.assign({ id: id, className: classNames(classes.root, className) }, rest, { children: _jsxs(_Fragment, { children: [_jsx(_Fragment, { children: commentsObject.comments.length > 0 ? (_jsx(InfiniteScroll, Object.assign({ height: '100%', dataLength: commentsObject.comments.length, next: handleNext, hasMoreNext: Boolean(commentsObject.next), loaderNext: _jsx(LessonCommentObjectSkeleton, Object.assign({}, CommentObjectSkeletonProps, { count: 1 })) }, { children: _jsx(List, Object.assign({ ref: commentsEndRef }, { children: commentsObject.comments.map((c, index) => (_jsx(ListItem, { children: _jsx(LessonCommentObject, Object.assign({ commentObject: c, lessonObject: commentsObject.lessonObject, onDelete: (comment) => handleCommentsUpdate(comment, true), isEditing: (editing) => setIsEditing(editing) }, CommentComponentProps, { CommentObjectSkeletonProps: CommentObjectSkeletonProps }), c.id) }, index))) })) }))) : null }), !editing && (_jsx(CommentObjectReply, { id: `reply-lessonCommentObjects`, showAvatar: false, replyIcon: true, editable: !commenting, onReply: handleCommentAction, EditorProps: { placeholder: intl.formatMessage(messages.commentEditorPlaceholder), uploadFile: true, uploadImage: false, isLessonCommentEditor: true } }, replyKey))] }) }))); }