2020-03-27 22:32:33 +00:00
|
|
|
import React, { useEffect, useMemo, useState } from 'react';
|
2019-07-10 05:41:09 +00:00
|
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
|
|
import { faTimes } from '@fortawesome/free-solid-svg-icons/faTimes';
|
|
|
|
import { CSSTransition } from 'react-transition-group';
|
2019-07-17 04:43:11 +00:00
|
|
|
import Spinner from '@/components/elements/Spinner';
|
2019-07-10 05:41:09 +00:00
|
|
|
|
2019-08-03 05:22:01 +00:00
|
|
|
export interface RequiredModalProps {
|
2019-07-10 05:41:09 +00:00
|
|
|
visible: boolean;
|
|
|
|
onDismissed: () => void;
|
2019-12-23 04:51:50 +00:00
|
|
|
appear?: boolean;
|
2019-08-03 05:22:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Props = RequiredModalProps & {
|
2019-07-10 05:41:09 +00:00
|
|
|
dismissable?: boolean;
|
|
|
|
closeOnEscape?: boolean;
|
|
|
|
closeOnBackground?: boolean;
|
2019-07-17 04:43:11 +00:00
|
|
|
showSpinnerOverlay?: boolean;
|
|
|
|
children: React.ReactNode;
|
2019-07-10 05:41:09 +00:00
|
|
|
}
|
|
|
|
|
2020-03-27 22:32:33 +00:00
|
|
|
export default ({ visible, appear, dismissable, showSpinnerOverlay, closeOnBackground = true, closeOnEscape = true, onDismissed, children }: Props) => {
|
|
|
|
const [render, setRender] = useState(visible);
|
|
|
|
|
|
|
|
const isDismissable = useMemo(() => {
|
|
|
|
return (dismissable || true) && !(showSpinnerOverlay || false);
|
|
|
|
}, [dismissable, showSpinnerOverlay]);
|
2019-07-10 05:41:09 +00:00
|
|
|
|
|
|
|
const handleEscapeEvent = (e: KeyboardEvent) => {
|
2020-03-27 22:32:33 +00:00
|
|
|
if (isDismissable && closeOnEscape && e.key === 'Escape') {
|
2019-07-10 05:41:09 +00:00
|
|
|
setRender(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-03-27 22:32:33 +00:00
|
|
|
useEffect(() => {
|
|
|
|
setRender(visible);
|
|
|
|
}, [visible]);
|
2019-07-10 05:41:09 +00:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
window.addEventListener('keydown', handleEscapeEvent);
|
|
|
|
|
|
|
|
return () => window.removeEventListener('keydown', handleEscapeEvent);
|
|
|
|
}, [render]);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<CSSTransition
|
|
|
|
timeout={250}
|
|
|
|
classNames={'fade'}
|
2020-03-27 22:32:33 +00:00
|
|
|
appear={appear}
|
2019-07-10 05:41:09 +00:00
|
|
|
in={render}
|
|
|
|
unmountOnExit={true}
|
2020-03-27 22:32:33 +00:00
|
|
|
onExited={() => onDismissed()}
|
2019-07-10 05:41:09 +00:00
|
|
|
>
|
|
|
|
<div className={'modal-mask'} onClick={e => {
|
2020-03-27 22:32:33 +00:00
|
|
|
if (isDismissable && closeOnBackground) {
|
2019-07-10 05:41:09 +00:00
|
|
|
e.stopPropagation();
|
|
|
|
if (e.target === e.currentTarget) {
|
|
|
|
setRender(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}}>
|
|
|
|
<div className={'modal-container top'}>
|
2020-03-27 22:32:33 +00:00
|
|
|
{isDismissable &&
|
2019-07-10 05:41:09 +00:00
|
|
|
<div className={'modal-close-icon'} onClick={() => setRender(false)}>
|
|
|
|
<FontAwesomeIcon icon={faTimes}/>
|
|
|
|
</div>
|
|
|
|
}
|
2020-03-27 22:32:33 +00:00
|
|
|
{showSpinnerOverlay &&
|
2019-07-17 04:43:11 +00:00
|
|
|
<div
|
|
|
|
className={'absolute w-full h-full rounded flex items-center justify-center'}
|
|
|
|
style={{ background: 'hsla(211, 10%, 53%, 0.25)' }}
|
|
|
|
>
|
2019-08-17 23:03:10 +00:00
|
|
|
<Spinner/>
|
2019-07-17 04:43:11 +00:00
|
|
|
</div>
|
|
|
|
}
|
2019-07-10 05:41:09 +00:00
|
|
|
<div className={'modal-content p-6'}>
|
2020-03-27 22:32:33 +00:00
|
|
|
{children}
|
2019-07-10 05:41:09 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</CSSTransition>
|
|
|
|
);
|
|
|
|
};
|