UNPKG

@craftercms/studio-ui

Version:

Services, components, models & utils to build CrafterCMS authoring extensions.

229 lines (227 loc) 8.52 kB
/* * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import React, { useEffect, useState, useMemo } from 'react'; import Card from '@mui/material/Card'; import CardHeader, { cardHeaderClasses } from '@mui/material/CardHeader'; import IconButton from '@mui/material/IconButton'; import EditRoundedIcon from '@mui/icons-material/EditRounded'; import DeleteRoundedIcon from '@mui/icons-material/DeleteRounded'; import ContentCopyIcon from '@mui/icons-material/ContentCopyRounded'; import CardMedia from '@mui/material/CardMedia'; import CardActions from '@mui/material/CardActions'; import Tooltip from '@mui/material/Tooltip'; import { FormattedMessage } from 'react-intl'; import CardActionArea from '@mui/material/CardActionArea'; import { alpha, Typography } from '@mui/material'; import { useSiteCardStyles } from '../SitesGrid/styles'; import { PublishingStatusButtonUI } from '../PublishingStatusButton'; import SiteStatusIndicator from '../SiteStatusIndicator/SiteStatusIndicator'; import { toColor } from '../../utils/string'; import useProjectPreviewImage from '../../hooks/useProjectPreviewImage'; import { PROJECT_PREVIEW_IMAGE_UPDATED } from '../../utils/constants'; import { fetchStatus } from '../../services/publishing'; import { catchError, delay, switchMap } from 'rxjs/operators'; import { of } from 'rxjs'; export function SiteCard(props) { const { site, onSiteClick, onDeleteSiteClick, onEditSiteClick, onDuplicateSiteClick, fallbackImageSrc, compact = false, disabled, onPublishButtonClick } = props; const { classes, cx: clsx } = useSiteCardStyles(); const [publishingStatus, setPublishingStatus] = useState(); const [isFetching, setIsFetching] = useState(false); const isSiteReady = site.state === 'READY'; const [dataUrl, fetch] = useProjectPreviewImage(site.id, fallbackImageSrc); const color = useMemo(() => toColor(site.name), [site.name]); useEffect(() => { if (isSiteReady) { setIsFetching(true); const subscription = fetchStatus(site.id) .pipe( // The back seems to 400 to checking publishing status right after creating a very large site. // This attempts to retry the request once after a delay. catchError((e, c) => of(null).pipe( delay(1000), switchMap(() => fetchStatus(site.id)) ) ) ) .subscribe({ next: (status) => { setPublishingStatus(status); setIsFetching(false); }, error: (error) => { console.log(error); setIsFetching(false); } }); return () => { subscription?.unsubscribe(); setIsFetching(false); }; } }, [site.id, isSiteReady]); useEffect(() => { let subscription; const callback = () => { subscription = fetch(); }; document.addEventListener(PROJECT_PREVIEW_IMAGE_UPDATED, callback); return () => { subscription?.unsubscribe(); document.removeEventListener(PROJECT_PREVIEW_IMAGE_UPDATED, callback); }; }, [fetch]); return React.createElement( Card, { className: clsx(classes.card, compact && 'compact'), sx: { position: 'relative' } }, React.createElement( CardActionArea, { onClick: () => onSiteClick(site), component: 'div', disabled: disabled || !isSiteReady }, React.createElement(CardHeader, { title: site.name, className: classes.cardHeader, subheader: site.description && React.createElement( Tooltip, { title: site.description }, React.createElement( Typography, { color: 'textSecondary', component: 'h2', variant: 'subtitle2', className: 'cardSubtitle' }, site.description ) ), onClick: (e) => { e.stopPropagation(); onSiteClick(site); }, titleTypographyProps: { variant: 'subtitle2', component: 'h2', className: 'cardTitle' }, sx: { [`.${cardHeaderClasses.action}`]: { alignSelf: 'center' }, ...(!isSiteReady && { paddingRight: '55px' }) } }), !compact && React.createElement(CardMedia, { component: dataUrl ? 'img' : 'div', className: classes.media, image: dataUrl, title: site.name, sx: (theme) => ({ display: 'flex', alignItems: 'center', placeContent: 'center', backgroundColor: theme.palette.mode === 'light' ? color : alpha(color, 0.6) }), children: dataUrl ? undefined : React.createElement( Typography, { variant: 'h6', component: 'span', sx: (theme) => ({ color: theme.palette.getContrastText(color) }) }, site.name ) }) ), React.createElement( CardActions, { className: classes.cardActions, sx: compact ? undefined : { minHeight: '64px' }, disableSpacing: true }, isSiteReady && React.createElement(PublishingStatusButtonUI, { isFetching: isFetching, enabled: publishingStatus?.enabled, status: publishingStatus?.status, totalItems: publishingStatus?.totalItems, numberOfItems: publishingStatus?.numberOfItems, variant: 'icon', size: compact ? 'small' : 'medium', onClick: (e) => onPublishButtonClick(e, site, publishingStatus), disabled: disabled }), isSiteReady && onEditSiteClick && React.createElement( Tooltip, { title: React.createElement(FormattedMessage, { id: 'words.edit', defaultMessage: 'Edit' }) }, React.createElement( IconButton, { onClick: () => onEditSiteClick(site), size: compact ? 'small' : 'medium', disabled: disabled }, React.createElement(EditRoundedIcon, null) ) ), isSiteReady && onDuplicateSiteClick && React.createElement( Tooltip, { title: React.createElement(FormattedMessage, { defaultMessage: 'Duplicate' }) }, React.createElement( IconButton, { onClick: () => onDuplicateSiteClick(site.id), size: compact ? 'small' : 'medium', disabled: disabled }, React.createElement(ContentCopyIcon, null) ) ), isSiteReady && onDeleteSiteClick && React.createElement( Tooltip, { title: React.createElement(FormattedMessage, { defaultMessage: 'Delete' }) }, React.createElement( IconButton, { onClick: () => onDeleteSiteClick(site), size: compact ? 'small' : 'medium', disabled: disabled }, React.createElement(DeleteRoundedIcon, null) ) ) ), !isSiteReady && React.createElement(SiteStatusIndicator, { state: site.state, sx: { position: 'absolute', top: '22px', right: '20px' } }) ); } export default SiteCard;