Feature/notification system #26
2 changed files with 115 additions and 76 deletions
|
|
@ -1,13 +1,18 @@
|
||||||
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 {
|
||||||
import { useNotifications, useWebSocketContext } from '@/hooks';
|
C,
|
||||||
|
Cardiology,
|
||||||
|
Cpr,
|
||||||
|
FourByFour,
|
||||||
|
} from "healthicons-react-native/dist/outline";
|
||||||
|
import { useWebSocketContext } from "@/hooks";
|
||||||
|
|
||||||
const callIconMap = {
|
const callIconMap = {
|
||||||
"CHEST PAIN|HEART PROBLEMS": Cardiology,
|
"CHEST PAIN|HEART PROBLEMS": Cardiology,
|
||||||
"CARDIAC ARREST|DEATH": Cpr,
|
"CARDIAC ARREST|DEATH": Cpr,
|
||||||
"MOTOR VEHICLE COLLISION (MVC)": FourByFour,
|
"MOTOR VEHICLE COLLISION (MVC)": FourByFour,
|
||||||
}
|
};
|
||||||
|
|
||||||
// Squares
|
// Squares
|
||||||
|
|
||||||
|
|
@ -38,86 +43,121 @@ const callIconMap = {
|
||||||
// RuralClinic - Medical Facility Response
|
// RuralClinic - Medical Facility Response
|
||||||
|
|
||||||
const formatCallTimePast = (callValue) => {
|
const formatCallTimePast = (callValue) => {
|
||||||
const initDate = new Date(callValue);
|
const initDate = new Date(callValue);
|
||||||
const currentTime = new Date();
|
const currentTime = new Date();
|
||||||
|
|
||||||
const timeDifference = currentTime - initDate;
|
const timeDifference = currentTime - initDate;
|
||||||
|
|
||||||
const days = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
|
const days = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
|
||||||
const hours = Math.floor((timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
const hours = Math.floor(
|
||||||
const minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
|
(timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
|
||||||
const seconds = Math.floor((timeDifference % (1000 * 60)) / 1000);
|
);
|
||||||
if (days && days !== 0) {
|
const minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
|
||||||
return `${days} day${days === 1 ? '' : 's'} ago`;
|
const seconds = Math.floor((timeDifference % (1000 * 60)) / 1000);
|
||||||
} else if (hours && hours !== 0) {
|
if (days && days !== 0) {
|
||||||
return `${hours} hour${hours === 1 ? '' : 's'} ago`;
|
return `${days} day${days === 1 ? "" : "s"} ago`;
|
||||||
} else if (minutes && minutes !== 0) {
|
} else if (hours && hours !== 0) {
|
||||||
return `${minutes} minute${minutes === 1 ? '' : 's'} ago`;
|
return `${hours} hour${hours === 1 ? "" : "s"} ago`;
|
||||||
} else if (seconds && seconds !== 0) {
|
} else if (minutes && minutes !== 0) {
|
||||||
return `${seconds} second${seconds === 1 ? '' : 's'} ago`;
|
return `${minutes} minute${minutes === 1 ? "" : "s"} ago`;
|
||||||
}
|
} else if (seconds && seconds !== 0) {
|
||||||
return `Unknown Time Past`;
|
return `${seconds} second${seconds === 1 ? "" : "s"} ago`;
|
||||||
}
|
}
|
||||||
|
return `Unknown Time Past`;
|
||||||
|
};
|
||||||
|
|
||||||
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";
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const getIncidents = async (departments, incidentStatus) => {
|
||||||
|
let response;
|
||||||
|
try {
|
||||||
|
response = await fetch(`${process.env.EXPO_PUBLIC_DATABASE_URL}/api/getRecentCalls`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
apiKey: process.env.EXPO_PUBLIC_DATABASE_API_KEY
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
departments,
|
||||||
|
status: incidentStatus,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to fetch initial calls:", e);
|
||||||
|
}
|
||||||
|
return response?.json() || [];
|
||||||
|
};
|
||||||
|
|
||||||
export const useCallFeed = () => {
|
export const useCallFeed = () => {
|
||||||
const departments = useDepartments();
|
const departments = useDepartments();
|
||||||
const { lastMessage } = useWebSocketContext();
|
const { lastMessage } = useWebSocketContext();
|
||||||
const [allCalls, setAllCalls] = useState([]);
|
const [allCalls, setAllCalls] = useState([]);
|
||||||
const { CallThemes } = departments?.accountDetails;
|
const [init, setInit] = useState(true);
|
||||||
const {
|
const { CallThemes, InitList } = departments?.accountDetails;
|
||||||
CriticalCallList,
|
const { CriticalCallList, HighCallList, MediumCallList, LowCallList } =
|
||||||
HighCallList,
|
CallThemes;
|
||||||
MediumCallList,
|
const [selectedStatus, setSelectedStatus] = useState({id: 'all', value: 'All Incidents'});
|
||||||
LowCallList,
|
|
||||||
} = CallThemes;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (lastMessage) {
|
const incidents = getIncidents(InitList?.map((dept) => { return dept?.id }), selectedStatus?.id);
|
||||||
const parsedMessage = JSON?.parse(lastMessage);
|
setAllCalls(incidents);
|
||||||
if (parsedMessage?.data) {
|
setInit(false);
|
||||||
setAllCalls([...allCalls, parsedMessage]);
|
}, []);
|
||||||
}
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (lastMessage && !init) {
|
||||||
|
const parsedMessage = JSON?.parse(lastMessage);
|
||||||
|
if (parsedMessage?.data) {
|
||||||
|
setAllCalls([...allCalls, parsedMessage]);
|
||||||
}
|
}
|
||||||
}, [lastMessage]);
|
|
||||||
|
|
||||||
const callColorSelector = (callAcuity, cardiacArrestCall, status) => {
|
|
||||||
if (status === 'CLOSED') {
|
|
||||||
return '#0000CD';
|
|
||||||
} else if (CriticalCallList.includes(cardiacArrestCall)) {
|
|
||||||
return '#8B0000';
|
|
||||||
} else if (HighCallList.includes(callAcuity)) {
|
|
||||||
return "#FF0000";
|
|
||||||
} else if (MediumCallList.includes(callAcuity)) {
|
|
||||||
return "#FF8C00";
|
|
||||||
} else if (LowCallList.includes(callAcuity)) {
|
|
||||||
return "#228B22";
|
|
||||||
}
|
|
||||||
return 'grey';
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
departments,
|
|
||||||
callIconMap,
|
|
||||||
callDetails: allCalls,
|
|
||||||
callColorSelector,
|
|
||||||
formatCallTimePast,
|
|
||||||
formatCallDateTime
|
|
||||||
}
|
}
|
||||||
}
|
}, [lastMessage]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!init) {
|
||||||
|
const incidents = getIncidents(InitList?.map((dept) => { return dept?.id }), selectedStatus?.id);
|
||||||
|
setAllCalls(incidents);
|
||||||
|
}
|
||||||
|
}, [selectedStatus]);
|
||||||
|
|
||||||
|
const callColorSelector = (callAcuity, cardiacArrestCall, status) => {
|
||||||
|
if (status === "CLOSED") {
|
||||||
|
return "#0000CD";
|
||||||
|
} else if (CriticalCallList.includes(cardiacArrestCall)) {
|
||||||
|
return "#8B0000";
|
||||||
|
} else if (HighCallList.includes(callAcuity)) {
|
||||||
|
return "#FF0000";
|
||||||
|
} else if (MediumCallList.includes(callAcuity)) {
|
||||||
|
return "#FF8C00";
|
||||||
|
} else if (LowCallList.includes(callAcuity)) {
|
||||||
|
return "#228B22";
|
||||||
|
}
|
||||||
|
return "grey";
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
departments,
|
||||||
|
callIconMap,
|
||||||
|
callDetails: allCalls,
|
||||||
|
callColorSelector,
|
||||||
|
formatCallTimePast,
|
||||||
|
formatCallDateTime,
|
||||||
|
selectedStatus,
|
||||||
|
setSelectedStatus
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { View, Text, TouchableOpacity } from 'react-native';
|
|
||||||
|
|
||||||
const departmentTypeMap = {
|
const departmentTypeMap = {
|
||||||
EMS: 'Medical Services',
|
EMS: 'Medical Services',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue