/* * Copyright (C) 2022 Kristóf Marussy * * This file is part of Sophie. * * Sophie is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, version 3. * * 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * SPDX-License-Identifier: AGPL-3.0-only */ import IconWarning from '@mui/icons-material/Warning'; import Badge from '@mui/material/Badge'; import { styled } from '@mui/material/styles'; import { observer } from 'mobx-react-lite'; import React, { useEffect, useState } from 'react'; import type Service from '../../stores/Service.js'; const ServiceIconRoot = styled('div', { name: 'ServiceIcon', slot: 'Root', shouldForwardProp: (prop) => prop !== 'hasError', })<{ hasError: boolean }>(({ theme, hasError }) => ({ width: 36, height: 36, borderRadius: theme.shape.borderRadius, background: 'currentColor', display: 'flex', justifyContent: 'center', alignItems: 'center', filter: hasError ? 'grayscale(100%)' : 'none', opacity: hasError ? theme.palette.action.disabledOpacity : 1, transition: theme.transitions.create(['filter', 'opacity'], { duration: hasError ? theme.transitions.duration.enteringScreen : theme.transitions.duration.leavingScreen, }), })); const ServiceIconText = styled('div', { name: 'ServiceIcon', slot: 'Text', })(({ theme }) => ({ display: 'inline-block', flex: 0, fontSize: theme.typography.pxToRem(24), color: theme.palette.primary.contrastText, })); const ServiceIconBadgeBase = styled(Badge)({ '& > .MuiBadge-badge': { zIndex: 200, }, }); const ServiceIconBadge = styled(ServiceIconBadgeBase, { name: 'ServiceIcon', slot: 'Badge', })(({ theme }) => ({ '& > .MuiBadge-dot': { background: theme.palette.mode === 'dark' ? theme.palette.text.primary : theme.palette.primary.light, }, })); const ServiceIconErrorBadge = styled(ServiceIconBadgeBase, { name: 'ServiceIcon', slot: 'ErrorBadge', })(({ theme }) => ({ '& > .MuiBadge-standard': { color: theme.palette.mode === 'dark' ? theme.palette.error.light : theme.palette.error.main, }, })); function ServiceIcon({ service }: { service: Service }): JSX.Element { const { settings: { name }, directMessageCount, indirectMessageCount, hasError, } = service; // Badge color histeresis for smooth appear / disappear animation. // If we compute hasDirectMessage = directMessageCount >= 1 directly (without any histeresis), // the badge momentarily turns light during the disappear animation. const [hasDirectMessage, setHasDirectMessage] = useState(false); useEffect(() => { if (directMessageCount >= 1) { setHasDirectMessage(true); } else if (indirectMessageCount >= 1) { setHasDirectMessage(false); } }, [directMessageCount, indirectMessageCount, setHasDirectMessage]); return ( : 0} anchorOrigin={{ vertical: 'bottom', horizontal: 'right', }} > ); } export default observer(ServiceIcon);