diff --git a/src/components/Captcha.jsx b/src/components/Captcha.jsx
index 9cda2851..607f864e 100644
--- a/src/components/Captcha.jsx
+++ b/src/components/Captcha.jsx
@@ -20,6 +20,7 @@ const Captcha = ({ callback, close }) => {
const [captchaUrl, setCaptchaUrl] = useState(getUrl());
const [text, setText] = useState('');
const [errors, setErrors] = useState([]);
+ const [imgLoaded, setImgLoaded] = useState(false);
return (
@@ -34,19 +35,39 @@ const Captcha = ({ callback, close }) => {
({t`Tip: Not case-sensitive; I and l are the same`})
-
![CAPTCHA]({captchaUrl})
setErrors([t`Could not load captcha`])}
- />
+
+
+
![CAPTCHA]({captchaUrl})
{setImgLoaded(true)}}
+ onError={() => setErrors([t`Could not load captcha`])}
+ />
+
{t`Can't read? Reload:`}
setCaptchaUrl(getUrl())}
+ onClick={() => {
+ setImgLoaded(false);
+ setCaptchaUrl(getUrl());
+ }}
>
diff --git a/src/components/ModalRoot.jsx b/src/components/ModalRoot.jsx
index eb653209..a65c5008 100644
--- a/src/components/ModalRoot.jsx
+++ b/src/components/ModalRoot.jsx
@@ -5,9 +5,8 @@
* @flow
*/
-import React from 'react';
-import Modal from 'react-modal';
-import { connect } from 'react-redux';
+import React, { useState, useEffect, useCallback } from 'react';
+import { useSelector, useDispatch } from 'react-redux';
import { MdClose } from 'react-icons/md';
import { t } from 'ttag';
@@ -38,44 +37,60 @@ const MODAL_COMPONENTS = {
/* other modals */
};
-const ModalRoot = ({ modalType, modalOpen, close }) => {
- const choice = MODAL_COMPONENTS[modalType || 'NONE'];
- const { content: SpecificModal, title } = choice;
+const ModalRoot = () => {
+ const [render, setRender] = useState(false);
+
+ const {
+ modalType,
+ modalOpen,
+ } = useSelector((state) => state.modal);
+
+ const {
+ title,
+ content: SpecificModal,
+ } = MODAL_COMPONENTS[modalType || 'NONE'];
+
+ const dispatch = useDispatch();
+ const close = useCallback(() => {
+ dispatch(hideModal());
+ }, [dispatch]);
+
+ const onTransitionEnd = () => {
+ if (!modalOpen) setRender(false);
+ };
+
+ useEffect(() => {
+ window.setTimeout(() => {
+ if (modalOpen) setRender(true);
+ }, 10);
+ }, [modalOpen]);
+
return (
-
- {title}
-
-
-
+ (render || modalOpen) && (
+
+ )
);
};
-function mapStateToProps(state: State) {
- const { modalType, modalOpen } = state.modal;
- return { modalType, modalOpen };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- close() {
- dispatch(hideModal());
- },
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(ModalRoot);
+export default React.memo(ModalRoot);
diff --git a/src/styles/default.css b/src/styles/default.css
index 192cb2ba..25b029af 100644
--- a/src/styles/default.css
+++ b/src/styles/default.css
@@ -336,17 +336,22 @@ tr:nth-child(even) {
border-radius: 4px;
outline: currentcolor none medium;
transform: translate(-50%, -50%);
+ transition: opacity 200ms ease-in-out;
+ opacity: 0;
}
.Modal {
height: 80%;
width: 70%;
max-height: 900px;
+ z-index: 5;
}
.Alert {
+ max-height: 100%;
padding: 15px;
text-align: center;
+ z-index: 6;
}
.modaltext, .modalcotext {
@@ -441,7 +446,7 @@ tr:nth-child(even) {
}
@media (max-width: 604px) {
- .Modal {
+ .Modal, .Alert {
position: fixed;
top: 0px;
left: 0px;
@@ -709,10 +714,6 @@ tr:nth-child(even) {
visibility: hidden;
}
-.ReactModal__Overlay--after-open, .Overlay.show {
+.Modal.show, .Alert.show, .Overlay.show {
opacity: 1;
}
-
-.ReactModal__Overlay--before-close{
- opacity: 0;
-}