Tones/app/incidents.jsx

357 lines
13 KiB
React
Raw Normal View History

import React, { useState, useRef, useEffect } from 'react';
import styled from 'styled-components';
import { useCallFeed } from '@/hooks';
2025-04-19 06:36:25 +00:00
import { router } from 'expo-router';
import { Platform, Linking, View, ScrollView, Text, TouchableOpacity } from 'react-native';
2025-04-19 06:36:25 +00:00
import { StatusBar } from 'expo-status-bar';
import { SafeAreaView } from 'react-native-safe-area-context';
import {
2025-08-10 14:14:56 +00:00
PageHeader,
PageFooter,
} from '@/components/generalHelpers.jsx';
import { Ionicons } from '@expo/vector-icons';
2025-04-19 06:36:25 +00:00
import { AccidentAndEmergency } from "healthicons-react-native/dist/outline";
import ActionSheet from 'react-native-actions-sheet';
const DepartmentActionSheet = styled(ActionSheet)``;
export default function Incidents() {
const actionSheetRef = useRef(null);
const callFeed = useCallFeed();
const {
2025-08-10 14:14:56 +00:00
departments,
callIconMap,
callDetails,
callColorSelector,
formatCallTimePast,
formatCallDateTime
} = callFeed;
2025-08-11 19:34:16 +00:00
const sortedAndFilteredCalls = callDetails.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))
2025-08-10 14:14:56 +00:00
.filter((item, index, self) => {
return index === self.findIndex(i => {
2025-08-11 19:34:16 +00:00
return `${i?.incident?.incID}${i?.response?.serviceName}` === `${item?.incident?.incID}${item?.response?.serviceName}`
});
2025-08-11 19:34:16 +00:00
})?.map(item => { return {...item, timestamp: item?.incident?.incDate} })
|| [];
2025-04-19 06:36:25 +00:00
const {
2025-08-10 14:14:56 +00:00
departmentTypeMap,
accountDetails,
deptList,
setDeptList,
selectedDepartment,
setSelectedDepartment,
updateSelectedDepartment,
selectedDepartmentColorPicker,
} = departments;
return (
<React.Fragment>
<PageHeader>
2025-08-10 14:14:56 +00:00
<View
style={{
flexDirection: 'column',
height: 80,
alignItems: 'center',
justifyContent: 'flex-end',
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();
}}
>
2025-08-10 14:14:56 +00:00
<Text
style={{
color: selectedDepartmentColorPicker(selectedDepartment?.type),
fontWeight: 600,
fontSize: 14
}}
>
{selectedDepartment?.deptAbv}
</Text>
</TouchableOpacity>
</View>
</PageHeader>
<ScrollView>
2025-08-10 14:14:56 +00:00
<StatusBar style="dark" />
<SafeAreaView />
<View style={{ flexDirection: 'column', padding: 20 }}>
{sortedAndFilteredCalls?.length ? (
sortedAndFilteredCalls?.map((callItem, index) => {
2025-08-11 19:34:16 +00:00
const { incident, address, response, timestamp } = callItem;
const {
2025-08-11 19:34:16 +00:00
serviceNumber,
incDate,
incNature,
incNatureCode,
incNatureCodeDesc,
status,
} = incident;
const {
2025-08-11 19:34:16 +00:00
streetAddress,
addressApartment,
town,
state,
locationName,
} = address;
const {
2025-08-11 19:34:16 +00:00
serviceName
} = response;
const SelectedIcon = callIconMap[incNature] || AccidentAndEmergency;
return (
2025-08-10 14:14:56 +00:00
<TouchableOpacity
key={`callDetails - ${timestamp}`}
2025-08-11 19:34:16 +00:00
style={{ paddingBottom: 15 }}
onPress={() => {
router.push({
pathname: '/call',
params: {
callDetails: btoa(JSON.stringify(call))
}
})
}}
>
2025-08-10 14:14:56 +00:00
<View
style={{
borderRadius: 12,
elevation: 3,
backgroundColor: '#fff',
shadowOffset: { width: 0, height: 0 },
shadowColor: callColorSelector(
2025-08-11 19:34:16 +00:00
incNatureCodeDesc,
incNature,
status
),
shadowOpacity: 1,
shadowRadius: 5,
padding: 10,
}}
>
<View style={{ flexDirection: 'column' }}>
<View key="callDateAndTime"
2025-08-10 14:14:56 +00:00
style={{
paddingBottom: 6,
2025-08-10 14:14:56 +00:00
flexDirection: 'row',
justifyContent: 'space-between'
}}
>
2025-08-11 19:34:16 +00:00
<Text style={{ fontSize: 12 }}>{formatCallDateTime(incDate)}</Text>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
2025-08-11 19:34:16 +00:00
<Text style={{ fontSize: 12 }}>{formatCallTimePast(incDate)}</Text>
{status === 'CLOSED' ? (
<Ionicons
name="lock-closed-outline"
color='red'
style={{
2025-08-10 14:14:56 +00:00
shadowColor: 'black',
shadowOffset: 0,
2025-08-10 14:14:56 +00:00
shadowOpacity: 1,
shadowRadius: 10
}}
/>
) : null}
</View>
</View>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
2025-08-10 14:14:56 +00:00
<SelectedIcon
color={callColorSelector(
2025-08-11 19:34:16 +00:00
incNatureCodeDesc,
incNature,
status
2025-08-10 14:14:56 +00:00
)}
opacity={0.3}
width={56}
height={56}
/>
<View style={{ flexDirection: 'column' }}>
2025-08-11 19:34:16 +00:00
{locationName ? (
2025-08-10 14:14:56 +00:00
<Text
style={{
color: 'black',
fontWeight: 600,
fontSize: 16
}}
>
2025-08-11 19:34:16 +00:00
{`${locationName}`}
2025-08-10 14:14:56 +00:00
</Text>
) : (
<View style={{ flexDirection: 'row' }}>
2025-08-10 14:14:56 +00:00
<Text
style={[{
color: 'black',
2025-08-10 14:14:56 +00:00
fontSize: 12,
fontWeight: 600
}]}
>
2025-08-11 19:34:16 +00:00
{`${streetAddress?.split(',')[0]}`}
</Text>
2025-08-11 19:34:16 +00:00
{addressApartment ? (
2025-08-10 14:14:56 +00:00
<Text
style={[{
color: 'black',
2025-08-10 14:14:56 +00:00
fontSize: 12,
fontWeight: 600
}]}
>
2025-08-11 19:34:16 +00:00
{` - ${addressApartment}`}
</Text>
2025-08-10 14:14:56 +00:00
) : null}
<Text
style={[{
color: 'black',
2025-08-10 14:14:56 +00:00
fontSize: 12,
fontWeight: 600
}]}
>
2025-08-11 19:34:16 +00:00
{` ${town}, ${state}`}
</Text>
</View>
)}
2025-08-10 14:14:56 +00:00
<Text
style={{
color: 'black',
fontWeight: 600,
fontSize: 16
}}
>
2025-08-11 19:34:16 +00:00
{`${incNature}`}
</Text>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
2025-08-10 14:14:56 +00:00
<Text
style={{
color: 'black',
fontSize: 12,
textShadowColor: callColorSelector(
2025-08-11 19:34:16 +00:00
incNatureCode,
incNature,
status
2025-08-10 14:14:56 +00:00
),
textShadowRadius: 1
}}
>
2025-08-11 19:34:16 +00:00
{`${incNatureCodeDesc}`}
</Text>
</View>
</View>
<View style={{ padding: 0 }}>
2025-08-10 14:14:56 +00:00
<View>
<Ionicons name="chevron-forward-outline" />
</View>
</View>
</View>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<Text
2025-08-10 14:14:56 +00:00
style={{
fontSize: 12,
}}
>
2025-08-11 19:34:16 +00:00
Service: {serviceName}
</Text>
<Text
style={{
fontSize: 12,
textAlign: 'right'
}}
>
2025-08-11 19:34:16 +00:00
{`Incident #: ${serviceNumber}`}
</Text>
</View>
</View>
</View>
</TouchableOpacity>
)
})) : (
2025-08-10 14:14:56 +00:00
<Text>There are no Calls</Text>
)}
</View>
2025-08-10 14:14:56 +00:00
</ScrollView>
<PageFooter>
<View
style={{
flexDirection: 'column',
height: 100,
alignItems: 'center',
justifyContent: 'flex-start',
paddingTop: 7
}}
/>
2025-08-10 14:14:56 +00:00
</PageFooter>
<DepartmentActionSheet
ref={actionSheetRef}
gestureEnabled
containerStyle={{
2025-08-10 14:14:56 +00:00
height: "50%",
width: "100%",
backgroundColor: '#ECEDEE',
}}
2025-08-10 14:14:56 +00:00
>
<View style={{ flexDirection: 'column', padding: 20 }}>
2025-08-10 14:14:56 +00:00
{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>
2025-08-10 14:14:56 +00:00
</DepartmentActionSheet>
</React.Fragment>
)
}