diff --git a/apps/mobile/src/app/(home)/_layout.tsx b/apps/mobile/src/app/(home)/_layout.tsx index 22370e0bc..63cbc17a2 100644 --- a/apps/mobile/src/app/(home)/_layout.tsx +++ b/apps/mobile/src/app/(home)/_layout.tsx @@ -116,10 +116,7 @@ export default function StackLayout() { name="settings/networks/index" options={{ header: () => NavigationSettings(t`Networks`) }} /> - NavigationSettings(t`Notifications`) }} - /> + NavigationSettings(t`Help`) }} diff --git a/apps/mobile/src/app/(home)/settings/display/index.tsx b/apps/mobile/src/app/(home)/settings/display/index.tsx index e98d04b4c..477b435e4 100644 --- a/apps/mobile/src/app/(home)/settings/display/index.tsx +++ b/apps/mobile/src/app/(home)/settings/display/index.tsx @@ -10,7 +10,6 @@ import { useLingui } from '@lingui/react'; import { BitcoinCircleIcon, - Box, DollarCircleIcon, PackageSecurityIcon, SheetRef, @@ -35,7 +34,7 @@ export default function SettingsDisplayScreen() { const { i18n } = useLingui(); return ( - + <> - + ); } diff --git a/apps/mobile/src/app/(home)/settings/notifications/_layout.tsx b/apps/mobile/src/app/(home)/settings/notifications/_layout.tsx new file mode 100644 index 000000000..2a4250578 --- /dev/null +++ b/apps/mobile/src/app/(home)/settings/notifications/_layout.tsx @@ -0,0 +1,66 @@ +import { useSafeAreaInsets } from 'react-native-safe-area-context'; + +import { BackButtonHeader } from '@/components/headers/back-button'; +import { SimpleHeader } from '@/components/headers/containers/simple-header'; +import { TitleHeader } from '@/components/headers/title'; +import { TabBar } from '@/components/tab-bar'; +import { AppRoutes } from '@/routes'; +import { t } from '@lingui/macro'; +import { Tabs, router, usePathname, useRouter } from 'expo-router'; + +function HeaderBottomTabs() { + const router = useRouter(); + const pathname = usePathname(); + return ( + + ); +} + +export default function SettingsNotificationsLayout() { + const insets = useSafeAreaInsets(); + + const NavigationHeader = ( + router.navigate(AppRoutes.Settings)} />} + center={} + bottom={} + /> + ); + + return ( + null}> + NavigationHeader, + }} + /> + NavigationHeader, + }} + /> + + ); +} diff --git a/apps/mobile/src/app/(home)/settings/notifications/email.tsx b/apps/mobile/src/app/(home)/settings/notifications/email.tsx new file mode 100644 index 000000000..3bb7790dc --- /dev/null +++ b/apps/mobile/src/app/(home)/settings/notifications/email.tsx @@ -0,0 +1,47 @@ +import { useRef } from 'react'; +import { TouchableOpacity } from 'react-native-gesture-handler'; + +import { EmailAddressSheet } from '@/features/settings/email-address-sheet'; +import { t } from '@lingui/macro'; + +import { + Avatar, + ChevronRightIcon, + EmailIcon, + Flag, + ItemLayout, + SheetRef, +} from '@leather.io/ui/native'; + +import SettingsScreenLayout from '../settings-screen.layout'; + +export default function SettingsNotificationsEmailScreen() { + const emailAddressSheetRef = useRef(null); + + return ( + <> + + { + emailAddressSheetRef.current?.present(); + }} + > + + + + } + > + } + captionLeft={t`Awaiting verification`} + titleLeft={t`Email address`} + /> + + + + + + ); +} diff --git a/apps/mobile/src/app/(home)/settings/notifications/index.tsx b/apps/mobile/src/app/(home)/settings/notifications/index.tsx index 00059cb86..6e6ae14d2 100644 --- a/apps/mobile/src/app/(home)/settings/notifications/index.tsx +++ b/apps/mobile/src/app/(home)/settings/notifications/index.tsx @@ -1,68 +1,30 @@ -import { useRef } from 'react'; -import { ScrollView } from 'react-native-gesture-handler'; -import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import { Switch, TouchableOpacity } from 'react-native-gesture-handler'; -import { EmailAddressSheet } from '@/features/settings/email-address-sheet'; -import { EmailNotificationsSheet } from '@/features/settings/email-notifications-sheet'; -import { PushNotificationsSheet } from '@/features/settings/push-notifications-sheet'; import { t } from '@lingui/macro'; -import { useTheme } from '@shopify/restyle'; -import { - Box, - Cell, - EmailIcon, - EmailNotificationIcon, - SheetRef, - SquareNotificationIcon, - Theme, -} from '@leather.io/ui/native'; +import { Avatar, Flag, ItemLayout, PlaceholderIcon } from '@leather.io/ui/native'; -export default function SettingsNotificationsScreen() { - const { bottom } = useSafeAreaInsets(); - const pushNotificationsSheetRef = useRef(null); - const emailNotificationsSheetRef = useRef(null); - const emailAddressSheetRef = useRef(null); - const theme = useTheme(); +import SettingsScreenLayout from '../settings-screen.layout'; +// TODO: Hook up to notifications service when available or use Expo? +export default function SettingsNotificationsScreen() { return ( - - - { - pushNotificationsSheetRef.current?.present(); - }} - /> - { - emailNotificationsSheetRef.current?.present(); - }} - /> - { - emailAddressSheetRef.current?.present(); - }} - /> - - - - - + + {}}> + + + + } + > + } + titleLeft={t`Notification`} + captionLeft={t`Description`} + /> + + + ); } diff --git a/apps/mobile/src/app/(home)/settings/security/index.tsx b/apps/mobile/src/app/(home)/settings/security/index.tsx index 459027f4b..c4c674fb9 100644 --- a/apps/mobile/src/app/(home)/settings/security/index.tsx +++ b/apps/mobile/src/app/(home)/settings/security/index.tsx @@ -5,7 +5,7 @@ import { AppAuthenticationSheet } from '@/features/settings/app-authentication-s import { useSettings } from '@/store/settings/settings'; import { t } from '@lingui/macro'; -import { Box, CookieIcon, KeyholeIcon, SheetRef } from '@leather.io/ui/native'; +import { CookieIcon, KeyholeIcon, SheetRef } from '@leather.io/ui/native'; import SettingsScreenLayout from '../settings-screen.layout'; import { SecurityCell } from './security-cell'; @@ -16,7 +16,7 @@ export default function SettingsSecurityScreen() { const settings = useSettings(); return ( - + <> - + ); } diff --git a/apps/mobile/src/components/headers/containers/simple-header.tsx b/apps/mobile/src/components/headers/containers/simple-header.tsx index 4afa4c069..e679fc605 100644 --- a/apps/mobile/src/components/headers/containers/simple-header.tsx +++ b/apps/mobile/src/components/headers/containers/simple-header.tsx @@ -9,6 +9,7 @@ interface SimpleHeaderProps { left?: ReactNode; center?: ReactNode; right?: ReactNode; + bottom?: ReactNode; insets: EdgeInsets; } export function SimpleHeader(props: SimpleHeaderProps) { @@ -40,6 +41,7 @@ export function SimpleHeader(props: SimpleHeaderProps) { {props?.right} + {props.bottom} ); } diff --git a/apps/mobile/src/components/sheets/input-sheet.layout.tsx b/apps/mobile/src/components/sheets/input-sheet.layout.tsx index c57897f60..18b9dfff9 100644 --- a/apps/mobile/src/components/sheets/input-sheet.layout.tsx +++ b/apps/mobile/src/components/sheets/input-sheet.layout.tsx @@ -3,6 +3,7 @@ import { RefObject, useState } from 'react'; import { useSettings } from '@/store/settings/settings'; import { + Avatar, Box, Button, IconProps, @@ -47,9 +48,9 @@ export function InputSheet({ - - + + + } title={title} /> diff --git a/apps/mobile/src/components/toast/index.tsx b/apps/mobile/src/components/toast/index.tsx index e73fb9bf3..9c4d7e864 100644 --- a/apps/mobile/src/components/toast/index.tsx +++ b/apps/mobile/src/components/toast/index.tsx @@ -4,7 +4,14 @@ import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-na import { ResponsiveValue, useTheme } from '@shopify/restyle'; -import { Box, CheckmarkCircleIcon, Text, Theme } from '@leather.io/ui/native'; +import { + Box, + CheckmarkCircleIcon, + ErrorTriangleIcon, + InfoCircleIcon, + Text, + Theme, +} from '@leather.io/ui/native'; import { ToastData, ToastMethods, ToastProps, ToastType } from './types'; @@ -19,10 +26,14 @@ const TOAST_OPEN_DURATION = 3000; function getIcon(type: ToastType, theme: Theme) { switch (type) { - case 'success': - return ; + case 'error': + return ; case 'info': - return null; + return ; + case 'success': + return ; + default: + return ; } } @@ -30,8 +41,9 @@ function getBackground( type: ToastType ): ResponsiveValue { switch (type) { - case 'success': + case 'error': case 'info': + case 'success': return 'ink.text-primary'; } } diff --git a/apps/mobile/src/components/toast/types.ts b/apps/mobile/src/components/toast/types.ts index 19a623055..ff5facb94 100644 --- a/apps/mobile/src/components/toast/types.ts +++ b/apps/mobile/src/components/toast/types.ts @@ -1,6 +1,6 @@ import { RefObject } from 'react'; -export type ToastType = 'success' | 'info'; +export type ToastType = 'error' | 'info' | 'success'; export interface ToastData { title: string; diff --git a/apps/mobile/src/features/settings/bitcoin-unit-sheet/bitcoin-unit-sheet.tsx b/apps/mobile/src/features/settings/bitcoin-unit-sheet/bitcoin-unit-sheet.tsx index 4e3ea198a..4ebe9688f 100644 --- a/apps/mobile/src/features/settings/bitcoin-unit-sheet/bitcoin-unit-sheet.tsx +++ b/apps/mobile/src/features/settings/bitcoin-unit-sheet/bitcoin-unit-sheet.tsx @@ -21,7 +21,7 @@ export function BitcoinUnitSheet({ sheetRef }: BitcoinUnitSheetProps) { const { i18n } = useLingui(); function onUpdateBitcoinUnit(unit: BitcoinUnit) { - settings.changeBitcoinUnit(unit); + settings.changeBitcoinUnitPreference(unit); displayToast({ title: t`Bitcoin unit updated`, type: 'success' }); } diff --git a/apps/mobile/src/features/settings/email-address-sheet.tsx b/apps/mobile/src/features/settings/email-address-sheet.tsx index 1e9d0dce8..26719de69 100644 --- a/apps/mobile/src/features/settings/email-address-sheet.tsx +++ b/apps/mobile/src/features/settings/email-address-sheet.tsx @@ -1,18 +1,58 @@ -import { RefObject } from 'react'; +import { RefObject, useState } from 'react'; +import { TextInput } from '@/components/text-input'; +import { useToastContext } from '@/components/toast/toast-context'; import { useSettings } from '@/store/settings/settings'; import { t } from '@lingui/macro'; +import { z } from 'zod'; -import { Sheet, SheetRef, Text } from '@leather.io/ui/native'; +import { emailAddressSchema } from '@leather.io/models'; +import { Button, EmailIcon, SheetRef, Text, UIBottomSheetTextInput } from '@leather.io/ui/native'; + +import { SettingsSheetLayout } from './settings-sheet.layout'; interface EmailAddressSheetProps { sheetRef: RefObject; } export function EmailAddressSheet({ sheetRef }: EmailAddressSheetProps) { - const { themeDerivedFromThemePreference } = useSettings(); + const [emailAddress, setEmailAddress] = useState(''); + const settings = useSettings(); + const { displayToast } = useToastContext(); + + function onSaveEmailAddress(address: string) { + try { + emailAddressSchema.parse(address); + } catch (err) { + if (err instanceof z.ZodError) { + displayToast({ title: t`Invalid email address`, type: 'error' }); + return; + } + } + + settings.changeEmailAddressPreference(address); + sheetRef.current?.close(); + displayToast({ title: t`Submitted, check your email`, type: 'success' }); + } + return ( - - {t`Hello`} - + } sheetRef={sheetRef} title={t`Email address`}> + {t`Provide an email address for receiving notifications`} + setEmailAddress(text)} + placeholder={t`Email address`} + TextInputComponent={UIBottomSheetTextInput} + value={emailAddress} + /> +