UNPKG

@selfcommunity/react-ui

Version:

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

182 lines (173 loc) • 15.4 kB
import { __rest } from "tslib"; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { Avatar, Box, Button, CardActions, CardContent, CardMedia, Chip, Icon, LinearProgress, Tooltip, Typography, useMediaQuery, useTheme, styled } from '@mui/material'; import { useThemeProps } from '@mui/system'; import { Link, SCRoutes, useSCFetchCourse, useSCRouting } from '@selfcommunity/react-core'; import { SCCourseJoinStatusType } from '@selfcommunity/types'; import classNames from 'classnames'; import { useMemo } from 'react'; import { FormattedMessage } from 'react-intl'; import { SCCourseTemplateType } from '../../types/course'; import CourseParticipantsButton from '../CourseParticipantsButton'; import Widget from '../Widget'; import { PREFIX } from './constants'; import CourseSkeleton from './Skeleton'; import { isCourseCompleted, isCourseNew } from '../../utils/course'; import UserAvatar from '../../shared/UserAvatar'; import BaseItemButton from '../../shared/BaseItemButton'; const classes = { root: `${PREFIX}-root`, chip: `${PREFIX}-chip`, previewRoot: `${PREFIX}-preview-root`, previewActions: `${PREFIX}-preview-actions`, previewAvatar: `${PREFIX}-preview-avatar`, previewCategory: `${PREFIX}-preview-category`, previewCompletedStatus: `${PREFIX}-preview-completed-status`, previewContent: `${PREFIX}-preview-content`, previewCreator: `${PREFIX}-preview-creator`, previewImage: `${PREFIX}-preview-image`, previewImageWrapper: `${PREFIX}-preview-image-wrapper`, previewInfo: `${PREFIX}-preview-info`, previewName: `${PREFIX}-preview-name`, previewNameWrapper: `${PREFIX}-preview-name-wrapper`, previewProgress: `${PREFIX}-preview-progress`, previewProgressBar: `${PREFIX}-preview-progress-bar`, snippetRoot: `${PREFIX}-snippet-root`, snippetAvatar: `${PREFIX}-snippet-avatar`, snippetAvatarUserProfile: `${PREFIX}-snippet-avatar-user-profile-view`, snippetImage: `${PREFIX}-snippet-image` }; const Root = styled(Widget, { name: PREFIX, slot: 'Root', overridesResolver: (_props, styles) => styles.root })(() => ({})); const PreviewRoot = styled(Box, { name: PREFIX, slot: 'PreviewRoot', overridesResolver: (_props, styles) => styles.previewRoot })(() => ({})); const SnippetRoot = styled(BaseItemButton, { name: PREFIX, slot: 'SnippetRoot', overridesResolver: (_props, styles) => styles.snippetRoot })(() => ({})); /** * > API documentation for the Community-JS Course component. Learn about the available props and the CSS API. * * * This component renders a course item. * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/Course) #### Import ```jsx import {course} from '@selfcommunity/react-ui'; ``` #### Component Name The name `SCCourse` can be used when providing style overrides in the theme. #### CSS |Rule Name|Global class|Description| |---|---|---| |root|.SCCourses-root|Styles applied to the root element.| |chip|.SCCourses-chip|Styles applied to the chip element.| |previewRoot|.SCCourses-preview-root|Styles applied to the root element in the preview template.| |previewActions|.SCCourses-preview-actions|Styles applied to the actions section in the preview template.| |previewAvatar|.SCCourses-preview-avatar|Styles applied to the avatar in the preview template.| |previewCategory|.SCCourses-preview-category|Styles applied to the category element in the preview template.| |previewCompletedStatus|.SCCourses-preview-completed-status|Styles applied to indicate the completed status in the preview template.| |previewContent|.SCCourses-preview-content|Styles applied to the content section in the preview template.| |previewCreator|.SCCourses-preview-creator|Styles applied to the creator element in the preview template.| |previewImage|.SCCourses-preview-image|Styles applied to the image in the preview template.| |previewImageWrapper|.SCCourses-preview-image-wrapper|Styles applied to the wrapper of the image in the preview template.| |previewInfo|.SCCourses-preview-info|Styles applied to the info section in the preview template.| |previewName|.SCCourses-preview-name|Styles applied to the name element in the preview template.| |previewNameWrapper|.SCCourses-preview-name-wrapper|Styles applied to the name wrapper in the preview template.| |previewProgress|.SCCourses-preview-progress|Styles applied to indicate the progress section in the preview template.| |previewProgressBar|.SCCourses-preview-progress-bar|Styles applied to the progress bar in the preview template.| |snippetRoot|.SCCourses-snippet-root|Styles applied to the root element in the snippet template.| |snippetAvatar|.SCCourses-snippet-avatar|Styles applied to the avatar element in the snippet template.| |snippetImage|.SCCourses-snippet-image|Styles applied to the image element in the snippet template.| * * @param inProps */ export default function Course(inProps) { var _a, _b, _c, _d, _e, _f, _g; // PROPS const props = useThemeProps({ props: inProps, name: PREFIX }); const { id = `course_object_${props.courseId ? props.courseId : props.course ? props.course.id : ''}`, courseId = null, course = null, className = null, template = SCCourseTemplateType.PREVIEW, actions, CourseParticipantsButtonComponentProps = {}, CourseSkeletonComponentProps = {}, userProfileSnippet } = props, rest = __rest(props, ["id", "courseId", "course", "className", "template", "actions", "CourseParticipantsButtonComponentProps", "CourseSkeletonComponentProps", "userProfileSnippet"]); // STATE const { scCourse } = useSCFetchCourse({ id: courseId, course }); const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.between('xs', 'md')); const MAX_VISIBLE_CATEGORIES = isMobile ? 3 : 1; // CONTEXT const scRoutingContext = useSCRouting(); const isCourseAdmin = useMemo(() => scCourse && (scCourse.join_status === SCCourseJoinStatusType.CREATOR || scCourse.join_status === SCCourseJoinStatusType.MANAGER), [scCourse]); /** * Renders course object */ if (!scCourse) { return _jsx(CourseSkeleton, Object.assign({ template: template }, CourseSkeletonComponentProps, rest, { actions: actions })); } const renderProgress = () => { if (isCourseCompleted(scCourse)) { return (_jsxs(Box, Object.assign({ className: classes.previewCompletedStatus }, { children: [_jsx(Icon, Object.assign({ color: "success" }, { children: "circle_checked" })), _jsx(Typography, Object.assign({ variant: "body1" }, { children: _jsx(FormattedMessage, { defaultMessage: "ui.course.completed", id: "ui.course.completed" }) }))] }))); } else if (scCourse.join_status === SCCourseJoinStatusType.JOINED) { return (_jsxs(_Fragment, { children: [_jsx(Typography, { children: _jsx(FormattedMessage, { id: "ui.course.completion.percentage", defaultMessage: "ui.course.completion.percentage", values: { percentage: `${Math.round(scCourse.user_completion_rate)}%` } }) }), _jsx(LinearProgress, { className: classes.previewProgressBar, variant: "determinate", color: "primary", value: scCourse.user_completion_rate })] })); } else if (isCourseAdmin) { return _jsx(CourseParticipantsButton, Object.assign({ course: scCourse }, CourseParticipantsButtonComponentProps)); } }; const chipLabel = (() => { if (isCourseAdmin) { return scCourse.privacy ? (_jsx(FormattedMessage, { defaultMessage: "ui.course.status.published", id: "ui.course.status.published" })) : (_jsx(FormattedMessage, { defaultMessage: "ui.course.status.draft", id: "ui.course.status.draft" })); } else if (isCourseCompleted(scCourse)) { return _jsx(FormattedMessage, { defaultMessage: "ui.course.status.completed", id: "ui.course.status.completed" }); } else if (scCourse.join_status === SCCourseJoinStatusType.JOINED) { return _jsx(FormattedMessage, { defaultMessage: "ui.course.status.joined", id: "ui.course.status.joined" }); } else if (isCourseNew(scCourse)) { return _jsx(FormattedMessage, { defaultMessage: "ui.course.status.new", id: "ui.course.status.new" }); } return null; })(); /** * Renders course object */ let contentObj; if (template === SCCourseTemplateType.PREVIEW) { contentObj = (_jsxs(PreviewRoot, Object.assign({ className: classes.previewRoot }, { children: [_jsxs(Box, Object.assign({ className: classes.previewImageWrapper }, { children: [_jsx(CardMedia, { component: "img", image: scCourse.image_medium, alt: scCourse.name, className: classes.previewImage }), (isCourseAdmin || isCourseCompleted(scCourse) || isCourseNew(scCourse) || scCourse.join_status === SCCourseJoinStatusType.JOINED) && (_jsx(Chip, { size: "small", component: "div", color: isCourseCompleted(scCourse) || (isCourseAdmin && scCourse.privacy) ? 'primary' : isCourseAdmin && !scCourse.privacy ? 'default' : scCourse.join_status === SCCourseJoinStatusType.JOINED ? 'warning' : 'secondary', label: chipLabel, className: classes.chip })), _jsx(Link, Object.assign({}, (!((_a = scCourse.created_by) === null || _a === void 0 ? void 0 : _a.deleted) && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, scCourse.created_by) }), { children: _jsx(UserAvatar, Object.assign({ hide: !((_b = scCourse.created_by) === null || _b === void 0 ? void 0 : _b.community_badge), smaller: true }, { children: _jsx(Avatar, { alt: scCourse.name, src: (_c = scCourse.created_by) === null || _c === void 0 ? void 0 : _c.avatar, className: classes.previewAvatar }) })) }))] })), _jsxs(CardContent, Object.assign({ className: classes.previewContent }, { children: [_jsx(Link, Object.assign({ className: classes.previewCreator }, (!((_d = scCourse.created_by) === null || _d === void 0 ? void 0 : _d.deleted) && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, scCourse.created_by) }), { children: _jsx(Typography, Object.assign({ variant: "body2" }, { children: (_e = scCourse.created_by) === null || _e === void 0 ? void 0 : _e.username })) })), _jsx(Link, Object.assign({ to: scRoutingContext.url(SCRoutes.COURSE_ROUTE_NAME, scCourse), className: classes.previewNameWrapper }, { children: _jsx(Typography, Object.assign({ variant: "h6", className: classes.previewName }, { children: scCourse.name })) })), _jsxs(Typography, Object.assign({ className: classes.previewInfo }, { children: [_jsx(FormattedMessage, { id: scCourse.privacy ? `ui.course.privacy.${scCourse.privacy}` : 'ui.course.privacy.draft', defaultMessage: scCourse.privacy ? `ui.course.privacy.${scCourse.privacy}` : 'ui.course.privacy.draft' }), ' - ', _jsx(FormattedMessage, { id: `ui.course.type.${scCourse.type}`, defaultMessage: `ui.course.type.${scCourse.type}` })] })), _jsxs(Box, Object.assign({ className: classes.previewCategory }, { children: [scCourse.categories.slice(0, MAX_VISIBLE_CATEGORIES).map((category) => (_jsx(Chip, { size: "small", label: category.name }, category.id))), scCourse.categories.length > MAX_VISIBLE_CATEGORIES && (_jsx(Tooltip, Object.assign({ title: _jsx(_Fragment, { children: scCourse.categories.slice(MAX_VISIBLE_CATEGORIES).map((cat) => (_jsx(Box, { children: cat.name }, cat.id))) }) }, { children: _jsx(Chip, { size: "small", label: `+${scCourse.categories.length - MAX_VISIBLE_CATEGORIES}`, sx: { cursor: 'pointer' } }) })))] })), _jsx(Box, Object.assign({ className: classes.previewProgress }, { children: renderProgress() }))] })), actions !== null && actions !== void 0 ? actions : (_jsx(CardActions, Object.assign({ className: classes.previewActions }, { children: _jsx(Button, Object.assign({ variant: "outlined", size: "small", component: Link, to: scRoutingContext.url(SCRoutes.COURSE_ROUTE_NAME, scCourse) }, { children: _jsx(FormattedMessage, { defaultMessage: "ui.course.see", id: "ui.course.see" }) })) })))] }))); } else { contentObj = (_jsx(SnippetRoot, { ButtonBaseProps: { component: Link, to: scRoutingContext.url(SCRoutes.COURSE_ROUTE_NAME, scCourse) }, elevation: 0, className: classes.snippetRoot, image: _jsxs(Box, Object.assign({ className: classes.snippetImage }, { children: [_jsx(Avatar, { variant: "square", alt: scCourse.name, src: scCourse.image_medium, className: userProfileSnippet ? classes.snippetAvatarUserProfile : classes.snippetAvatar }), !userProfileSnippet && (isCourseAdmin || isCourseCompleted(scCourse) || isCourseNew(scCourse) || scCourse.join_status === SCCourseJoinStatusType.JOINED) && (_jsx(Chip, { size: "small", component: "div", color: isCourseCompleted(scCourse) || (isCourseAdmin && scCourse.privacy) ? 'primary' : isCourseAdmin && !scCourse.privacy ? 'default' : scCourse.join_status === SCCourseJoinStatusType.JOINED ? 'warning' : 'secondary', label: chipLabel, className: classes.chip }))] })), primary: _jsxs(_Fragment, { children: [!userProfileSnippet && (_jsx(Link, Object.assign({}, (!((_f = scCourse.created_by) === null || _f === void 0 ? void 0 : _f.deleted) && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, scCourse.created_by) }), { children: _jsx(Typography, Object.assign({ component: "span" }, { children: (_g = scCourse.created_by) === null || _g === void 0 ? void 0 : _g.username })) }))), _jsx(Link, Object.assign({ to: scRoutingContext.url(SCRoutes.COURSE_ROUTE_NAME, scCourse) }, { children: _jsx(Typography, Object.assign({ variant: "body1" }, { children: scCourse.name })) }))] }), secondary: _jsx(_Fragment, { children: userProfileSnippet ? (_jsx(_Fragment, { children: !scCourse.hide_member_count && (_jsx(FormattedMessage, { id: "ui.course.userProfileSnippet.students", defaultMessage: "ui.course.userProfileSnippet.students", values: { students: scCourse.member_count } })) })) : (_jsxs(_Fragment, { children: [_jsx(FormattedMessage, { id: scCourse.privacy ? `ui.course.privacy.${scCourse.privacy}` : 'ui.course.privacy.draft', defaultMessage: scCourse.privacy ? `ui.course.privacy.${scCourse.privacy}` : 'ui.course.privacy.draft' }), ' - ', _jsx(FormattedMessage, { id: `ui.course.type.${scCourse.type}`, defaultMessage: `ui.course.type.${scCourse.type}` })] })) }), actions: actions !== null && actions !== void 0 ? actions : (_jsx(Button, Object.assign({ size: "small", variant: "outlined", component: Link, to: scRoutingContext.url(SCRoutes.COURSE_ROUTE_NAME, scCourse) }, { children: _jsx(FormattedMessage, { defaultMessage: "ui.course.see", id: "ui.course.see" }) }))) })); } /** * Renders root object */ return (_jsx(Root, Object.assign({ id: id, className: classNames(classes.root, className, `${PREFIX}-${template}`) }, rest, { children: contentObj }))); }