mirror of
https://github.com/urosran/cally.git
synced 2025-07-16 18:16:17 +00:00
Added notifciations
This commit is contained in:
@ -10,6 +10,8 @@ import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
|
||||
import NavBrainDumpIcon from "@/assets/svgs/NavBrainDumpIcon";
|
||||
import NavCalendarIcon from "@/assets/svgs/NavCalendarIcon";
|
||||
import NavSettingsIcon from "@/assets/svgs/NavSettingsIcon";
|
||||
import FeedbackNavIcon from "@/assets/svgs/FeedbackNavIcon";
|
||||
import {MaterialIcons} from "@expo/vector-icons";
|
||||
import {useSetAtom} from "jotai";
|
||||
import {
|
||||
isFamilyViewAtom,
|
||||
@ -17,7 +19,7 @@ import {
|
||||
toDosPageIndex,
|
||||
userSettingsView,
|
||||
} from "@/components/pages/calendar/atoms";
|
||||
import FeedbackNavIcon from "@/assets/svgs/FeedbackNavIcon";
|
||||
import Ionicons from "@expo/vector-icons/Ionicons";
|
||||
|
||||
export default function TabLayout() {
|
||||
const {mutateAsync: signOut} = useSignOut();
|
||||
@ -139,6 +141,19 @@ export default function TabLayout() {
|
||||
}}
|
||||
icon={<NavBrainDumpIcon/>}
|
||||
/>
|
||||
<DrawerButton
|
||||
color="#e0ca03"
|
||||
title={"Notifications"}
|
||||
bgColor={"#ffdda1"}
|
||||
pressFunc={() => {
|
||||
props.navigation.navigate("notifications");
|
||||
setPageIndex(0);
|
||||
setToDosIndex(0);
|
||||
setUserView(true);
|
||||
setIsFamilyView(false);
|
||||
}}
|
||||
icon={<Ionicons name="notifications-outline" size={24} color={"#ffa200"} />}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<Button
|
||||
@ -242,6 +257,13 @@ export default function TabLayout() {
|
||||
title: "To-Dos",
|
||||
}}
|
||||
/>
|
||||
<Drawer.Screen
|
||||
name="notifications"
|
||||
options={{
|
||||
drawerLabel: "Notifications",
|
||||
title: "Notifications",
|
||||
}}
|
||||
/>
|
||||
<Drawer.Screen
|
||||
name="feedback"
|
||||
options={{drawerLabel: "Feedback", title: "Feedback"}}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import BrainDumpPage from "@/components/pages/brain_dump/BrainDumpPage";
|
||||
import {BrainDumpProvider} from "@/contexts/DumpContext";
|
||||
import { ScrollView } from "react-native-gesture-handler";
|
||||
import {View} from "react-native-ui-lib";
|
||||
import BrainDumpPage from "@/components/pages/brain_dump/BrainDumpPage";
|
||||
|
||||
export default function Screen() {
|
||||
return (
|
||||
|
5
app/(auth)/notifications/_layout.tsx
Normal file
5
app/(auth)/notifications/_layout.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import {Stack} from "expo-router";
|
||||
|
||||
export default function StackLayout () {
|
||||
return <Stack screenOptions={{headerShown: false}}/>
|
||||
}
|
7
app/(auth)/notifications/index.tsx
Normal file
7
app/(auth)/notifications/index.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
import NotificationsPage from "@/components/pages/notifications/NotificationsPage";
|
||||
|
||||
export default function Screen() {
|
||||
return (
|
||||
<NotificationsPage/>
|
||||
);
|
||||
}
|
@ -15,7 +15,6 @@ import {CalendarEvent} from "@/components/pages/calendar/interfaces";
|
||||
import {Text} from "react-native-ui-lib";
|
||||
import {addDays, compareAsc, isWithinInterval, subDays} from "date-fns";
|
||||
import {useCalSync} from "@/hooks/useCalSync";
|
||||
import { useIsMutating } from "react-query";
|
||||
import {useSyncEvents} from "@/hooks/useSyncOnScroll";
|
||||
|
||||
interface EventCalendarProps {
|
||||
|
60
components/pages/notifications/NotificationsPage.tsx
Normal file
60
components/pages/notifications/NotificationsPage.tsx
Normal file
@ -0,0 +1,60 @@
|
||||
import {FlatList, ScrollView, StyleSheet} from "react-native";
|
||||
import React from "react";
|
||||
import {Card, Text, View} from "react-native-ui-lib";
|
||||
import HeaderTemplate from "@/components/shared/HeaderTemplate";
|
||||
import {useGetNotifications} from "@/hooks/firebase/useGetNotifications";
|
||||
import {formatDistanceToNow} from "date-fns";
|
||||
|
||||
const NotificationsPage = () => {
|
||||
const {data: notifications} = useGetNotifications()
|
||||
|
||||
console.log(notifications?.[0]?.timestamp)
|
||||
|
||||
|
||||
return (
|
||||
<View flexG height={"100%"}>
|
||||
<View flexG>
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
>
|
||||
<View marginH-25>
|
||||
<HeaderTemplate
|
||||
message={"Welcome to your notifications!"}
|
||||
isWelcome={false}
|
||||
children={
|
||||
<Text
|
||||
style={{fontFamily: "Manrope_400Regular", fontSize: 14}}
|
||||
>
|
||||
See your notifications here.
|
||||
</Text>
|
||||
}
|
||||
/>
|
||||
<View>
|
||||
<FlatList data={notifications ?? []} renderItem={({item}) => <Card padding-20 gap-10>
|
||||
<Text text70>{item.content}</Text>
|
||||
<View row spread>
|
||||
<Text text90>{formatDistanceToNow(new Date(item.timestamp), { addSuffix: true })}</Text>
|
||||
<Text text90>{item.timestamp.toLocaleDateString()}</Text>
|
||||
</View>
|
||||
</Card>}/>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
searchField: {
|
||||
borderWidth: 0.7,
|
||||
borderColor: "#9b9b9b",
|
||||
borderRadius: 15,
|
||||
height: 42,
|
||||
paddingLeft: 10,
|
||||
marginVertical: 20,
|
||||
},
|
||||
});
|
||||
|
||||
export default NotificationsPage;
|
@ -1,6 +1,6 @@
|
||||
const {onRequest} = require("firebase-functions/v2/https");
|
||||
const {getAuth} = require("firebase-admin/auth");
|
||||
const {getFirestore} = require("firebase-admin/firestore");
|
||||
const {getFirestore, Timestamp} = require("firebase-admin/firestore");
|
||||
const logger = require("firebase-functions/logger");
|
||||
const functions = require('firebase-functions');
|
||||
const admin = require('firebase-admin');
|
||||
@ -22,7 +22,7 @@ exports.sendNotificationOnEventCreation = functions.firestore
|
||||
.document('Events/{eventId}')
|
||||
.onCreate(async (snapshot, context) => {
|
||||
const eventData = snapshot.data();
|
||||
const { familyId, creatorId, email } = eventData;
|
||||
const { familyId, creatorId, email, title } = eventData;
|
||||
|
||||
if (!familyId || !creatorId) {
|
||||
console.error('Missing familyId or creatorId in event data');
|
||||
@ -44,7 +44,7 @@ exports.sendNotificationOnEventCreation = functions.firestore
|
||||
|
||||
notificationTimeout = setTimeout(async () => {
|
||||
const eventMessage = eventCount === 1
|
||||
? `An event "${eventData.title}" has been added. Check it out!`
|
||||
? `An event "${title}" has been added. Check it out!`
|
||||
: `${eventCount} new events have been added.`;
|
||||
|
||||
let messages = pushTokens.map(pushToken => {
|
||||
@ -85,6 +85,22 @@ exports.sendNotificationOnEventCreation = functions.firestore
|
||||
}
|
||||
}
|
||||
|
||||
// Save the notification in Firestore for record-keeping
|
||||
const notificationData = {
|
||||
creatorId,
|
||||
familyId,
|
||||
content: eventMessage,
|
||||
eventId: context.params.eventId,
|
||||
timestamp: Timestamp.now(),
|
||||
};
|
||||
|
||||
try {
|
||||
await db.collection("Notifications").add(notificationData);
|
||||
console.log("Notification stored in Firestore:", notificationData);
|
||||
} catch (error) {
|
||||
console.error("Error saving notification to Firestore:", error);
|
||||
}
|
||||
|
||||
// Reset state variables after notifications are sent
|
||||
eventCount = 0;
|
||||
pushTokens = [];
|
||||
|
29
hooks/firebase/useGetNotifications.ts
Normal file
29
hooks/firebase/useGetNotifications.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import {useQuery} from "react-query";
|
||||
import firestore from "@react-native-firebase/firestore";
|
||||
import {useAuthContext} from "@/contexts/AuthContext";
|
||||
|
||||
export const useGetNotifications = () => {
|
||||
const { user, profileData } = useAuthContext();
|
||||
|
||||
return useQuery({
|
||||
queryKey: ["notifications", user?.uid],
|
||||
queryFn: async () => {
|
||||
const snapshot = await firestore()
|
||||
.collection("Notifications")
|
||||
.where("familyId", "==", profileData?.familyId)
|
||||
.get();
|
||||
|
||||
return snapshot.docs.map((doc) => {
|
||||
const data = doc.data();
|
||||
|
||||
return {...data, timestamp: new Date(data.timestamp.seconds * 1000 + data.timestamp.nanoseconds / 1e6)} as {
|
||||
creatorId: string,
|
||||
familyId: string,
|
||||
content: string,
|
||||
eventId: string,
|
||||
timestamp: Date,
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
};
|
Reference in New Issue
Block a user