Skip to content

Commit

Permalink
Update NotificationView to use deviceNotifState and allow close o…
Browse files Browse the repository at this point in the history
…n all notifications
  • Loading branch information
Jon-edge committed Nov 1, 2024
1 parent 6c9b41a commit 1f0b6f7
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 50 deletions.
2 changes: 1 addition & 1 deletion src/actions/LocalSettingsActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export const writeSpendingLimits = async (account: EdgeAccount, spendingLimits:
* Track the state of whether particular one-time notifications associated with
* the account were interacted with or dismissed.
**/
export const writeNotifDismissInfo = async (account: EdgeAccount, accountNotifDismissInfo: AccountNotifDismissInfo) => {
export const writeAccountNotifDismissInfo = async (account: EdgeAccount, accountNotifDismissInfo: AccountNotifDismissInfo) => {
const updatedSettings = { ...localAccountSettings, accountNotifDismissInfo }
return await writeLocalAccountSettings(account, updatedSettings)
}
Expand Down
109 changes: 60 additions & 49 deletions src/components/notification/NotificationView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { sprintf } from 'sprintf-js'

import { showBackupModal } from '../../actions/BackupModalActions'
import { getLocalAccountSettings, writeNotifDismissInfo } from '../../actions/LocalSettingsActions'
import { useAsyncEffect } from '../../hooks/useAsyncEffect'
import { getDeviceSettings, modifyDeviceNotifInfo } from '../../actions/DeviceSettingsActions'
import { useAsyncNavigation } from '../../hooks/useAsyncNavigation'
import { useHandler } from '../../hooks/useHandler'
import { useWatch } from '../../hooks/useWatch'
Expand All @@ -33,42 +32,60 @@ interface Props {
footerHeight: number
}

const hideBanner = async (deviceNotifStateKey: string) => {
await modifyDeviceNotifInfo(deviceNotifStateKey, { isBannerHidden: true })
}

const NotificationViewComponent = (props: Props) => {
const { navigation, hasTabs, footerHeight } = props
const { deviceNotifState } = getDeviceSettings()

const navigationDebounced = useAsyncNavigation(navigation)
const theme = useTheme()
const dispatch = useDispatch()

const account = useSelector(state => state.core.account)
const detectedTokensRedux = useSelector(state => state.core.enabledDetectedTokens)
const needsPasswordCheck = useSelector(state => state.ui.passwordReminder.needsPasswordCheck)

const wallets = useWatch(account, 'currencyWallets')
const otpKey = useWatch(account, 'otpKey')

const { bottom: insetBottom } = useSafeAreaInsets()
const footerOpenRatio = useSceneFooterState(state => state.footerOpenRatio)

const [autoDetectTokenCards, setAutoDetectTokenCards] = React.useState<React.JSX.Element[]>([])
const [otpReminderCard, setOtpReminderCard] = React.useState<React.JSX.Element>()
const accountNotifDismissInfo = getLocalAccountSettings().accountNotifDismissInfo

const isLightAccount = account.id != null && account.username == null

const handleBackupClose = useHandler(async () => {
await hideBanner('lightAccountReminder')
})
const handleBackupPress = useHandler(async () => {
await handleBackupClose()
await showBackupModal({ navigation: navigationDebounced })
})

const handlePasswordReminderClose = useHandler(async () => {
await hideBanner('pwReminder')
})
const handlePasswordReminderPress = useHandler(async () => {
await handlePasswordReminderClose()
await Airship.show(bridge => <PasswordReminderModal bridge={bridge} navigation={navigationDebounced} />)
})

const handle2FaEnabledDismiss = useHandler(async () => {
await writeNotifDismissInfo(account, { ...accountNotifDismissInfo, ip2FaNotifShown: true })
const handle2FaEnabledClose = useHandler(async () => {
await hideBanner('ip2FaReminder')
// TODO: Move this to NotificationCenterScene
// await writeAccountNotifDismissInfo(account, { ...accountNotifDismissInfo, ip2FaNotifShown: true })
})
const handle2FaEnabledPress = useHandler(async () => {
await handle2FaEnabledClose()
await openBrowserUri(config.ip2faSite)
await handle2FaEnabledDismiss()
})

const handleOtpReminderClose = useHandler(async () => {
await hideBanner('otpReminder')
})
const handleOtpReminderPress = useHandler(async () => {
await handleOtpReminderClose()
const otpReminderModal = await getOtpReminderModal(account)
if (otpReminderModal != null) await otpReminderModal()
})

const handleLayout = useHandler((event: LayoutChangeEvent) => {
Expand All @@ -80,16 +97,28 @@ const NotificationViewComponent = (props: Props) => {
React.useEffect(() => {
const newNotifs: React.JSX.Element[] = []
Object.keys(wallets).forEach(walletId => {
const newTokenKey = `newToken-${walletId}`
const newTokenIds = detectedTokensRedux[walletId]

const dismissNewTokens = (walletId: string) => {
const handleCloseNewToken = async () => {
// Since this isn't a priority notification, we can just fully complete
// it here
await modifyDeviceNotifInfo(newTokenKey, { isBannerHidden: true, isCompleted: true, isShown: false })
dispatch({
type: 'CORE/DISMISS_NEW_TOKENS',
data: { walletId }
})
}
const handlePressNewToken = async () => {
await handleCloseNewToken()
navigationDebounced.navigate('manageTokens', {
walletId,
newTokenIds
})
}

if (newTokenIds != null && newTokenIds.length > 0) {
const isShowNewTokenNotif = deviceNotifState[newTokenKey] != null && !deviceNotifState[newTokenKey].isBannerHidden
if (isShowNewTokenNotif && newTokenIds != null && newTokenIds.length > 0) {
const { name, currencyInfo } = wallets[walletId]

newNotifs.push(
Expand All @@ -102,38 +131,16 @@ const NotificationViewComponent = (props: Props) => {
? sprintf(lstrings.notif_tokens_detected_on_address_1s, currencyInfo.currencyCode)
: sprintf(lstrings.notif_tokens_detected_on_wallet_name_1s, name)
}
onPress={() => {
dismissNewTokens(walletId)
navigationDebounced.navigate('manageTokens', {
walletId,
newTokenIds
})
}}
onClose={() => dismissNewTokens(walletId)}
onPress={handlePressNewToken}
onClose={handleCloseNewToken}
/>
)
}

setAutoDetectTokenCards(newNotifs)
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [detectedTokensRedux, handleBackupPress, theme])

// Check for 2FA/OTP reminder disabled notifications
// Periodically remind the user to enable 2FA/OTP
useAsyncEffect(
async () => {
const otpReminderModal = await getOtpReminderModal(account)

if (otpReminderModal != null) {
setOtpReminderCard(
<NotificationCard type="warning" title={lstrings.otp_reset_modal_header} message={lstrings.notif_otp_message} onPress={otpReminderModal} />
)
}
},
[account],
'otpNotificationCard'
)
}, [detectedTokensRedux, deviceNotifState, handleBackupPress, theme])

return (
<NotificationCardsContainer
Expand All @@ -143,41 +150,45 @@ const NotificationViewComponent = (props: Props) => {
footerOpenRatio={footerOpenRatio}
onLayout={handleLayout}
>
<EdgeAnim visible={isLightAccount} enter={fadeIn} exit={fadeOut}>
<EdgeAnim visible={deviceNotifState.lightAccountReminder != null && !deviceNotifState.lightAccountReminder.isBannerHidden} enter={fadeIn} exit={fadeOut}>
<NotificationCard
type="warning"
title={lstrings.backup_notification_title}
message={sprintf(lstrings.backup_notification_body, config.appName)}
persistent
onPress={handleBackupPress}
onClose={handleBackupClose}
/>
</EdgeAnim>
<EdgeAnim visible={autoDetectTokenCards.length > 0} enter={fadeIn} exit={fadeOut}>
{autoDetectTokenCards}
</EdgeAnim>
<EdgeAnim visible={otpReminderCard != null} enter={fadeIn} exit={fadeOut}>
{otpReminderCard}
<EdgeAnim visible={deviceNotifState.otpReminder != null && !deviceNotifState.otpReminder.isBannerHidden} enter={fadeIn} exit={fadeOut}>
<NotificationCard
type="warning"
title={lstrings.otp_reset_modal_header}
message={lstrings.notif_otp_message}
onPress={handleOtpReminderPress}
onClose={handleOtpReminderClose}
/>
</EdgeAnim>
<EdgeAnim visible={needsPasswordCheck} enter={fadeIn} exit={fadeOut}>
<EdgeAnim visible={deviceNotifState.pwReminder != null && !deviceNotifState.pwReminder.isBannerHidden} enter={fadeIn} exit={fadeOut}>
<NotificationCard
type="info"
title={lstrings.password_reminder_card_title}
message={lstrings.password_reminder_card_body}
onPress={handlePasswordReminderPress}
onClose={handlePasswordReminderClose}
/>
</EdgeAnim>
<EdgeAnim
visible={!isLightAccount && otpKey == null && accountNotifDismissInfo != null && !accountNotifDismissInfo.ip2FaNotifShown}
enter={fadeIn}
exit={fadeOut}
>
<EdgeAnim visible={deviceNotifState.ip2FaReminder != null && !deviceNotifState.ip2FaReminder.isBannerHidden} enter={fadeIn} exit={fadeOut}>
<NotificationCard
type="info"
title={lstrings.notif_ip_validation_enabled_title}
message={sprintf(lstrings.notif_ip_validation_enabled_body_1s, config.appName)}
iconUri={getThemedIconUri(theme, 'notifications/icon-lock')}
onPress={handle2FaEnabledPress}
onClose={handle2FaEnabledDismiss}
onClose={handle2FaEnabledClose}
/>
</EdgeAnim>
</NotificationCardsContainer>
Expand Down

0 comments on commit 1f0b6f7

Please sign in to comment.