From 2ab790e083e3ceb43fff74c2b9e45afebab94164 Mon Sep 17 00:00:00 2001 From: Dina Date: Tue, 29 Jun 2021 14:27:24 -0400 Subject: [PATCH 1/2] added action/reducer to trigger and unmount toast --- src/frontend/src/layouts/App.jsx | 6 +++--- src/frontend/src/layouts/Toasts.jsx | 33 +++++++++++++++++++++-------- src/frontend/src/state.js | 6 ++++++ 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/frontend/src/layouts/App.jsx b/src/frontend/src/layouts/App.jsx index ebfe359..8e4b004 100644 --- a/src/frontend/src/layouts/App.jsx +++ b/src/frontend/src/layouts/App.jsx @@ -34,17 +34,17 @@ const App = () => { toasts={[ { type: ToastTypes.info, - title: `Test Toast`, + title: `Info Test Toast`, body: `This is a test toast. It should say some things. Then it should disappear.`, }, { type: ToastTypes.danger, - title: `Test Toast`, + title: `Danger Test Toast`, body: `This is a test toast. It should say some things. Then it should disappear.`, }, { type: ToastTypes.success, - title: `Test Toast`, + title: `Success Test Toast`, body: `This is a test toast. It should say some things. Then it should disappear.`, }, ]} diff --git a/src/frontend/src/layouts/Toasts.jsx b/src/frontend/src/layouts/Toasts.jsx index 2de128b..9ce52c4 100644 --- a/src/frontend/src/layouts/Toasts.jsx +++ b/src/frontend/src/layouts/Toasts.jsx @@ -1,7 +1,9 @@ -import React, { useState, useEffect } from "react"; +import { useState, useEffect, useContext } from "react"; import { CSSTransition } from 'react-transition-group'; + import Card, { CardBody, CardHeader, CardHeaderAction } from "../elements/Card"; import styled, { keyframes, css } from "styled-components"; +import { StateContext } from "../state"; // countdown animation does not use transition-group const countdown = keyframes` @@ -19,8 +21,7 @@ const countdownStyle = css` animation: ${countdown} 6s linear 250ms; animation-fill-mode: forwards; `; - -import Card, { CardBody, CardHeader, CardHeaderAction } from "../elements/Card"; +//import Card, { CardBody, CardHeader, CardHeaderAction } from "../elements/Card"; const ToastCard = styled(Card)` height: 6em; @@ -121,11 +122,11 @@ const ToastContainer = styled.div` `; const Toasts = ({ toasts = [] }) => { - + const { state } = useContext(StateContext); return ( - {toasts.map(({ title, body, type }) => ( - + {toasts.filter(toast => state.toast.includes(toast.title)).map(({ title, body, type }) => ( + ))} ); @@ -134,16 +135,29 @@ const Toasts = ({ toasts = [] }) => { const Toast = ({ title, body, type }) => { const [show, setShow] = useState(false); + const { dispatch } = useContext(StateContext); let timer; useEffect( () => { - setShow(true); // activate enter animation on mount - return clearTimeout(timer); // clear timer on unmount + setShow(true); // activate enter animation on mount + return () => { // clean up timer and state on unmount + clearTimeout(timer); + unmount(); + } }, [] ); + // sets timer to 6 seconds before automatic close const startCountdown = () => { - timer = setTimeout(() =>setShow(false), 6000); + timer = setTimeout(() => setShow(false), 6000); + }; + + // clears state after component unmounts + const unmount = () => { + dispatch({ + type: `unmountToast`, + payload: title + }) }; return ( @@ -152,6 +166,7 @@ const Toast = ({ title, body, type }) => { timeout={400} classNames='toast' onEntered={() => startCountdown()} + onExited={() => unmount()} unmountOnExit > diff --git a/src/frontend/src/state.js b/src/frontend/src/state.js index 7815e06..f8f9c4c 100644 --- a/src/frontend/src/state.js +++ b/src/frontend/src/state.js @@ -2,7 +2,9 @@ import React, { useReducer } from "react"; const initialState = { user: null, + toast: [], }; + const StateContext = React.createContext(null); const reducer = (state = initialState, action) => { @@ -11,6 +13,10 @@ const reducer = (state = initialState, action) => { return { ...state, user: action.payload }; case `unsetUser`: return { ...state, user: null }; + case `triggerToast`: + return { ...state, toast: [...state.toast, action.payload] }; + case `unmountToast`: + return { ...state, toast: state.toast.filter(toast => toast !== action.payload)}; default: console.warn(`Unknown reducer action received`, action); return state; From 4ad4c250ab6b919475c2e60f7228da5413501cf5 Mon Sep 17 00:00:00 2001 From: Dina Date: Tue, 29 Jun 2021 17:08:22 -0400 Subject: [PATCH 2/2] code cleanup --- src/frontend/src/layouts/Toasts.jsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/frontend/src/layouts/Toasts.jsx b/src/frontend/src/layouts/Toasts.jsx index 9ce52c4..fa6f5bb 100644 --- a/src/frontend/src/layouts/Toasts.jsx +++ b/src/frontend/src/layouts/Toasts.jsx @@ -21,7 +21,6 @@ const countdownStyle = css` animation: ${countdown} 6s linear 250ms; animation-fill-mode: forwards; `; -//import Card, { CardBody, CardHeader, CardHeaderAction } from "../elements/Card"; const ToastCard = styled(Card)` height: 6em; @@ -125,16 +124,17 @@ const Toasts = ({ toasts = [] }) => { const { state } = useContext(StateContext); return ( - {toasts.filter(toast => state.toast.includes(toast.title)).map(({ title, body, type }) => ( - + {toasts + .filter(toast => state.toast.includes(toast.title)) + .map(({ title, body, type }) => ( + ))} ); - }; const Toast = ({ title, body, type }) => { - const [show, setShow] = useState(false); + const [ show, setShow ] = useState(false); const { dispatch } = useContext(StateContext); let timer; @@ -143,7 +143,7 @@ const Toast = ({ title, body, type }) => { return () => { // clean up timer and state on unmount clearTimeout(timer); unmount(); - } + }; }, [] ); @@ -157,7 +157,7 @@ const Toast = ({ title, body, type }) => { dispatch({ type: `unmountToast`, payload: title - }) + }); }; return ( @@ -168,7 +168,7 @@ const Toast = ({ title, body, type }) => { onEntered={() => startCountdown()} onExited={() => unmount()} unmountOnExit - > + > {title} setShow(false)}>Close