fix: flash modals stack up and are not visible until scrolled to top (#35808)
Co-authored-by: Mrugesh Mohapatra <1884376+raisedadead@users.noreply.github.com>
This commit is contained in:
committed by
mrugesh
parent
8f633299ef
commit
b1956a7ba1
161
client/package-lock.json
generated
161
client/package-lock.json
generated
@ -1064,6 +1064,48 @@
|
||||
"loose-envify": "^1.3.1",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"react-transition-group": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
|
||||
"integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
|
||||
"requires": {
|
||||
"dom-helpers": "^3.4.0",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-lifecycles-compat": "^3.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz",
|
||||
"integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.2"
|
||||
}
|
||||
},
|
||||
"dom-helpers": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
|
||||
"integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2"
|
||||
}
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.2",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz",
|
||||
"integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -16213,6 +16255,65 @@
|
||||
"prop-types-extra": "^1.0.1",
|
||||
"react-transition-group": "^2.2.0",
|
||||
"warning": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz",
|
||||
"integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.2"
|
||||
}
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.8.6",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
|
||||
"integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA=="
|
||||
},
|
||||
"react-transition-group": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
|
||||
"integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
|
||||
"requires": {
|
||||
"dom-helpers": "^3.4.0",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-lifecycles-compat": "^3.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"dom-helpers": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
|
||||
"integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2"
|
||||
}
|
||||
},
|
||||
"prop-types": {
|
||||
"version": "15.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.8.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.2",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz",
|
||||
"integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-prop-types": {
|
||||
@ -16374,24 +16475,58 @@
|
||||
}
|
||||
},
|
||||
"react-transition-group": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.4.0.tgz",
|
||||
"integrity": "sha512-Xv5d55NkJUxUzLCImGSanK8Cl/30sgpOEMGc5m86t8+kZwrPxPCPcFqyx83kkr+5Lz5gs6djuvE5By+gce+VjA==",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.1.0.tgz",
|
||||
"integrity": "sha512-/OITbogb3emGN49WaP7468QGSde7er5w6eIHldIDCSQBq/9QTSCzs8OgpgmOnaUXCXzBUcK1zoZ6DqRlM8CJtA==",
|
||||
"requires": {
|
||||
"dom-helpers": "^3.3.1",
|
||||
"loose-envify": "^1.3.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-lifecycles-compat": "^3.0.4"
|
||||
"dom-helpers": "^3.4.0",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"prop-types": {
|
||||
"version": "15.6.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz",
|
||||
"integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==",
|
||||
"@babel/runtime": {
|
||||
"version": "7.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz",
|
||||
"integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.3.1",
|
||||
"object-assign": "^4.1.1"
|
||||
"regenerator-runtime": "^0.13.2"
|
||||
}
|
||||
},
|
||||
"dom-helpers": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
|
||||
"integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2"
|
||||
}
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"prop-types": {
|
||||
"version": "15.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.8.1"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.8.6",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
|
||||
"integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA=="
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.2",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz",
|
||||
"integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -44,15 +44,16 @@
|
||||
"react": "^16.8.6",
|
||||
"react-calendar-heatmap": "^1.8.0",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-instantsearch-dom": "^5.5.0",
|
||||
"react-ga": "^2.5.7",
|
||||
"react-helmet": "^5.2.0",
|
||||
"react-instantsearch-dom": "^5.5.0",
|
||||
"react-monaco-editor": "^0.25.1",
|
||||
"react-redux": "^5.0.7",
|
||||
"react-reflex": "^3.0.13",
|
||||
"react-responsive": "^6.1.1",
|
||||
"react-spinkit": "^3.0.0",
|
||||
"react-stripe-elements": "^2.0.3",
|
||||
"react-transition-group": "^4.1.0",
|
||||
"react-youtube": "^7.9.0",
|
||||
"redux": "^4.0.1",
|
||||
"redux-actions": "^2.6.5",
|
||||
|
@ -1,7 +1,24 @@
|
||||
.flash-message {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
flex-direction: row-reverse;
|
||||
margin-bottom: 0px;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.flash-message-enter {
|
||||
opacity: 0;
|
||||
}
|
||||
.flash-message-enter-active {
|
||||
opacity: 1;
|
||||
transition: opacity 500ms;
|
||||
}
|
||||
.flash-message-exit {
|
||||
opacity: 1;
|
||||
}
|
||||
.flash-message-exit-active {
|
||||
opacity: 0;
|
||||
transition: opacity 100ms;
|
||||
}
|
||||
|
@ -1,35 +1,30 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Alert } from '@freecodecamp/react-bootstrap';
|
||||
import { TransitionGroup, CSSTransition } from 'react-transition-group';
|
||||
|
||||
import './flash.css';
|
||||
|
||||
function createDismissHandler(fn, id) {
|
||||
return () => fn(id);
|
||||
}
|
||||
|
||||
function Flash({ messages, onClose }) {
|
||||
return messages.map(({ type, message, id }) => (
|
||||
<Alert
|
||||
bsStyle={type}
|
||||
className='flash-message'
|
||||
key={id}
|
||||
onDismiss={createDismissHandler(onClose, id)}
|
||||
>
|
||||
<div dangerouslySetInnerHTML={{ __html: message }} />
|
||||
</Alert>
|
||||
));
|
||||
function Flash({ flashMessage, onClose }) {
|
||||
const { type, message, id } = flashMessage;
|
||||
return (
|
||||
<TransitionGroup>
|
||||
<CSSTransition classNames='flash-message' key={id} timeout={500}>
|
||||
<Alert bsStyle={type} className='flash-message' onDismiss={onClose}>
|
||||
<div dangerouslySetInnerHTML={{ __html: message }} />
|
||||
</Alert>
|
||||
</CSSTransition>
|
||||
</TransitionGroup>
|
||||
);
|
||||
}
|
||||
|
||||
Flash.displayName = 'FlashMessages';
|
||||
Flash.propTypes = {
|
||||
messages: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
message: PropTypes.string
|
||||
})
|
||||
),
|
||||
flashMessage: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
message: PropTypes.string
|
||||
}),
|
||||
onClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
|
@ -6,7 +6,7 @@ import { createTypes } from '../../../utils/createTypes';
|
||||
export const ns = 'flash';
|
||||
|
||||
const initialState = {
|
||||
messages: []
|
||||
message: {}
|
||||
};
|
||||
|
||||
const types = createTypes(['createFlashMessage', 'removeFlashMessage'], ns);
|
||||
@ -19,17 +19,17 @@ export const createFlashMessage = createAction(
|
||||
);
|
||||
export const removeFlashMessage = createAction(types.removeFlashMessage);
|
||||
|
||||
export const flashMessagesSelector = state => state[ns].messages;
|
||||
export const flashMessageSelector = state => state[ns].message;
|
||||
|
||||
export const reducer = handleActions(
|
||||
{
|
||||
[types.createFlashMessage]: (state, { payload }) => ({
|
||||
...state,
|
||||
messages: [...state.messages, payload]
|
||||
message: payload
|
||||
}),
|
||||
[types.removeFlashMessage]: (state, { payload }) => ({
|
||||
[types.removeFlashMessage]: state => ({
|
||||
...state,
|
||||
messages: state.messages.filter(msg => msg.id !== payload)
|
||||
message: {}
|
||||
})
|
||||
},
|
||||
initialState
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
onlineStatusChange,
|
||||
isOnlineSelector
|
||||
} from '../../redux';
|
||||
import { flashMessagesSelector, removeFlashMessage } from '../Flash/redux';
|
||||
import { flashMessageSelector, removeFlashMessage } from '../Flash/redux';
|
||||
|
||||
import { isBrowser } from '../../../utils';
|
||||
|
||||
@ -58,14 +58,12 @@ const metaKeywords = [
|
||||
const propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
fetchUser: PropTypes.func.isRequired,
|
||||
flashMessages: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
message: PropTypes.string
|
||||
})
|
||||
),
|
||||
hasMessages: PropTypes.bool,
|
||||
flashMessage: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
message: PropTypes.string
|
||||
}),
|
||||
hasMessage: PropTypes.bool,
|
||||
isOnline: PropTypes.bool.isRequired,
|
||||
isSignedIn: PropTypes.bool,
|
||||
landingPage: PropTypes.bool,
|
||||
@ -78,12 +76,12 @@ const propTypes = {
|
||||
|
||||
const mapStateToProps = createSelector(
|
||||
isSignedInSelector,
|
||||
flashMessagesSelector,
|
||||
flashMessageSelector,
|
||||
isOnlineSelector,
|
||||
(isSignedIn, flashMessages, isOnline) => ({
|
||||
(isSignedIn, flashMessage, isOnline) => ({
|
||||
isSignedIn,
|
||||
flashMessages,
|
||||
hasMessages: !!flashMessages.length,
|
||||
flashMessage,
|
||||
hasMessage: !!flashMessage.message,
|
||||
isOnline
|
||||
})
|
||||
);
|
||||
@ -128,8 +126,8 @@ class DefaultLayout extends Component {
|
||||
render() {
|
||||
const {
|
||||
children,
|
||||
hasMessages,
|
||||
flashMessages = [],
|
||||
hasMessage,
|
||||
flashMessage,
|
||||
isOnline,
|
||||
isSignedIn,
|
||||
landingPage,
|
||||
@ -162,8 +160,8 @@ class DefaultLayout extends Component {
|
||||
className={`default-layout ${landingPage ? 'landing-page' : ''}`}
|
||||
>
|
||||
<OfflineWarning isOnline={isOnline} isSignedIn={isSignedIn} />
|
||||
{hasMessages ? (
|
||||
<Flash messages={flashMessages} onClose={removeFlashMessage} />
|
||||
{hasMessage && flashMessage ? (
|
||||
<Flash flashMessage={flashMessage} onClose={removeFlashMessage} />
|
||||
) : null}
|
||||
{children}
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user