-
Notifications
You must be signed in to change notification settings - Fork 508
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Mobile): add notifications opt-In screen (#4837)
* chore: adds new images for notification onboarding optIn * refactor: enables notifications method on hook * refactor: adds Notification item & adpat for new 2 button pattern * refactor: adds new variant to button * refactor: adds logic to handle themed driven images & buttons * chore: adds jest mocks and fix tests * chore: adds navigation and onboarding awareness to Service * refactor: rollbacks Onboarding changes in favour of OptIn screens * feat: adds reusable floating view * feat: adds reusable OptIn component * refactor: rollback tests changes on onboarding flow * chore: adds auxiliary constants * chore: moves mock to central place * feat: adds optIn on navigation stack * chore: adds a (temp) icon for enable notification OptIn * refactor: adds new UX on how Notifications will be propmt to be enabled
- Loading branch information
1 parent
750d476
commit 70f4db2
Showing
23 changed files
with
337 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import React from 'react' | ||
import { useColorScheme } from 'react-native' | ||
import { OptIn } from '@/src/components/OptIn' | ||
import useNotifications from '@/src/hooks/useNotifications' | ||
import { router, useFocusEffect } from 'expo-router' | ||
|
||
function NotificationsOptIn() { | ||
const { enableNotifications, isAppNotificationEnabled } = useNotifications() | ||
const colorScheme = useColorScheme() | ||
|
||
useFocusEffect(() => { | ||
if (isAppNotificationEnabled) { | ||
router.replace('/(tabs)') | ||
} | ||
}) | ||
|
||
const image = | ||
colorScheme === 'dark' | ||
? require('@/assets/images/notifications-dark.png') | ||
: require('@/assets/images/notifications-light.png') | ||
|
||
return ( | ||
<OptIn | ||
testID="notifications-opt-in" | ||
title="Stay in the loop with account activity" | ||
description="Get notified when you receive assets, and when transactions require your action." | ||
image={image} | ||
isVisible | ||
ctaButton={{ | ||
onPress: enableNotifications, | ||
label: 'Enable notifications', | ||
}} | ||
secondaryButton={{ | ||
onPress: () => router.back(), | ||
label: 'Maybe later', | ||
}} | ||
/> | ||
) | ||
} | ||
|
||
export default NotificationsOptIn |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
apps/mobile/src/components/FloatingContainer/FloatingContainer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { Layout } from '@/src/store/constants' | ||
import React, { FC, useMemo } from 'react' | ||
import { useSafeAreaInsets } from 'react-native-safe-area-context' | ||
|
||
import { KeyboardAvoidingView, KeyboardAvoidingViewProps, Platform, StyleSheet, View } from 'react-native' | ||
|
||
interface FloatingContainerProps { | ||
children: React.ReactNode | ||
noOffset?: boolean | ||
sticky?: boolean | ||
keyboardAvoidEnabled?: boolean | ||
onLayout?: KeyboardAvoidingViewProps['onLayout'] | ||
testID?: string | ||
} | ||
|
||
export const FloatingContainer: FC<FloatingContainerProps> = ({ | ||
children, | ||
noOffset, | ||
sticky, | ||
keyboardAvoidEnabled, | ||
onLayout, | ||
testID, | ||
}: FloatingContainerProps) => { | ||
const bottomInset = useSafeAreaInsets().bottom | ||
const deviceBottom = Layout.isSmallDevice ? 10 : 20 | ||
|
||
const bottomPadding = useMemo(() => { | ||
return Math.max(bottomInset, deviceBottom) | ||
}, [bottomInset]) | ||
|
||
const keyboardVerticalOffset = useMemo(() => { | ||
return noOffset ? 0 : Platform.select({ ios: 40, default: 0 }) | ||
}, [noOffset]) | ||
|
||
return ( | ||
<KeyboardAvoidingView | ||
testID={testID} | ||
behavior={sticky ? 'height' : 'position'} | ||
keyboardVerticalOffset={keyboardVerticalOffset} | ||
enabled={keyboardAvoidEnabled} | ||
style={[styles.floatingContainer, { paddingBottom: bottomPadding }]} | ||
onLayout={onLayout} | ||
> | ||
<View style={styles.childContainer}>{children}</View> | ||
</KeyboardAvoidingView> | ||
) | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
floatingContainer: { | ||
position: 'fixed', | ||
bottom: -40, | ||
width: '100%', | ||
zIndex: 1, | ||
}, | ||
childContainer: { | ||
flexDirection: 'column', | ||
justifyContent: 'space-between', | ||
flexGrow: 1, | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import { FloatingContainer } from './FloatingContainer' | ||
export { FloatingContainer } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import React from 'react' | ||
import { ImageSourcePropType, StyleSheet } from 'react-native' | ||
import { View, Image, Text } from 'tamagui' | ||
import { SafeButton } from '@/src/components/SafeButton' | ||
import { WINDOW_HEIGHT } from '@/src/store/constants' | ||
import { FloatingContainer } from '../FloatingContainer' | ||
|
||
interface OptInProps { | ||
title: string | ||
ctaButton: { | ||
onPress: () => void | ||
label: string | ||
} | ||
kicker?: string | ||
description?: string | ||
image?: ImageSourcePropType | ||
secondaryButton?: { | ||
onPress: () => void | ||
label: string | ||
} | ||
testID?: string | ||
isVisible?: boolean | ||
} | ||
|
||
export const OptIn: React.FC<OptInProps> = React.memo( | ||
({ testID, kicker, title, description, image, ctaButton, secondaryButton, isVisible }: OptInProps) => { | ||
if (!isVisible) { | ||
return | ||
} | ||
|
||
return ( | ||
<View | ||
testID={testID} | ||
style={styles.wrapper} | ||
padding="$4" | ||
gap="$8" | ||
alignItems="center" | ||
justifyContent="flex-start" | ||
> | ||
{kicker && ( | ||
<Text textAlign="center" fontWeight={700} fontSize="$4" lineHeight="$6"> | ||
{kicker} | ||
</Text> | ||
)} | ||
<Text textAlign="center" fontWeight={600} fontSize="$8" lineHeight="$8"> | ||
{title} | ||
</Text> | ||
{description && ( | ||
<Text textAlign="center" fontWeight={400} fontSize="$4"> | ||
{description} | ||
</Text> | ||
)} | ||
{image && <Image style={styles.image} source={image} />} | ||
|
||
<FloatingContainer sticky testID="notifications-opt-in-cta-buttons"> | ||
<SafeButton onPress={ctaButton.onPress} label={ctaButton.label} /> | ||
{secondaryButton && ( | ||
<SafeButton variant="secondary" onPress={secondaryButton.onPress} label={secondaryButton.label} /> | ||
)} | ||
</FloatingContainer> | ||
</View> | ||
) | ||
}, | ||
) | ||
|
||
const styles = StyleSheet.create({ | ||
wrapper: { | ||
flex: 1, | ||
}, | ||
image: { | ||
width: '100%', | ||
height: Math.abs(WINDOW_HEIGHT * 0.42), | ||
}, | ||
}) | ||
|
||
OptIn.displayName = 'OptIn' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import { OptIn } from './OptIn' | ||
export { OptIn } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 1 addition & 13 deletions
14
apps/mobile/src/features/Onboarding/Onboarding.container.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,7 @@ | ||
import React from 'react' | ||
import { OnboardingCarousel } from './components/OnboardingCarousel' | ||
import { items } from './components/OnboardingCarousel/items' | ||
import { useRouter } from 'expo-router' | ||
import { SafeButton } from '@/src/components/SafeButton' | ||
|
||
export function Onboarding() { | ||
const router = useRouter() | ||
|
||
const onGetStartedPress = () => { | ||
router.navigate('/(tabs)') | ||
} | ||
|
||
return ( | ||
<OnboardingCarousel items={items}> | ||
<SafeButton onPress={onGetStartedPress} label="Get started" /> | ||
</OnboardingCarousel> | ||
) | ||
return <OnboardingCarousel items={items} /> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.