UNPKG

@selfcommunity/react-ui

Version:

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

107 lines (106 loc) • 8.17 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { Avatar, Box, Button, Divider, Skeleton, Stack, Typography } from '@mui/material'; import { Fragment, memo, useCallback, useEffect, useMemo, useReducer, useState } from 'react'; import { CacheStrategies, Logger } from '@selfcommunity/utils'; import { SCOPE_SC_UI } from '../../../constants/Errors'; import { FormattedDate, FormattedMessage } from 'react-intl'; import { LoadingButton } from '@mui/lab'; import { PREFIX } from '../constants'; import { DEFAULT_PAGINATION_OFFSET } from '../../../constants/Pagination'; import { actionWidgetTypes, dataWidgetReducer, stateWidgetInitializer } from '../../../utils/widget'; import { Link, SCCache, SCRoutes, useSCRouting, useSCUser } from '@selfcommunity/react-core'; import { CourseService, Endpoints, http } from '@selfcommunity/api-services'; import { getUrlLesson } from '../../../utils/course'; const classes = { container: `${PREFIX}-comments-container`, outerWrapper: `${PREFIX}-outer-wrapper`, innerWrapper: `${PREFIX}-inner-wrapper`, userWrapper: `${PREFIX}-user-wrapper`, avatar: `${PREFIX}-avatar`, userInfo: `${PREFIX}-user-info`, circle: `${PREFIX}-circle`, button: `${PREFIX}-button`, contrastColor: `${PREFIX}-contrast-color` }; function CommentSkeleton({ id }) { return (_jsxs(Box, Object.assign({ className: classes.outerWrapper }, { children: [_jsx(Skeleton, { animation: "wave", variant: "text", width: "90px", height: "21px" }), _jsx(Divider, {}), _jsxs(Stack, Object.assign({ className: classes.innerWrapper }, { children: [Array.from(new Array(id)).map((_, i) => (_jsxs(Stack, Object.assign({ className: classes.userWrapper }, { children: [_jsx(Skeleton, { animation: "wave", variant: "circular", className: classes.avatar }), _jsxs(Box, { children: [_jsxs(Stack, Object.assign({ className: classes.userInfo }, { children: [_jsx(Skeleton, { animation: "wave", variant: "text", width: "90px", height: "21px" }), _jsx(Box, { className: classes.circle }), _jsx(Skeleton, { animation: "wave", variant: "text", width: "90px", height: "21px" })] })), _jsx(Skeleton, { animation: "wave", variant: "text", width: "180px", height: "21px" })] })] }), i))), _jsx(Skeleton, { animation: "wave", variant: "rounded", width: "112px", height: "36px", className: classes.button })] }))] }))); } function CommentsSkeleton() { return (_jsxs(Box, Object.assign({ className: classes.container }, { children: [_jsx(Skeleton, { animation: "wave", variant: "text", width: "90px", height: "21px" }), Array.from(new Array(2)).map((_, i) => (_jsx(CommentSkeleton, { id: 4 }, i))), _jsx(Skeleton, { animation: "wave", variant: "rounded", width: "88px", height: "36px" })] }))); } function Comments(props) { // PROPS const { course, endpointQueryParams = { limit: 3, offset: DEFAULT_PAGINATION_OFFSET } } = props; // STATES const [state, dispatch] = useReducer(dataWidgetReducer, { isLoadingNext: false, next: null, cacheKey: SCCache.getWidgetStateCacheKey(SCCache.USER_COMMENTS_COURSES_STATE_CACHE_PREFIX_KEY, course.id), cacheStrategy: CacheStrategies.CACHE_FIRST, visibleItems: endpointQueryParams.limit }, stateWidgetInitializer); const [isLoading, setIsLoading] = useState(false); // CONTEXTS const scUserContext = useSCUser(); const scRoutingContext = useSCRouting(); // CALLBACKS const _init = useCallback(() => { if (!state.initialized && !state.isLoadingNext) { dispatch({ type: actionWidgetTypes.LOADING_NEXT }); CourseService.getCourseComments(course.id, Object.assign({}, endpointQueryParams)) .then((payload) => { dispatch({ type: actionWidgetTypes.LOAD_NEXT_SUCCESS, payload: Object.assign(Object.assign({}, payload), { initialized: true }) }); }) .catch((error) => { dispatch({ type: actionWidgetTypes.LOAD_NEXT_FAILURE, payload: { errorLoadNext: error } }); Logger.error(SCOPE_SC_UI, error); }); } }, [state.isLoadingNext, state.initialized, course, dispatch]); // EFFECTS useEffect(() => { let _t; if (scUserContext.user) { _t = setTimeout(_init); return () => { clearTimeout(_t); }; } }, [scUserContext.user, _init]); // HANDLERS const handleNext = useCallback(() => { setIsLoading(true); dispatch({ type: actionWidgetTypes.LOADING_NEXT }); http .request({ url: state.next, method: Endpoints.GetCourseComments.method }) .then((res) => { dispatch({ type: actionWidgetTypes.LOAD_NEXT_SUCCESS, payload: res.data }); setIsLoading(false); }) .catch((error) => { Logger.error(SCOPE_SC_UI, error); }); }, [state.next, dispatch, setIsLoading]); // MEMOS const renderComments = useMemo(() => { const map = new Map(); state.results.forEach((comment) => { const name = comment.extras.lesson.name; if (!map.has(name)) { map.set(name, [comment]); } else { map.set(name, [...map.get(name), comment]); } }); return Array.from(map.entries()).map(([name, comments]) => (_jsxs(Box, Object.assign({ className: classes.outerWrapper }, { children: [_jsx(Typography, Object.assign({ variant: "h5" }, { children: name })), _jsx(Divider, {}), _jsxs(Stack, Object.assign({ className: classes.innerWrapper }, { children: [comments.map((comment) => (_jsxs(Stack, Object.assign({ className: classes.userWrapper }, { children: [_jsx(Avatar, { src: comment.created_by.avatar, alt: comment.created_by.username, className: classes.avatar }), _jsxs(Box, { children: [_jsxs(Stack, Object.assign({ className: classes.userInfo }, { children: [_jsx(Typography, Object.assign({ variant: "body1" }, { children: comment.created_by.username })), _jsx(Box, { className: classes.circle }), _jsx(Typography, Object.assign({ variant: "body2" }, { children: _jsx(FormattedDate, { value: comment.created_at }) }))] })), _jsx(Typography, { variant: "body1", component: "div", dangerouslySetInnerHTML: { __html: comment.html } })] })] }), comment.id))), _jsx(Button, Object.assign({ component: Link, to: scRoutingContext.url(SCRoutes.COURSE_LESSON_COMMENTS_ROUTE_NAME, getUrlLesson(comments[0].extras.course, comments[0].extras.lesson, comments[0].extras.section)), size: "small", variant: "outlined", color: "inherit", className: classes.button }, { children: _jsx(Typography, Object.assign({ variant: "body2" }, { children: _jsx(FormattedMessage, { id: "ui.course.dashboard.teacher.tab.comments.lessons.btn.label", defaultMessage: "ui.course.dashboard.teacher.tab.comments.lessons.btn.label" }) })) }))] }))] }), name))); }, [state.results]); if (!state.initialized) { return _jsx(CommentsSkeleton, {}); } return (_jsx(Box, Object.assign({ className: classes.container }, { children: state.count > 0 ? (_jsxs(Fragment, { children: [_jsx(Typography, Object.assign({ variant: "body1" }, { children: _jsx(FormattedMessage, { id: "ui.course.dashboard.teacher.tab.comments.number", defaultMessage: "ui.course.dashboard.teacher.tab.comments.number", values: { commentsNumber: state.count } }) })), renderComments, isLoading && _jsx(CommentSkeleton, { id: 1 }), _jsx(LoadingButton, Object.assign({ size: "small", variant: "outlined", color: "inherit", loading: isLoading, disabled: !state.next, onClick: handleNext }, { children: _jsx(Typography, Object.assign({ variant: "body2" }, { children: _jsx(FormattedMessage, { id: "ui.course.dashboard.teacher.tab.comments.btn.label", defaultMessage: "ui.course.dashboard.teacher.tab.comments.btn.label" }) })) }))] })) : (_jsx(Typography, Object.assign({ variant: "body2" }, { children: _jsx(FormattedMessage, { id: "ui.course.dashboard.teacher.tab.comments.empty", defaultMessage: "ui.course.dashboard.teacher.tab.comments.empty" }) }))) }))); } export default memo(Comments);