Notifications + AsyncStorage
This commit is contained in:
@@ -1,12 +1,40 @@
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { Session } from "@supabase/supabase-js";
|
||||
import { Redirect, Tabs } from "expo-router";
|
||||
import * as Notifications from 'expo-notifications';
|
||||
import { Redirect, router, Tabs } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function UseNotificationObserver() {
|
||||
useEffect(() => {
|
||||
function redirect(notification: Notifications.Notification) {
|
||||
const aId = notification.request.content.data?.aId;
|
||||
|
||||
if (typeof aId === 'string') {
|
||||
router.push({pathname: "/assignment/viewDetailsAssignment", params: { aId }});
|
||||
}
|
||||
}
|
||||
|
||||
const response = Notifications.getLastNotificationResponse();
|
||||
if (response?.notification) {
|
||||
redirect(response.notification);
|
||||
}
|
||||
|
||||
const subscription = Notifications.addNotificationResponseReceivedListener(response => {
|
||||
redirect(response.notification);
|
||||
});
|
||||
|
||||
return () => {
|
||||
subscription.remove();
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
|
||||
export default function TabLayout() {
|
||||
const [session, SetSession] = useState<Session | null>(null)
|
||||
const [loading, SetLoading] = useState(true);
|
||||
|
||||
UseNotificationObserver();
|
||||
|
||||
useEffect(() => {
|
||||
const loadSession = async () => {
|
||||
const { data } = await supabase.auth.getSession();
|
||||
@@ -38,18 +66,6 @@ export default function TabLayout() {
|
||||
<Tabs.Screen name="assignments" options={{title: "Assignments"}} />
|
||||
<Tabs.Screen name="subjects" options={{title: "Subjects"}} />
|
||||
<Tabs.Screen name="timer" options={{title: "Timer"}} />
|
||||
|
||||
<Tabs.Screen name="subject/createSubject" options={{ href: null }} />
|
||||
<Tabs.Screen name="subject/editSubject" options={{ href: null }} />
|
||||
<Tabs.Screen name="subject/viewDetailsSubject" options={{ href: null }} />
|
||||
|
||||
<Tabs.Screen name="assignment/createAssignment" options={{ href: null }} />
|
||||
<Tabs.Screen name="assignment/editAssignment" options={{ href: null }} />
|
||||
<Tabs.Screen name="assignment/viewDetailsAssignment" options={{ href: null }} />
|
||||
|
||||
<Tabs.Screen name="task/createTask" options={{ href: null }} />
|
||||
<Tabs.Screen name="task/editTask" options={{ href: null }} />
|
||||
<Tabs.Screen name="task/viewDetailsTask" options={{ href: null }} />
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,34 @@
|
||||
import { defaultStyles } from "@/constants/defaultStyles";
|
||||
import { RegisterForLocalNotificationsAsync } from '@/lib/notifications';
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { Session } from '@supabase/supabase-js';
|
||||
import { Stack } from "expo-router";
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Button, Text, View } from "react-native";
|
||||
|
||||
export default function HomeScreen() {
|
||||
const [session, SetSession] = useState<Session | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
supabase.auth
|
||||
.getSession()
|
||||
.then(({ data }) => SetSession(data.session ?? null));
|
||||
|
||||
const { data: sub } = supabase.auth.onAuthStateChange(
|
||||
(_event, newSession) => {
|
||||
SetSession(newSession);
|
||||
}
|
||||
);
|
||||
|
||||
return () => sub.subscription.unsubscribe();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (session) {
|
||||
RegisterForLocalNotificationsAsync();
|
||||
}
|
||||
}, [session])
|
||||
|
||||
return (
|
||||
<View style={defaultStyles.container}>
|
||||
<Stack.Screen
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import { Stack } from "expo-router";
|
||||
import '../global.css';
|
||||
import "../global.css";
|
||||
|
||||
export default function RootLayout() {
|
||||
return <Stack screenOptions={{ headerShown: false }} />;
|
||||
return (
|
||||
<Stack>
|
||||
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="subject" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="assignment" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="task" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="createUser" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="login" options={{ headerShown: false }} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
11
app/assignment/_layout.tsx
Normal file
11
app/assignment/_layout.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Stack } from "expo-router";
|
||||
|
||||
export default function AssignmentLayout() {
|
||||
return (
|
||||
<Stack>
|
||||
<Stack.Screen name="createAssignment" options={{ title: "Create Assignment" }} />
|
||||
<Stack.Screen name="editAssignment" options={{ title: "Edit Assignment" }} />
|
||||
<Stack.Screen name="viewDetailsAssignment" options={{ title: "Assignment Details" }} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import { defaultStyles } from '@/constants/defaultStyles';
|
||||
import * as AsyncStorage from '@/lib/asyncStorage';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import * as Notifications from 'expo-notifications';
|
||||
import { router, Stack, useLocalSearchParams } from 'expo-router';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
@@ -18,37 +20,62 @@ import {
|
||||
|
||||
export default function CreateAssignment() {
|
||||
const sId = (useLocalSearchParams().sId as string) ?? null;
|
||||
|
||||
const [title, SetTitle] = useState('');
|
||||
const [description, SetDescription] = useState('');
|
||||
const [deadline, SetDeadline] = useState('');
|
||||
const [isCompleted, SetIsCompleted] = useState(false);
|
||||
const [isSaving, SetIsSaving] = useState(false);
|
||||
|
||||
const ScheduleDeadlineReminder = async (aId: string, title: string, deadline: string) => {
|
||||
const dl = new Date(deadline);
|
||||
|
||||
if (isNaN(dl.getTime())) return null;
|
||||
|
||||
const deadlineReminder = new Date(dl.getTime() - 24 * 60 * 60 * 1000);
|
||||
|
||||
if (deadlineReminder <= new Date()) return null;
|
||||
|
||||
const nId = await Notifications.scheduleNotificationAsync({
|
||||
content: {
|
||||
title: 'Assignment deadline coming up',
|
||||
body: `${title} is due in 24 hours.`,
|
||||
data: { aId },
|
||||
},
|
||||
trigger: {
|
||||
type: Notifications.SchedulableTriggerInputTypes.DATE,
|
||||
date: deadlineReminder,
|
||||
},
|
||||
});
|
||||
|
||||
return nId;
|
||||
}
|
||||
|
||||
const CreateAssignment = async () => {
|
||||
if (title.trim() === '') {
|
||||
Alert.alert('Title is required!');
|
||||
return;
|
||||
}
|
||||
|
||||
const { data, error: userError } = await supabase.auth.getUser();
|
||||
const { data: userData, error: userError } = await supabase.auth.getUser();
|
||||
|
||||
if (userError || !data.user) {
|
||||
if (userError || !userData.user) {
|
||||
router.replace('../createUser');
|
||||
return;
|
||||
}
|
||||
|
||||
SetIsSaving(true);
|
||||
|
||||
const { error: dbError } = await supabase.from('assignments').insert({
|
||||
const { data: assignmentData, error: dbError } = await supabase.from('assignments').insert({
|
||||
title: title.trim(),
|
||||
description: description.trim(),
|
||||
deadline: deadline.trim(),
|
||||
isCompleted,
|
||||
lastChanged: new Date().toISOString(),
|
||||
uId: data.user.id,
|
||||
uId: userData.user.id,
|
||||
sId,
|
||||
});
|
||||
})
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (dbError) {
|
||||
SetIsSaving(false);
|
||||
@@ -58,6 +85,14 @@ export default function CreateAssignment() {
|
||||
|
||||
Alert.alert('Assignment successfully created!');
|
||||
|
||||
if (!isCompleted && assignmentData) {
|
||||
const nId = await ScheduleDeadlineReminder(assignmentData.aId, assignmentData.title, assignmentData.deadline);
|
||||
|
||||
if (nId) {
|
||||
await AsyncStorage.SaveAssignmentNotificationId(assignmentData.aId, nId);
|
||||
}
|
||||
}
|
||||
|
||||
SetTitle('');
|
||||
SetDescription('');
|
||||
SetDeadline('');
|
||||
@@ -1,5 +1,7 @@
|
||||
import { defaultStyles } from '@/constants/defaultStyles';
|
||||
import { GetAssignmentNotificationId, RemoveAssignmentNotificationId, SaveAssignmentNotificationId } from '@/lib/asyncStorage';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import * as Notifications from 'expo-notifications';
|
||||
import { router, Stack, useFocusEffect, useLocalSearchParams } from 'expo-router';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { ActivityIndicator, Alert, Button, Keyboard, KeyboardAvoidingView, Platform, Pressable, Text, TextInput, TouchableWithoutFeedback, View } from 'react-native';
|
||||
@@ -20,6 +22,39 @@ export default function EditAssignment() {
|
||||
const [assignment, SetAssignment] = useState<Assignment | null>(null)
|
||||
const [isSaving, SetIsSaving] = useState(false);
|
||||
|
||||
const ScheduleDeadlineReminder = async (aId: string, title: string, deadline: string) => {
|
||||
const dl = new Date(deadline);
|
||||
|
||||
if (isNaN(dl.getTime())) return null;
|
||||
|
||||
const deadlineReminder = new Date(dl.getTime() - 24 * 60 * 60 * 1000);
|
||||
|
||||
if (deadlineReminder <= new Date()) return null;
|
||||
|
||||
const nId = await Notifications.scheduleNotificationAsync({
|
||||
content: {
|
||||
title: 'Assignment deadline coming up',
|
||||
body: `${title} is due in 24 hours.`,
|
||||
data: { aId },
|
||||
},
|
||||
trigger: {
|
||||
type: Notifications.SchedulableTriggerInputTypes.DATE,
|
||||
date: deadlineReminder,
|
||||
},
|
||||
});
|
||||
|
||||
return nId;
|
||||
}
|
||||
|
||||
const CancelDeadlineReminder = async (aId: string) => {
|
||||
const nId = await GetAssignmentNotificationId(aId);
|
||||
|
||||
if (!nId) return;
|
||||
|
||||
await Notifications.cancelScheduledNotificationAsync(nId);
|
||||
await RemoveAssignmentNotificationId(aId);
|
||||
}
|
||||
|
||||
const GetAssignment = async (aId: string) => {
|
||||
const { data, error } = await supabase.from("assignments").select("*").eq("aId", aId).single();
|
||||
|
||||
@@ -47,24 +82,27 @@ export default function EditAssignment() {
|
||||
return;
|
||||
}
|
||||
|
||||
const { data, error: userError } = await supabase.auth.getUser();
|
||||
const { data: userData, error: userError } = await supabase.auth.getUser();
|
||||
|
||||
if(userError || !data.user) {
|
||||
if(userError || !userData.user) {
|
||||
router.replace("../createUser");
|
||||
return;
|
||||
}
|
||||
|
||||
SetIsSaving(true);
|
||||
|
||||
const { error: dbError } = await supabase.from("assignments").update({
|
||||
const { data: assignmentData, error: dbError } = await supabase.from("assignments").update({
|
||||
title: assignment.title,
|
||||
description: assignment.description,
|
||||
deadline: assignment.deadline,
|
||||
isCompleted: assignment.isCompleted,
|
||||
lastChanged: new Date().toISOString(),
|
||||
uId: data.user.id,
|
||||
uId: userData.user.id,
|
||||
sId: assignment.sId,
|
||||
}).eq("aId", aId);
|
||||
})
|
||||
.eq("aId", aId)
|
||||
.select()
|
||||
.single();
|
||||
|
||||
SetIsSaving(false);
|
||||
|
||||
@@ -75,6 +113,18 @@ export default function EditAssignment() {
|
||||
|
||||
Alert.alert("Assignment successfully edited!");
|
||||
|
||||
if (assignmentData) {
|
||||
await CancelDeadlineReminder(assignmentData.aId);
|
||||
|
||||
if (!assignmentData.isCompleted) {
|
||||
const nId = await ScheduleDeadlineReminder(assignmentData.aId, assignmentData.title, assignmentData.deadline);
|
||||
|
||||
if (nId) {
|
||||
await SaveAssignmentNotificationId(assignmentData.aId, nId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
router.back();
|
||||
}
|
||||
|
||||
11
app/subject/_layout.tsx
Normal file
11
app/subject/_layout.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Stack } from "expo-router";
|
||||
|
||||
export default function SubjectLayout() {
|
||||
return (
|
||||
<Stack>
|
||||
<Stack.Screen name="createSubject" options={{ title: "Create Subject" }} />
|
||||
<Stack.Screen name="editSubject" options={{ title: "Edit Subject" }} />
|
||||
<Stack.Screen name="viewDetailsSubject" options={{ title: "Subject Details" }} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
11
app/task/_layout.tsx
Normal file
11
app/task/_layout.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Stack } from "expo-router";
|
||||
|
||||
export default function TaskLayout() {
|
||||
return (
|
||||
<Stack>
|
||||
<Stack.Screen name="createTask" options={{ title: "Create Task" }} />
|
||||
<Stack.Screen name="editTask" options={{ title: "Edit Task" }} />
|
||||
<Stack.Screen name="viewDetailsTask" options={{ title: "Task Details" }} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
15
lib/asyncStorage.ts
Normal file
15
lib/asyncStorage.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
|
||||
const notificationKey = (aId: string) => `assignment_notification_${aId}`;
|
||||
|
||||
export async function SaveAssignmentNotificationId(aId: string, notificationId: string) {
|
||||
await AsyncStorage.setItem(notificationKey(aId), notificationId);
|
||||
}
|
||||
|
||||
export async function GetAssignmentNotificationId(aId: string) {
|
||||
return await AsyncStorage.getItem(notificationKey(aId));
|
||||
}
|
||||
|
||||
export async function RemoveAssignmentNotificationId(aId: string) {
|
||||
await AsyncStorage.removeItem(notificationKey(aId));
|
||||
}
|
||||
39
lib/notifications.ts
Normal file
39
lib/notifications.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import * as Notifications from 'expo-notifications';
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
Notifications.setNotificationHandler({
|
||||
handleNotification: async () => ({
|
||||
shouldPlaySound: true,
|
||||
shouldSetBadge: true,
|
||||
shouldShowBanner: true,
|
||||
shouldShowList: true,
|
||||
}),
|
||||
});
|
||||
|
||||
function HandleRegistrationError(errorMessage: string) {
|
||||
alert(errorMessage);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
export async function RegisterForLocalNotificationsAsync() {
|
||||
if (Platform.OS === 'android') {
|
||||
await Notifications.setNotificationChannelAsync('default', {
|
||||
name: 'default',
|
||||
importance: Notifications.AndroidImportance.MAX
|
||||
});
|
||||
}
|
||||
|
||||
const { status: existingStatus } = await Notifications.getPermissionsAsync();
|
||||
|
||||
let finalStatus = existingStatus;
|
||||
|
||||
if (existingStatus !== 'granted') {
|
||||
const { status } = await Notifications.requestPermissionsAsync();
|
||||
finalStatus = status;
|
||||
}
|
||||
|
||||
if (finalStatus !== 'granted') {
|
||||
HandleRegistrationError('Permission not granted for local notifications');
|
||||
return;
|
||||
}
|
||||
}
|
||||
173
notes/work-report-2026-04-22.md
Normal file
173
notes/work-report-2026-04-22.md
Normal file
@@ -0,0 +1,173 @@
|
||||
## #Overview
|
||||
|
||||
Implemented a full local notification system for assignment deadlines using Expo Notifications, integrated with Supabase-backed assignment data.
|
||||
|
||||
---
|
||||
|
||||
## #CoreFeatures
|
||||
|
||||
### #LocalNotifications
|
||||
|
||||
* Integrated `expo-notifications` for scheduling local device notifications
|
||||
* Configured notification handler for:
|
||||
|
||||
* banner display
|
||||
* sound
|
||||
* badge updates
|
||||
* Notifications trigger even when:
|
||||
|
||||
* app is in background
|
||||
* app is fully closed
|
||||
|
||||
---
|
||||
|
||||
### #DeadlineReminderLogic
|
||||
|
||||
* Implemented reminder scheduling based on assignment deadlines
|
||||
* Default behavior:
|
||||
|
||||
* notify **24 hours before deadline**
|
||||
* Prevented invalid scheduling:
|
||||
|
||||
* skip if reminder time is in the past
|
||||
* validate deadline input before scheduling
|
||||
|
||||
---
|
||||
|
||||
### #AssignmentIntegration
|
||||
|
||||
* Notifications tied directly to assignment lifecycle:
|
||||
|
||||
#### On Create:
|
||||
|
||||
* Insert assignment into Supabase
|
||||
* Retrieve inserted assignment (`aId`)
|
||||
* Schedule reminder if not completed
|
||||
|
||||
#### On Edit:
|
||||
|
||||
* Cancel existing scheduled notification
|
||||
* Update assignment in Supabase
|
||||
* Schedule new reminder if still active
|
||||
|
||||
#### On Delete:
|
||||
|
||||
* Cancel scheduled notification
|
||||
* Remove stored notification reference
|
||||
|
||||
---
|
||||
|
||||
### #NotificationPersistence
|
||||
|
||||
* Stored notification IDs locally using AsyncStorage
|
||||
* Structure:
|
||||
|
||||
* `assignmentId → notificationId`
|
||||
* Enables:
|
||||
|
||||
* precise cancellation
|
||||
* avoiding duplicate notifications
|
||||
|
||||
---
|
||||
|
||||
### #NotificationCancellation
|
||||
|
||||
* Implemented cancellation flow using:
|
||||
|
||||
* `Notifications.cancelScheduledNotificationAsync(notificationId)`
|
||||
* Ensures:
|
||||
|
||||
* no duplicate reminders on edit
|
||||
* no orphan notifications after deletion
|
||||
|
||||
---
|
||||
|
||||
### #NotificationRouting
|
||||
|
||||
* Implemented navigation on notification tap
|
||||
* Uses:
|
||||
|
||||
* `Notifications.addNotificationResponseReceivedListener`
|
||||
* `Notifications.getLastNotificationResponse()`
|
||||
|
||||
#### Behavior:
|
||||
|
||||
* Works when:
|
||||
|
||||
* app is open
|
||||
* app is in background
|
||||
* app is launched from notification
|
||||
|
||||
#### Routing:
|
||||
|
||||
* Extract `aId` from `notification.content.data`
|
||||
* Navigate using Expo Router:
|
||||
|
||||
```ts
|
||||
router.push({
|
||||
pathname: "/assignment/viewDetailsAssignment",
|
||||
params: { aId }
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### #AuthIntegration
|
||||
|
||||
* Notification observer only runs when user session exists
|
||||
* Prevents routing into protected screens when unauthenticated
|
||||
|
||||
---
|
||||
|
||||
## #ArchitectureDecisions
|
||||
|
||||
### #LocalVsBackend
|
||||
|
||||
* Chose **local notifications only**
|
||||
* No backend push notifications used
|
||||
* Rationale:
|
||||
|
||||
* single-user reminders
|
||||
* simpler implementation
|
||||
* no need for push tokens or server logic
|
||||
|
||||
---
|
||||
|
||||
### #DataSeparation
|
||||
|
||||
* Supabase:
|
||||
|
||||
* stores assignment data (source of truth)
|
||||
* Device (AsyncStorage):
|
||||
|
||||
* stores notification IDs (device-specific state)
|
||||
|
||||
---
|
||||
|
||||
### #RoutingApproach
|
||||
|
||||
* Used existing static route:
|
||||
|
||||
* `/assignment/viewDetailsAssignment`
|
||||
* Passed `aId` via params instead of dynamic route `[aId].tsx`
|
||||
* Keeps current structure intact
|
||||
|
||||
---
|
||||
|
||||
## #Summary
|
||||
|
||||
A complete local notification system has been implemented with:
|
||||
|
||||
* deadline-based scheduling
|
||||
* lifecycle-aware updates (create/edit/delete)
|
||||
* duplicate prevention
|
||||
* device-level persistence
|
||||
* deep-link style navigation on tap
|
||||
|
||||
This provides a solid, production-ready foundation for assignment reminders within the app.
|
||||
|
||||
|
||||
Interesting sources:
|
||||
https://docs.expo.dev/versions/latest/sdk/async-storage/
|
||||
https://docs.expo.dev/versions/latest/sdk/securestore/
|
||||
https://docs.expo.dev/versions/latest/sdk/notifications/
|
||||
178
package-lock.json
generated
178
package-lock.json
generated
@@ -10,6 +10,7 @@
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@expo/vector-icons": "^15.0.3",
|
||||
"@react-native-async-storage/async-storage": "2.2.0",
|
||||
"@react-navigation/bottom-tabs": "^7.4.0",
|
||||
"@react-navigation/elements": "^2.6.3",
|
||||
"@react-navigation/native": "^7.1.8",
|
||||
@@ -20,6 +21,7 @@
|
||||
"expo-haptics": "~15.0.8",
|
||||
"expo-image": "~3.0.11",
|
||||
"expo-linking": "~8.0.11",
|
||||
"expo-notifications": "~0.32.16",
|
||||
"expo-router": "~6.0.23",
|
||||
"expo-secure-store": "~15.0.8",
|
||||
"expo-splash-screen": "~31.0.13",
|
||||
@@ -2309,6 +2311,12 @@
|
||||
"url": "https://github.com/sponsors/nzakas"
|
||||
}
|
||||
},
|
||||
"node_modules/@ide/backoff": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@ide/backoff/-/backoff-1.0.0.tgz",
|
||||
"integrity": "sha512-F0YfUDjvT+Mtt/R4xdl2X0EYCHMMiJqNLdxHD++jDT5ydEFIyqbCHh51Qx2E211dgZprPKhV7sHmnXKpLuvc5g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@isaacs/fs-minipass": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
|
||||
@@ -2837,6 +2845,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native-async-storage/async-storage": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz",
|
||||
"integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"merge-options": "^3.0.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-native": "^0.0.0-0 || >=0.65 <1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native/assets-registry": {
|
||||
"version": "0.81.5",
|
||||
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.5.tgz",
|
||||
@@ -4423,6 +4443,19 @@
|
||||
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/assert": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz",
|
||||
"integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"is-nan": "^1.3.2",
|
||||
"object-is": "^1.1.5",
|
||||
"object.assign": "^4.1.4",
|
||||
"util": "^0.12.5"
|
||||
}
|
||||
},
|
||||
"node_modules/async-function": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
|
||||
@@ -4443,7 +4476,6 @@
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
||||
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"possible-typed-array-names": "^1.0.0"
|
||||
@@ -4664,6 +4696,12 @@
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/badgin": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/badgin/-/badgin-1.2.3.tgz",
|
||||
"integrity": "sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
@@ -4880,7 +4918,6 @@
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz",
|
||||
"integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
@@ -4899,7 +4936,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -4913,7 +4949,6 @@
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
|
||||
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
@@ -5473,7 +5508,6 @@
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0",
|
||||
@@ -5500,7 +5534,6 @@
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.0.1",
|
||||
@@ -5604,7 +5637,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
@@ -5733,7 +5765,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -5780,7 +5811,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
@@ -6326,6 +6356,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/expo-application": {
|
||||
"version": "7.0.8",
|
||||
"resolved": "https://registry.npmjs.org/expo-application/-/expo-application-7.0.8.tgz",
|
||||
"integrity": "sha512-qFGyxk7VJbrNOQWBbE09XUuGuvkOgFS9QfToaK2FdagM2aQ+x3CvGV2DuVgl/l4ZxPgIf3b/MNh9xHpwSwn74Q==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"expo": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-asset": {
|
||||
"version": "12.0.12",
|
||||
"resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-12.0.12.tgz",
|
||||
@@ -6458,6 +6497,26 @@
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-notifications": {
|
||||
"version": "0.32.16",
|
||||
"resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.32.16.tgz",
|
||||
"integrity": "sha512-QQD/UA6v7LgvwIJ+tS7tSvqJZkdp0nCSj9MxsDk/jU1GttYdK49/5L2LvE/4U0H7sNBz1NZAyhDZozg8xgBLXw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@expo/image-utils": "^0.8.8",
|
||||
"@ide/backoff": "^1.0.0",
|
||||
"abort-controller": "^3.0.0",
|
||||
"assert": "^2.0.0",
|
||||
"badgin": "^1.1.5",
|
||||
"expo-application": "~7.0.8",
|
||||
"expo-constants": "~18.0.13"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"expo": "*",
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-router": {
|
||||
"version": "6.0.23",
|
||||
"resolved": "https://registry.npmjs.org/expo-router/-/expo-router-6.0.23.tgz",
|
||||
@@ -7221,7 +7280,6 @@
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
|
||||
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-callable": "^1.2.7"
|
||||
@@ -7330,7 +7388,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
|
||||
"integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -7358,7 +7415,6 @@
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
@@ -7401,7 +7457,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
@@ -7550,7 +7605,6 @@
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -7591,7 +7645,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0"
|
||||
@@ -7620,7 +7673,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -7633,7 +7685,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
@@ -7898,6 +7949,22 @@
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-arguments": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz",
|
||||
"integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"has-tostringtag": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-array-buffer": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
|
||||
@@ -8014,7 +8081,6 @@
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
|
||||
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -8126,7 +8192,6 @@
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
|
||||
"integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.4",
|
||||
@@ -8167,6 +8232,22 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-nan": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz",
|
||||
"integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.0",
|
||||
"define-properties": "^1.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-negative-zero": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
|
||||
@@ -8206,11 +8287,19 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-obj": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
|
||||
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-regex": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
|
||||
"integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
@@ -8293,7 +8382,6 @@
|
||||
"version": "1.1.15",
|
||||
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
|
||||
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"which-typed-array": "^1.1.16"
|
||||
@@ -9246,7 +9334,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -9258,6 +9345,18 @@
|
||||
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/merge-options": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
|
||||
"integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-plain-obj": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
@@ -9916,11 +10015,26 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object-is": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
|
||||
"integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object-keys": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -9930,7 +10044,6 @@
|
||||
"version": "4.1.7",
|
||||
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
|
||||
"integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
@@ -10483,7 +10596,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
|
||||
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -11706,7 +11818,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
|
||||
"integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
@@ -11856,7 +11967,6 @@
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.1.4",
|
||||
@@ -13155,6 +13265,19 @@
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/util": {
|
||||
"version": "0.12.5",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
|
||||
"integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"is-arguments": "^1.0.4",
|
||||
"is-generator-function": "^1.0.7",
|
||||
"is-typed-array": "^1.1.3",
|
||||
"which-typed-array": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
@@ -13548,7 +13671,6 @@
|
||||
"version": "1.1.20",
|
||||
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz",
|
||||
"integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"available-typed-arrays": "^1.0.7",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/vector-icons": "^15.0.3",
|
||||
"@react-native-async-storage/async-storage": "2.2.0",
|
||||
"@react-navigation/bottom-tabs": "^7.4.0",
|
||||
"@react-navigation/elements": "^2.6.3",
|
||||
"@react-navigation/native": "^7.1.8",
|
||||
@@ -22,6 +23,7 @@
|
||||
"expo-haptics": "~15.0.8",
|
||||
"expo-image": "~3.0.11",
|
||||
"expo-linking": "~8.0.11",
|
||||
"expo-notifications": "~0.32.16",
|
||||
"expo-router": "~6.0.23",
|
||||
"expo-secure-store": "~15.0.8",
|
||||
"expo-splash-screen": "~31.0.13",
|
||||
|
||||
Reference in New Issue
Block a user