-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Notifications: contextualize email notifications #327
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thinking about this, we may want to throw the error instead (and perhaps all the requests should be throwing those errors, similar to https://github.com/aragon/aragon/blob/master/src/components/GlobalPreferences/Notifications/notification-service-api.js#L60). |
||
} | ||
|
||
if (!asyncCancelled.current) { | ||
setEmail(email) | ||
if (needsSignature !== Boolean(response.needsSignature)) { | ||
setNeedsSignature(!needsSignature) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trying to figure out how are you thinking to handle the action after the signature? i mean after the signature is successful we need to call again the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, exactly, that was something I wanted to leave to the state machine manager, given that we could have different machines based on the area (preferences or modal).
Similar to above, I was hoping the manager would handle this. These functions just attempt to "optimistically" call the API, and if it fails, it'll let us know either with the error or a state change. |
||
} | ||
} | ||
}, | ||
[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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I used the same |
||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Giving a second thought to this, i think that here we are going to be fetching the juror email every time an account is connected, and when the cookie has expired we are going to ask the juror to sign a message just for connecting his account and not sure if that is what we want. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. Yes, it sounds like we should do this in a callback instead. |
||
|
||
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 } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: we may want to rename this file to be
EmailNotificationsApiProvider
for clarity.