Introduces Unicode-safe base64 encoding/decoding for call details between incidents and call screens. Refactors PageHeader to accept left, center, and right header props for more flexible layouts. Updates call.jsx and register.jsx to use the new header structure, and improves department/unit rendering and modal dropdowns for department selection. Generalizes and modernizes UI code for better maintainability and cross-platform compatibility.
172 lines
5 KiB
JavaScript
172 lines
5 KiB
JavaScript
import React, { useState, useEffect } from "react";
|
|
import { useDepartments } from "../useDepartments";
|
|
import {
|
|
Cardiology,
|
|
Cpr,
|
|
FourByFour,
|
|
} from "healthicons-react-native/dist/outline";
|
|
import { useWebSocketContext } from "@/hooks";
|
|
|
|
const callIconMap = {
|
|
"CHEST PAIN|HEART PROBLEMS": Cardiology,
|
|
"CARDIAC ARREST|DEATH": Cpr,
|
|
"MOTOR VEHICLE COLLISION (MVC)": FourByFour,
|
|
};
|
|
|
|
// Squares
|
|
|
|
// Cariology - Heart
|
|
// BurnUnit - Fire
|
|
// AccidentAndEmergency - Misc.
|
|
// Rheumatology - Bone/Crash
|
|
// Sonography - Baby
|
|
// PainManagement - CPR/Cardiac Arrest
|
|
// Respiratory - Diff Breathing
|
|
|
|
// Others
|
|
|
|
// HeartOrgan - Heart
|
|
// Burn - Burns
|
|
// FHIR - Structure Fire
|
|
// Sonogram - Baby
|
|
// SUV - Crash
|
|
// Joints - Bone
|
|
// Pain - CPR/Cardiac Arrest
|
|
// Skull - CPR/Cardiac Arrest
|
|
// CPR - CPR/Cardiac Arrest
|
|
// Pneumonia - Diff Breathing
|
|
// CoughingAlt - Diff Breathing
|
|
// Diabetes - Diabetic Emergency
|
|
// BloodDrop - Bleeding Emergencies
|
|
// Bacteria - Sick
|
|
// RuralClinic - Medical Facility Response
|
|
|
|
const formatCallTimePast = (callValue) => {
|
|
const initDate = new Date(callValue);
|
|
const currentTime = new Date();
|
|
|
|
const timeDifference = currentTime - initDate;
|
|
|
|
const days = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
|
|
const hours = Math.floor(
|
|
(timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
|
|
);
|
|
const minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
|
|
const seconds = Math.floor((timeDifference % (1000 * 60)) / 1000);
|
|
if (days && days !== 0) {
|
|
return `${days} day${days === 1 ? "" : "s"} ago`;
|
|
} else if (hours && hours !== 0) {
|
|
return `${hours} hour${hours === 1 ? "" : "s"} ago`;
|
|
} else if (minutes && minutes !== 0) {
|
|
return `${minutes} minute${minutes === 1 ? "" : "s"} ago`;
|
|
} else if (seconds && seconds !== 0) {
|
|
return `${seconds} second${seconds === 1 ? "" : "s"} ago`;
|
|
}
|
|
return `Unknown Time Past`;
|
|
};
|
|
|
|
const formatCallDateTime = (callValue) => {
|
|
const initDate = new Date(callValue);
|
|
if (initDate) {
|
|
const formattedDate = `${initDate.toLocaleDateString("en-US", {
|
|
month: "short",
|
|
day: "numeric",
|
|
year: "numeric",
|
|
})}`;
|
|
const hours = initDate.getHours().toString().padStart(2, "0");
|
|
const minutes = initDate.getMinutes().toString().padStart(2, "0");
|
|
const formattedTime = `${hours}:${minutes}`;
|
|
|
|
return `${formattedDate} - ${formattedTime}`;
|
|
}
|
|
return "Date Unavailable";
|
|
};
|
|
|
|
const getIncidents = async (departments, incidentStatus) => {
|
|
let response;
|
|
try {
|
|
response = await fetch(`${process.env.EXPO_PUBLIC_DATABASE_URL}/getCallsParams`, {
|
|
method: "POST",
|
|
headers: {
|
|
apiKey: process.env.EXPO_PUBLIC_DATABASE_API_KEY,
|
|
"Content-Type": 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
numCalls: 25,
|
|
departments,
|
|
status: incidentStatus
|
|
}),
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
} catch (e) {
|
|
console.error("Failed to fetch initial calls:", e);
|
|
}
|
|
return response?.json() || [];
|
|
};
|
|
|
|
export const useCallFeed = (callPage = false) => {
|
|
const departments = useDepartments();
|
|
const { lastMessage } = useWebSocketContext();
|
|
const [allCalls, setAllCalls] = useState([]);
|
|
const [init, setInit] = useState(true);
|
|
const { CallThemes, InitList } = departments?.accountDetails;
|
|
const { CriticalCallList, HighCallList, MediumCallList, LowCallList } =
|
|
CallThemes;
|
|
const [selectedStatus, setSelectedStatus] = useState({id: 'all', value: 'All Incidents'});
|
|
|
|
useEffect(() => {
|
|
async function fetchData() {
|
|
const incidents = await getIncidents(InitList?.map((dept) => { return dept?.deptId }), selectedStatus?.id);
|
|
setAllCalls(incidents);
|
|
setInit(false);
|
|
}
|
|
if (!callPage) fetchData();
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (lastMessage && !init) {
|
|
const parsedMessage = JSON?.parse(lastMessage);
|
|
if (parsedMessage?.data) {
|
|
setAllCalls([...allCalls, parsedMessage]);
|
|
}
|
|
}
|
|
}, [lastMessage]);
|
|
|
|
useEffect(() => {
|
|
async function fetchData() {
|
|
const incidents = await getIncidents(InitList?.map((dept) => { return dept?.deptId }), selectedStatus?.id);
|
|
setAllCalls(incidents);
|
|
}
|
|
if (!init) {
|
|
if (!callPage) fetchData();
|
|
}
|
|
}, [selectedStatus]);
|
|
|
|
const callColorSelector = (callAcuity, cardiacArrestCall, status) => {
|
|
if (status?.toLowerCase() === "closed") {
|
|
return "#0000CD";
|
|
} else if (CriticalCallList.some(critical => cardiacArrestCall.includes(critical))) {
|
|
return "#8B0000";
|
|
} else if (HighCallList.some(high => callAcuity.includes(high))) {
|
|
return "#FF0000";
|
|
} else if (MediumCallList.some(medium => callAcuity.includes(medium))) {
|
|
return "#FF8C00";
|
|
} else if (LowCallList.some(low => callAcuity.includes(low))) {
|
|
return "#228B22";
|
|
}
|
|
return "grey";
|
|
};
|
|
|
|
return {
|
|
departments,
|
|
callIconMap,
|
|
callDetails: allCalls,
|
|
callColorSelector,
|
|
formatCallTimePast,
|
|
formatCallDateTime,
|
|
selectedStatus,
|
|
setSelectedStatus
|
|
};
|
|
};
|