/* * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'react' import { Button, ProgressBar, Toast } from 'react-bootstrap' import { ForkAwesomeIcon } from '../common/fork-awesome/fork-awesome-icon' import { ShowIf } from '../common/show-if/show-if' import type { IconName } from '../common/fork-awesome/types' import { Trans, useTranslation } from 'react-i18next' import { Logger } from '../../utils/logger' import { cypressId } from '../../utils/cypress-attribute' import { useEffectOnce, useInterval } from 'react-use' import styles from './notifications.module.scss' import { DateTime } from 'luxon' import type { UiNotification } from './types' import { useUiNotifications } from './ui-notification-boundary' const STEPS_PER_SECOND = 10 const log = new Logger('UiNotificationToast') export interface UiNotificationProps { notification: UiNotification } /** * Renders a single notification. * * @param notification The notification to render */ export const UiNotificationToast: React.FC = ({ notification }) => { const { t } = useTranslation() const [remainingSteps, setRemainingSteps] = useState(() => notification.durationInSecond * STEPS_PER_SECOND) const { dismissNotification } = useUiNotifications() const dismissNow = useCallback(() => { log.debug(`Dismiss notification ${notification.uuid} immediately`) setRemainingSteps(0) }, [notification.uuid]) useEffectOnce(() => { log.debug(`Show notification ${notification.uuid}`) }) const formatCreatedAtDate = useCallback(() => { return DateTime.fromSeconds(notification.createdAtTimestamp).toRelative({ style: 'short' }) }, [notification]) const [formattedCreatedAtDate, setFormattedCreatedAtDate] = useState(() => formatCreatedAtDate()) useInterval( () => { setRemainingSteps((lastRemainingSteps) => lastRemainingSteps - 1) setFormattedCreatedAtDate(formatCreatedAtDate()) }, !notification.dismissed && remainingSteps > 0 ? 1000 / STEPS_PER_SECOND : null ) useEffect(() => { if (remainingSteps <= 0 && !notification.dismissed) { log.debug(`Dismiss notification ${notification.uuid}`) dismissNotification(notification.uuid) } }, [remainingSteps, notification.dismissed, notification.uuid, dismissNotification]) const buttonsDom = useMemo( () => notification.buttons?.map((button, buttonIndex) => { const buttonClick = () => { button.onClick() dismissNow() } return ( ) }), [dismissNow, notification.buttons] ) const contentDom = useMemo(() => { return t(notification.contentI18nKey, notification.contentI18nOptions) .split('\n') .map((value, lineNumber) => { return ( {value}
) }) }, [notification.contentI18nKey, notification.contentI18nOptions, t]) return ( {formattedCreatedAtDate} {contentDom}
{buttonsDom}
) }