UNPKG

@selfcommunity/react-ui

Version:

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

202 lines (201 loc) • 15.2 kB
import { __rest } from "tslib"; import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; import { Fragment, memo, useCallback, useEffect, useMemo, useState } from 'react'; import { PREFIX } from './constants'; import { Avatar, Box, Divider, LinearProgress, Stack, styled, Typography, useThemeProps } from '@mui/material'; import classNames from 'classnames'; import HeaderCourseDashboard from './Header'; import { SCCourseJoinStatusType, SCCourseLessonCompletionStatusType, SCCoursePrivacyType } from '@selfcommunity/types'; import { FormattedMessage, useIntl } from 'react-intl'; import ActionButton from './Student/ActionButton'; import { CLAPPING } from '../../assets/courses/clapping'; import { SCRoutes, useSCFetchCourse, useSCRouting, Link, useSCUser, useSCContext } from '@selfcommunity/react-core'; import AccordionLessons from '../../shared/AccordionLessons'; import { CourseService } from '@selfcommunity/api-services'; import { Logger } from '@selfcommunity/utils'; import { SCOPE_SC_UI } from '../../constants/Errors'; import { useSnackbar } from 'notistack'; import StudentSkeleton from './Student/Skeleton'; import UserAvatar from '../../shared/UserAvatar'; const BUTTON_MESSAGES = { dashboard: 'ui.course.dashboard.student.button.dashboard', request: 'ui.course.dashboard.student.button.request', signUp: 'ui.course.dashboard.student.button.signUp', review: 'ui.course.dashboard.student.button.review', cancel: 'ui.course.dashboard.student.button.cancel', start: 'ui.course.dashboard.student.button.start', continue: 'ui.course.dashboard.student.button.continue' }; const SNACKBAR_MESSAGES = { cancel: 'ui.course.dashboard.student.snackbar.success.cancel', enroll: 'ui.course.dashboard.student.snackbar.success.enroll', request: 'ui.course.dashboard.student.snackbar.success.request' }; const classes = { root: `${PREFIX}-root`, studentContainer: `${PREFIX}-student-container`, userWrapper: `${PREFIX}-user-wrapper`, actionsWrapper: `${PREFIX}-actions-wrapper`, user: `${PREFIX}-user`, avatar: `${PREFIX}-avatar`, description: `${PREFIX}-description`, progress: `${PREFIX}-progress`, lessonsSections: `${PREFIX}-lessons-sections`, circle: `${PREFIX}-circle`, accordion: `${PREFIX}-accordion`, margin: `${PREFIX}-margin`, box: `${PREFIX}-box`, percentageWrapper: `${PREFIX}-percentage-wrapper`, completedWrapper: `${PREFIX}-completed-wrapper`, contrastColor: `${PREFIX}-contrast-color` }; function getUrlNextLesson(course) { var _a, _b, _c; const data = { id: course.id, slug: course.slug }; if (course.user_completion_rate === 100) { Object.assign(data, { section_id: (_a = course.sections) === null || _a === void 0 ? void 0 : _a[0].id, lesson_id: (_b = course.sections) === null || _b === void 0 ? void 0 : _b[0].lessons[0].id }); return data; } (_c = course.sections) === null || _c === void 0 ? void 0 : _c.some((section) => { var _a; const isNextLessonInThisSection = section.num_lessons_completed < section.num_lessons && !section.locked; if (isNextLessonInThisSection) { Object.assign(data, { section_id: section.id, lesson_id: (_a = section.lessons.find((lesson) => lesson.completion_status === SCCourseLessonCompletionStatusType.UNCOMPLETED)) === null || _a === void 0 ? void 0 : _a.id }); } return isNextLessonInThisSection; }); return data; } function getIsNextLessonLocked(course) { var _a; if (course.join_status === null) { return undefined; } return (_a = course.sections) === null || _a === void 0 ? void 0 : _a.every((section) => { var _a, _b; return (section.num_lessons_completed < section.num_lessons && ((_b = (_a = section.lessons) === null || _a === void 0 ? void 0 : _a.find((lesson) => lesson.completion_status === SCCourseLessonCompletionStatusType.UNCOMPLETED)) === null || _b === void 0 ? void 0 : _b.locked)); }); } const Root = styled(Box, { name: PREFIX, slot: 'Root', overridesResolver: (_props, styles) => styles.root })(() => ({})); function Student(inProps) { // PROPS const props = useThemeProps({ props: inProps, name: PREFIX }); const { courseId, course, className } = props, rest = __rest(props, ["courseId", "course", "className"]); // STATES const [sentRequest, setSentRequest] = useState(null); const [loadingRequest, setLoadingRequest] = useState(false); // CONTEXTS const scRoutingContext = useSCRouting(); const scContext = useSCContext(); const scUserContext = useSCUser(); // HOOKS const { scCourse, setSCCourse } = useSCFetchCourse({ id: courseId, course }); const intl = useIntl(); const { enqueueSnackbar } = useSnackbar(); // EFFETCS useEffect(() => { if (scCourse) { setSentRequest(scCourse.join_status === SCCourseJoinStatusType.REQUESTED); } }, [scCourse, setSentRequest]); // HANDLERS const handleRequest = useCallback(() => { setLoadingRequest(true); let request; if (sentRequest) { request = CourseService.leaveOrRemoveCourseRequest(scCourse.id); } else { request = CourseService.joinOrAcceptInviteToCourse(scCourse.id); } request .then((data) => { let updatedCourse; if (data) { updatedCourse = data; } else { updatedCourse = Object.assign(Object.assign({}, scCourse), { join_status: null }); } setSCCourse(updatedCourse); setSentRequest((prev) => !prev); setLoadingRequest(false); enqueueSnackbar(_jsx(FormattedMessage, { id: updatedCourse.join_status === SCCourseJoinStatusType.REQUESTED ? SNACKBAR_MESSAGES.request : updatedCourse.join_status === SCCourseJoinStatusType.JOINED ? SNACKBAR_MESSAGES.enroll : SNACKBAR_MESSAGES.cancel, defaultMessage: updatedCourse.join_status === SCCourseJoinStatusType.REQUESTED ? SNACKBAR_MESSAGES.request : updatedCourse.join_status === SCCourseJoinStatusType.JOINED ? SNACKBAR_MESSAGES.enroll : SNACKBAR_MESSAGES.cancel }), { variant: 'success', autoHideDuration: 3000 }); }) .catch((error) => { enqueueSnackbar(_jsx(FormattedMessage, { id: "ui.common.error.action", defaultMessage: "ui.common.error.action" }), { variant: 'error', autoHideDuration: 3000 }); Logger.error(SCOPE_SC_UI, error); }); }, [scCourse, sentRequest, setLoadingRequest]); const handleAnonymousAction = useCallback(() => { scContext.settings.handleAnonymousAction(); }, [scContext.settings.handleAnonymousAction]); // MEMOS const actionButton = useMemo(() => { if (!scCourse) { return _jsx(_Fragment, {}); } return (_jsxs(Stack, Object.assign({ className: classes.actionsWrapper }, { children: [(scCourse.join_status === SCCourseJoinStatusType.CREATOR || scCourse.join_status === SCCourseJoinStatusType.MANAGER) && (_jsx(ActionButton, { labelId: BUTTON_MESSAGES.dashboard, to: scRoutingContext.url(SCRoutes.COURSE_DASHBOARD_ROUTE_NAME, scCourse), color: "inherit", variant: "outlined" })), (((scCourse.privacy === SCCoursePrivacyType.PRIVATE || scCourse.privacy === SCCoursePrivacyType.SECRET) && (scCourse.join_status === SCCourseJoinStatusType.MANAGER || scCourse.join_status === SCCourseJoinStatusType.JOINED)) || (scCourse.privacy === SCCoursePrivacyType.OPEN && scCourse.join_status !== SCCourseJoinStatusType.CREATOR)) && (_jsx(ActionButton, { labelId: scCourse.join_status === null ? BUTTON_MESSAGES.signUp : scCourse.user_completion_rate === 0 ? BUTTON_MESSAGES.start : scCourse.user_completion_rate === 100 ? BUTTON_MESSAGES.review : BUTTON_MESSAGES.continue, to: scCourse.join_status !== null ? scRoutingContext.url(SCRoutes.COURSE_LESSON_ROUTE_NAME, getUrlNextLesson(scCourse)) : undefined, disabled: getIsNextLessonLocked(scCourse), color: scCourse.user_completion_rate === 100 ? 'inherit' : undefined, variant: scCourse.user_completion_rate === 100 ? 'outlined' : undefined, loading: scCourse.join_status === null ? loadingRequest : undefined, onClick: !scUserContext.user ? handleAnonymousAction : scCourse.join_status === null ? handleRequest : undefined })), scCourse.privacy === SCCoursePrivacyType.PRIVATE && (scCourse.join_status === null || scCourse.join_status === SCCourseJoinStatusType.REQUESTED) && (_jsx(ActionButton, { labelId: sentRequest ? BUTTON_MESSAGES.cancel : BUTTON_MESSAGES.request, color: "inherit", variant: "outlined", loading: loadingRequest, onClick: handleRequest }))] }))); }, [scCourse, sentRequest, loadingRequest, handleRequest]); if (!scCourse) { return _jsx(StudentSkeleton, {}); } return (_jsxs(Root, Object.assign({ className: classNames(classes.root, classes.studentContainer, className) }, rest, { children: [_jsx(HeaderCourseDashboard, { course: scCourse }), _jsx(Divider, {}), _jsxs(Stack, Object.assign({ className: classes.userWrapper }, { children: [_jsxs(Stack, Object.assign({ className: classes.user }, { children: [_jsx(Link, Object.assign({}, (!scCourse.created_by.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, scCourse.created_by) }), { children: _jsx(UserAvatar, Object.assign({ hide: !scCourse.created_by.community_badge, smaller: true }, { children: _jsx(Avatar, { className: classes.avatar, src: scCourse.created_by.avatar, alt: scCourse.created_by.username }) })) })), _jsxs(Box, { children: [_jsx(Link, Object.assign({}, (!scCourse.created_by.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, scCourse.created_by) }), { children: _jsx(Typography, Object.assign({ variant: "body1" }, { children: scCourse.created_by.username })) })), _jsx(Typography, Object.assign({ variant: "body1" }, { children: _jsx(FormattedMessage, { id: "ui.course.dashboard.header.user.creator", defaultMessage: "ui.course.dashboard.header.user.creator" }) }))] })] })), actionButton] })), _jsx(Divider, {}), (((scCourse.privacy === SCCoursePrivacyType.PRIVATE || scCourse.privacy === SCCoursePrivacyType.SECRET) && (scCourse.join_status === SCCourseJoinStatusType.CREATOR || scCourse.join_status === SCCourseJoinStatusType.MANAGER || scCourse.join_status === SCCourseJoinStatusType.JOINED)) || scCourse.privacy === SCCoursePrivacyType.OPEN || scCourse.privacy === SCCoursePrivacyType.DRAFT) && scCourse.description && (_jsxs(Fragment, { children: [_jsx(Typography, Object.assign({ variant: "h6", className: classNames(classes.margin, classes.contrastColor) }, { children: _jsx(FormattedMessage, { id: "ui.course.dashboard.student.description", defaultMessage: "ui.course.dashboard.student.description" }) })), _jsx(Stack, Object.assign({ className: classes.box }, { children: _jsx(Typography, Object.assign({ variant: "body1", className: classes.description }, { children: scCourse.description })) }))] })), (((scCourse.privacy === SCCoursePrivacyType.PRIVATE || scCourse.privacy === SCCoursePrivacyType.SECRET) && (scCourse.join_status === SCCourseJoinStatusType.MANAGER || scCourse.join_status === SCCourseJoinStatusType.JOINED)) || (scCourse.privacy === SCCoursePrivacyType.OPEN && scCourse.join_status !== SCCourseJoinStatusType.CREATOR)) && (_jsxs(Fragment, { children: [scCourse.join_status !== null && (_jsxs(Fragment, { children: [_jsx(Typography, Object.assign({ variant: "h6", className: classNames(classes.margin, classes.contrastColor) }, { children: _jsx(FormattedMessage, { id: "ui.course.dashboard.student.progress", defaultMessage: "ui.course.dashboard.student.progress" }) })), _jsxs(Stack, Object.assign({ className: classes.box }, { children: [_jsxs(Stack, Object.assign({ className: classes.percentageWrapper }, { children: [_jsx(Typography, Object.assign({ variant: "body1" }, { children: _jsx(FormattedMessage, { id: "ui.course.dashboard.student.progress.described", defaultMessage: "ui.course.dashboard.student.progress.described", values: { progress: scCourse.num_lessons_completed, end: scCourse.num_lessons } }) })), _jsx(Typography, Object.assign({ variant: "body1" }, { children: _jsx(FormattedMessage, { id: "ui.course.dashboard.student.progress.percentage", defaultMessage: "ui.course.dashboard.student.progress.percentage", values: { percentage: scCourse.user_completion_rate } }) }))] })), _jsx(LinearProgress, { className: classes.progress, variant: "determinate", value: scCourse.user_completion_rate })] }))] })), scCourse.user_completion_rate === 100 && (_jsxs(Stack, Object.assign({ className: classNames(classes.completedWrapper, classes.margin) }, { children: [_jsx(Typography, Object.assign({ variant: "h3", className: classes.contrastColor }, { children: _jsx(FormattedMessage, { id: "ui.course.dashboard.student.completed", defaultMessage: "ui.course.dashboard.student.completed" }) })), _jsx("img", { src: CLAPPING, alt: intl.formatMessage({ id: 'ui.course.dashboard.student.completed', defaultMessage: 'ui.course.dashboard.student.completed' }), width: 32, height: 32 })] }))), _jsx(Typography, Object.assign({ variant: "h6", className: classNames(classes.margin, classes.contrastColor) }, { children: _jsx(FormattedMessage, { id: "ui.course.dashboard.student.contents", defaultMessage: "ui.course.dashboard.student.contents" }) })), _jsxs(Stack, Object.assign({ className: classes.lessonsSections }, { children: [_jsx(Typography, Object.assign({ variant: "h5" }, { children: _jsx(FormattedMessage, { id: "ui.course.table.sections.title", defaultMessage: "ui.course.table.sections.title", values: { sectionsNumber: scCourse.num_sections } }) })), _jsx(Box, { className: classes.circle }), _jsx(Typography, Object.assign({ variant: "h5" }, { children: _jsx(FormattedMessage, { id: "ui.course.table.lessons.title", defaultMessage: "ui.course.table.lessons.title", values: { lessonsNumber: scCourse.num_lessons } }) }))] })), _jsx(AccordionLessons, { course: scCourse, className: classes.accordion })] }))] }))); } export default memo(Student);