import React, { useEffect, useState } from "react"; import './../../css/components/magicPopup.css'; import { Button } from '@SharePoint/rencredit_uikit'; /** * Компонент всплывающего окна */ /** * Варианты типов для всплывающих окон: info - стандартный вид, error - произошла ошибка, attention - обратить внимание, success - успешное событие */ type PopupType = 'info' | 'success' | 'error' | 'attention'; //Интерфейс для передаваемых пропсов объекта всплывающего окна interface MagicPopupProps { key: number, id: number, //Уникальный идентификатор, по котором всплывающее окно будет в том числе размонтироваться message: string, //Текст всплывающего окна renderIndex: number, //Индекс рендеринга компонента. Так как может отрисовываться сразу несколько popup, чтобы корректно их отрисовывать с анимацией с задержкой по времени, нужно передавать индекс компонента в наборе. Передавать "вручную" не нужно, он сам рассчитывается в компоненте MagicPopupContainer type: PopupType, //Тип всплывающего окна, определяющий его внешний вид timeOut?: boolean, //Если передается true, для элемента будет запущен стандартный таймер исчезновения. ВАЖНО! для всплывающих окон типа error таймер не будет активироваться, даже если передается. Пользователь должен гарантированно ознакомиться с сообщением и сам его закрыть onClose?: (id: number) => void //Колбэк для полного размонтирования компонента со страницы } /** * Компонент всплывающих окон * @param props * @returns */ export default function MagicPopup (props: MagicPopupProps) { //Объект с классами для иконок font-awesome в зависимости от переданного типа всплывающего окна. При изменении, необходимо поменять названия классов в magicPopup.css! const iconNameObj = { info: 'fa-circle-info', success: 'fa-circle-check', error: 'fa-circle-xmark', attention: 'fa-circle-exclamation' } //С помощью деструктуризации указываем значение типа окна по умолчанию const {message, timeOut = true, onClose} = props; //Задержка исчезновения popup const popupDelay = 300; //Итоговая длительность таймера перед закрытием конкретного popup, учитывая его положение в наборе передаваемых попапов const hideTimeOut: number = 3000 + popupDelay; //Стейт для размонтирования попапа const [popupVisible, setPopupVisible] = useState(true) //Стейт для плавного сокрытия popup. Класс плавного сокрытия присваивается за пол секунды до полного исчезновения через popupVisible, чтобы сначала плавно сокрыть блок из интерфейса, а затем полностью удалить его из DOM const [popupHideClass, setPopupHideClass] = useState('popup-visible') //Стейт плавного появления popup. Каждый следующий popup в передаваемом наборе должен появляться с небольшой задержкой const [popupShowClass, setPopupFadeinClass] = useState(''); //Стейт запуска анимированного таймера исчезновения popup const [popupTimer, setPopupTimer] = useState(''); //Функция сокрытия popup. Сначала присваиваем класс, который анимированно скрывает popup, а через небольшую задержку размонтируем компонент function hidePopupBlock (): void { setPopupHideClass('hidePopup'); setTimeout ( () => { setPopupVisible(false); }, 300) //Вызываем метод удаления экземпляра компонента из набора. Так как попапы отрисовываются на основе компонента PopupContainer с набором компонентов MagicPopup, то после их размонтирования, их необходимо и удалить из набора в PopupContainer. Без их удаления, при вызове новых попапов, весь набор с уже просмотренными попапами будет снова отрисовываться. onClose && onClose(props.id) }; //При рендеринге сразу же запускается таймер сокрытия popup, если аргумент timeOut = true и тип окна != error useEffect( () => { if (timeOut && props.type !== 'error') { setTimeout( () => { //Задержка для отображения таймера нужна, так как при вызове рендеринга нескольких окон, каждое последующее появляется с задержкой. Без задержки ниже, таймер будет запускаться для всех popup одновременно и когда появится последний popup, его таймер уже может закончиться setPopupTimer('timerProgress') }, popupDelay) //Через небольшую задержку после сокрытия компонента срабатывает таймер на размонтирование компонента и удаления его из набора setTimeout( () => { hidePopupBlock() }, hideTimeOut) } //Появление popup при рендеринге setTimeout ( () => { setPopupFadeinClass('show') }, popupDelay) }, []) return ( popupVisible ? //
Раз
{message}
: null ); };