@blocklet/ui-react
Version:
Some useful front-end web components that can be used in Blocklets.
208 lines (199 loc) • 7.66 kB
JSX
import { SessionContext } from '@arcblock/did-connect/lib/Session';
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import { translate } from '@arcblock/ux/lib/Locale/util';
import SessionPermission from '@arcblock/ux/lib/SessionPermission';
import { Icon } from '@iconify/react';
import { Close as CloseIcon } from '@mui/icons-material';
import { Box, ClickAwayListener, Fade, IconButton, Paper } from '@mui/material';
import { useMemoizedFn } from 'ahooks';
import PropTypes from 'prop-types';
import { use } from 'react';
import InstallerItem from './installer-item';
import translations from './locales';
import useComponentInstalled from './use-component-installed';
function ComponentInstaller({
warnIcon = null,
did,
noPermissionMute = false,
onInstalled = null,
onError = null,
children,
closeByOutSize = false,
onClose = null,
fallback = null,
disabled = false,
roles = ['owner', 'admin'],
}) {
const { locale } = useLocaleContext();
const t = useMemoizedFn((key, data = {}) => {
return translate(translations, key, locale, 'en', data);
});
const { installed, optComponents, installStatus, definedInBlockletYML } = useComponentInstalled({
did,
onInstalled,
onError,
});
const sessionCtx = use(SessionContext);
const handleClose = () => {
onClose?.(false);
};
if (disabled) {
return children;
}
return (
<SessionPermission session={sessionCtx?.session} roles={roles}>
{({ hasPermission }) => {
if (installed) {
return children;
}
if (noPermissionMute && !hasPermission) {
return fallback || null;
}
if (typeof children === 'function') {
return (
<>
{fallback}
{children({
hasPermission,
optComponents,
installStatus,
})}
</>
);
}
// not installed, but has permission, can install directly
return (
<>
{fallback}
<ClickAwayListener
onClickAway={(e) => {
e.preventDefault();
e.stopPropagation();
if (closeByOutSize) {
handleClose();
}
}}>
<Fade in timeout={350}>
<Paper
variant="outlined"
sx={{
position: 'fixed',
top: 20,
right: 20,
zIndex: 3000,
borderRadius: 1.5,
width: 400,
maxWidth: '90vw',
borderColor: 'divider',
border: '0 !important',
fontSize: '14px',
textAlign: 'left',
boxShadow: ({ palette }) =>
`0px 8px 16px 0px ${palette.grey[100]}, 0px 0px 0px 1px ${palette.grey[100]}`,
}}>
{!definedInBlockletYML ? (
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<Box
sx={{
padding: '20px 24px',
marginLeft: 0,
display: 'flex',
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'flex-start',
}}>
{warnIcon || <Icon icon="mdi:warning-box" style={{ color: 'yellowgreen', fontSize: 24 }} />}
<Box sx={{ marginLeft: 1, fontSize: '16px', fontWeight: 'bold' }}>
{t('componentInstallerTitle')}
</Box>
<Box sx={{ flex: 1 }} />
{onClose ? (
<IconButton variant="outlined" className="button" onClick={handleClose}>
<CloseIcon />
</IconButton>
) : null}
</Box>
<Box sx={{ width: '100%', height: '1px', backgroundColor: 'grey.100' }} />
<Box sx={{ padding: '20px 24px', marginTop: 0 }}>
{t('componentInstallerNoDefinedInBlockletYML')}: {did}
</Box>
</Box>
) : (
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<Box
sx={{
padding: '20px 24px',
marginLeft: 0,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-start',
}}>
{warnIcon || <Icon icon="mdi:warning-box" style={{ color: 'yellowgreen', fontSize: 24 }} />}
<Box sx={{ marginLeft: 1, fontSize: '16px', fontWeight: 'bold' }}>
{t('componentInstallerTitle')}
</Box>
<Box sx={{ flex: 1 }} />
{onClose ? (
<IconButton variant="outlined" className="button" onClick={handleClose}>
<CloseIcon />
</IconButton>
) : null}
</Box>
<Box sx={{ width: '100%', height: '1px', backgroundColor: 'grey.100' }} />
<Box sx={{ maxHeight: '70vh', overflowY: 'auto' }}>
{optComponents.map((optionalComponent, index) => {
return (
<InstallerItem
t={t}
key={optionalComponent.meta?.did || index}
hasPermission={hasPermission}
index={index}
optionalComponent={optionalComponent}
installStatus={installStatus[optionalComponent.meta?.did]}
/>
);
})}
</Box>
{hasPermission ? null : (
<>
<Box sx={{ width: '100%', height: '1px', backgroundColor: 'grey.100' }} />
<Box sx={{ padding: '20px 24px' }}>
<Box sx={{ opacity: 1 }}>{t('componentInstallerSuggestions')}</Box>
</Box>
</>
)}
</Box>
)}
</Paper>
</Fade>
</ClickAwayListener>
</>
);
}}
</SessionPermission>
);
}
ComponentInstaller.propTypes = {
disabled: PropTypes.bool,
warnIcon: PropTypes.node,
did: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]).isRequired,
noPermissionMute: PropTypes.bool,
onInstalled: PropTypes.func,
onError: PropTypes.func,
children: PropTypes.any.isRequired,
closeByOutSize: PropTypes.bool,
onClose: PropTypes.func,
fallback: PropTypes.node,
roles: PropTypes.array,
};
export default function WrapComponentInstaller(props) {
if (window.blocklet) {
return <ComponentInstaller {...props} />;
}
return props.children;
}
WrapComponentInstaller.propTypes = {
...ComponentInstaller.propTypes,
children: PropTypes.any.isRequired,
};