@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
312 lines (303 loc) • 17.2 kB
JavaScript
import { __rest } from "tslib";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useCallback, useContext, useMemo, useState } from 'react';
import { styled } from '@mui/material/styles';
import { Backdrop, Box, Button, Collapse, Divider, Grid, Icon, IconButton, Stack, Tooltip, Typography } from '@mui/material';
import { http, Endpoints } from '@selfcommunity/api-services';
import { Link, SCUserContext, UserUtils, useSCContext } from '@selfcommunity/react-core';
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import Widget from '../Widget';
import { useThemeProps } from '@mui/system';
import HiddenPlaceholder from '../../shared/HiddenPlaceholder';
import { CONTACT_PROD, CONTACT_STAGE, HUB_PROD, HUB_STAGE, PREFIX } from './constants';
import LogoPlaceholder from '../../assets/logo';
import Grow from '@mui/material/Grow';
const classes = {
root: `${PREFIX}-root`,
title: `${PREFIX}-title`,
content: `${PREFIX}-content`,
actions: `${PREFIX}-actions`,
action: `${PREFIX}-action`,
actionHighlighted: `${PREFIX}-action-highlighted`,
tutorial: `${PREFIX}-tutorial`,
tutorialContent: `${PREFIX}-tutorial-content`,
tutorialTitle: `${PREFIX}-tutorial-title`,
tutorialTitleClose: `${PREFIX}-tutorial-title-close`,
tutorialDesc: `${PREFIX}-tutorial-desc`,
tutorialOpen: `${PREFIX}-tutorial-open`,
divider: `${PREFIX}-divider`,
tutorialControls: `${PREFIX}-tutorial-controls`,
btnStep: `${PREFIX}-btn-step`,
btnPreviousStep: `${PREFIX}-btn-previous-step`,
btnNextStep: `${PREFIX}-btn-next-step`
};
const Root = styled(Widget, {
name: PREFIX,
slot: 'Root'
})(({ theme }) => ({
padding: '0px !important',
[`&.${classes.tutorialOpen}`]: {
position: 'relative',
zIndex: theme.zIndex.drawer + 2,
[`& .${classes.tutorial}`]: {
padding: 0
}
},
[`& .${classes.title}`]: {
display: 'flex',
justifyContent: 'center',
marginBottom: theme.spacing(1)
},
[`& .${classes.content}`]: {
padding: `${theme.spacing(2)} 0 0 0`,
backgroundColor: '#EFEFEF'
},
[`& .${classes.actions}`]: {
display: 'flex',
paddingBottom: 0,
boxShadow: 'inset -1px -3px 7px -4px #CECECE',
'-webkit-overflow-scrolling': 'touch',
overflowX: 'auto',
overflowY: 'hidden',
scrollbarWidth: 'none' /* Firefox */,
'-ms-overflow-style': 'none' /* IE and Edge */,
'&::-webkit-scrollbar': {
display: 'none'
}
},
[`& .${classes.action}`]: {
padding: `0px 2px ${theme.spacing(2)} 2px`,
display: 'flex',
flexGrow: 1,
justifyContent: 'center',
'& .MuiButton-root': {
color: theme.palette.getContrastText(theme.palette.common.white),
backgroundColor: theme.palette.common.white,
'&:hover': {
color: theme.palette.getContrastText(theme.palette.primary.main),
backgroundColor: theme.palette.primary.main
}
}
},
[`& .${classes.tutorialContent}`]: {
width: '100%'
},
[`& .${classes.divider}`]: {
paddingTop: theme.spacing()
},
[`& .${classes.tutorialTitle}`]: {
position: 'relative',
fontWeight: 700,
fontSize: 15,
padding: `${theme.spacing(3)} ${theme.spacing()} ${theme.spacing()} ${theme.spacing(3)}`
},
[`& .${classes.tutorialTitleClose}`]: {
position: 'absolute',
top: theme.spacing(3),
right: theme.spacing(3)
},
[`& .${classes.tutorialDesc}`]: {
fontSize: 14,
fontWeight: 500,
color: theme.palette.grey[700],
padding: `0px ${theme.spacing(3)} ${theme.spacing()} ${theme.spacing(3)}`
},
[`& .${classes.tutorialControls}`]: {
padding: theme.spacing(2)
},
[`& .${classes.actionHighlighted}`]: {
position: 'relative',
'&:before': {
content: '""',
display: 'block',
position: 'absolute',
bottom: -11,
width: 10,
height: 10,
transform: 'translateY(-50%) rotate(45deg)',
boxShadow: '0px -20px 20px 0px #CECECE',
zIndex: 0,
backgroundColor: theme.palette.common.white
},
'& .MuiButton-root': {
backgroundColor: theme.palette.primary.main,
color: theme.palette.common.white
}
},
[`& .${classes.btnStep}`]: {
borderRadius: 3
}
}));
/**
* > API documentation for the Community-JS PlatformWidget component. Learn about the available props and the CSS API.
*
*
* This component renders a widget containing the links that allow users and moderators to handle their application content.
* Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/Platform)
#### Import
```jsx
import {PlatformWidget} from '@selfcommunity/react-ui';
```
#### Component Name
The name `SCPlatformWidget` can be used when providing style overrides in the theme.
#### CSS
|Rule Name|Global class|Description|
|---|---|---|
|root|.SCPlatformWidget-root|Styles applied to the root element.|
|title|.SCPlatformWidget-title|Styles applied to the title element.|
|actions|.SCPlatformWidget-actions|Styles applied to the actions container.|
|action|.SCPlatformWidget-action|Styles applied to the single action element.|
|actionHighlighted|.SCPlatformWidget-action-highlighted|Styles applied to the action highlighted.|
|tutorial|.SCPlatformWidget-tutorial|Styles applied to the tutorial element.|
|tutorialContent|.SCPlatformWidget-tutorial-content|Styles applied to the content of the tutorial element.|
|tutorialTitle|.SCPlatformWidget-tutorial-title|Styles applied to the title element of the tutorial.|
|tutorialTitleClose|.SCPlatformWidget-tutorial-title-close|Styles applied to the close button of the title in the tutorial.|
|tutorialDesc|.SCPlatformWidget-tutorial-desc|Styles applied to the tutorial description element.|
|tutorialOpen|.SCPlatformWidget-tutorial-open|Styles applied to the tutorial element when is active.|
|divider|.SCPlatformWidget-divider|Styles applied to the divider element in the tutorial container.|
|tutorialControls|.SCPlatformWidget-tutorial-controls|Styles applied to the tutorial bottom controls.|
|btnStep|.SCPlatformWidget-btn-step|Styles applied to the button next/previous/skip/close of the tutorial controls.|
|btnPreviousStep|.SCPlatformWidget-btn-previous-step|Styles applied to the button previous element of the tutorial controls.|
|btnNextStep|.SCPlatformWidget-btn-next-step|Styles applied to the button next element of the tutorial controls.|
*
* @param inProps
*/
export default function PlatformWidget(inProps) {
var _a;
// PROPS
const props = useThemeProps({
props: inProps,
name: PREFIX
});
const { autoHide, className, title = null, startActions = [], endActions = [], hideConsoleAction = false, hideModerationAction = false, hideHubAction = false, hideContactUsAction = false, onHeightChange } = props, rest = __rest(props, ["autoHide", "className", "title", "startActions", "endActions", "hideConsoleAction", "hideModerationAction", "hideHubAction", "hideContactUsAction", "onHeightChange"]);
// CONTEXT
const scContext = useSCContext();
const scUserContext = useContext(SCUserContext);
// STATE
const [tutorialIndex, setTutorialIndex] = useState(0);
const [isTutorialOpen, setIsTutorialOpen] = useState(false);
// CONST
const isAdmin = useMemo(() => UserUtils.isAdmin(scUserContext.user), [scUserContext.user]);
const isEditor = useMemo(() => UserUtils.isEditor(scUserContext.user), [scUserContext.user]);
const isModerator = useMemo(() => UserUtils.isModerator(scUserContext.user), [scUserContext.user]);
const isCommunityOwner = useMemo(() => { var _a; return ((_a = scUserContext === null || scUserContext === void 0 ? void 0 : scUserContext.user) === null || _a === void 0 ? void 0 : _a.id) === 1; }, [scUserContext.user]);
const isStage = scContext.settings.portal.includes('stage');
const actions = [
...startActions,
...((isAdmin || isEditor) && !hideConsoleAction
? [
{
render: (_jsx(Button, Object.assign({ variant: "outlined", size: "small", onClick: () => fetchPlatform('') }, { children: _jsx(FormattedMessage, { id: "ui.platformWidget.adm", defaultMessage: "ui.platformWidget.adm" }) }))),
title: _jsx(FormattedMessage, { id: "ui.platformWidget.adm", defaultMessage: "ui.platformWidget.adm" }),
content: _jsx(FormattedMessage, { id: "ui.platformWidget.adm.desc", defaultMessage: "ui.platformWidget.adm.desc" })
}
]
: []),
...((isAdmin || isModerator) && !hideModerationAction
? [
{
render: (_jsx(Button, Object.assign({ variant: "outlined", size: "small", onClick: () => fetchPlatform('/moderation/flags/') }, { children: _jsx(FormattedMessage, { id: "ui.platformWidget.mod", defaultMessage: "ui.platformWidget.mod" }) }))),
title: _jsx(FormattedMessage, { id: "ui.platformWidget.mod", defaultMessage: "ui.platformWidget.mod" }),
content: _jsx(FormattedMessage, { id: "ui.platformWidget.mod.desc", defaultMessage: "ui.platformWidget.mod.desc" })
}
]
: []),
...(isAdmin && isCommunityOwner && !hideHubAction
? [
{
render: (_jsx(Button, Object.assign({ variant: "outlined", size: "small", component: Link, to: isStage ? HUB_STAGE : HUB_PROD, target: "_blank" }, { children: _jsx(FormattedMessage, { id: "ui.platformWidget.hub", defaultMessage: "ui.platformWidget.hub" }) }))),
title: _jsx(FormattedMessage, { id: "ui.platformWidget.hub", defaultMessage: "ui.platformWidget.hub" }),
content: _jsx(FormattedMessage, { id: "ui.platformWidget.hub.desc", defaultMessage: "ui.platformWidget.hub.desc" })
}
]
: []),
...(isCommunityOwner && !hideContactUsAction
? [
{
render: (_jsx(Button, Object.assign({ variant: "outlined", size: "small", component: Link, to: isStage ? CONTACT_STAGE : CONTACT_PROD, target: "_blank" }, { children: _jsx(FormattedMessage, { id: "ui.platformWidget.contactUs", defaultMessage: "ui.platformWidget.contactUs" }) }))),
title: _jsx(FormattedMessage, { id: "ui.platformWidget.contactUs", defaultMessage: "ui.platformWidget.contactUs" }),
content: _jsx(FormattedMessage, { id: "ui.platformWidget.contactUs.desc", defaultMessage: "ui.platformWidget.contactUs.desc" })
}
]
: []),
...endActions
];
/**
* Handle open tutorial
*/
const handleOpenTutorial = useCallback(() => {
setTutorialIndex(0);
setIsTutorialOpen(true);
onHeightChange && onHeightChange();
}, [setTutorialIndex, setIsTutorialOpen, onHeightChange]);
/**
* Handle close tutorial
*/
const handleCloseTutorial = useCallback(() => {
setIsTutorialOpen(false);
setTutorialIndex(0);
onHeightChange && onHeightChange();
}, [setIsTutorialOpen, setTutorialIndex, onHeightChange]);
/**
* Handle next step tutorial
*/
const handlePrevious = useCallback(() => {
if (tutorialIndex > 0) {
setTutorialIndex((prev) => prev - 1);
}
else {
handleCloseTutorial();
}
onHeightChange && onHeightChange();
}, [tutorialIndex, setTutorialIndex, handleCloseTutorial, onHeightChange]);
/**
* Handle next step tutorial
*/
const handleNext = useCallback(() => {
if (tutorialIndex < actions.length - 1) {
setTutorialIndex((prev) => prev + 1);
}
else {
handleCloseTutorial();
}
onHeightChange && onHeightChange();
}, [actions, tutorialIndex, setTutorialIndex, handleCloseTutorial, onHeightChange]);
/**
* Fetches platform url
*/
function fetchPlatform(query) {
http
.request({
url: Endpoints.Platform.url(),
method: Endpoints.Platform.method,
params: {
next: query
}
})
.then((res) => {
const platformUrl = res.data.platform_url;
window.open(platformUrl, '_blank').focus();
})
.catch((error) => {
console.log(error);
});
}
/**
* Render tutorial
*/
const tutorial = (_jsxs(Grid, Object.assign({ container: true, spacing: isAdmin ? 1 : 3, justifyContent: "center", className: classes.tutorial }, { children: [!isTutorialOpen && (_jsx(Grid, Object.assign({ item: true, xs: "auto", alignItems: "center", justifyContent: "center" }, { children: _jsx(IconButton, Object.assign({ size: "medium", onClick: handleOpenTutorial }, { children: _jsx(Icon, { children: "info" }) })) }))), _jsx(Collapse, Object.assign({ in: isTutorialOpen, className: classes.tutorialContent }, { children: isTutorialOpen && (_jsxs(Grid, Object.assign({ item: true, xs: "auto" }, { children: [_jsxs(Typography, Object.assign({ variant: 'body2', className: classes.tutorialTitle, component: 'div' }, { children: [_jsx(Grow, Object.assign({ in: true, timeout: 1000 }, { children: _jsx("span", { children: actions[tutorialIndex].title }) })), _jsx(IconButton, Object.assign({ size: 'small', className: classes.tutorialTitleClose, onClick: handleCloseTutorial }, { children: _jsx(Icon, { children: "close" }) }))] })), _jsx(Grow, Object.assign({ in: true, timeout: 1200 }, { children: _jsx(Typography, Object.assign({ variant: 'body2', className: classes.tutorialDesc }, { children: actions[tutorialIndex].content })) })), _jsx(Divider, { className: classes.divider }), _jsxs(Stack, Object.assign({ direction: "row", justifyContent: "space-between", alignItems: "center", spacing: 2, className: classes.tutorialControls }, { children: [_jsx(Button, Object.assign({ variant: "text", size: "small", onClick: handlePrevious, className: classNames(classes.btnStep, classes.btnPreviousStep) }, { children: tutorialIndex === 0 ? (_jsx(FormattedMessage, { id: "ui.platformWidget.tutorial.skip", defaultMessage: "ui.platformWidget.tutorial.skip" })) : (_jsx(FormattedMessage, { id: "ui.platformWidget.tutorial.previous", defaultMessage: "ui.platformWidget.tutorial.previous" })) })), _jsxs(Typography, Object.assign({ component: 'div' }, { children: [tutorialIndex + 1, "/", actions.length] })), _jsx(Button, Object.assign({ variant: "contained", size: "small", color: "primary", onClick: handleNext, className: classNames(classes.btnStep, classes.btnNextStep) }, { children: tutorialIndex === actions.length - 1 ? (_jsx(FormattedMessage, { id: "ui.platformWidget.tutorial.close", defaultMessage: "ui.platformWidget.tutorial.close" })) : (_jsx(FormattedMessage, { id: "ui.platformWidget.tutorial.next", defaultMessage: "ui.platformWidget.tutorial.next" })) }))] }))] }))) }))] })));
/**
* Renders platform card
*/
const content = (_jsxs(Grid, Object.assign({ container: true, spacing: isAdmin ? 1 : 3, justifyContent: "center", className: classes.content }, { children: [_jsx(Grid, Object.assign({ item: true, xs: 12 }, { children: title ? (title) : (_jsx(Box, Object.assign({ className: classes.title }, { children: _jsx(Tooltip, Object.assign({ title: _jsx(FormattedMessage, { id: "ui.platformWidget.title.tooltip", defaultMessage: "ui.platformWidget.title.tooltip" }), placement: "top" }, { children: _jsx("img", { src: LogoPlaceholder, alt: "logo" }) })) }))) })), _jsxs(Grid, Object.assign({ item: true, xs: 12, className: classes.actions }, { children: [_jsx(Grid, { item: true, xs: 1, className: classes.action }), actions.map((a, i) => {
return (_jsx(Grid, Object.assign({ item: true, xs: "auto", className: classNames(classes.action, { [classes.actionHighlighted]: tutorialIndex === i && isTutorialOpen }) }, { children: a.render }), i));
}), _jsx(Grid, { item: true, xs: 1, className: classes.action })] }))] })));
/**
* Renders root object (if not hidden by autoHide prop)
*/
if (!autoHide && ((_a = scUserContext === null || scUserContext === void 0 ? void 0 : scUserContext.user) === null || _a === void 0 ? void 0 : _a.role)) {
return (_jsxs(_Fragment, { children: [_jsxs(Root, Object.assign({ className: classNames(classes.root, className, { [classes.tutorialOpen]: isTutorialOpen }) }, rest, { children: [content, tutorial] })), _jsx(Backdrop, { sx: { color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }, open: isTutorialOpen, onClick: handleCloseTutorial })] }));
}
return _jsx(HiddenPlaceholder, {});
}