Skip to content

Commit

Permalink
Merge branch 'main' of github.com:safe-global/safe-wallet-web into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
katspaugh committed Sep 28, 2023
2 parents 3e026a4 + a44252b commit e807c40
Show file tree
Hide file tree
Showing 10 changed files with 952 additions and 249 deletions.
2 changes: 1 addition & 1 deletion src/components/safe-messages/MsgSummary/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const MsgSummary = ({ msg }: { msg: SafeMessage }): ReactElement => {
const isConfirmed = msg.status === SafeMessageStatus.CONFIRMED

return (
<Box className={classNames(txSummaryCss.gridContainer, txSummaryCss.columnTemplateWithoutNonce)}>
<Box className={classNames(txSummaryCss.gridContainer, txSummaryCss.columnTemplate)}>
<Box gridArea="type" className={txSummaryCss.columnWrap}>
<MsgType msg={msg} />
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ListItemButton,
ListItemIcon,
ListItemText,
CircularProgress,
} from '@mui/material'
import { Fragment, useEffect, useMemo, useState } from 'react'
import type { ReactElement } from 'react'
Expand Down Expand Up @@ -44,7 +45,9 @@ export const transformAddedSafes = (addedSafes: AddedSafesState): NotifiableSafe
}

// Convert data structure of currently notified Safes
const transformCurrentSubscribedSafes = (allPreferences?: PushNotificationPreferences): NotifiableSafes | undefined => {
export const _transformCurrentSubscribedSafes = (
allPreferences?: PushNotificationPreferences,
): NotifiableSafes | undefined => {
if (!allPreferences) {
return
}
Expand All @@ -60,7 +63,10 @@ const transformCurrentSubscribedSafes = (allPreferences?: PushNotificationPrefer
}

// Merges added Safes and currently notified Safes into a single data structure without duplicates
const mergeNotifiableSafes = (addedSafes: AddedSafesState, currentSubscriptions?: NotifiableSafes): NotifiableSafes => {
export const _mergeNotifiableSafes = (
addedSafes: AddedSafesState,
currentSubscriptions?: NotifiableSafes,
): NotifiableSafes => {
const notifiableSafes = transformAddedSafes(addedSafes)

if (!currentSubscriptions) {
Expand All @@ -78,13 +84,19 @@ const mergeNotifiableSafes = (addedSafes: AddedSafesState, currentSubscriptions?
return notifiableSafes
}

const getTotalNotifiableSafes = (notifiableSafes: NotifiableSafes): number => {
export const _getTotalNotifiableSafes = (notifiableSafes: NotifiableSafes): number => {
return Object.values(notifiableSafes).reduce((acc, safeAddresses) => {
return (acc += safeAddresses.length)
}, 0)
}

const areAllSafesSelected = (notifiableSafes: NotifiableSafes, selectedSafes: NotifiableSafes): boolean => {
export const _areAllSafesSelected = (notifiableSafes: NotifiableSafes, selectedSafes: NotifiableSafes): boolean => {
const entries = Object.entries(notifiableSafes)

if (entries.length === 0) {
return false
}

return Object.entries(notifiableSafes).every(([chainId, safeAddresses]) => {
const hasChain = Object.keys(selectedSafes).includes(chainId)
const hasEverySafe = safeAddresses?.every((safeAddress) => selectedSafes[chainId]?.includes(safeAddress))
Expand All @@ -93,13 +105,24 @@ const areAllSafesSelected = (notifiableSafes: NotifiableSafes, selectedSafes: No
}

// Total number of signatures required to register selected Safes
const getTotalSignaturesRequired = (selectedSafes: NotifiableSafes, currentNotifiedSafes?: NotifiableSafes): number => {
return Object.keys(selectedSafes).filter((chainId) => {
return !Object.keys(currentNotifiedSafes || {}).includes(chainId)
}).length
export const _getTotalSignaturesRequired = (
selectedSafes: NotifiableSafes,
currentNotifiedSafes?: NotifiableSafes,
): number => {
return Object.entries(selectedSafes)
.filter(([, safeAddresses]) => safeAddresses.length > 0)
.reduce((acc, [chainId, safeAddresses]) => {
const isNewChain = !currentNotifiedSafes?.[chainId]
const isNewSafe = safeAddresses.some((safeAddress) => !currentNotifiedSafes?.[chainId]?.includes(safeAddress))

if (isNewChain || isNewSafe) {
acc += 1
}
return acc
}, 0)
}

const shouldRegisterSelectedSafes = (
export const _shouldRegisterSelectedSafes = (
selectedSafes: NotifiableSafes,
currentNotifiedSafes?: NotifiableSafes,
): boolean => {
Expand All @@ -108,7 +131,10 @@ const shouldRegisterSelectedSafes = (
})
}

const shouldUnregsiterSelectedSafes = (selectedSafes: NotifiableSafes, currentNotifiedSafes?: NotifiableSafes) => {
export const _shouldUnregsiterSelectedSafes = (
selectedSafes: NotifiableSafes,
currentNotifiedSafes?: NotifiableSafes,
) => {
return Object.entries(currentNotifiedSafes || {}).some(([chainId, safeAddresses]) => {
return safeAddresses.some((safeAddress) => !selectedSafes[chainId]?.includes(safeAddress))
})
Expand All @@ -117,7 +143,7 @@ const shouldUnregsiterSelectedSafes = (selectedSafes: NotifiableSafes, currentNo
// onSave logic

// Safes that need to be registered with the service
const getSafesToRegister = (
export const _getSafesToRegister = (
selectedSafes: NotifiableSafes,
currentNotifiedSafes?: NotifiableSafes,
): NotifiableSafes | undefined => {
Expand All @@ -141,7 +167,7 @@ const getSafesToRegister = (
}

// Safes that need to be unregistered with the service
const getSafesToUnregister = (
export const _getSafesToUnregister = (
selectedSafes: NotifiableSafes,
currentNotifiedSafes?: NotifiableSafes,
): NotifiableSafes | undefined => {
Expand Down Expand Up @@ -171,7 +197,7 @@ const getSafesToUnregister = (
}

// Whether the device needs to be unregistered from the service
const shouldUnregisterDevice = (
export const _shouldUnregisterDevice = (
chainId: string,
safeAddresses: Array<string>,
currentNotifiedSafes?: NotifiableSafes,
Expand All @@ -192,6 +218,7 @@ const shouldUnregisterDevice = (
export const GlobalPushNotifications = (): ReactElement | null => {
const chains = useChains()
const addedSafes = useAppSelector(selectAllAddedSafes)
const [isLoading, setIsLoading] = useState(false)

const { dismissPushNotificationBanner } = useDismissPushNotificationsBanner()
const { getAllPreferences } = useNotificationPreferences()
Expand All @@ -204,7 +231,7 @@ export const GlobalPushNotifications = (): ReactElement | null => {
// Current Safes registered for notifications in indexedDB
const currentNotifiedSafes = useMemo(() => {
const allPreferences = getAllPreferences()
return transformCurrentSubscribedSafes(allPreferences)
return _transformCurrentSubscribedSafes(allPreferences)
}, [getAllPreferences])

// `currentNotifiedSafes` is initially undefined until indexedDB resolves
Expand All @@ -222,15 +249,15 @@ export const GlobalPushNotifications = (): ReactElement | null => {

// Merged added Safes and `currentNotifiedSafes` (in case subscriptions aren't added)
const notifiableSafes = useMemo(() => {
return mergeNotifiableSafes(addedSafes, currentNotifiedSafes)
return _mergeNotifiableSafes(addedSafes, currentNotifiedSafes)
}, [addedSafes, currentNotifiedSafes])

const totalNotifiableSafes = useMemo(() => {
return getTotalNotifiableSafes(notifiableSafes)
return _getTotalNotifiableSafes(notifiableSafes)
}, [notifiableSafes])

const isAllSelected = useMemo(() => {
return areAllSafesSelected(notifiableSafes, selectedSafes)
return _areAllSafesSelected(notifiableSafes, selectedSafes)
}, [notifiableSafes, selectedSafes])

const onSelectAll = () => {
Expand All @@ -249,13 +276,13 @@ export const GlobalPushNotifications = (): ReactElement | null => {
}

const totalSignaturesRequired = useMemo(() => {
return getTotalSignaturesRequired(selectedSafes, currentNotifiedSafes)
return _getTotalSignaturesRequired(selectedSafes, currentNotifiedSafes)
}, [currentNotifiedSafes, selectedSafes])

const canSave = useMemo(() => {
return (
shouldRegisterSelectedSafes(selectedSafes, currentNotifiedSafes) ||
shouldUnregsiterSelectedSafes(selectedSafes, currentNotifiedSafes)
_shouldRegisterSelectedSafes(selectedSafes, currentNotifiedSafes) ||
_shouldUnregsiterSelectedSafes(selectedSafes, currentNotifiedSafes)
)
}, [selectedSafes, currentNotifiedSafes])

Expand All @@ -264,17 +291,20 @@ export const GlobalPushNotifications = (): ReactElement | null => {
return
}

setIsLoading(true)

// Although the (un-)registration functions will request permission in getToken we manually
// check beforehand to prevent multiple promises in registrationPromises from throwing
const isGranted = await requestNotificationPermission()

if (!isGranted) {
setIsLoading(false)
return
}

const registrationPromises: Array<Promise<unknown>> = []

const safesToRegister = getSafesToRegister(selectedSafes, currentNotifiedSafes)
const safesToRegister = _getSafesToRegister(selectedSafes, currentNotifiedSafes)
if (safesToRegister) {
registrationPromises.push(registerNotifications(safesToRegister))

Expand All @@ -284,10 +314,10 @@ export const GlobalPushNotifications = (): ReactElement | null => {
})
}

const safesToUnregister = getSafesToUnregister(selectedSafes, currentNotifiedSafes)
const safesToUnregister = _getSafesToUnregister(selectedSafes, currentNotifiedSafes)
if (safesToUnregister) {
const unregistrationPromises = Object.entries(safesToUnregister).flatMap(([chainId, safeAddresses]) => {
if (shouldUnregisterDevice(chainId, safeAddresses, currentNotifiedSafes)) {
if (_shouldUnregisterDevice(chainId, safeAddresses, currentNotifiedSafes)) {
return unregisterDeviceNotifications(chainId)
}
return safeAddresses.map((safeAddress) => unregisterSafeNotifications(chainId, safeAddress))
Expand All @@ -299,6 +329,8 @@ export const GlobalPushNotifications = (): ReactElement | null => {
await Promise.all(registrationPromises)

trackEvent(PUSH_NOTIFICATION_EVENTS.SAVE_SETTINGS)

setIsLoading(false)
}

if (totalNotifiableSafes === 0) {
Expand All @@ -322,8 +354,8 @@ export const GlobalPushNotifications = (): ReactElement | null => {

<CheckWallet allowNonOwner>
{(isOk) => (
<Button variant="contained" disabled={!canSave || !isOk} onClick={onSave}>
Save
<Button variant="contained" disabled={!canSave || !isOk || isLoading} onClick={onSave}>
{isLoading ? <CircularProgress size={20} /> : 'Save'}
</Button>
)}
</CheckWallet>
Expand Down
Loading

0 comments on commit e807c40

Please sign in to comment.