@selfcommunity/react-templates
Version:
React Templates Components to integrate a Community created with SelfCommunity.
198 lines (197 loc) • 12.1 kB
JavaScript
import { __rest } from "tslib";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Fragment, useCallback, useEffect, useMemo, useState } from 'react';
import { useThemeProps } from '@mui/system';
import { Box, Icon, IconButton, Typography, useMediaQuery, useTheme, Alert, styled } from '@mui/material';
import { PREFIX } from './constants';
import { SCCourseJoinStatusType, SCCourseLessonCompletionStatusType } from '@selfcommunity/types';
import { SCRoutes, useSCFetchCourse, useSCFetchLesson, useSCRouting, Link } from '@selfcommunity/react-core';
import classNames from 'classnames';
import { CourseCompletedDialog, HiddenPlaceholder, LessonAppbar, LessonDrawer, LessonObject, SCLessonActionsType } from '@selfcommunity/react-ui';
import { CourseInfoViewType, CourseService } from '@selfcommunity/api-services';
import { FormattedMessage } from 'react-intl';
import { LoadingButton } from '@mui/lab';
import { useSnackbar } from 'notistack';
import { getUrlLesson } from '@selfcommunity/react-ui';
const classes = {
root: `${PREFIX}-root`,
containerRoot: `${PREFIX}-container-root`,
navigation: `${PREFIX}-navigation`,
navigationTitle: `${PREFIX}-navigation-title`,
previewInfo: `${PREFIX}-preview-info`,
button: `${PREFIX}-button`
};
const Root = styled(Box, {
name: PREFIX,
slot: 'Root',
overridesResolver: (_props, styles) => [styles.root]
})(() => ({}));
const Container = styled(Box, {
name: PREFIX,
slot: 'ContainerRoot',
overridesResolver: (_props, styles) => styles.containerRoot,
shouldForwardProp: (prop) => prop !== 'open'
})(() => ({}));
export default function Lesson(inProps) {
var _a, _b, _c;
// PROPS
const props = useThemeProps({
props: inProps,
name: PREFIX
});
const { className = null, courseId, sectionId, lessonId, LessonAppbarProps = {}, LessonDrawerProps = {}, editMode = false, previewMode = false, onEditModeClose = null, onLessonChange = null, onActivePanelChange = null, onLessonStatusChange = null, lessonAction = null } = props, rest = __rest(props, ["className", "courseId", "sectionId", "lessonId", "LessonAppbarProps", "LessonDrawerProps", "editMode", "previewMode", "onEditModeClose", "onLessonChange", "onActivePanelChange", "onLessonStatusChange", "lessonAction"]);
// HOOKS
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const [_lessonId, setLessonId] = useState(lessonId);
const [_sectionId, setSectionId] = useState(sectionId);
const { scLesson, setSCLesson } = useSCFetchLesson({ id: _lessonId, courseId, sectionId: _sectionId });
const { scCourse, refreshCourse } = useSCFetchCourse({
id: courseId,
params: { view: editMode || previewMode ? CourseInfoViewType.EDIT : CourseInfoViewType.USER }
});
const { enqueueSnackbar } = useSnackbar();
const scRoutingContext = useSCRouting();
// STATE
const [activePanel, setActivePanel] = useState(lessonAction);
const [settings, setSettings] = useState(null);
const [updating, setUpdating] = useState(false);
const [lessonContent, setLessonContent] = useState('');
const [lessonMedias, setLessonMedias] = useState((_a = scLesson === null || scLesson === void 0 ? void 0 : scLesson.medias) !== null && _a !== void 0 ? _a : []);
const [loading, setLoading] = useState(false);
const [completed, setCompleted] = useState(null);
const availableLessons = useMemo(() => {
if (!(scCourse === null || scCourse === void 0 ? void 0 : scCourse.sections))
return [];
return scCourse.sections.flatMap((section) => section.lessons.map((lesson) => (Object.assign(Object.assign({}, lesson), { section }))));
}, [scCourse]);
const [currentLessonIndex, setCurrentLessonIndex] = useState(availableLessons.findIndex((lesson) => lesson.id === lessonId));
const isPrevDisabled = availableLessons.length === 0 || currentLessonIndex <= 0 || ((_b = availableLessons[currentLessonIndex - 1]) === null || _b === void 0 ? void 0 : _b.locked);
const isNextDisabled = availableLessons.length === 0 || currentLessonIndex >= availableLessons.length - 1 || ((_c = availableLessons[currentLessonIndex + 1]) === null || _c === void 0 ? void 0 : _c.locked);
const [openDialog, setOpenDialog] = useState(false);
const isCourseAdmin = useMemo(() => scCourse && scCourse.join_status === SCCourseJoinStatusType.CREATOR, [scCourse]);
//EFFECTS
useEffect(() => {
const index = availableLessons.findIndex((lesson) => lesson.id === lessonId);
setCurrentLessonIndex(index);
}, [lessonId, availableLessons]);
useEffect(() => {
if (scLesson) {
setCompleted(scLesson.completion_status === SCCourseLessonCompletionStatusType.COMPLETED);
}
}, [scLesson]);
// HANDLERS
/**
* Handles lesson settings change
* @param newSettings
*/
const handleSettingsChange = (newSettings) => {
setSettings(newSettings);
};
const handleOpenDrawer = (panel) => {
setActivePanel((prevPanel) => (prevPanel === panel ? null : panel));
onActivePanelChange && onActivePanelChange(panel);
};
const handleCloseDrawer = () => {
setActivePanel(null);
onEditModeClose && onEditModeClose();
onActivePanelChange && onActivePanelChange(null);
};
const handleLessonContentEdit = (html) => {
setLessonContent(html);
};
const handleLessonMediaEdit = (medias) => {
setLessonMedias(medias);
};
const handleChangeLesson = (l, s) => {
setLessonId(l.id);
setSectionId(s.id);
onLessonChange && onLessonChange(l.id, s.id);
};
/**
* Handles Lesson Edit
*/
const handleLessonUpdate = () => {
setUpdating(true);
const mediaIds = lessonMedias.map((media) => media.id);
const data = Object.assign(Object.assign({}, settings), { type: scLesson.type, name: scLesson.name, text: lessonContent, medias: mediaIds });
CourseService.updateCourseLesson(scCourse.id, sectionId, scLesson.id, data)
.then((data) => {
setUpdating(false);
setSCLesson(data);
enqueueSnackbar(_jsx(FormattedMessage, { id: "templates.lesson.save.success", defaultMessage: "templates.lesson.save.success" }), {
variant: 'success',
autoHideDuration: 3000
});
})
.catch((error) => {
setUpdating(false);
enqueueSnackbar(_jsx(FormattedMessage, { id: "templates.lesson.save.error", defaultMessage: "templates.lesson.save.error" }), {
variant: 'error',
autoHideDuration: 3000
});
console.log(error);
});
};
/**
* Handles prev lesson navigation
*/
const handlePrev = () => {
if (isPrevDisabled)
return;
const newLessonIndex = currentLessonIndex - 1;
const newLesson = availableLessons[newLessonIndex];
setCurrentLessonIndex(newLessonIndex);
handleChangeLesson(newLesson, newLesson.section);
};
/**
* Handles next lesson navigation
*/
const handleNext = () => {
if (isNextDisabled)
return;
const newLessonIndex = currentLessonIndex + 1;
const newLesson = availableLessons[newLessonIndex];
setCurrentLessonIndex(newLessonIndex);
handleChangeLesson(newLesson, newLesson.section);
};
/**
* Handles toggle lesson complete/uncompleted
*/
const toggleLessonCompletion = () => {
setLoading(true);
const service = completed
? () => CourseService.markLessonIncomplete(scLesson.course_id, scLesson.section_id, scLesson.id)
: () => CourseService.markLessonComplete(scLesson.course_id, scLesson.section_id, scLesson.id);
service()
.then(() => {
setCompleted(!completed);
setLoading(false);
refreshCourse();
if (!completed && scCourse.num_lessons === scCourse.num_lessons_completed + 1) {
setOpenDialog(true);
}
onLessonStatusChange === null || onLessonStatusChange === void 0 ? void 0 : onLessonStatusChange();
})
.catch((error) => {
setLoading(false);
console.log(error);
});
};
/**
* Handles complete lesson dialog close
*/
const handleCloseDialog = useCallback(() => {
setOpenDialog(false);
}, [setOpenDialog]);
/**
* Rendering
*/
if (!scLesson || !scCourse) {
return _jsx(HiddenPlaceholder, {});
}
return (_jsxs(Fragment, { children: [_jsxs(Root, Object.assign({ className: classNames(classes.root, className) }, rest, { children: [_jsx(LessonAppbar, Object.assign({ showComments: scLesson.comments_enabled, editMode: editMode, activePanel: activePanel, title: scCourse.name, handleOpen: handleOpenDrawer, onSave: handleLessonUpdate, updating: updating }, LessonAppbarProps)), _jsxs(Container, Object.assign({ open: Boolean(activePanel) || editMode, className: classes.containerRoot }, { children: [previewMode && (_jsx(Alert, Object.assign({ severity: "info", className: classes.previewInfo }, { children: _jsx(Typography, Object.assign({ variant: "body1" }, { children: _jsx(FormattedMessage, { id: "templates.lesson.previewMode", defaultMessage: "templates.lesson.previewMode", values: {
link: (...chunks) => (_jsx(Link, Object.assign({ to: scRoutingContext.url(SCRoutes.COURSE_LESSON_EDIT_ROUTE_NAME, getUrlLesson(scCourse, scLesson)) }, { children: chunks }))),
linkBack: (...chunks) => _jsx(Link, Object.assign({ to: scRoutingContext.url(SCRoutes.COURSE_DASHBOARD_ROUTE_NAME, scCourse) }, { children: chunks }))
} }) })) }))), _jsx(Box, Object.assign({ className: classes.navigation }, { children: _jsx(Typography, Object.assign({ variant: "body2", color: "text.secondary" }, { children: _jsx(FormattedMessage, { id: "templates.lesson.number", defaultMessage: "templates.lesson.number", values: { from: currentLessonIndex + 1, to: availableLessons.length } }) })) })), _jsxs(Box, Object.assign({ className: classes.navigationTitle }, { children: [_jsx(Typography, Object.assign({ variant: "h5" }, { children: scLesson.name })), _jsxs(Box, { children: [_jsx(IconButton, Object.assign({ onClick: handlePrev, disabled: isPrevDisabled }, { children: _jsx(Icon, { children: "arrow_back" }) })), _jsx(IconButton, Object.assign({ onClick: handleNext, disabled: isNextDisabled }, { children: _jsx(Icon, { children: "arrow_next" }) }))] })] })), _jsx(LessonObject, { course: scCourse, lesson: scLesson, editMode: editMode, onContentChange: handleLessonContentEdit, onMediaChange: handleLessonMediaEdit }), !isCourseAdmin && !editMode && !previewMode && (_jsx(LoadingButton, Object.assign({ className: classes.button, loading: loading, size: "small", variant: completed ? 'outlined' : 'contained', startIcon: !completed && _jsx(Icon, { children: "arrow_next" }), endIcon: completed && _jsx(Icon, { children: "circle_checked" }), onClick: toggleLessonCompletion }, { children: completed ? (_jsx(FormattedMessage, { id: "templates.lesson.button.completed", defaultMessage: "templates.lesson.button.completed" })) : (_jsx(FormattedMessage, { id: "templates.lesson.button.complete", defaultMessage: "templates.lesson.button.complete" })) })))] })), _jsx(LessonDrawer, Object.assign({ course: scCourse, lesson: scLesson, editMode: isMobile ? activePanel === SCLessonActionsType.SETTINGS : editMode, previewMode: previewMode, activePanel: activePanel, handleClose: handleCloseDrawer, handleChangeLesson: handleChangeLesson, LessonEditFormProps: { lesson: scLesson, onSave: handleLessonUpdate, updating: updating, onSettingsChange: handleSettingsChange } }, LessonDrawerProps))] })), openDialog && _jsx(CourseCompletedDialog, { course: scCourse, onClose: handleCloseDialog })] }));
}