Skip to content

Commit

Permalink
Notifications: contextualize email notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
sohkai committed May 15, 2020
1 parent 20c02b2 commit 9aaf1a6
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 26 deletions.
55 changes: 29 additions & 26 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -20,32 +21,34 @@ function App() {
<WalletProvider>
<BrowserRouter>
<ActivityProvider>
<Main
assetsUrl="/aragon-ui/"
layout={false}
scrollView={false}
theme={theme}
>
<GlobalErrorHandler>
<ToastHub threshold={1} timeout={1500}>
<CourtConfigProvider>
<CourtClockProvider>
<RequestQueueProvider>
<MainView>
<OnboardingLoader>
<EmailNotificationsLoader />
<AppLoader>
<Routes />
</AppLoader>
</OnboardingLoader>
<RequestPanel />
</MainView>
</RequestQueueProvider>
</CourtClockProvider>
</CourtConfigProvider>
</ToastHub>
</GlobalErrorHandler>
</Main>
<EmailNotificationsProvider>
<Main
assetsUrl="/aragon-ui/"
layout={false}
scrollView={false}
theme={theme}
>
<GlobalErrorHandler>
<ToastHub threshold={1} timeout={1500}>
<CourtConfigProvider>
<CourtClockProvider>
<RequestQueueProvider>
<MainView>
<OnboardingLoader>
<EmailNotificationsLoader />
<AppLoader>
<Routes />
</AppLoader>
</OnboardingLoader>
<RequestPanel />
</MainView>
</RequestQueueProvider>
</CourtClockProvider>
</CourtConfigProvider>
</ToastHub>
</GlobalErrorHandler>
</Main>
</EmailNotificationsProvider>
</ActivityProvider>
</BrowserRouter>
</WalletProvider>
Expand Down
142 changes: 142 additions & 0 deletions src/components/EmailNotifications/EmailNotificationsProvider.js
Original file line number Diff line number Diff line change
@@ -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 (
<EmailNotificationsContext.Provider
value={{
email,
handleOnSubscribe,
handleOnSubscribeExistingEmail,
needsSignature,
subscriptionDetails,
}}
>
{children}
</EmailNotificationsContext.Provider>
)
}

EmailNotificationsProvider.propTypes = {
children: PropTypes.node,
}

function useEmailNotifications() {
return useContext(EmailNotificationsContext)
}

export { EmailNotificationsProvider, useEmailNotifications }

0 comments on commit 9aaf1a6

Please sign in to comment.