From 05fce569042750baa01d424fc7008f5770860f44 Mon Sep 17 00:00:00 2001 From: Matt DiMeglio Date: Sat, 5 Oct 2024 19:10:41 -0400 Subject: [PATCH] Single Call View Init Finish & Multi Call Started --- app/_layout.tsx | 18 +- app/generalHelpers.jsx | 12 +- app/incidents.jsx | 202 ++++++ app/landing.jsx | 884 +++++++++++++++++++++--- app/login.jsx | 18 +- app/register.jsx | 10 +- hooks/index.js | 2 + hooks/useCallFeed/index.js | 1 + hooks/useCallFeed/useCallFeed.js | 0 hooks/useCallFeed/useCallFeed.jsx | 183 +++++ hooks/useDepartments/index.js | 1 + hooks/useDepartments/useDepartments.jsx | 122 ++++ package-lock.json | 157 ++++- package.json | 2 + 14 files changed, 1472 insertions(+), 140 deletions(-) create mode 100644 app/incidents.jsx create mode 100644 hooks/index.js create mode 100644 hooks/useCallFeed/index.js delete mode 100644 hooks/useCallFeed/useCallFeed.js create mode 100644 hooks/useCallFeed/useCallFeed.jsx create mode 100644 hooks/useDepartments/index.js create mode 100644 hooks/useDepartments/useDepartments.jsx diff --git a/app/_layout.tsx b/app/_layout.tsx index 2fceb79..268ecb7 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -7,25 +7,10 @@ export const unstable_settings = { }; export default function App() { - - const [auth, setAuth] = useState(false); - useEffect(() => { - if (auth) { - router.replace('./landing'); - } else { - router.replace('/login'); - } + router.replace('/login'); }, []); - useEffect(() => { - if (auth) { - router.replace('./landing'); - } else { - router.replace('/login'); - } - }, [auth]); - return ( + ); diff --git a/app/generalHelpers.jsx b/app/generalHelpers.jsx index a0a02ce..be881d3 100644 --- a/app/generalHelpers.jsx +++ b/app/generalHelpers.jsx @@ -207,7 +207,17 @@ export const PageHeader = ({ children }) => { return ( - + + {children} + + ) +} + +export const PageFooter = ({ + children +}) => { + return ( + {children} ) diff --git a/app/incidents.jsx b/app/incidents.jsx new file mode 100644 index 0000000..c3eb616 --- /dev/null +++ b/app/incidents.jsx @@ -0,0 +1,202 @@ +import React, { useState, useRef, useEffect } from 'react'; +import styled from 'styled-components'; +import { useCallFeed } from '../hooks/useCallFeed'; +import { Platform, Linking, View, ScrollView, Text, TouchableOpacity } from 'react-native'; +import { + PageHeader, + PageFooter, +} from './generalHelpers.jsx'; +import { Ionicons } from '@expo/vector-icons'; +import ActionSheet from 'react-native-actions-sheet'; + +const DepartmentActionSheet = styled(ActionSheet)``; + +export default function Incidents() { + const actionSheetRef = useRef(null); + const callFeed = useCallFeed(); + + const { + departments, + callIconMap, + callDetails, + callColorSelector, + } = callFeed; + + const { + departmentTypeMap, + accountDetails, + deptList, + setDeptList, + selectedDepartment, + setSelectedDepartment, + updateSelectedDepartment, + selectedDepartmentColorPicker, + } = departments; + + const { Incident, Address, Person, Response } = callDetails; + const { CallThemes, InitList } = accountDetails; + const { + IncID, + IncNumber, + JurisdictionNumber, + ServiceNumber, + ServiceID, + IncDate, + IncNature, + IncNatureCode, + IncNatureCodeDesc, + Notes, + Status, + Origin, + } = Incident; + const { + StreetAddress, + AddressApartment, + Town, + State, + ZipCode, + Latitude, + Longitude, + County, + Intersection1, + Intersection2, + LocationName, + WeatherCondition, + } = Address; + const { + Name, + Age, + Gender, + Statement, + Conscious, + Breathing, + CallBackNumber, + } = Person; + const { + Units + } = Response; + const { + CriticalCallList, + HighCallList, + MediumCallList, + LowCallList, + } = CallThemes; + + return ( + + + + { + actionSheetRef.current?.show(); + }} + > + + {selectedDepartment?.deptAbv} + + + + + + + + + + + + + {deptList?.map((item) => { + return ( + + { + actionSheetRef.current?.hide(); + return updateSelectedDepartment( + selectedDepartment?.deptId, + item?.deptId + ) + }} + > + + + {item?.dept} + + {item?.primary ? : null} + + {`${item?.deptAbv} - ${departmentTypeMap[item?.type]}`} + + + ); + })} + + + + ) +} \ No newline at end of file diff --git a/app/landing.jsx b/app/landing.jsx index 1b95a5d..3e31875 100644 --- a/app/landing.jsx +++ b/app/landing.jsx @@ -1,145 +1,799 @@ import React, { useState, useRef, useEffect } from 'react'; -import { View, ScrollView, Text, TouchableOpacity } from 'react-native'; +import { useCallFeed } from '../hooks/useCallFeed'; +import { Platform, Linking, View, ScrollView, Text, TouchableOpacity } from 'react-native'; import { StatusBar } from 'expo-status-bar'; import { SafeAreaView } from 'react-native-safe-area-context'; import { Ionicons } from '@expo/vector-icons'; +import { AccidentAndEmergency } from "healthicons-react-native/dist/outline"; +import { Phone } from "healthicons-react-native/dist/filled"; import { PageHeader, - StyledContainer, + PageFooter, } from './generalHelpers.jsx'; -import ActionSheet from 'react-native-actions-sheet'; - -const typeMap = { - EMS: 'Medical Services', - Fire: 'Fire Department', - Rescue: 'Fire & EMS' -} - -const initList = [ - { - deptId: 0, - dept: 'Darien EMS', - deptAbv: 'DEMS', - rank: 'Assistant Director', - rankAbv: 'Asst. Director', - type: 'EMS', - primary: true, - selected: true, - admin: true, - }, - { - deptId: 1, - dept: 'Noroton Fire Department', - deptAbv: 'NFD', - rank: 'Lieutenant', - rankAbv: 'Lt.', - type: 'Fire', - primary: false, - selected: false, - admin: true, - }, - { - deptId: 2, - dept: 'Stamford Fire Department', - deptAbv: 'SFD', - rank: 'Paramedic', - rankAbv: 'EMT-P', - type: 'Rescue', - primary: false, - selected: false, - admin: true, - }, -] export default function Landing() { const actionSheetRef = useRef(null); - const [deptList, setDeptList] = useState(initList); - const [selectedDepartment, setSelectedDepartment] = useState(deptList?.find((dept) => { - return dept?.primary; - })); + const callFeed = useCallFeed(); - const updateSelectedDepartment = (currentSelectedId, newSelectedId) => { - if (currentSelectedId !== newSelectedId) { - setDeptList(deptList?.map((item) => { - if (item?.selected) { - item.selected = false; - } - if (item?.deptId === newSelectedId) { - item.selected = true; - } - return item; - })) + const { + departments, + callIconMap, + callDetails, + callColorSelector, + } = callFeed; + + const { + departmentTypeMap, + accountDetails, + selectedDepartment, + setSelectedDepartment, + updateSelectedDepartment, + selectedDepartmentColorPicker, + } = departments; + + const { Incident, Address, Person, Response } = callDetails; + const { CallThemes } = accountDetails; + const { + IncID, + IncNumber, + JurisdictionNumber, + ServiceNumber, + ServiceID, + IncDate, + IncNature, + IncNatureCode, + IncNatureCodeDesc, + Notes, + Status, + Origin, + } = Incident; + const { + StreetAddress, + AddressApartment, + Town, + State, + ZipCode, + Latitude, + Longitude, + County, + Intersection1, + Intersection2, + LocationName, + WeatherCondition, + } = Address; + const { + Name, + Age, + Gender, + Statement, + Conscious, + Breathing, + CallBackNumber, + } = Person; + const { + Units + } = Response; + + const SelectedIcon = callIconMap[IncNature] || AccidentAndEmergency; + + const ownDepartmentResponse = Units?.map((unit) => { + if (unit?.Department === selectedDepartment?.dept || + selectedDepartment?.addDepts?.includes(unit?.Department)) { + return unit; } + return null; + })?.filter((filterItem) => { + return filterItem; + }); + + const mutualAidDepartmentResponse = Units?.map((unit) => { + if (unit?.Department !== selectedDepartment?.dept && + !selectedDepartment?.addDepts?.includes(unit?.Department)) { + return unit; + } + return null; + })?.filter((filterItem) => { + return filterItem; + });; + + 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 formatResponseTimes = (time) => { + if (time === null) { + return ''; + } + const initTime = new Date(time); + const hours = initTime.getHours().toString().padStart(2, '0'); + const minutes = initTime.getMinutes().toString().padStart(2, '0'); + return `${hours}:${minutes}`; }; - useEffect(() => { - if (deptList) { - setSelectedDepartment(deptList?.find((dept) => { - return dept?.selected; - })); - } - }, [deptList]) + const openMaps = (latitude, longitude) => { + const daddr = `${latitude},${longitude}`; + const company = Platform.OS === "ios" ? "apple" : "google"; + Linking.openURL(`http://maps.${company}.com/maps?daddr=${daddr}`); + }; + + const callNumber = (number) => { + const formattedNumber = number.replace(/[()\-\s]/g, ''); + Linking.openURL(`tel:${formattedNumber}`); + }; return ( - - { - actionSheetRef.current?.show(); - }}> - {selectedDepartment?.deptAbv} + + { + actionSheetRef.current?.show(); + }} + > + + {selectedDepartment?.deptAbv} + - + - - - {deptList?.map((item) => { - return ( - - {return updateSelectedDepartment(selectedDepartment?.deptId, item?.deptId)}} - > - - {item?.dept} - {item?.primary ? : null} + + {formatCallDateTime(IncDate)} + {formatCallTimePast(IncDate)} + + + + + + + + + {`${IncNature}`} + + + + {`${IncNatureCodeDesc}`} + + - {`${item?.deptAbv} - ${typeMap[item?.type]}`} - + + + {Status === 'CLOSED' ? ( + + This Incident is Closed. + + ) : } + + {`Incident #: ${ServiceNumber}`} + + - ); - })} + + + + + + + + {LocationName ? ( + + {`${LocationName}`} + + ) : null } + { + return openMaps(Latitude, Longitude); + }} + > + + {`${StreetAddress}`} + + + {`${Town}, ${State}`} + + + {AddressApartment ? ( + + + + {`${AddressApartment}`} + + + ) : null} + + + + Map + + { + return openMaps(Latitude, Longitude); + }} + > + Nav + + + + + + + + + + + {Intersection1} + + + + + + {Intersection2} + + + + + + + {selectedDepartment?.supervisor ? ( + + + + + + {`${Name}`} + + { + return callNumber(CallBackNumber); + }} + > + + {`${CallBackNumber}`} + + + + { + return callNumber(CallBackNumber); + }} + > + + + + + + + ) : null } + + + + {`${Age} `} + + + {`${Gender} - `} + + + {`Concious: ${Conscious} | `} + + + {`Breathing: ${Breathing}`} + + + + {`${Statement}`} + + + + + + + + + + + {Units?.length > 0 ? ( + + {ownDepartmentResponse?.length > 0 ? ( + + + + Units + Disp + Resp + Arr + {selectedDepartment?.type === 'EMS' || selectedDepartment?.type === 'Rescue' ? ( + Trans + ) : null} + BIS + + + + {ownDepartmentResponse?.map((unit) => { + return ( + + + {unit?.Unit} + + + {formatResponseTimes(unit?.Dispatched)} + + + {formatResponseTimes(unit?.Responding)} + + + {formatResponseTimes(unit?.OnScene)} + + {selectedDepartment?.type === 'EMS' || + selectedDepartment?.type === 'Rescue' ? ( + + {formatResponseTimes(unit?.Transporting)} + + ) : null } + + {formatResponseTimes(unit?.InService)} + + + ) + })} + + + + ) : ( + + + {`No ${selectedDepartment?.dept} Units Responding`} + + + ) } + {mutualAidDepartmentResponse?.length > 0 ? ( + + + + M/A + Disp + Resp + Arr + {selectedDepartment?.type === 'EMS' || selectedDepartment?.type === 'Rescue' ? ( + Trans + ) : null} + BIS + + + {mutualAidDepartmentResponse?.map((unit) => { + return ( + + + {unit?.Unit} + + + {formatResponseTimes(unit?.Dispatched)} + + + {formatResponseTimes(unit?.Responding)} + + + {formatResponseTimes(unit?.OnScene)} + + {selectedDepartment?.type === 'EMS' || + selectedDepartment?.type === 'Rescue' ? ( + + {formatResponseTimes(unit?.Transporting)} + + ) : null } + + {formatResponseTimes(unit?.InService)} + + + ) + })} + + ) : null } + + ) : ( + + No Units Responding + + )} + + + + + + Incident Notes + + + + + {Notes?.split('\n').map((note, index) => ( + + {note} + {index < Notes.split('\n').length - 1 && ( + + )} + + ))} + + - + + + + ); } \ No newline at end of file diff --git a/app/login.jsx b/app/login.jsx index 521d3ba..bf9eec7 100644 --- a/app/login.jsx +++ b/app/login.jsx @@ -22,10 +22,10 @@ import { LoginTextInput } from './generalHelpers.jsx'; -export default function TabLayout() { +export default function Login() { const [hidePassword, setHidePassword] = useState(true); const [loginButtonDisabled, setLoginButtonDisabled] = useState(true); - const [auth, setAuth] = useState(true); + const [auth, setAuth] = useState(false); const formik = useFormik({ initialValues: { @@ -52,8 +52,14 @@ export default function TabLayout() { }, [formValues]) useEffect(() => { + // Temp for Testing + // if (!auth) { + // setTimeout(() => { + // router.navigate('./incidents'); + // }, 1000); + // } if (auth) { - router.navigate('./landing'); + router.navigate('./incidents'); } }, [auth]) @@ -104,6 +110,12 @@ export default function TabLayout() { Register + + Incidents + + + Landing + diff --git a/app/register.jsx b/app/register.jsx index 9e952e1..5dab3f6 100644 --- a/app/register.jsx +++ b/app/register.jsx @@ -65,10 +65,12 @@ export default function Register() { return ( - - - Back to Login - + + + + Back to Login + + diff --git a/hooks/index.js b/hooks/index.js new file mode 100644 index 0000000..efebedc --- /dev/null +++ b/hooks/index.js @@ -0,0 +1,2 @@ +export { useCallFeed } from './useCallFeed'; +export { useDepartments } from './useDepartments'; \ No newline at end of file diff --git a/hooks/useCallFeed/index.js b/hooks/useCallFeed/index.js new file mode 100644 index 0000000..5100e13 --- /dev/null +++ b/hooks/useCallFeed/index.js @@ -0,0 +1 @@ +export { useCallFeed } from "./useCallFeed"; \ No newline at end of file diff --git a/hooks/useCallFeed/useCallFeed.js b/hooks/useCallFeed/useCallFeed.js deleted file mode 100644 index e69de29..0000000 diff --git a/hooks/useCallFeed/useCallFeed.jsx b/hooks/useCallFeed/useCallFeed.jsx new file mode 100644 index 0000000..be8eeee --- /dev/null +++ b/hooks/useCallFeed/useCallFeed.jsx @@ -0,0 +1,183 @@ +import React, { useState, useEffect } from 'react'; +import { useDepartments } from '../useDepartments'; +import { Cardiology, Cpr, FourByFour } from "healthicons-react-native/dist/outline"; + +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 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", + }, + ] + } +} + +export const useCallFeed = () => { + const departments = useDepartments(); + const { CallThemes } = departments?.accountDetails; + const { + CriticalCallList, + HighCallList, + MediumCallList, + LowCallList, + } = CallThemes; + + 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, + callColorSelector, + } +} \ No newline at end of file diff --git a/hooks/useDepartments/index.js b/hooks/useDepartments/index.js new file mode 100644 index 0000000..dcc4235 --- /dev/null +++ b/hooks/useDepartments/index.js @@ -0,0 +1 @@ +export { useDepartments } from './useDepartments'; \ No newline at end of file diff --git a/hooks/useDepartments/useDepartments.jsx b/hooks/useDepartments/useDepartments.jsx new file mode 100644 index 0000000..a0ddf69 --- /dev/null +++ b/hooks/useDepartments/useDepartments.jsx @@ -0,0 +1,122 @@ +import React, { useState, useEffect } from 'react'; +import { View, Text, TouchableOpacity } from 'react-native'; + +const departmentTypeMap = { + EMS: 'Medical Services', + Fire: 'Fire Department', + Rescue: 'Fire & EMS' +} + +const accountDetails = { + "CallThemes" : { + "CriticalCallList": [ + "CARDIAC ARREST|DEATH", + ], + "HighCallList": [ + "ALS" + ], + "MediumCallList": [ + "ALS-STANDARD", + "BLS-PRIORITY" + ], + "LowCallList": [ + "BLS-STANDARD" + ] + }, + "InitList": [ + { + deptId: 0, + dept: 'Darien EMS', + addDepts: [ + 'Darien EMS Supv' + ], + deptAbv: 'DEMS', + rank: 'Assistant Director', + rankAbv: 'Asst. Director', + type: 'EMS', + primary: true, + selected: true, + supervisor: true, + admin: true, + hasVolunteer: true, + }, + { + deptId: 1, + dept: 'Noroton Fire Department', + deptAbv: 'NFD', + rank: 'Lieutenant', + rankAbv: 'Lt.', + type: 'Fire', + primary: false, + selected: false, + supervisor: true, + admin: true, + hasVolunteer: true, + }, + { + deptId: 2, + dept: 'Stamford Fire Department', + deptAbv: 'SFD', + rank: 'Paramedic', + rankAbv: 'EMT-P', + type: 'Rescue', + primary: false, + selected: false, + supervisor: false, + admin: true, + hasVolunteer: false, + }, + ] +} + +export const useDepartments = () => { + const { InitList } = accountDetails; + const [deptList, setDeptList] = useState(InitList); + const [selectedDepartment, setSelectedDepartment] = useState(deptList?.find((dept) => { + return dept?.primary; + })); + + const updateSelectedDepartment = (currentSelectedId, newSelectedId) => { + if (currentSelectedId !== newSelectedId) { + setDeptList(deptList?.map((item) => { + if (item?.selected) { + item.selected = false; + } + if (item?.deptId === newSelectedId) { + item.selected = true; + } + return item; + })) + } + }; + + const selectedDepartmentColorPicker = (deptartmentType) => { + if (deptartmentType === 'Fire') { + return '#FF0000'; + } else if (deptartmentType === 'EMS') { + return '#FF8C00'; + } else if (deptartmentType === 'Rescue') { + return '#0000CD'; + } + return 'grey'; + }; + + useEffect(() => { + if (deptList) { + setSelectedDepartment(deptList?.find((dept) => { + return dept?.selected; + })); + } + }, [deptList]); + + return { + departmentTypeMap, + accountDetails, + deptList, + setDeptList, + selectedDepartment, + setSelectedDepartment, + updateSelectedDepartment, + selectedDepartmentColorPicker + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 5da916c..565fe7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "expo-system-ui": "~3.0.7", "expo-web-browser": "~13.0.3", "formik": "^2.4.6", + "healthicons-react-native": "^3.0.0", "react": "18.2.0", "react-dom": "18.2.0", "react-native": "0.74.3", @@ -29,6 +30,7 @@ "react-native-reanimated": "~3.10.1", "react-native-safe-area-context": "4.10.5", "react-native-screens": "3.31.1", + "react-native-svg": "^15.7.1", "react-native-textinput-effects": "^0.6.3", "react-native-web": "~0.19.10", "styled-components": "^6.1.12" @@ -7724,6 +7726,12 @@ "node": ">= 6" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, "node_modules/bplist-creator": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.7.tgz", @@ -8558,6 +8566,22 @@ "hyphenate-style-name": "^1.0.3" } }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/css-to-react-native": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", @@ -8568,6 +8592,40 @@ "postcss-value-parser": "^4.0.2" } }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-tree/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -8907,6 +8965,32 @@ "node": ">=8" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, "node_modules/domexception": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", @@ -8920,6 +9004,35 @@ "node": ">=12" } }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dotenv": { "version": "16.4.5", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", @@ -8997,7 +9110,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, "engines": { "node": ">=0.12" }, @@ -10467,6 +10579,16 @@ "node": ">= 0.4" } }, + "node_modules/healthicons-react-native": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/healthicons-react-native/-/healthicons-react-native-3.0.0.tgz", + "integrity": "sha512-0M9Tz+72tnQgv+LpneTCEwQgmXOgbdEVILiqdEtOYC/ADmlJeMGWSjJlYiur9+/jLW0uLkUuYDe6ePz5bXxB3g==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.6 || ^17 || ^18", + "react-native": ">=0.50.0" + } + }, "node_modules/hermes-estree": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.19.1.tgz", @@ -14086,6 +14208,12 @@ "resolved": "https://registry.npmjs.org/md5hex/-/md5hex-1.0.0.tgz", "integrity": "sha512-c2YOUbp33+6thdCUi34xIyOU/a7bvGKj/3DB1iaPMTuPHf/Q2d5s4sn1FaCOO43XkXggnb08y5W2PU8UNYNLKQ==" }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "license": "CC0-1.0" + }, "node_modules/memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", @@ -14935,6 +15063,18 @@ "node": ">=4" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/nullthrows": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", @@ -15914,6 +16054,21 @@ "react-native": "*" } }, + "node_modules/react-native-svg": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.7.1.tgz", + "integrity": "sha512-Xc11L4t6/DtmUwrQqHR7S45Qy3cIWpcfGlmEatVeZ9c1N8eAK79heJmGRgCOVrXESrrLEHfP/AYGf0BGyrvV6A==", + "license": "MIT", + "dependencies": { + "css-select": "^5.1.0", + "css-tree": "^1.1.3", + "warn-once": "0.1.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-textinput-effects": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/react-native-textinput-effects/-/react-native-textinput-effects-0.6.3.tgz", diff --git a/package.json b/package.json index 2d2a2ae..ff3bb92 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "expo-system-ui": "~3.0.7", "expo-web-browser": "~13.0.3", "formik": "^2.4.6", + "healthicons-react-native": "^3.0.0", "react": "18.2.0", "react-dom": "18.2.0", "react-native": "0.74.3", @@ -36,6 +37,7 @@ "react-native-reanimated": "~3.10.1", "react-native-safe-area-context": "4.10.5", "react-native-screens": "3.31.1", + "react-native-svg": "^15.7.1", "react-native-textinput-effects": "^0.6.3", "react-native-web": "~0.19.10", "styled-components": "^6.1.12"