Skip to content

Commit

Permalink
Fix: don't show push notifications banner if wallet not conencted; do…
Browse files Browse the repository at this point in the history
…n't track banner dismissal on enable all/customize
  • Loading branch information
katspaugh committed Oct 9, 2023
1 parent 011a0c6 commit e867d75
Showing 1 changed file with 122 additions and 96 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { useEffect, useRef, type ReactElement } from 'react'
import { Button, Chip, Grid, SvgIcon, Typography, IconButton } from '@mui/material'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useCallback, useEffect, useRef } from 'react'
import type { ReactElement } from 'react'

import { CustomTooltip } from '@/components/common/CustomTooltip'
import { AppRoutes } from '@/config/routes'
import { useAppSelector } from '@/store'
import { selectAddedSafes, selectAllAddedSafes, selectTotalAdded } from '@/store/addedSafesSlice'
import { selectAddedSafes, selectAllAddedSafes } from '@/store/addedSafesSlice'
import PushNotificationIcon from '@/public/images/notifications/push-notification.svg'
import useLocalStorage from '@/services/local-storage/useLocalStorage'
import { useNotificationRegistrations } from '../hooks/useNotificationRegistrations'
import { PUSH_NOTIFICATION_EVENTS } from '@/services/analytics/events/push-notifications'
import { trackEvent } from '@/services/analytics'
import useSafeInfo from '@/hooks/useSafeInfo'
import useChainId from '@/hooks/useChainId'
import CheckWallet from '@/components/common/CheckWallet'
import CloseIcon from '@/public/images/common/close.svg'
import { useNotificationPreferences } from '../hooks/useNotificationPreferences'
Expand All @@ -22,6 +22,7 @@ import useOnboard from '@/hooks/wallets/useOnboard'
import { assertWalletChain } from '@/services/tx/tx-sender/sdk'
import { useCurrentChain, useHasFeature } from '@/hooks/useChains'
import { FEATURES } from '@/utils/chains'
import useWallet from '@/hooks/wallets/useWallet'
import type { AddedSafesOnChain } from '@/store/addedSafesSlice'
import type { PushNotificationPreferences } from '@/services/push-notifications/preferences'
import type { NotifiableSafes } from '../logic'
Expand Down Expand Up @@ -86,69 +87,146 @@ export const _getSafesToRegister = (
return { [chainId]: newlyAddedSafes }
}

const TrackBanner = (): null => {
const hasTracked = useRef(false)
type BannerProps = {
children: ReactElement
onDismiss?: () => void
onCustomize?: () => void
onEnableAll?: () => void
}

useEffect(() => {
if (hasTracked.current) {
return
}
const Banner = ({ children, onDismiss, onEnableAll, onCustomize }: BannerProps) => {
const { chainName = '' } = useCurrentChain() || {}
const { query } = useRouter()

trackEvent(PUSH_NOTIFICATION_EVENTS.SHOW_BANNER)
hasTracked.current = true
}, [])
return (
<CustomTooltip
className={css.banner}
title={
<Grid container className={css.container}>
<Grid item xs={3}>
<Chip label="New" className={css.chip} />
<SvgIcon component={PushNotificationIcon} inheritViewBox fontSize="inherit" className={css.icon} />
</Grid>

return null
<Grid item xs={9}>
<Typography variant="subtitle2" fontWeight={700}>
Enable push notifications
</Typography>

<IconButton onClick={onDismiss} className={css.close}>
<SvgIcon component={CloseIcon} inheritViewBox color="border" fontSize="small" />
</IconButton>

<Typography mt={0.5} mb={1.5} variant="body2">
Get notified about pending signatures, incoming and outgoing transactions for all Safe Accounts on{' '}
{chainName} when {`Safe{Wallet}`} is in the background or closed.
</Typography>

{/* Cannot wrap singular button as it causes style inconsistencies */}
<CheckWallet>
{(isOk) => (
<div className={css.buttons}>
<Button
variant="contained"
size="small"
className={css.button}
onClick={onEnableAll}
disabled={!isOk}
>
Enable all
</Button>

<Link passHref href={{ pathname: AppRoutes.settings.notifications, query }} onClick={onCustomize}>
<Button variant="outlined" size="small" className={css.button}>
Customize
</Button>
</Link>
</div>
)}
</CheckWallet>
</Grid>
</Grid>
}
open
>
<span>{children}</span>
</CustomTooltip>
)
}

export const PushNotificationsBanner = ({ children }: { children: ReactElement }): ReactElement => {
const isNotificationFeatureEnabled = useHasFeature(FEATURES.PUSH_NOTIFICATIONS)
const chain = useCurrentChain()
const totalAddedSafes = useAppSelector(selectTotalAdded)
const { safe, safeAddress } = useSafeInfo()
const addedSafesOnChain = useAppSelector((state) => selectAddedSafes(state, safe.chainId))
const { query } = useRouter()
const useEnableAll = (addedSafes: AddedSafesOnChain | undefined) => {
const chainId = useChainId()
const onboard = useOnboard()
const { getAllPreferences } = useNotificationPreferences()
const { registerNotifications } = useNotificationRegistrations()

return async () => {
if (!onboard || !addedSafes) return

const allPreferences = getAllPreferences()
const safesToRegister = _getSafesToRegister(chainId, addedSafes, allPreferences)

await assertWalletChain(onboard, chainId)
await registerNotifications(safesToRegister)
}
}

const { getPreferences, getAllPreferences } = useNotificationPreferences()
const { dismissPushNotificationBanner, isPushNotificationBannerDismissed } = useDismissPushNotificationsBanner()
const useShowBanner = (addedSafes: AddedSafesOnChain | undefined): boolean => {
const isNotificationFeatureEnabled = useHasFeature(FEATURES.PUSH_NOTIFICATIONS)
const { safe, safeAddress } = useSafeInfo()
const wallet = useWallet()
const { getPreferences } = useNotificationPreferences()
const { isPushNotificationBannerDismissed } = useDismissPushNotificationsBanner()

const isSafeAdded = !!addedSafesOnChain?.[safeAddress]
const isSafeAdded = !!addedSafes?.[safeAddress]
const isSafeRegistered = getPreferences(safe.chainId, safeAddress)

const shouldShowBanner =
isNotificationFeatureEnabled && !isPushNotificationBannerDismissed && isSafeAdded && !isSafeRegistered
isNotificationFeatureEnabled && !isPushNotificationBannerDismissed && isSafeAdded && !isSafeRegistered && !!wallet

const { registerNotifications } = useNotificationRegistrations()
return shouldShowBanner
}

const dismissBanner = useCallback(() => {
trackEvent(PUSH_NOTIFICATION_EVENTS.DISMISS_BANNER)
dismissPushNotificationBanner(safe.chainId)
}, [dismissPushNotificationBanner, safe.chainId])
export const PushNotificationsBanner = ({ children }: { children: ReactElement }): ReactElement => {
const chainId = useChainId()
const addedSafesOnChain = useAppSelector((state) => selectAddedSafes(state, chainId))
const { dismissPushNotificationBanner } = useDismissPushNotificationsBanner()
const hasTracked = useRef(false)
const enableAll = useEnableAll(addedSafesOnChain)
const shouldShowBanner = useShowBanner(addedSafesOnChain)

const onEnableAll = async () => {
if (!onboard || !addedSafesOnChain) {
return
}
// Track the banner impression
useEffect(() => {
if (!shouldShowBanner || hasTracked.current) return
trackEvent(PUSH_NOTIFICATION_EVENTS.SHOW_BANNER)
hasTracked.current = true
}, [shouldShowBanner])

trackEvent(PUSH_NOTIFICATION_EVENTS.ENABLE_ALL)
// Dismiss the banner
const dismissBanner = () => {
dismissPushNotificationBanner(chainId)
}

const allPreferences = getAllPreferences()
const safesToRegister = _getSafesToRegister(safe.chainId, addedSafesOnChain, allPreferences)
// On dismiss, track the event and dismiss the banner
const onDismiss = () => {
trackEvent(PUSH_NOTIFICATION_EVENTS.DISMISS_BANNER)
dismissBanner
}

// On enable all, track the event and enable all notifications
const onEnableAll = async () => {
trackEvent(PUSH_NOTIFICATION_EVENTS.ENABLE_ALL)
try {
await assertWalletChain(onboard, safe.chainId)
await enableAll()
} catch {
return
}

await registerNotifications(safesToRegister)

dismissBanner()
}

// On customize, track the event and navigate to the settings page
const onCustomize = () => {
trackEvent(PUSH_NOTIFICATION_EVENTS.CUSTOMIZE_SETTINGS)

dismissBanner()
}

Expand All @@ -157,60 +235,8 @@ export const PushNotificationsBanner = ({ children }: { children: ReactElement }
}

return (
<>
<TrackBanner />
<CustomTooltip
className={css.banner}
title={
<Grid container className={css.container}>
<Grid item xs={3}>
<Chip label="New" className={css.chip} />
<SvgIcon component={PushNotificationIcon} inheritViewBox fontSize="inherit" className={css.icon} />
</Grid>
<Grid item xs={9}>
<Typography variant="subtitle2" fontWeight={700}>
Enable push notifications
</Typography>
<IconButton onClick={dismissBanner} className={css.close}>
<SvgIcon component={CloseIcon} inheritViewBox color="border" fontSize="small" />
</IconButton>
<Typography mt={0.5} mb={1.5} variant="body2">
Get notified about pending signatures, incoming and outgoing transactions for all Safe Accounts on{' '}
{chain?.chainName} when Safe
{`{Wallet}`} is in the background or closed.
</Typography>
{/* Cannot wrap singular button as it causes style inconsistencies */}
<CheckWallet>
{(isOk) => (
<div className={css.buttons}>
{totalAddedSafes > 0 && (
<Button
variant="contained"
size="small"
className={css.button}
onClick={onEnableAll}
disabled={!isOk || !onboard}
>
Enable all
</Button>
)}
{safe && (
<Link passHref href={{ pathname: AppRoutes.settings.notifications, query }} onClick={onCustomize}>
<Button variant="outlined" size="small" className={css.button}>
Customize
</Button>
</Link>
)}
</div>
)}
</CheckWallet>
</Grid>
</Grid>
}
open
>
<span>{children}</span>
</CustomTooltip>
</>
<Banner onDismiss={onDismiss} onEnableAll={onEnableAll} onCustomize={onCustomize}>
{children}
</Banner>
)
}

0 comments on commit e867d75

Please sign in to comment.