diff --git a/src/App.js b/src/App.js
index 3bb97dec..fd0d6c32 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 './providers/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 }