Feature/notification system #26
14 changed files with 1008 additions and 504 deletions
59
app/_layout.jsx
Normal file
59
app/_layout.jsx
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { router, Stack } from 'expo-router';
|
||||||
|
import { GlobalVariablesProvider, WebSocketProvider } from '../contexts';
|
||||||
|
import { useNotifications, useWebSocketContext } from '@/hooks';
|
||||||
|
|
||||||
|
export const unstable_settings = {
|
||||||
|
initialRouteName: 'login',
|
||||||
|
};
|
||||||
|
|
||||||
|
function AppTest() {
|
||||||
|
const [ oldMessage, setOldMessage ] = useState(1);
|
||||||
|
const { lastMessage } = useWebSocketContext();
|
||||||
|
const { schedulePushNotification } = useNotifications();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
router.replace('/login');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const parseAddress = (data) => {
|
||||||
|
const { Address } = data;
|
||||||
|
const { StreetAddress, AddressApartment, Town, State } = Address;
|
||||||
|
const response = `${StreetAddress}${AddressApartment ? ` - ${AddressApartment}` : ''} ${Town}, ${State}`
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (lastMessage) {
|
||||||
|
const parsedMessage = JSON?.parse(lastMessage);
|
||||||
|
if (parsedMessage?.data && new Date(oldMessage)?.getTime() < new Date(parsedMessage?.timestamp)?.getTime()) {
|
||||||
|
setOldMessage(new Date(parsedMessage?.timestamp)?.getTime());
|
||||||
|
schedulePushNotification(
|
||||||
|
`${parsedMessage?.data?.Response?.ServiceName} - ${parsedMessage?.data?.Incident?.IncNatureCode}`,
|
||||||
|
`${parsedMessage?.data?.Incident?.IncNature}\n${parseAddress(parsedMessage?.data)}`,
|
||||||
|
parsedMessage?.data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [lastMessage]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack
|
||||||
|
screenOptions={{
|
||||||
|
headerShown: false
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack.Screen name="login" />
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return (
|
||||||
|
<GlobalVariablesProvider>
|
||||||
|
<WebSocketProvider>
|
||||||
|
<AppTest />
|
||||||
|
</WebSocketProvider>
|
||||||
|
</GlobalVariablesProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
import React, { useEffect } from 'react';
|
|
||||||
import { router, Stack } from 'expo-router';
|
|
||||||
import { WebSocketProvider } from '../contexts/WebSocketContext';
|
|
||||||
|
|
||||||
export const unstable_settings = {
|
|
||||||
initialRouteName: 'login',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function App() {
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
router.replace('/login');
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<WebSocketProvider>
|
|
||||||
<Stack
|
|
||||||
screenOptions={{
|
|
||||||
headerShown: false
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Stack.Screen name="login" />
|
|
||||||
</Stack>
|
|
||||||
</WebSocketProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { useCallFeed } from '../hooks/useCallFeed';
|
import { useCallFeed } from '@/hooks';
|
||||||
import { router } from 'expo-router';
|
import { router } from 'expo-router';
|
||||||
import { Platform, Linking, View, ScrollView, Text, TouchableOpacity } from 'react-native';
|
import { Platform, Linking, View, ScrollView, Text, TouchableOpacity } from 'react-native';
|
||||||
import { StatusBar } from 'expo-status-bar';
|
import { StatusBar } from 'expo-status-bar';
|
||||||
|
|
@ -16,343 +16,343 @@ import ActionSheet from 'react-native-actions-sheet';
|
||||||
const DepartmentActionSheet = styled(ActionSheet)``;
|
const DepartmentActionSheet = styled(ActionSheet)``;
|
||||||
|
|
||||||
export default function Incidents() {
|
export default function Incidents() {
|
||||||
const actionSheetRef = useRef(null);
|
const actionSheetRef = useRef(null);
|
||||||
const callFeed = useCallFeed();
|
const callFeed = useCallFeed();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
departments,
|
departments,
|
||||||
callIconMap,
|
callIconMap,
|
||||||
callDetails,
|
callDetails,
|
||||||
callColorSelector,
|
callColorSelector,
|
||||||
formatCallTimePast,
|
formatCallTimePast,
|
||||||
formatCallDateTime
|
formatCallDateTime
|
||||||
} = callFeed;
|
} = callFeed;
|
||||||
|
|
||||||
const sortedAndFilteredCalls = callDetails
|
const sortedAndFilteredCalls = callDetails
|
||||||
.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))
|
.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))
|
||||||
.filter((item, index, self) => {
|
.filter((item, index, self) => {
|
||||||
return index === self.findIndex(i => {
|
return index === self.findIndex(i => {
|
||||||
return `${i?.data?.Incident?.IncID}${i?.data?.Response?.ServiceName}` === `${item?.data?.Incident?.IncID}${item?.data?.Response?.ServiceName}`
|
return `${i?.data?.Incident?.IncID}${i?.data?.Response?.ServiceName}` === `${item?.data?.Incident?.IncID}${item?.data?.Response?.ServiceName}`
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
departmentTypeMap,
|
departmentTypeMap,
|
||||||
accountDetails,
|
accountDetails,
|
||||||
deptList,
|
deptList,
|
||||||
setDeptList,
|
setDeptList,
|
||||||
selectedDepartment,
|
selectedDepartment,
|
||||||
setSelectedDepartment,
|
setSelectedDepartment,
|
||||||
updateSelectedDepartment,
|
updateSelectedDepartment,
|
||||||
selectedDepartmentColorPicker,
|
selectedDepartmentColorPicker,
|
||||||
} = departments;
|
} = departments;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<PageHeader>
|
<PageHeader>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
height: 80,
|
height: 80,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'flex-end',
|
justifyContent: 'flex-end',
|
||||||
paddingBottom: 7
|
paddingBottom: 7
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={{
|
||||||
|
borderRadius: 6,
|
||||||
|
elevation: 3,
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
shadowOffset: { width: 0, height: 0 },
|
||||||
|
shadowColor: '#333',
|
||||||
|
shadowOpacity: .8,
|
||||||
|
shadowRadius: 2,
|
||||||
|
paddingHorizontal: 10,
|
||||||
|
paddingVertical: 2,
|
||||||
|
}}
|
||||||
|
onPress={() => {
|
||||||
|
actionSheetRef.current?.show();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
color: selectedDepartmentColorPicker(selectedDepartment?.type),
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: 14
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{selectedDepartment?.deptAbv}
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</PageHeader>
|
||||||
|
<ScrollView>
|
||||||
|
<StatusBar style="dark" />
|
||||||
|
<SafeAreaView />
|
||||||
|
<View style={{ flexDirection: 'column', padding: 20 }}>
|
||||||
|
{sortedAndFilteredCalls?.length ? (
|
||||||
|
sortedAndFilteredCalls?.map((callItem, index) => {
|
||||||
|
const { data: call, timestamp } = callItem;
|
||||||
|
const { Incident, Address, Response } = call;
|
||||||
|
const {
|
||||||
|
ServiceNumber,
|
||||||
|
IncDate,
|
||||||
|
IncNature,
|
||||||
|
IncNatureCode,
|
||||||
|
IncNatureCodeDesc,
|
||||||
|
Status,
|
||||||
|
} = Incident;
|
||||||
|
const {
|
||||||
|
StreetAddress,
|
||||||
|
AddressApartment,
|
||||||
|
Town,
|
||||||
|
State,
|
||||||
|
LocationName,
|
||||||
|
} = Address;
|
||||||
|
const {
|
||||||
|
ServiceName
|
||||||
|
} = Response;
|
||||||
|
const SelectedIcon = callIconMap[IncNature] || AccidentAndEmergency;
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
key={`callDetails - ${timestamp}`}
|
||||||
|
style={{ padding: 2 }}
|
||||||
|
onPress={() => {
|
||||||
|
router.push({
|
||||||
|
pathname: '/call',
|
||||||
|
params: {
|
||||||
|
callDetails: btoa(JSON.stringify(call))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<TouchableOpacity
|
<View
|
||||||
style={{
|
style={{
|
||||||
borderRadius: 6,
|
borderRadius: 12,
|
||||||
elevation: 3,
|
elevation: 3,
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
shadowOffset: { width: 0, height: 0 },
|
shadowOffset: { width: 0, height: 0 },
|
||||||
shadowColor: '#333',
|
shadowColor: callColorSelector(
|
||||||
shadowOpacity: .8,
|
IncNatureCode,
|
||||||
shadowRadius: 2,
|
IncNature,
|
||||||
paddingHorizontal: 10,
|
Status
|
||||||
paddingVertical: 2,
|
),
|
||||||
|
shadowOpacity: 1,
|
||||||
|
shadowRadius: 5,
|
||||||
|
padding: 10,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View style={{ flexDirection: 'column' }}>
|
||||||
|
<View key="callDateAndTime"
|
||||||
|
style={{
|
||||||
|
paddingBottom: 6,
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between'
|
||||||
}}
|
}}
|
||||||
onPress={() => {
|
>
|
||||||
actionSheetRef.current?.show();
|
<Text style={{ fontSize: 12 }}>{formatCallDateTime(IncDate)}</Text>
|
||||||
}}
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||||
>
|
<Text style={{ fontSize: 12 }}>{formatCallTimePast(IncDate)}</Text>
|
||||||
<Text
|
{Status === 'CLOSED' ? (
|
||||||
|
<Ionicons
|
||||||
|
name="lock-closed-outline"
|
||||||
|
color='red'
|
||||||
|
style={{
|
||||||
|
shadowColor: 'black',
|
||||||
|
shadowOffset: 0,
|
||||||
|
shadowOpacity: 1,
|
||||||
|
shadowRadius: 10
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||||
|
<SelectedIcon
|
||||||
|
color={callColorSelector(
|
||||||
|
IncNatureCode,
|
||||||
|
IncNature,
|
||||||
|
Status
|
||||||
|
)}
|
||||||
|
opacity={0.3}
|
||||||
|
width={56}
|
||||||
|
height={56}
|
||||||
|
/>
|
||||||
|
<View style={{ flexDirection: 'column' }}>
|
||||||
|
{LocationName ? (
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
color: 'black',
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: 16
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{`${LocationName}`}
|
||||||
|
</Text>
|
||||||
|
) : (
|
||||||
|
<View style={{ flexDirection: 'row' }}>
|
||||||
|
<Text
|
||||||
|
style={[{
|
||||||
|
color: 'black',
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: 600
|
||||||
|
}]}
|
||||||
|
>
|
||||||
|
{`${StreetAddress}`}
|
||||||
|
</Text>
|
||||||
|
{AddressApartment ? (
|
||||||
|
<Text
|
||||||
|
style={[{
|
||||||
|
color: 'black',
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: 600
|
||||||
|
}]}
|
||||||
|
>
|
||||||
|
{` - ${AddressApartment}`}
|
||||||
|
</Text>
|
||||||
|
) : null }
|
||||||
|
<Text
|
||||||
|
style={[{
|
||||||
|
color: 'black',
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: 600
|
||||||
|
}]}
|
||||||
|
>
|
||||||
|
{` ${Town}, ${State}`}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
<Text
|
||||||
style={{
|
style={{
|
||||||
color: selectedDepartmentColorPicker(selectedDepartment?.type),
|
color: 'black',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
fontSize: 14
|
fontSize: 16
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{`${IncNature}`}
|
||||||
|
</Text>
|
||||||
|
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
color: 'black',
|
||||||
|
fontSize: 12,
|
||||||
|
textShadowColor: callColorSelector(
|
||||||
|
IncNatureCode,
|
||||||
|
IncNature,
|
||||||
|
Status
|
||||||
|
),
|
||||||
|
textShadowRadius: 1
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{`${IncNatureCodeDesc}`}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={{ padding: 0 }}>
|
||||||
|
<View>
|
||||||
|
<Ionicons name="chevron-forward-outline" />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontSize: 12,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Service: {ServiceName}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontSize: 12,
|
||||||
|
textAlign: 'right'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{`Incident #: ${ServiceNumber}`}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)
|
||||||
|
})) : (
|
||||||
|
<Text>There are no Calls</Text>
|
||||||
|
) }
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
<PageFooter>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: 'column',
|
||||||
|
height: 100,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
paddingTop: 7
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</PageFooter>
|
||||||
|
<DepartmentActionSheet
|
||||||
|
ref={actionSheetRef}
|
||||||
|
gestureEnabled
|
||||||
|
containerStyle={{
|
||||||
|
height: "50%",
|
||||||
|
width: "100%",
|
||||||
|
backgroundColor: '#ECEDEE',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View style={{ flexDirection: 'column', padding: 20 }}>
|
||||||
|
{deptList?.map((item) => {
|
||||||
|
return (
|
||||||
|
<View style={{ padding: 2 }} key={item?.deptId}>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={{
|
||||||
|
borderRadius: 6,
|
||||||
|
elevation: 3,
|
||||||
|
backgroundColor: item?.selected ? 'grey' : '#fff',
|
||||||
|
shadowOffset: { width: 1, height: 1 },
|
||||||
|
shadowColor: '#333',
|
||||||
|
shadowOpacity: 0.3,
|
||||||
|
shadowRadius: 2,
|
||||||
|
marginHorizontal: 20,
|
||||||
|
marginVertical: 6,
|
||||||
|
padding: 10
|
||||||
|
}}
|
||||||
|
onPress={() => {
|
||||||
|
actionSheetRef.current?.hide();
|
||||||
|
return updateSelectedDepartment(
|
||||||
|
selectedDepartment?.deptId,
|
||||||
|
item?.deptId
|
||||||
|
)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{selectedDepartment?.deptAbv}
|
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
||||||
</Text>
|
<Text
|
||||||
</TouchableOpacity>
|
style={{
|
||||||
</View>
|
color: selectedDepartmentColorPicker(
|
||||||
</PageHeader>
|
item?.type
|
||||||
<ScrollView>
|
),
|
||||||
<StatusBar style="dark" />
|
fontWeight: 600,
|
||||||
<SafeAreaView />
|
fontSize: 16
|
||||||
<View style={{ flexDirection: 'column', padding: 20 }}>
|
|
||||||
{sortedAndFilteredCalls?.length ? (
|
|
||||||
sortedAndFilteredCalls?.map((callItem, index) => {
|
|
||||||
const { data: call, timestamp } = callItem;
|
|
||||||
const { Incident, Address, Response } = call;
|
|
||||||
const {
|
|
||||||
ServiceNumber,
|
|
||||||
IncDate,
|
|
||||||
IncNature,
|
|
||||||
IncNatureCode,
|
|
||||||
IncNatureCodeDesc,
|
|
||||||
Status,
|
|
||||||
} = Incident;
|
|
||||||
const {
|
|
||||||
StreetAddress,
|
|
||||||
AddressApartment,
|
|
||||||
Town,
|
|
||||||
State,
|
|
||||||
LocationName,
|
|
||||||
} = Address;
|
|
||||||
const {
|
|
||||||
ServiceName
|
|
||||||
} = Response;
|
|
||||||
const SelectedIcon = callIconMap[IncNature] || AccidentAndEmergency;
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
key={`callDetails - ${timestamp}`}
|
|
||||||
style={{ padding: 2 }}
|
|
||||||
onPress={() => {
|
|
||||||
router.push({
|
|
||||||
pathname: '/call',
|
|
||||||
params: {
|
|
||||||
callDetails: btoa(JSON.stringify(call))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
borderRadius: 12,
|
|
||||||
elevation: 3,
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
shadowOffset: { width: 0, height: 0 },
|
|
||||||
shadowColor: callColorSelector(
|
|
||||||
IncNatureCode,
|
|
||||||
IncNature,
|
|
||||||
Status
|
|
||||||
),
|
|
||||||
shadowOpacity: 1,
|
|
||||||
shadowRadius: 5,
|
|
||||||
padding: 10,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View style={{ flexDirection: 'column' }}>
|
{item?.dept}
|
||||||
<View key="callDateAndTime"
|
</Text>
|
||||||
style={{
|
{item?.primary ? <Ionicons name="star" size={16} color="yellow" style={{
|
||||||
paddingBottom: 6,
|
paddingLeft: 20,
|
||||||
flexDirection: 'row',
|
shadowColor: '#333',
|
||||||
justifyContent: 'space-between'
|
shadowOffset: 1,
|
||||||
}}
|
shadowOpacity: 1,
|
||||||
>
|
shadowRadius: 6
|
||||||
<Text style={{ fontSize: 12 }}>{formatCallDateTime(IncDate)}</Text>
|
}} /> : null}
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
||||||
<Text style={{ fontSize: 12 }}>{formatCallTimePast(IncDate)}</Text>
|
|
||||||
{Status === 'CLOSED' ? (
|
|
||||||
<Ionicons
|
|
||||||
name="lock-closed-outline"
|
|
||||||
color='red'
|
|
||||||
style={{
|
|
||||||
shadowColor: 'black',
|
|
||||||
shadowOffset: 0,
|
|
||||||
shadowOpacity: 1,
|
|
||||||
shadowRadius: 10
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
||||||
<SelectedIcon
|
|
||||||
color={callColorSelector(
|
|
||||||
IncNatureCode,
|
|
||||||
IncNature,
|
|
||||||
Status
|
|
||||||
)}
|
|
||||||
opacity={0.3}
|
|
||||||
width={56}
|
|
||||||
height={56}
|
|
||||||
/>
|
|
||||||
<View style={{ flexDirection: 'column' }}>
|
|
||||||
{LocationName ? (
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
color: 'black',
|
|
||||||
fontWeight: 600,
|
|
||||||
fontSize: 16
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{`${LocationName}`}
|
|
||||||
</Text>
|
|
||||||
) : (
|
|
||||||
<View style={{ flexDirection: 'row' }}>
|
|
||||||
<Text
|
|
||||||
style={[{
|
|
||||||
color: 'black',
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: 600
|
|
||||||
}]}
|
|
||||||
>
|
|
||||||
{`${StreetAddress}`}
|
|
||||||
</Text>
|
|
||||||
{AddressApartment ? (
|
|
||||||
<Text
|
|
||||||
style={[{
|
|
||||||
color: 'black',
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: 600
|
|
||||||
}]}
|
|
||||||
>
|
|
||||||
{` - ${AddressApartment}`}
|
|
||||||
</Text>
|
|
||||||
) : null }
|
|
||||||
<Text
|
|
||||||
style={[{
|
|
||||||
color: 'black',
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: 600
|
|
||||||
}]}
|
|
||||||
>
|
|
||||||
{` ${Town}, ${State}`}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
color: 'black',
|
|
||||||
fontWeight: 600,
|
|
||||||
fontSize: 16
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{`${IncNature}`}
|
|
||||||
</Text>
|
|
||||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
color: 'black',
|
|
||||||
fontSize: 12,
|
|
||||||
textShadowColor: callColorSelector(
|
|
||||||
IncNatureCode,
|
|
||||||
IncNature,
|
|
||||||
Status
|
|
||||||
),
|
|
||||||
textShadowRadius: 1
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{`${IncNatureCodeDesc}`}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<View style={{ padding: 0 }}>
|
|
||||||
<View>
|
|
||||||
<Ionicons name="chevron-forward-outline" />
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
fontSize: 12,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Service: {ServiceName}
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
fontSize: 12,
|
|
||||||
textAlign: 'right'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{`Incident #: ${ServiceNumber}`}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)
|
|
||||||
})) : (
|
|
||||||
<Text>There are no Calls</Text>
|
|
||||||
) }
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
<PageFooter>
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
flexDirection: 'column',
|
|
||||||
height: 100,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'flex-start',
|
|
||||||
paddingTop: 7
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</PageFooter>
|
|
||||||
<DepartmentActionSheet
|
|
||||||
ref={actionSheetRef}
|
|
||||||
gestureEnabled
|
|
||||||
containerStyle={{
|
|
||||||
height: "50%",
|
|
||||||
width: "100%",
|
|
||||||
backgroundColor: '#ECEDEE',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View style={{ flexDirection: 'column', padding: 20 }}>
|
|
||||||
{deptList?.map((item) => {
|
|
||||||
return (
|
|
||||||
<View style={{ padding: 2 }} key={item?.deptId}>
|
|
||||||
<TouchableOpacity
|
|
||||||
style={{
|
|
||||||
borderRadius: 6,
|
|
||||||
elevation: 3,
|
|
||||||
backgroundColor: item?.selected ? 'grey' : '#fff',
|
|
||||||
shadowOffset: { width: 1, height: 1 },
|
|
||||||
shadowColor: '#333',
|
|
||||||
shadowOpacity: 0.3,
|
|
||||||
shadowRadius: 2,
|
|
||||||
marginHorizontal: 20,
|
|
||||||
marginVertical: 6,
|
|
||||||
padding: 10
|
|
||||||
}}
|
|
||||||
onPress={() => {
|
|
||||||
actionSheetRef.current?.hide();
|
|
||||||
return updateSelectedDepartment(
|
|
||||||
selectedDepartment?.deptId,
|
|
||||||
item?.deptId
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
color: selectedDepartmentColorPicker(
|
|
||||||
item?.type
|
|
||||||
),
|
|
||||||
fontWeight: 600,
|
|
||||||
fontSize: 16
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item?.dept}
|
|
||||||
</Text>
|
|
||||||
{item?.primary ? <Ionicons name="star" size={16} color="yellow" style={{
|
|
||||||
paddingLeft: 20,
|
|
||||||
shadowColor: '#333',
|
|
||||||
shadowOffset: 1,
|
|
||||||
shadowOpacity: 1,
|
|
||||||
shadowRadius: 6
|
|
||||||
}} /> : null}
|
|
||||||
</View>
|
|
||||||
<Text>{`${item?.deptAbv} - ${departmentTypeMap[item?.type]}`}</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
</View>
|
||||||
);
|
<Text>{`${item?.deptAbv} - ${departmentTypeMap[item?.type]}`}</Text>
|
||||||
})}
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
</DepartmentActionSheet>
|
);
|
||||||
</React.Fragment>
|
})}
|
||||||
)
|
</View>
|
||||||
|
</DepartmentActionSheet>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
35
contexts/GlobalVariablesContext.js
Normal file
35
contexts/GlobalVariablesContext.js
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
import React, { createContext, useEffect, useState } from 'react';
|
||||||
|
import { AppState } from 'react-native';
|
||||||
|
|
||||||
|
export const GlobalVariablesContext = createContext(null);
|
||||||
|
|
||||||
|
export const GlobalVariablesProvider = ({ children }) => {
|
||||||
|
const [appState, setAppState] = useState(AppState.currentState);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleAppStateChange = (nextAppState) => {
|
||||||
|
if (appState.match(/active/) && nextAppState.match(/inactive|background/)) {
|
||||||
|
console.log('App is in background or inactive');
|
||||||
|
} else if (appState.match(/inactive|background/) && nextAppState === 'active') {
|
||||||
|
console.log('App is in the foreground');
|
||||||
|
}
|
||||||
|
setAppState(nextAppState);
|
||||||
|
};
|
||||||
|
const subscription = AppState.addEventListener('change', handleAppStateChange);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
subscription.remove();
|
||||||
|
};
|
||||||
|
}, [appState]);
|
||||||
|
|
||||||
|
const exportedVariables = {
|
||||||
|
appState,
|
||||||
|
setAppState
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GlobalVariablesContext.Provider value={exportedVariables}>
|
||||||
|
{children}
|
||||||
|
</GlobalVariablesContext.Provider>
|
||||||
|
)
|
||||||
|
};
|
||||||
2
contexts/index.js
Normal file
2
contexts/index.js
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
export { GlobalVariablesProvider, GlobalVariablesContext } from './GlobalVariablesContext';
|
||||||
|
export { WebSocketProvider, WebSocketContext } from './WebSocketContext';
|
||||||
|
|
@ -1,2 +1,5 @@
|
||||||
export { useCallFeed } from './useCallFeed';
|
export { useCallFeed } from './useCallFeed';
|
||||||
export { useDepartments } from './useDepartments';
|
export { useDepartments } from './useDepartments';
|
||||||
|
export { useGlobalVariablesContext } from './useGlobalVariablesContext';
|
||||||
|
export { useNotifications } from './useNotifications';
|
||||||
|
export { useWebSocketContext } from './useWebSocketContext';
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useDepartments } from '../useDepartments';
|
import { useDepartments } from '../useDepartments';
|
||||||
import { C, Cardiology, Cpr, FourByFour } from "healthicons-react-native/dist/outline";
|
import { C, Cardiology, Cpr, FourByFour } from "healthicons-react-native/dist/outline";
|
||||||
import { useWebSocketContext } from '../useWebSocketContext';
|
import { useNotifications, useWebSocketContext } from '@/hooks';
|
||||||
|
|
||||||
const callIconMap = {
|
const callIconMap = {
|
||||||
"CHEST PAIN|HEART PROBLEMS": Cardiology,
|
"CHEST PAIN|HEART PROBLEMS": Cardiology,
|
||||||
|
|
@ -37,119 +37,6 @@ const callIconMap = {
|
||||||
// Bacteria - Sick
|
// Bacteria - Sick
|
||||||
// RuralClinic - Medical Facility Response
|
// RuralClinic - Medical Facility Response
|
||||||
|
|
||||||
const callDetails = {
|
|
||||||
"Incident": {
|
|
||||||
"IncID": 75,
|
|
||||||
"IncNumber": 6873,
|
|
||||||
"JurisdictionNumber": 3,
|
|
||||||
"ServiceNumber": 42,
|
|
||||||
"ServiceID": 45,
|
|
||||||
"IncDate": "2024-09-25T01:01:01.55",
|
|
||||||
// "IncNature": "CHEST PAIN|HEART PROBLEMS",
|
|
||||||
"IncNature": "MOTOR VEHICLE COLLISION (MVC)",
|
|
||||||
// "IncNature": "CARDIAC ARREST|DEATH",
|
|
||||||
"IncNatureCode": "ALS",
|
|
||||||
"IncNatureCodeDesc": "ALS PRIORITY (ALS)",
|
|
||||||
"Notes": "570, 16:30> 311 Responding\n580, 16:25> Call Dispatched",
|
|
||||||
"Status": "OPEN",
|
|
||||||
"Origin": "911"
|
|
||||||
},
|
|
||||||
"Address": {
|
|
||||||
"StreetAddress": "275 E Main St",
|
|
||||||
"AddressApartment": "IFO",
|
|
||||||
"Town": "Bridgeport",
|
|
||||||
"State": "CT",
|
|
||||||
"ZipCode": "06608",
|
|
||||||
"Latitude": 41.178435683035445,
|
|
||||||
"Longitude": -73.18194442701176,
|
|
||||||
"County": "Fairfield",
|
|
||||||
"Intersection1": "E MAIN ST",
|
|
||||||
"Intersection2": "STRATFORD AVE",
|
|
||||||
"LocationName": "Chipotle Mexican Grill",
|
|
||||||
"WeatherCondition": "Foggy"
|
|
||||||
},
|
|
||||||
"Person": {
|
|
||||||
"Name": "John Doe",
|
|
||||||
"Age": 19,
|
|
||||||
"Gender": "Female",
|
|
||||||
"Statement": "BLOOD PRESSURE 56/41 - IN AND OUT OF CON",
|
|
||||||
"Conscious": "No",
|
|
||||||
"Breathing": "Yes",
|
|
||||||
"CallBackNumber": "(223) 456-7890"
|
|
||||||
},
|
|
||||||
"Response": {
|
|
||||||
"IncID": 75,
|
|
||||||
"ResponseID": 75,
|
|
||||||
"ServiceID": 45,
|
|
||||||
"ServiceName": "DARIEN EMS",
|
|
||||||
"Units": [
|
|
||||||
{
|
|
||||||
"Unit": 311,
|
|
||||||
"Department": 'Darien EMS',
|
|
||||||
"Dispatched": "2024-09-25T01:01:01.55",
|
|
||||||
"Responding": "2024-09-25T01:02:02.55",
|
|
||||||
"OnScene": "2024-09-25T01:10:10.55",
|
|
||||||
"Transporting": "2024-09-25T01:25:01.55",
|
|
||||||
"InService": "2024-09-25T02:00:01.55",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Unit": 315,
|
|
||||||
"Department": 'Darien EMS Supv',
|
|
||||||
"Dispatched": "2024-09-25T01:01:01.55",
|
|
||||||
"Responding": "2024-09-25T01:03:03.15",
|
|
||||||
"OnScene": "2024-09-25T01:11:11.55",
|
|
||||||
"Transporting": null,
|
|
||||||
"InService": "2024-09-25T02:10:01.55",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Unit": 310,
|
|
||||||
"Department": 'Darien EMS',
|
|
||||||
"Dispatched": "2024-09-25T01:01:01.55",
|
|
||||||
"Responding": "2024-09-25T01:01:01.55",
|
|
||||||
"OnScene": "2024-09-25T01:06:06.55",
|
|
||||||
"Transporting": "2024-09-25T01:25:01.55",
|
|
||||||
"InService": "2024-09-25T02:15:01.55",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Unit": 'NHT20',
|
|
||||||
"Department": 'Noroton Heights Fire Department',
|
|
||||||
"Dispatched": "2024-09-25T01:01:01.55",
|
|
||||||
"Responding": "2024-09-25T01:08:08.55",
|
|
||||||
"OnScene": "2024-09-25T01:12:12.55",
|
|
||||||
"Transporting": null,
|
|
||||||
"InService": "2024-09-25T01:01:01.55",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Unit": 'NFDE31',
|
|
||||||
"Department": 'Noroton Fire Department',
|
|
||||||
"Dispatched": "2024-09-25T01:01:01.55",
|
|
||||||
"Responding": "2024-09-25T01:07:07.55",
|
|
||||||
"OnScene": "2024-09-25T01:14:14.55",
|
|
||||||
"Transporting": null,
|
|
||||||
"InService": "2024-09-25T01:01:01.55",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Unit": 'DFDT43',
|
|
||||||
"Department": 'Darien Fire Department',
|
|
||||||
"Dispatched": "2024-09-25T01:01:01.55",
|
|
||||||
"Responding": "2024-09-25T01:10:10.55",
|
|
||||||
"OnScene": "2024-09-25T01:18:18.55",
|
|
||||||
"Transporting": null,
|
|
||||||
"InService": "2024-09-25T01:01:01.55",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Unit": 1514,
|
|
||||||
"Department": 'Greenwich EMS',
|
|
||||||
"Dispatched": "2024-09-25T01:15:15.55",
|
|
||||||
"Responding": "2024-09-25T01:30:30.55",
|
|
||||||
"OnScene": "2024-09-25T01:45:45.55",
|
|
||||||
"Transporting": "2024-09-25T02:05:15.55",
|
|
||||||
"InService": "2024-09-25T02:25:01.55",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatCallTimePast = (callValue) => {
|
const formatCallTimePast = (callValue) => {
|
||||||
const initDate = new Date(callValue);
|
const initDate = new Date(callValue);
|
||||||
const currentTime = new Date();
|
const currentTime = new Date();
|
||||||
|
|
@ -173,20 +60,20 @@ const formatCallTimePast = (callValue) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatCallDateTime = (callValue) => {
|
const formatCallDateTime = (callValue) => {
|
||||||
const initDate = new Date(callValue);
|
const initDate = new Date(callValue);
|
||||||
if (initDate) {
|
if (initDate) {
|
||||||
const formattedDate = `${initDate.toLocaleDateString('en-US', {
|
const formattedDate = `${initDate.toLocaleDateString('en-US', {
|
||||||
month: 'short',
|
month: 'short',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
})}`;
|
})}`;
|
||||||
const hours = initDate.getHours().toString().padStart(2, '0');
|
const hours = initDate.getHours().toString().padStart(2, '0');
|
||||||
const minutes = initDate.getMinutes().toString().padStart(2, '0');
|
const minutes = initDate.getMinutes().toString().padStart(2, '0');
|
||||||
const formattedTime = `${hours}:${minutes}`;
|
const formattedTime = `${hours}:${minutes}`;
|
||||||
|
|
||||||
return `${formattedDate} - ${formattedTime}`;
|
return `${formattedDate} - ${formattedTime}`;
|
||||||
}
|
}
|
||||||
return 'Date Unavailable';
|
return 'Date Unavailable';
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useCallFeed = () => {
|
export const useCallFeed = () => {
|
||||||
|
|
@ -195,34 +82,34 @@ export const useCallFeed = () => {
|
||||||
const [allCalls, setAllCalls] = useState([]);
|
const [allCalls, setAllCalls] = useState([]);
|
||||||
const { CallThemes } = departments?.accountDetails;
|
const { CallThemes } = departments?.accountDetails;
|
||||||
const {
|
const {
|
||||||
CriticalCallList,
|
CriticalCallList,
|
||||||
HighCallList,
|
HighCallList,
|
||||||
MediumCallList,
|
MediumCallList,
|
||||||
LowCallList,
|
LowCallList,
|
||||||
} = CallThemes;
|
} = CallThemes;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (lastMessage) {
|
if (lastMessage) {
|
||||||
const parsedMessage = JSON?.parse(lastMessage);
|
const parsedMessage = JSON?.parse(lastMessage);
|
||||||
if (parsedMessage?.data) {
|
if (parsedMessage?.data) {
|
||||||
setAllCalls([...allCalls, parsedMessage]);
|
setAllCalls([...allCalls, parsedMessage]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}, [lastMessage]);
|
}, [lastMessage]);
|
||||||
|
|
||||||
const callColorSelector = (callAcuity, cardiacArrestCall, status) => {
|
const callColorSelector = (callAcuity, cardiacArrestCall, status) => {
|
||||||
if (status === 'CLOSED') {
|
if (status === 'CLOSED') {
|
||||||
return '#0000CD';
|
return '#0000CD';
|
||||||
} else if (CriticalCallList.includes(cardiacArrestCall)) {
|
} else if (CriticalCallList.includes(cardiacArrestCall)) {
|
||||||
return '#8B0000';
|
return '#8B0000';
|
||||||
} else if (HighCallList.includes(callAcuity)) {
|
} else if (HighCallList.includes(callAcuity)) {
|
||||||
return "#FF0000";
|
return "#FF0000";
|
||||||
} else if (MediumCallList.includes(callAcuity)) {
|
} else if (MediumCallList.includes(callAcuity)) {
|
||||||
return "#FF8C00";
|
return "#FF8C00";
|
||||||
} else if (LowCallList.includes(callAcuity)) {
|
} else if (LowCallList.includes(callAcuity)) {
|
||||||
return "#228B22";
|
return "#228B22";
|
||||||
}
|
}
|
||||||
return 'grey';
|
return 'grey';
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
1
hooks/useGlobalVariablesContext/index.js
Normal file
1
hooks/useGlobalVariablesContext/index.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { useGlobalVariablesContext } from './useGlobalVariablesContext';
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { GlobalVariablesContext } from '../../contexts';
|
||||||
|
|
||||||
|
export const useGlobalVariablesContext = () => useContext(GlobalVariablesContext);
|
||||||
1
hooks/useNotifications/index.js
Normal file
1
hooks/useNotifications/index.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { useNotifications } from './useNotifications';
|
||||||
115
hooks/useNotifications/useNotifications.jsx
Normal file
115
hooks/useNotifications/useNotifications.jsx
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
|
||||||
|
import { useState, useEffect, useRef } from 'react';
|
||||||
|
import { Platform } from 'react-native';
|
||||||
|
import * as Device from 'expo-device';
|
||||||
|
import * as Notifications from 'expo-notifications';
|
||||||
|
import Constants from 'expo-constants';
|
||||||
|
|
||||||
|
Notifications.setNotificationHandler({
|
||||||
|
handleNotification: async () => ({
|
||||||
|
shouldShowAlert: true,
|
||||||
|
shouldPlaySound: false,
|
||||||
|
shouldSetBadge: false,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const schedulePushNotification = async (title, body, dataObj) => {
|
||||||
|
await Notifications.scheduleNotificationAsync({
|
||||||
|
content: {
|
||||||
|
title,
|
||||||
|
body,
|
||||||
|
data: { data: dataObj },
|
||||||
|
},
|
||||||
|
trigger: {
|
||||||
|
type: Notifications.SchedulableTriggerInputTypes.TIME_INTERVAL,
|
||||||
|
seconds: 2,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const registerForPushNotificationsAsync = async () => {
|
||||||
|
let token;
|
||||||
|
|
||||||
|
if (Platform.OS === 'android') {
|
||||||
|
await Notifications.setNotificationChannelAsync('myNotificationChannel', {
|
||||||
|
name: 'A channel is needed for the permissions prompt to appear',
|
||||||
|
importance: Notifications.AndroidImportance.MAX,
|
||||||
|
vibrationPattern: [0, 250, 250, 250],
|
||||||
|
lightColor: '#FF231F7C',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Device.isDevice) {
|
||||||
|
const { status: existingStatus } = await Notifications.getPermissionsAsync();
|
||||||
|
let finalStatus = existingStatus;
|
||||||
|
if (existingStatus !== 'granted') {
|
||||||
|
const { status } = await Notifications.requestPermissionsAsync();
|
||||||
|
finalStatus = status;
|
||||||
|
}
|
||||||
|
if (finalStatus !== 'granted') {
|
||||||
|
alert('Failed to get push token for push notification!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Learn more about projectId:
|
||||||
|
// https://docs.expo.dev/push-notifications/push-notifications-setup/#configure-projectid
|
||||||
|
// EAS projectId is used here.
|
||||||
|
try {
|
||||||
|
const projectId =
|
||||||
|
Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId;
|
||||||
|
if (!projectId) {
|
||||||
|
throw new Error('Project ID not found');
|
||||||
|
}
|
||||||
|
token = (
|
||||||
|
await Notifications.getExpoPushTokenAsync({
|
||||||
|
projectId,
|
||||||
|
})
|
||||||
|
).data;
|
||||||
|
console.log(token);
|
||||||
|
} catch (e) {
|
||||||
|
token = `${e}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert('Must use physical device for Push Notifications');
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useNotifications = () => {
|
||||||
|
const [expoPushToken, setExpoPushToken] = useState('');
|
||||||
|
const [channels, setChannels] = useState([]);
|
||||||
|
const [notification, setNotification] = useState(undefined);
|
||||||
|
const notificationListener = useRef();
|
||||||
|
const responseListener = useRef();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
registerForPushNotificationsAsync().then(token => token && setExpoPushToken(token));
|
||||||
|
|
||||||
|
if (Platform.OS === 'android') {
|
||||||
|
Notifications.getNotificationChannelsAsync().then(value => setChannels(value ?? []));
|
||||||
|
}
|
||||||
|
notificationListener.current = Notifications.addNotificationReceivedListener(notification => {
|
||||||
|
setNotification(notification);
|
||||||
|
});
|
||||||
|
|
||||||
|
responseListener.current = Notifications.addNotificationResponseReceivedListener(response => {
|
||||||
|
console.log(response);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
notificationListener.current &&
|
||||||
|
Notifications.removeNotificationSubscription(notificationListener.current);
|
||||||
|
responseListener.current &&
|
||||||
|
Notifications.removeNotificationSubscription(responseListener.current);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return ({
|
||||||
|
schedulePushNotification: async (title, body, dataObj) => {
|
||||||
|
await schedulePushNotification(title, body, dataObj);
|
||||||
|
},
|
||||||
|
expoPushToken,
|
||||||
|
expoNotificationChannels: channels,
|
||||||
|
expoNotification: notification,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { WebSocketContext } from '../../contexts/WebSocketContext';
|
import { WebSocketContext } from '../../contexts';
|
||||||
|
|
||||||
export const useWebSocketContext = () => useContext(WebSocketContext);
|
export const useWebSocketContext = () => useContext(WebSocketContext);
|
||||||
|
|
|
||||||
421
package-lock.json
generated
421
package-lock.json
generated
|
|
@ -12,8 +12,10 @@
|
||||||
"@react-navigation/native": "^6.0.2",
|
"@react-navigation/native": "^6.0.2",
|
||||||
"expo": "^52.0.46",
|
"expo": "^52.0.46",
|
||||||
"expo-constants": "~17.0.8",
|
"expo-constants": "~17.0.8",
|
||||||
|
"expo-device": "^7.0.3",
|
||||||
"expo-font": "~13.0.4",
|
"expo-font": "~13.0.4",
|
||||||
"expo-linking": "~7.0.5",
|
"expo-linking": "~7.0.5",
|
||||||
|
"expo-notifications": "^0.29.14",
|
||||||
"expo-router": "~4.0.20",
|
"expo-router": "~4.0.20",
|
||||||
"expo-splash-screen": "~0.29.24",
|
"expo-splash-screen": "~0.29.24",
|
||||||
"expo-status-bar": "~2.0.1",
|
"expo-status-bar": "~2.0.1",
|
||||||
|
|
@ -2908,6 +2910,12 @@
|
||||||
"js-yaml": "bin/js-yaml.js"
|
"js-yaml": "bin/js-yaml.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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/cliui": {
|
"node_modules/@isaacs/cliui": {
|
||||||
"version": "8.0.2",
|
"version": "8.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||||
|
|
@ -4750,6 +4758,19 @@
|
||||||
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
|
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
|
||||||
"license": "MIT"
|
"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/ast-types": {
|
"node_modules/ast-types": {
|
||||||
"version": "0.15.2",
|
"version": "0.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.15.2.tgz",
|
||||||
|
|
@ -4783,6 +4804,21 @@
|
||||||
"node": ">= 4.0.0"
|
"node": ">= 4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/available-typed-arrays": {
|
||||||
|
"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==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"possible-typed-array-names": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/babel-core": {
|
"node_modules/babel-core": {
|
||||||
"version": "7.0.0-bridge.0",
|
"version": "7.0.0-bridge.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
|
||||||
|
|
@ -5009,6 +5045,12 @@
|
||||||
"@babel/core": "^7.0.0"
|
"@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": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
|
|
@ -5253,6 +5295,24 @@
|
||||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/call-bind": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.0",
|
||||||
|
"es-define-property": "^1.0.0",
|
||||||
|
"get-intrinsic": "^1.2.4",
|
||||||
|
"set-function-length": "^1.2.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/call-bind-apply-helpers": {
|
"node_modules/call-bind-apply-helpers": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||||
|
|
@ -5266,6 +5326,22 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/call-bound": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
|
"get-intrinsic": "^1.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/caller-callsite": {
|
"node_modules/caller-callsite": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
|
||||||
|
|
@ -6080,6 +6156,23 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/define-data-property": {
|
||||||
|
"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==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-define-property": "^1.0.0",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"gopd": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/define-lazy-prop": {
|
"node_modules/define-lazy-prop": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
|
||||||
|
|
@ -6089,6 +6182,23 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/define-properties": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"define-data-property": "^1.0.1",
|
||||||
|
"has-property-descriptors": "^1.0.0",
|
||||||
|
"object-keys": "^1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/del": {
|
"node_modules/del": {
|
||||||
"version": "6.1.1",
|
"version": "6.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz",
|
||||||
|
|
@ -6777,6 +6887,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/expo-application": {
|
||||||
|
"version": "6.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-application/-/expo-application-6.0.2.tgz",
|
||||||
|
"integrity": "sha512-qcj6kGq3mc7x5yIb5KxESurFTJCoEKwNEL34RdPEvTB/xhl7SeVZlu05sZBqxB1V4Ryzq/LsCb7NHNfBbb3L7A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/expo-asset": {
|
"node_modules/expo-asset": {
|
||||||
"version": "11.0.5",
|
"version": "11.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-11.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-11.0.5.tgz",
|
||||||
|
|
@ -6808,6 +6927,44 @@
|
||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/expo-device": {
|
||||||
|
"version": "7.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-device/-/expo-device-7.0.3.tgz",
|
||||||
|
"integrity": "sha512-uNGhDYmpDj/3GySWZmRiYSt52Phdim11p0pXfgpCq/nMks0+UPZwl3D0vin5N8/gpVe5yzb13GYuFxiVoDyniw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ua-parser-js": "^0.7.33"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/expo-device/node_modules/ua-parser-js": {
|
||||||
|
"version": "0.7.40",
|
||||||
|
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.40.tgz",
|
||||||
|
"integrity": "sha512-us1E3K+3jJppDBa3Tl0L3MOJiGhe1C6P0+nIvQAFYbxlMAx0h81eOwLmU57xgqToduDDPx3y5QsdjPfDu+FgOQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/ua-parser-js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "paypal",
|
||||||
|
"url": "https://paypal.me/faisalman"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/faisalman"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"ua-parser-js": "script/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/expo-file-system": {
|
"node_modules/expo-file-system": {
|
||||||
"version": "18.0.12",
|
"version": "18.0.12",
|
||||||
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-18.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-18.0.12.tgz",
|
||||||
|
|
@ -6922,6 +7079,26 @@
|
||||||
"invariant": "^2.2.4"
|
"invariant": "^2.2.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/expo-notifications": {
|
||||||
|
"version": "0.29.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.29.14.tgz",
|
||||||
|
"integrity": "sha512-AVduNx9mKOgcAqBfrXS1OHC9VAQZrDQLbVbcorMjPDGXW7m0Q5Q+BG6FYM/saVviF2eO8fhQRsTT40yYv5/bhQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@expo/image-utils": "^0.6.5",
|
||||||
|
"@ide/backoff": "^1.0.0",
|
||||||
|
"abort-controller": "^3.0.0",
|
||||||
|
"assert": "^2.0.0",
|
||||||
|
"badgin": "^1.1.5",
|
||||||
|
"expo-application": "~6.0.2",
|
||||||
|
"expo-constants": "~17.0.8"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*",
|
||||||
|
"react": "*",
|
||||||
|
"react-native": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/expo-router": {
|
"node_modules/expo-router": {
|
||||||
"version": "4.0.20",
|
"version": "4.0.20",
|
||||||
"resolved": "https://registry.npmjs.org/expo-router/-/expo-router-4.0.20.tgz",
|
"resolved": "https://registry.npmjs.org/expo-router/-/expo-router-4.0.20.tgz",
|
||||||
|
|
@ -7466,6 +7643,21 @@
|
||||||
"integrity": "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==",
|
"integrity": "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==",
|
||||||
"license": "BSD-2-Clause"
|
"license": "BSD-2-Clause"
|
||||||
},
|
},
|
||||||
|
"node_modules/for-each": {
|
||||||
|
"version": "0.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
|
||||||
|
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-callable": "^1.2.7"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/foreground-child": {
|
"node_modules/foreground-child": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
|
||||||
|
|
@ -7809,6 +8001,18 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/has-property-descriptors": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-define-property": "^1.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/has-symbols": {
|
"node_modules/has-symbols": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
|
|
@ -8179,6 +8383,22 @@
|
||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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-arrayish": {
|
"node_modules/is-arrayish": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||||
|
|
@ -8191,6 +8411,18 @@
|
||||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
|
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/is-callable": {
|
||||||
|
"version": "1.2.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
|
||||||
|
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "2.16.1",
|
"version": "2.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||||
|
|
@ -8258,6 +8490,24 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-generator-function": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bound": "^1.0.3",
|
||||||
|
"get-proto": "^1.0.0",
|
||||||
|
"has-tostringtag": "^1.0.2",
|
||||||
|
"safe-regex-test": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-glob": {
|
"node_modules/is-glob": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||||
|
|
@ -8270,6 +8520,22 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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-number": {
|
"node_modules/is-number": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||||
|
|
@ -8316,6 +8582,24 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"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==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bound": "^1.0.2",
|
||||||
|
"gopd": "^1.2.0",
|
||||||
|
"has-tostringtag": "^1.0.2",
|
||||||
|
"hasown": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-stream": {
|
"node_modules/is-stream": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
|
||||||
|
|
@ -8325,6 +8609,21 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-typed-array": {
|
||||||
|
"version": "1.1.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
|
||||||
|
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"which-typed-array": "^1.1.16"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-wsl": {
|
"node_modules/is-wsl": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
|
||||||
|
|
@ -11020,6 +11319,51 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/object.assign": {
|
||||||
|
"version": "4.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
|
||||||
|
"integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind": "^1.0.8",
|
||||||
|
"call-bound": "^1.0.3",
|
||||||
|
"define-properties": "^1.2.1",
|
||||||
|
"es-object-atoms": "^1.0.0",
|
||||||
|
"has-symbols": "^1.1.0",
|
||||||
|
"object-keys": "^1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/on-finished": {
|
"node_modules/on-finished": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||||
|
|
@ -11519,6 +11863,15 @@
|
||||||
"node": ">=4.0.0"
|
"node": ">=4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/possible-typed-array-names": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.49",
|
"version": "8.4.49",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
|
||||||
|
|
@ -12587,6 +12940,23 @@
|
||||||
],
|
],
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/safe-regex-test": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bound": "^1.0.2",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"is-regex": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/safer-buffer": {
|
"node_modules/safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
|
|
@ -12851,6 +13221,23 @@
|
||||||
"integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==",
|
"integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/set-function-length": {
|
||||||
|
"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==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"define-data-property": "^1.1.4",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"function-bind": "^1.1.2",
|
||||||
|
"get-intrinsic": "^1.2.4",
|
||||||
|
"gopd": "^1.0.1",
|
||||||
|
"has-property-descriptors": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/setimmediate": {
|
"node_modules/setimmediate": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||||
|
|
@ -14141,6 +14528,19 @@
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
"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/utils-merge": {
|
"node_modules/utils-merge": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||||
|
|
@ -14409,6 +14809,27 @@
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/which-typed-array": {
|
||||||
|
"version": "1.1.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
|
||||||
|
"integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"available-typed-arrays": "^1.0.7",
|
||||||
|
"call-bind": "^1.0.8",
|
||||||
|
"call-bound": "^1.0.4",
|
||||||
|
"for-each": "^0.3.5",
|
||||||
|
"get-proto": "^1.0.1",
|
||||||
|
"gopd": "^1.2.0",
|
||||||
|
"has-tostringtag": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/wonka": {
|
"node_modules/wonka": {
|
||||||
"version": "6.3.5",
|
"version": "6.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.5.tgz",
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,10 @@
|
||||||
"@react-navigation/native": "^6.0.2",
|
"@react-navigation/native": "^6.0.2",
|
||||||
"expo": "^52.0.46",
|
"expo": "^52.0.46",
|
||||||
"expo-constants": "~17.0.8",
|
"expo-constants": "~17.0.8",
|
||||||
|
"expo-device": "^7.0.3",
|
||||||
"expo-font": "~13.0.4",
|
"expo-font": "~13.0.4",
|
||||||
"expo-linking": "~7.0.5",
|
"expo-linking": "~7.0.5",
|
||||||
|
"expo-notifications": "^0.29.14",
|
||||||
"expo-router": "~4.0.20",
|
"expo-router": "~4.0.20",
|
||||||
"expo-splash-screen": "~0.29.24",
|
"expo-splash-screen": "~0.29.24",
|
||||||
"expo-status-bar": "~2.0.1",
|
"expo-status-bar": "~2.0.1",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue