Skip to content

Commit

Permalink
feat: settings notifications, closes leather-io/issues#195
Browse files Browse the repository at this point in the history
  • Loading branch information
fbwoolf committed Sep 26, 2024
1 parent 936fa26 commit 05e9656
Show file tree
Hide file tree
Showing 19 changed files with 298 additions and 180 deletions.
5 changes: 1 addition & 4 deletions apps/mobile/src/app/(home)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,7 @@ export default function StackLayout() {
name="settings/networks/index"
options={{ header: () => NavigationSettings(t`Networks`) }}
/>
<Stack.Screen
name="settings/notifications/index"
options={{ header: () => NavigationSettings(t`Notifications`) }}
/>
<Stack.Screen name="settings/notifications" options={{ headerShown: false }} />
<Stack.Screen
name="settings/help/index"
options={{ header: () => NavigationSettings(t`Help`) }}
Expand Down
5 changes: 2 additions & 3 deletions apps/mobile/src/app/(home)/settings/display/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { useLingui } from '@lingui/react';

import {
BitcoinCircleIcon,
Box,
DollarCircleIcon,
PackageSecurityIcon,
SheetRef,
Expand All @@ -35,7 +34,7 @@ export default function SettingsDisplayScreen() {
const { i18n } = useLingui();

return (
<Box flex={1} backgroundColor="ink.background-primary">
<>
<SettingsScreenLayout>
<DisplayCell
title={t`Theme`}
Expand Down Expand Up @@ -74,6 +73,6 @@ export default function SettingsDisplayScreen() {
<BitcoinUnitSheet sheetRef={bitcoinUnitSheetRef} />
<ConversionUnitSheet sheetRef={conversionUnitSheetRef} />
<AccountIdentifierSheet sheetRef={accountIdentifierSheetRef} />
</Box>
</>
);
}
66 changes: 66 additions & 0 deletions apps/mobile/src/app/(home)/settings/notifications/_layout.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<TabBar
tabs={[
{
onPress() {
router.navigate(AppRoutes.SettingsNotifications);
},
title: t`Push`,
isActive: pathname === AppRoutes.SettingsNotifications,
},
{
onPress() {
router.navigate(AppRoutes.SettingsNotificationsEmail);
},
title: t`Email`,
isActive: pathname === AppRoutes.SettingsNotificationsEmail,
},
]}
/>
);
}

export default function SettingsNotificationsLayout() {
const insets = useSafeAreaInsets();

const NavigationHeader = (
<SimpleHeader
insets={insets}
left={<BackButtonHeader onPress={() => router.navigate(AppRoutes.Settings)} />}
center={<TitleHeader title={t`Notifications`} />}
bottom={<HeaderBottomTabs />}
/>
);

return (
<Tabs tabBar={() => null}>
<Tabs.Screen
name="index"
options={{
title: t`Push`,
header: () => NavigationHeader,
}}
/>
<Tabs.Screen
name="email"
options={{
title: t`Email`,
header: () => NavigationHeader,
}}
/>
</Tabs>
);
}
47 changes: 47 additions & 0 deletions apps/mobile/src/app/(home)/settings/notifications/email.tsx
Original file line number Diff line number Diff line change
@@ -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<SheetRef>(null);

return (
<>
<SettingsScreenLayout>
<TouchableOpacity
onPress={() => {
emailAddressSheetRef.current?.present();
}}
>
<Flag
img={
<Avatar>
<EmailIcon />
</Avatar>
}
>
<ItemLayout
actionIcon={<ChevronRightIcon variant="small" />}
captionLeft={t`Awaiting verification`}
titleLeft={t`Email address`}
/>
</Flag>
</TouchableOpacity>
</SettingsScreenLayout>
<EmailAddressSheet sheetRef={emailAddressSheetRef} />
</>
);
}
82 changes: 22 additions & 60 deletions apps/mobile/src/app/(home)/settings/notifications/index.tsx
Original file line number Diff line number Diff line change
@@ -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<SheetRef>(null);
const emailNotificationsSheetRef = useRef<SheetRef>(null);
const emailAddressSheetRef = useRef<SheetRef>(null);
const theme = useTheme<Theme>();
import SettingsScreenLayout from '../settings-screen.layout';

// TODO: Hook up to notifications service when available or use Expo?
export default function SettingsNotificationsScreen() {
return (
<Box flex={1} backgroundColor="ink.background-primary">
<ScrollView
contentContainerStyle={{
paddingHorizontal: theme.spacing['5'],
paddingTop: theme.spacing['5'],
paddingBottom: theme.spacing['5'] + bottom,
gap: theme.spacing[5],
}}
>
<Cell
title={t`Push notifications`}
subtitle={t`All enabled`}
Icon={SquareNotificationIcon}
onPress={() => {
pushNotificationsSheetRef.current?.present();
}}
/>
<Cell
title={t`Email notifications`}
subtitle={t`5 enabled`}
Icon={EmailNotificationIcon}
onPress={() => {
emailNotificationsSheetRef.current?.present();
}}
/>
<Cell
title={t`Email address`}
subtitle={t`None/Awaiting verification/Verified`}
Icon={EmailIcon}
onPress={() => {
emailAddressSheetRef.current?.present();
}}
/>
</ScrollView>
<PushNotificationsSheet sheetRef={pushNotificationsSheetRef} />
<EmailNotificationsSheet sheetRef={emailNotificationsSheetRef} />
<EmailAddressSheet sheetRef={emailAddressSheetRef} />
</Box>
<SettingsScreenLayout>
<TouchableOpacity onPress={() => {}}>
<Flag
img={
<Avatar>
<PlaceholderIcon />
</Avatar>
}
>
<ItemLayout
actionIcon={<Switch disabled value={false} />}
titleLeft={t`Notification`}
captionLeft={t`Description`}
/>
</Flag>
</TouchableOpacity>
</SettingsScreenLayout>
);
}
6 changes: 3 additions & 3 deletions apps/mobile/src/app/(home)/settings/security/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -16,7 +16,7 @@ export default function SettingsSecurityScreen() {
const settings = useSettings();

return (
<Box flex={1} backgroundColor="ink.background-primary">
<>
<SettingsScreenLayout>
<SecurityCell
title={t`Analytics`}
Expand All @@ -37,6 +37,6 @@ export default function SettingsSecurityScreen() {
</SettingsScreenLayout>
<AnalyticsSheet sheetRef={analyticsSheetRef} />
<AppAuthenticationSheet sheetRef={appAuthenticationSheetRef} />
</Box>
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface SimpleHeaderProps {
left?: ReactNode;
center?: ReactNode;
right?: ReactNode;
bottom?: ReactNode;
insets: EdgeInsets;
}
export function SimpleHeader(props: SimpleHeaderProps) {
Expand Down Expand Up @@ -40,6 +41,7 @@ export function SimpleHeader(props: SimpleHeaderProps) {
{props?.right}
</Box>
</Box>
{props.bottom}
</Box>
);
}
7 changes: 4 additions & 3 deletions apps/mobile/src/components/sheets/input-sheet.layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { RefObject, useState } from 'react';
import { useSettings } from '@/store/settings/settings';

import {
Avatar,
Box,
Button,
IconProps,
Expand Down Expand Up @@ -47,9 +48,9 @@ export function InputSheet({
<Box>
<SheetHeader
icon={
<Box bg="ink.background-secondary" borderRadius="round" flexDirection="row" p="2">
<TitleIcon color="ink.text-primary" />
</Box>
<Avatar>
<TitleIcon />
</Avatar>
}
title={title}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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' });
}

Expand Down
52 changes: 46 additions & 6 deletions apps/mobile/src/features/settings/email-address-sheet.tsx
Original file line number Diff line number Diff line change
@@ -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<SheetRef>;
}
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: 'info' });
return;
}
}

settings.changeEmailAddressPreference(address);
sheetRef.current?.close();
displayToast({ title: t`Email submitted, please check your email`, type: 'success' });
}

return (
<Sheet isScrollView ref={sheetRef} themeVariant={themeDerivedFromThemePreference}>
<Text>{t`Hello`}</Text>
</Sheet>
<SettingsSheetLayout icon={<EmailIcon />} sheetRef={sheetRef} title={t`Email address`}>
<Text>{t`Provide an email address for receiving notifications`}</Text>
<TextInput
autoCapitalize="none"
autoComplete="off"
autoCorrect={false}
autoFocus
inputState="focused"
onChangeText={text => setEmailAddress(text)}
placeholder={t`Email address`}
TextInputComponent={UIBottomSheetTextInput}
value={emailAddress}
/>
<Button
buttonState="default"
onPress={() => onSaveEmailAddress(emailAddress)}
title={t`Save`}
/>
</SettingsSheetLayout>
);
}
18 changes: 0 additions & 18 deletions apps/mobile/src/features/settings/email-notifications-sheet.tsx

This file was deleted.

Loading

0 comments on commit 05e9656

Please sign in to comment.