frontend: basic notifications testing screen
Pedro Lucas Porcellis porcellis@eletrotupi.com · 4 months ago
fe2deb48e4d91c97820de01dec6dd464c725329f Browse filesParents
6360c22Changed files
3
Additions
+154
Deletions
-1
frontend/app/(tabs)/_layout.tsx
1 1
import { Tabs, Redirect, router } from 'expo-router';
2 2
import React, { useEffect } from 'react';
3 3
import { View, ActivityIndicator } from 'react-native';
4 4
5 5
import { HapticTab } from '@/components/misc/haptic-tab';
6 6
import { IconSymbol } from '@/components/ui/icon-symbol';
7 7
import { Colors } from '@/constants/theme';
8 8
import { useColorScheme } from '@/hooks/use-color-scheme';
9 9
import { useAuth } from '@/context/AuthContext';
10 +
import * as Notifications from "expo-notifications";
10 11
11 12
export default function TabLayout() {
12 13
const colorScheme = useColorScheme();
13 14
const { isAuthenticated, isLoading } = useAuth();
14 15
15 16
useEffect(() => {
16 17
if (!isLoading && !isAuthenticated) {
17 18
router.replace('/auth/login');
18 19
}
19 20
}, [isAuthenticated, isLoading]);
21 +
22 +
// TODO: Store the notification in a hook ctx, then capture if was
23 +
useEffect(() => {
24 +
const subscription = Notifications.addNotificationResponseReceivedListener(response => {
25 +
const screen = response.notification.request.content.data?.screen;
26 +
27 +
if (screen === 'notifications') {
28 +
router.push('/notifications');
29 +
}
30 +
});
31 +
32 +
// Handle notification tap when app was already open
33 +
Notifications.setNotificationHandler({
34 +
handleNotification: async () => ({
35 +
shouldShowAlert: true,
36 +
shouldPlaySound: false,
37 +
shouldSetBadge: false,
38 +
}),
39 +
});
40 +
41 +
return () => subscription.remove();
42 +
}, []);
20 43
21 44
if (isLoading) {
22 45
return (
23 46
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
24 47
<ActivityIndicator size="large" />
79 102
}}
80 103
/>
81 104
</Tabs>
82 105
);
83 106
}
frontend/app/(tabs)/new/index.tsx
1 1
import { useEffect, useState } from "react";
2 2
import { StyleSheet, View, Text, ActivityIndicator } from "react-native";
3 3
4 4
import { ThemedText } from "@/components/misc/themed-text";
5 5
import { ThemedView } from "@/components/misc/themed-view";
37 37
const initQuickRegister = () => {
38 38
// TODO: Set down on camelCase vs kebab case
39 39
router.navigate(`/new/entry?initialMood=${mood}`);
40 40
};
41 41
42 +
const onNotificationPress = () => {
43 +
router.push('/notifications');
44 +
}
45 +
42 46
return (
43 47
<ScreenLayout
44 48
userName={user.firstName}
45 49
userAvatar={user.avatarURL}
46 -
onNotificationPress={() => console.log("Notifications")}
50 +
onNotificationPress={onNotificationPress}
47 51
showNotificationBadge={true}
48 52
>
49 53
<Section>
50 54
<SectionHeader
51 55
title="Como você está hoje?"
185 189
fontSize: 11,
186 190
fontWeight: 600,
187 191
lineHeight: 16.5,
188 192
},
189 193
});
/dev/null → frontend/app/notifications.tsx
1 +
import {
2 +
View,
3 +
Text,
4 +
StyleSheet,
5 +
ScrollView,
6 +
KeyboardAvoidingView,
7 +
Platform,
8 +
Alert,
9 +
} from 'react-native';
10 +
11 +
import {
12 +
useState, useEffect
13 +
} from 'react';
14 +
import * as Notifications from 'expo-notifications';
15 +
import { useAuth } from "@/context/AuthContext";
16 +
17 +
import { StatusBar } from 'expo-status-bar';
18 +
import { SafeAreaView } from 'react-native-safe-area-context';
19 +
import { useThemeColor } from '@/hooks/use-theme-color';
20 +
import { Button } from '@/components/ui/Button';
21 +
22 +
export default function NotificationsPage() {
23 +
const { user } = useAuth();
24 +
const backgroundColor = useThemeColor({}, 'background');
25 +
const [expoPushToken, setExpoPushToken] = useState(user.pushToken);
26 +
const [notification, setNotification] = useState<Notifications.Notification | undefined>(
27 +
undefined
28 +
);
29 +
30 +
useEffect(() => {
31 +
const notificationListener = Notifications
32 +
.addNotificationReceivedListener(notification => {
33 +
setNotification(notification);
34 +
});
35 +
36 +
const responseListener = Notifications
37 +
.addNotificationResponseReceivedListener(response => {
38 +
console.log(response);
39 +
});
40 +
41 +
return () => {
42 +
notificationListener.remove();
43 +
responseListener.remove();
44 +
};
45 +
}, []);
46 +
47 +
useEffect(() => {
48 +
setExpoPushToken(user.pushToken)
49 +
}, [user]);
50 +
51 +
async function sendPushNotification(expoPushToken: string) {
52 +
if (expoPushToken) {
53 +
const message = {
54 +
to: expoPushToken,
55 +
sound: 'default',
56 +
title: 'Oi meu querido',
57 +
body: 'Vamo escutar um The Doors',
58 +
data: { screen: 'notifications' },
59 +
};
60 +
61 +
const response = await fetch('https://exp.host/--/api/v2/push/send', {
62 +
method: 'POST',
63 +
headers: {
64 +
Accept: 'application/json',
65 +
'Accept-encoding': 'gzip, deflate',
66 +
'Content-Type': 'application/json',
67 +
},
68 +
body: JSON.stringify(message),
69 +
});
70 +
}
71 +
}
72 +
73 +
return (
74 +
<SafeAreaView style={[styles.container, { backgroundColor }]}>
75 +
<StatusBar style={'dark'} />
76 +
<KeyboardAvoidingView
77 +
behavior='height'
78 +
style={styles.keyboardView}
79 +
>
80 +
<ScrollView
81 +
contentContainerStyle={styles.scrollContainer}
82 +
showsVerticalScrollIndicator={false}
83 +
>
84 +
<View>
85 +
<Text>
86 +
Uma notificação!!!
87 +
</Text>
88 +
</View>
89 +
90 +
<View style={{ alignItems: 'center', justifyContent: 'center' }}>
91 +
<Text>Title: {notification && notification.request.content.title} </Text>
92 +
<Text>Body: {notification && notification.request.content.body}</Text>
93 +
<Text>Data: {notification && JSON.stringify(notification.request.content.data)}</Text>
94 +
</View>
95 +
96 +
<Button
97 +
title="Quer ver uma coisa?"
98 +
onPress={async () => {
99 +
await sendPushNotification(expoPushToken);
100 +
}}
101 +
/>
102 +
103 +
</ScrollView>
104 +
</KeyboardAvoidingView>
105 +
</SafeAreaView>
106 +
);
107 +
}
108 +
109 +
const styles = StyleSheet.create({
110 +
container: {
111 +
flex: 1,
112 +
},
113 +
keyboardView: {
114 +
flex: 1,
115 +
},
116 +
scrollContainer: {
117 +
flexGrow: 1,
118 +
paddingHorizontal: 24,
119 +
justifyContent: 'start',
120 +
minHeight: '100%',
121 +
},
122 +
header: {
123 +
alignItems: 'left',
124 +
marginBottom: 40,
125 +
},
126 +
});