Feature/notification system #26

Open
mattdimegs wants to merge 34 commits from feature/notification-system into main
4 changed files with 86 additions and 63 deletions
Showing only changes of commit cb1758fb55 - Show all commits

View file

@ -1,8 +1,8 @@
import React, { useState, useRef, useEffect } from 'react';
import React, { useRef } from 'react';
import styled from 'styled-components';
import { useCallFeed } from '../hooks/useCallFeed';
import { Platform, Linking, View, ScrollView, Text, TouchableOpacity } from 'react-native';
import { useLocalSearchParams, router } from 'expo-router';
import { useLocalSearchParams } from 'expo-router';
import { StatusBar } from 'expo-status-bar';
import { SafeAreaView } from 'react-native-safe-area-context';
import { Ionicons } from '@expo/vector-icons';
@ -11,7 +11,7 @@ import { Phone } from "healthicons-react-native/dist/filled";
import {
PageHeader,
PageFooter,
} from '../components/generalHelpers.jsx';
} from '@/components/generalHelpers.jsx';
import ActionSheet from 'react-native-actions-sheet';
const DepartmentActionSheet = styled(ActionSheet)``;

View file

@ -28,13 +28,13 @@ export default function Incidents() {
formatCallDateTime
} = callFeed;
const sortedAndFilteredCalls = callDetails
.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))
const sortedAndFilteredCalls = callDetails.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))
.filter((item, index, self) => {
return index === self.findIndex(i => {
return `${i?.data?.Incident?.IncID}${i?.data?.Response?.ServiceName}` === `${item?.data?.Incident?.IncID}${item?.data?.Response?.ServiceName}`
});
return `${i?.incident?.incID}${i?.response?.serviceName}` === `${item?.incident?.incID}${item?.response?.serviceName}`
});
})?.map(item => { return {...item, timestamp: item?.incident?.incDate} })
|| [];
const {
departmentTypeMap,
@ -93,31 +93,30 @@ export default function Incidents() {
<View style={{ flexDirection: 'column', padding: 20 }}>
{sortedAndFilteredCalls?.length ? (
sortedAndFilteredCalls?.map((callItem, index) => {
const { data: call, timestamp } = callItem;
const { Incident, Address, Response } = call;
const { incident, address, response, timestamp } = callItem;
const {
ServiceNumber,
IncDate,
IncNature,
IncNatureCode,
IncNatureCodeDesc,
Status,
} = Incident;
serviceNumber,
incDate,
incNature,
incNatureCode,
incNatureCodeDesc,
status,
} = incident;
const {
StreetAddress,
AddressApartment,
Town,
State,
LocationName,
} = Address;
streetAddress,
addressApartment,
town,
state,
locationName,
} = address;
const {
ServiceName
} = Response;
const SelectedIcon = callIconMap[IncNature] || AccidentAndEmergency;
serviceName
} = response;
const SelectedIcon = callIconMap[incNature] || AccidentAndEmergency;
return (
<TouchableOpacity
key={`callDetails - ${timestamp}`}
style={{ padding: 2 }}
style={{ paddingBottom: 15 }}
onPress={() => {
router.push({
pathname: '/call',
@ -134,9 +133,9 @@ export default function Incidents() {
backgroundColor: '#fff',
shadowOffset: { width: 0, height: 0 },
shadowColor: callColorSelector(
IncNatureCode,
IncNature,
Status
incNatureCodeDesc,
incNature,
status
),
shadowOpacity: 1,
shadowRadius: 5,
@ -151,10 +150,10 @@ export default function Incidents() {
justifyContent: 'space-between'
}}
>
<Text style={{ fontSize: 12 }}>{formatCallDateTime(IncDate)}</Text>
<Text style={{ fontSize: 12 }}>{formatCallDateTime(incDate)}</Text>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Text style={{ fontSize: 12 }}>{formatCallTimePast(IncDate)}</Text>
{Status === 'CLOSED' ? (
<Text style={{ fontSize: 12 }}>{formatCallTimePast(incDate)}</Text>
{status === 'CLOSED' ? (
<Ionicons
name="lock-closed-outline"
color='red'
@ -171,16 +170,16 @@ export default function Incidents() {
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
<SelectedIcon
color={callColorSelector(
IncNatureCode,
IncNature,
Status
incNatureCodeDesc,
incNature,
status
)}
opacity={0.3}
width={56}
height={56}
/>
<View style={{ flexDirection: 'column' }}>
{LocationName ? (
{locationName ? (
<Text
style={{
color: 'black',
@ -188,7 +187,7 @@ export default function Incidents() {
fontSize: 16
}}
>
{`${LocationName}`}
{`${locationName}`}
</Text>
) : (
<View style={{ flexDirection: 'row' }}>
@ -199,9 +198,9 @@ export default function Incidents() {
fontWeight: 600
}]}
>
{`${StreetAddress}`}
{`${streetAddress?.split(',')[0]}`}
</Text>
{AddressApartment ? (
{addressApartment ? (
<Text
style={[{
color: 'black',
@ -209,7 +208,7 @@ export default function Incidents() {
fontWeight: 600
}]}
>
{` - ${AddressApartment}`}
{` - ${addressApartment}`}
</Text>
) : null}
<Text
@ -219,7 +218,7 @@ export default function Incidents() {
fontWeight: 600
}]}
>
{` ${Town}, ${State}`}
{` ${town}, ${state}`}
</Text>
</View>
)}
@ -230,7 +229,7 @@ export default function Incidents() {
fontSize: 16
}}
>
{`${IncNature}`}
{`${incNature}`}
</Text>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<Text
@ -238,14 +237,14 @@ export default function Incidents() {
color: 'black',
fontSize: 12,
textShadowColor: callColorSelector(
IncNatureCode,
IncNature,
Status
incNatureCode,
incNature,
status
),
textShadowRadius: 1
}}
>
{`${IncNatureCodeDesc}`}
{`${incNatureCodeDesc}`}
</Text>
</View>
</View>
@ -261,7 +260,7 @@ export default function Incidents() {
fontSize: 12,
}}
>
Service: {ServiceName}
Service: {serviceName}
</Text>
<Text
style={{
@ -269,7 +268,7 @@ export default function Incidents() {
textAlign: 'right'
}}
>
{`Incident #: ${ServiceNumber}`}
{`Incident #: ${serviceNumber}`}
</Text>
</View>
</View>

View file

@ -86,16 +86,16 @@ const formatCallDateTime = (callValue) => {
const getIncidents = async (departments, incidentStatus) => {
let response;
try {
response = await fetch(`${process.env.EXPO_PUBLIC_DATABASE_URL}/api/getRecentCalls`, {
response = await fetch(`${process.env.EXPO_PUBLIC_DATABASE_URL}/getRecentCalls/${5}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
apiKey: process.env.EXPO_PUBLIC_DATABASE_API_KEY
},
body: JSON.stringify({
departments,
status: incidentStatus,
}),
// body: JSON.stringify({
// callCount: 25,
// departments,
// status: incidentStatus,
// }),
});
} catch (e) {
console.error("Failed to fetch initial calls:", e);
@ -114,9 +114,12 @@ export const useCallFeed = () => {
const [selectedStatus, setSelectedStatus] = useState({id: 'all', value: 'All Incidents'});
useEffect(() => {
const incidents = getIncidents(InitList?.map((dept) => { return dept?.id }), selectedStatus?.id);
async function fetchData() {
const incidents = await getIncidents(InitList?.map((dept) => { return dept?.id }), selectedStatus?.id);
setAllCalls(incidents);
setInit(false);
}
fetchData();
}, []);
useEffect(() => {
@ -129,14 +132,17 @@ export const useCallFeed = () => {
}, [lastMessage]);
useEffect(() => {
if (!init) {
const incidents = getIncidents(InitList?.map((dept) => { return dept?.id }), selectedStatus?.id);
async function fetchData() {
const incidents = await getIncidents(InitList?.map((dept) => { return dept?.id }), selectedStatus?.id);
setAllCalls(incidents);
}
if (!init) {
fetchData();
}
}, [selectedStatus]);
const callColorSelector = (callAcuity, cardiacArrestCall, status) => {
if (status === "CLOSED") {
if (status?.toLowerCase() === "closed") {
return "#0000CD";
} else if (CriticalCallList.includes(cardiacArrestCall)) {
return "#8B0000";

View file

@ -12,14 +12,32 @@ const accountDetails = {
"CARDIAC ARREST|DEATH",
],
"HighCallList": [
"ALS"
"EMS ALS PRIORITY (ALS)",
"EMS Advanced Life Support life threatening response (ALS)",
"EMS ALS Intercept Required",
"EMS ALS Response Cardiac Related",
"EMS ALS Response Respiratory Distress",
"EMS ALS Response Stroke Alert",
"EMS Basic Life Support with Paramedic Assist (BLS)",
"EMS ALS Tiered Response with Fire",
"EMS Response Behavioral Emergency (ALS)",
"EMS Response Obstetric Emergency (ALS)",
"EMS ALS Response Overdose / Poisoning",
"EMS ALS Priority Interfacility Transfer",
"EMS Response Unresponsive / Unconscious Patient (ALS)"
],
"MediumCallList": [
"ALS-STANDARD",
"BLS-PRIORITY"
"BLS-PRIORITY",
"EMS BLS Priority Response",
"EMS BLS Response Fall Injury"
],
"LowCallList": [
"BLS-STANDARD"
"EMS Standard Basic Life Support Response (BLS)",
"EMS BLS Non-Emergency Transport",
"EMS BLS Standby Event Coverage",
"EMS Public Assist Lift Only (BLS)",
"EMS BLS Scheduled Interfacility Transport"
]
},
"InitList": [