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