From 9aaf1a655f9be106e65bbb1e621373a2fbd8866f Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Fri, 15 May 2020 22:26:16 +0200 Subject: [PATCH] Notifications: contextualize email notifications --- src/App.js | 55 +++---- .../EmailNotificationsProvider.js | 142 ++++++++++++++++++ 2 files changed, 171 insertions(+), 26 deletions(-) create mode 100644 src/components/EmailNotifications/EmailNotificationsProvider.js diff --git a/src/App.js b/src/App.js index ed00edb7..3857fd16 100644 --- a/src/App.js +++ b/src/App.js @@ -7,6 +7,7 @@ import GlobalErrorHandler from './GlobalErrorHandler' import MainView from './components/MainView' import OnboardingLoader from './components/OnboardingLoader' import EmailNotificationsLoader from './components/EmailNotificationsLoader' +import EmailNotificationsProvider from './components/EmailNotificationsProvider' import RequestPanel from './components/RequestPanel/RequestPanel' import Routes from './Routes' import { ActivityProvider } from './components/Activity/ActivityProvider' @@ -20,32 +21,34 @@ function App() { -
- - - - - - - - - - - - - - - - - - - -
+ +
+ + + + + + + + + + + + + + + + + + + +
+
diff --git a/src/components/EmailNotifications/EmailNotificationsProvider.js b/src/components/EmailNotifications/EmailNotificationsProvider.js new file mode 100644 index 00000000..6ad4ce07 --- /dev/null +++ b/src/components/EmailNotifications/EmailNotificationsProvider.js @@ -0,0 +1,142 @@ +import React, { + useCallback, + useContext, + useEffect, + useRef, + useState, +} from 'react' +import PropTypes from 'prop-types' +import { useWallet } from '../../providers/Wallet' +import { + getJurorEmail, + getSubscriptionDetails, + subscribeExistingEmail, + subscribeToNotifications, +} from '../../services/servicesRequests' + +const EmailNotificationsContext = React.createContext() + +function EmailNotificationsProvider({ children }) { + const { account } = useWallet() + + const asyncCancelled = useRef(false) + const [email, setEmail] = useState(null) + const [needsSignature, setNeedsSignature] = useState(false) + const [subscriptionDetails, setSubscriptionDetails] = useState({ + error: null, + fetching: false, + }) + + const handleOnSubscribe = useCallback( + async email => { + const response = await subscribeToNotifications(account, email) + + if (response.error && !response.needsSignature) { + return response.error + } + + if (!asyncCancelled.current) { + setEmail(email) + if (needsSignature !== Boolean(response.needsSignature)) { + setNeedsSignature(!needsSignature) + } + } + }, + [account, needsSignature] + ) + + const handleOnSubscribeExistingEmail = useCallback(async () => { + const response = await subscribeExistingEmail(account) + + if (response.error && !response.needsSignature) { + return response.error + } + + if (!asyncCancelled.current) { + if (email !== response.email) { + setEmail(response.email) + if (needsSignature !== Boolean(response.needsSignature)) { + setNeedsSignature(!needsSignature) + } + } + } + }, [account, email, needsSignature]) + + // Cancel any async requests if this provider is unmounted + useEffect(() => { + return () => { + asyncCancelled.current = true + } + }, []) + + // When account connects, fetch their subscription details + useEffect(() => { + if (!account) { + return + } + + const fetchSubscriptionDetails = async () => { + const response = await getSubscriptionDetails(account) + + if (!asyncCancelled.current) { + setSubscriptionDetails({ + ...response, + fetching: false, + }) + } + } + + setSubscriptionDetails(subscriptionDetails => ({ + ...subscriptionDetails, + error: null, + fetching: true, + })) + fetchSubscriptionDetails() + }, [account]) + + // Once we know the account has an associated email, fetch its email + useEffect(() => { + if (!subscriptionDetails.emailExists) { + return + } + + const getEmail = async () => { + const { needsSignature, email } = await getJurorEmail(account) + + if (!asyncCancelled.current) { + if (email) { + setEmail(email) + } + if (needsSignature) { + setNeedsSignature(true) + } + } + } + + getEmail() + }, [account, subscriptionDetails.emailExists]) + + return ( + + {children} + + ) +} + +EmailNotificationsProvider.propTypes = { + children: PropTypes.node, +} + +function useEmailNotifications() { + return useContext(EmailNotificationsContext) +} + +export { EmailNotificationsProvider, useEmailNotifications }