Browse Source

refactor(Incident Report) : get and post data

master
farhantock 3 months ago
parent
commit
0f8f5d1f3c
  1. 138
      src/screens/incident-page/dialogForm.js
  2. 117
      src/screens/incident-page/index.js
  3. 228
      src/screens/incident-page/stepComponent/chronology.js
  4. 107
      src/screens/incident-page/stepComponent/containedAction.js
  5. 182
      src/screens/incident-page/stepComponent/incident.js
  6. 147
      src/screens/incident-page/stepComponent/location.js
  7. 208
      src/screens/incident-page/stepComponent/media.js
  8. 71
      src/screens/incident-page/stepComponent/report.js
  9. 35
      src/screens/incident-page/stepComponent/time.js

138
src/screens/incident-page/dialogForm.js

@ -1,6 +1,6 @@
import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react';
import { StatusBar } from 'react-native';
import { Button, Text, Appbar, } from 'react-native-paper';
import { BackHandler, StatusBar } from 'react-native';
import { Button, Dialog, Appbar, useTheme, Text, } from 'react-native-paper';
import { StyleSheet, View, } from 'react-native';
import { colors } from '../../utils/color';
import { strings } from '../../utils/i18n';
@ -11,10 +11,97 @@ import ReportScreen from './stepComponent/report';
import IncidentScreen from './stepComponent/incident';
import ChronologyScreen from './stepComponent/chronology';
import MediaScreen from './stepComponent/media';
import { useFocusEffect } from '@react-navigation/native';
import { resetIncidentReport } from '../../appredux/actions';
import { useDispatch } from 'react-redux';
import {
setIncidentDate, setIncidentTime, setReportDate, setReportTime, setDataRecepient, setDataReporter,
setArea, setIncidentLocation, setReportLocation, setDataIncident, setDataAchievement, setDataTypeRisk,
setIncidentRiskPotential, setRiskLevel, setChronology, setRootCase, setDataPrevention
} from '../../appredux/modules/incidentReport/actions';
export default function DialogForm({ route, navigation }) {
const theme = useTheme()
const dispatch = useDispatch()
const isDarkTheme = theme.dark
const [active, setActive] = useState(0);
const labels = ["Waktu", "Lokasi", "Pelapor", "Kejadian", "Kronologis", "Media"];
const [visible, setVisible] = useState(false);
const showDialog = () => setVisible(true);
const hideDialog = () => setVisible(false);
const labels = [strings('incidentReport.timeStep'), strings('incidentReport.locationStep'), strings('incidentReport.reportStep'), strings("incidentReport.incidentStep"), strings('incidentReport.chronologyStep'), "Media"];
useEffect(() => {
if (route.params?.item) {
const { item } = route.params;
console.log("item.incidentDate", item.info);
dispatch(setIncidentDate(item.info.incidentDate));
dispatch(setReportDate(item.info.reportDate));
dispatch(setDataRecepient(item.info.dataRecipient));
dispatch(setDataReporter(item.info.dataReporter));
dispatch(setArea(item.info.areaType));
dispatch(setIncidentLocation(item.info.incidentLocation));
dispatch(setReportLocation(item.info.reportLocation));
dispatch(setDataIncident(item.info.incidentList));
dispatch(setDataAchievement(item.info.achievement));
dispatch(setIncidentRiskPotential(item.info.incidentRiskPotential));
dispatch(setRiskLevel(item.info.riskLevel));
dispatch(setChronology(item.info.chronology));
dispatch(setRootCase(item.info.rootCase));
dispatch(setDataPrevention(item.info.prevention));
dispatch(setDataTypeRisk(item.info.typeRiskIncident));
}
}, [route.params?.item]);
useFocusEffect(
useCallback(() => {
const onBackPress = () => {
if (active === 0) {
showDialog();
return true; // prevent default behavior (navigation back)
} else {
setActive(prevActive => prevActive - 1);
return true;
}
};
BackHandler.addEventListener('hardwareBackPress', onBackPress);
return () => BackHandler.removeEventListener('hardwareBackPress', onBackPress);
}, [active])
);
const handleSendIncidentReport = async () => {
const payload = {
project_charter_id: projectCharter,
info: {
achievement: dataAchievment,
incidentList: dataIncidentReport,
incidentDate: incidentDate,
reportDate: reportDate,
incidentLocation: incidentLocation,
reportLocation: reportLocation,
prevention: dataPrevention,
incidentRiskPotential: incidentRiskPotential,
areaType: area,
chronology: chronology,
rootCase: rootCase,
riskLevel: riskLevel,
supervisor: supervisor,
reporter: reporter,
typeRiskIncident: typeRiskIncident,
date: date,
dataReporter: dataReporter,
dataRecipient: dataRecipient,
etc: otherText,
etcAchievment: otherTextAchievment
},
status: statusReport
};
}
const renderStepContent = useMemo(() => {
switch (active) {
@ -47,13 +134,13 @@ export default function DialogForm({ route, navigation }) {
}
};
return (
<View style={styles.container}>
<View style={[styles.container, { backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.pureWhite }]}>
<StatusBar backgroundColor={colors.beanRed} barStyle="light-content" />
<Appbar.Header mode='center-aligned' style={{ backgroundColor: colors.beanRed }}>
<Appbar.BackAction color={colors.pureWhite} onPress={() => { navigation.goBack() }} />
<Appbar.BackAction color={colors.pureWhite} onPress={showDialog} />
<Appbar.Content titleStyle={{ fontWeight: 'bold' }} color={colors.pureWhite} title={strings('incidentReport.title')} />
</Appbar.Header>
<View style={{ width: '100%', marginTop: 15, marginBottom: 2, backgroundColor: colors.pureWhite }}>
<View style={{ width: '100%', marginTop: 15, marginBottom: 2, backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.pureWhite }}>
<StepIndicator
stepCount={labels.length}
customStyles={stepIndicatorStyles}
@ -71,17 +158,34 @@ export default function DialogForm({ route, navigation }) {
</Button>
{active === labels.length - 1 ?
(
<Button mode="contained" style={[styles.button, { backgroundColor: colors.beanRed }]} onPress={() => console.log('Handle Saved')}>
<Button mode="contained" textColor={isDarkTheme ? theme.colors.surface : theme.colors.pureWhite} style={[styles.button, { backgroundColor: colors.beanRed }]} onPress={() => console.log('Handle Saved')}>
Simpan
</Button>
)
: (
<Button mode="contained" style={[styles.button, { backgroundColor: colors.beanRed }]} onPress={handleNext}>
<Button mode="contained" textColor={isDarkTheme ? theme.colors.surface : theme.colors.pureWhite} style={[styles.button, { backgroundColor: colors.beanRed }]} onPress={handleNext}>
Lanjut
</Button>
)}
</View>
<Dialog visible={visible} onDismiss={hideDialog} style={[styles.dialog, { backgroundColor: isDarkTheme ? theme.colors.background : theme.colors.pureWhite }]}>
<Dialog.Title style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }}>{strings('global.confirm')}</Dialog.Title>
<Dialog.Content>
<Text variant="bodyLarge" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }}>{strings('global.backMessage')}</Text>
<Text variant="bodyMedium" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }}>{strings('global.message')}</Text>
<Button buttonColor={colors.blue} textColor={theme.colors.pureWhite} style={{ borderRadius: 10, marginVertical: 20, paddingVertical: 5 }} contentStyle={{ flexDirection: 'row-reverse' }} mode="contained" onPress={() => {
dispatch(resetIncidentReport());
navigation.goBack();
}}>
{strings('global.yes')}
</Button>
<Button style={{ borderRadius: 10, paddingVertical: 5 }} contentStyle={{ flexDirection: 'row-reverse' }} textColor={isDarkTheme ? theme.colors.semiBlue : theme.colors.blue} mode="outlined" onPress={hideDialog}>
{strings('global.no')}
</Button>
</Dialog.Content>
</Dialog>
</View >
)
}
@ -90,7 +194,6 @@ const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 20,
backgroundColor: colors.pureWhite
},
cardView: {
marginTop: 10,
@ -114,7 +217,14 @@ const styles = StyleSheet.create({
padding: 10,
paddingBottom: 20,
},
dialog: {
marginVertical: 20,
padding: 20,
marginHorizontal: 20,
borderRadius: 10,
justifyContent: "center",
alignItems: "center"
}
})
const stepIndicatorStyles = {
@ -133,12 +243,12 @@ const stepIndicatorStyles = {
stepIndicatorFinishedColor: colors.beanRed,
stepIndicatorUnFinishedColor: colors.semiRed,
stepIndicatorCurrentColor: colors.beanRed,
stepIndicatorLabelFontSize: 12,
currentStepIndicatorLabelFontSize: 12,
stepIndicatorLabelFontSize: 11,
currentStepIndicatorLabelFontSize: 11,
stepIndicatorLabelCurrentColor: colors.pureWhite,
stepIndicatorLabelFinishedColor: colors.pureWhite,
stepIndicatorLabelUnFinishedColor: colors.beanRed,
labelColor: colors.semiRed,
labelSize: 12,
labelSize: 11,
currentStepLabelColor: colors.beanRed
}

117
src/screens/incident-page/index.js

@ -4,24 +4,77 @@ import { RefreshControl, StyleSheet, View, ScrollView, Image, Dimensions, Status
import { colors } from '../../utils/color';
import Icon from 'react-native-vector-icons/AntDesign';
import { strings } from '../../utils/i18n';
import RequestModule from '../../services/api/request';
import moment from 'moment';
import 'moment/locale/id';
import { useSelector } from 'react-redux';
moment.locale('id');
const PAGE_SIZE = 25;
export default function IncidentScreen({ route, navigation }) {
const incidentData = [
{ id: 1, date: "Senin, 02-05-2024 21:03", location: "Kangean Site Indonesia", company: "Kangean Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "KEI2301M" },
{ id: 2, date: "Selasa, 03-05-2024 10:15", location: "Sumatra Site Indonesia", company: "Sumatra Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "SEI2402M" },
{ id: 3, date: "Rabu, 04-05-2024 15:20", location: "Java Site Indonesia", company: "Java Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "JEI2503M" },
{ id: 4, date: "Kamis, 05-05-2024 18:30", location: "Bali Site Indonesia", company: "Bali Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "BEI2604M" },
{ id: 5, date: "Jumat, 06-05-2024 08:00", location: "Sulawesi Site Indonesia", company: "Sulawesi Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "SEI2705M" },
{ id: 5, date: "Sabtu, 07-05-2024 08:00", location: "Sulawesi Site Indonesia", company: "Sulawesi Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "SEI2705M" },
{ id: 5, date: "Minggu, 08-05-2024 08:00", location: "Sulawesi Site Indonesia", company: "Sulawesi Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "SEI2705M" }
];
const theme = useTheme();
const isDarkTheme = theme.dark;
const { user } = useSelector(state => state.userReducer);
const request = new RequestModule('incident-report');
const [refreshing, setRefreshing] = useState(false);
const [page, setPage] = useState(0);
const [dataIncident, setDataIncident] = useState([]);
const [loading, setLoading] = useState(false);
const onRefresh = useCallback(() => {
setRefreshing(true);
setPage(0);
getIncidentData(0);
}, []);
useEffect(() => {
getIncidentData(page);
}, [page]);
const getIncidentData = async (pageNum) => {
if (loading) return;
setLoading(true);
const payload = {
paging: { start: pageNum * PAGE_SIZE, length: PAGE_SIZE },
joins: [
{ name: 'project_charter', column_join: 'project_charter_id', column_results: ['sicn', 'project_name', 'icn', 'regional', 'client_name'] },
{ name: "m_regional", column_join: "id", references: "project_charter.regional", column_results: ['name'] },
],
columns: [
{ name: 'project_charter_id', logic_operator: '=', value: user?.assigment_hr?.project_charter_id.toString(), operator: 'AND' },
{ name: 'deleted_at', logic_operator: 'IS NULL', operator: 'AND' },
],
orders: { columns: ['created_at', 'id'], ascending: false },
};
const result = await request.getDataSearch(payload);
setDataIncident((prevData) =>
pageNum === 0 ? result.data.data : [...prevData, ...result.data.data]
);
setPage(pageNum + 1);
setRefreshing(false);
setLoading(false);
};
const handleScroll = ({ nativeEvent }) => {
if (isCloseToBottom(nativeEvent)) {
getPresenceHistory(page);
}
};
const isCloseToBottom = ({ layoutMeasurement, contentOffset, contentSize }) => {
return layoutMeasurement.height + contentOffset.y >= contentSize.height - 20;
};
const handleEdit = (item) => {
navigation.navigate('DialogFormIncident', { item });
};
return (
<View style={styles.container}>
<StatusBar backgroundColor={colors.white} barStyle='dark-content' translucent={true} />
<Appbar.Header mode='center-aligned' style={{ backgroundColor: colors.pureWhite, elevation: 4 }}>
<View style={[styles.container, { backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.pureWhite }]}>
<StatusBar backgroundColor={isDarkTheme ? theme.colors.background : theme.colors.pureWhite} barStyle={isDarkTheme ? 'light-content' : 'dark-content'} translucent={true} />
<Appbar.Header mode='center-aligned' style={{ backgroundColor: isDarkTheme ? theme.colors.background : theme.colors.pureWhite, elevation: 4 }}>
<Appbar.BackAction onPress={() => { navigation.goBack() }} />
<Appbar.Content titleStyle={{ fontWeight: 'bold' }} title={strings('incidentReport.title')} />
<Appbar.Content titleStyle={{ fontWeight: 'bold' }} color={isDarkTheme ? theme.colors.pureWhite : theme.colors.black} title={strings('incidentReport.title')} />
</Appbar.Header>
<View style={{ width: '100%', marginTop: 10, marginBottom: 5 }}>
@ -29,23 +82,34 @@ export default function IncidentScreen({ route, navigation }) {
{strings('incidentReport.add')}
</Button>
</View>
<ScrollView style={{ backgroundColor: colors.pureWhite }}>
{incidentData.map((incident) => (
<TouchableRipple key={incident.id} onPress={() => { navigation.navigate('DialogFormIncident') }}>
<Card key={incident.id} elevation={2} style={styles.card}>
<ScrollView
style={{ flex: 1, marginTop: 5, backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.pureWhite }}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
colors={[colors.blue]}
progressBackgroundColor={colors.pureWhite}
/>
}
onScroll={handleScroll}
scrollEventThrottle={400}
>
{dataIncident.map((incident) => (
<TouchableRipple key={incident.id} onPress={() => handleEdit(incident)}>
<Card key={incident.id} elevation={2} style={[styles.card, { backgroundColor: isDarkTheme ? theme.colors.background : theme.colors.pureWhite }]}>
<View style={styles.cardContent}>
<View style={styles.leftContent}>
<Icon name="warning" size={25} color={colors.blue} />
<Icon name="warning" size={25} color={isDarkTheme ? theme.colors.pureWhite : theme.colors.blue} />
</View>
<View style={styles.midContent}>
<Text variant="bodySmall" style={styles.subText}>{incident.date}</Text>
<Text variant="headlineMedium" style={styles.Text}>{incident.location}</Text>
<Text variant="bodySmall" style={styles.subText}>{incident.company}</Text>
<Text variant="bodySmall" style={styles.subText}>{incident.icn} - {incident.sicn}</Text>
<Text variant="bodySmall" style={[styles.subText, { color: isDarkTheme ? theme.colors.pureWhite : theme.colors.blue }]}>{moment(incident.created_at).format('dddd, DD-MM-YYYY HH:mm')}</Text>
<Text variant="headlineMedium" style={[styles.Text, { color: isDarkTheme ? theme.colors.pureWhite : theme.colors.blue }]}>{incident.join.project_charter_project_name}</Text>
<Text variant="bodySmall" style={[styles.subText, { color: isDarkTheme ? theme.colors.pureWhite : theme.colors.blue }]}>{incident.join.project_charter_client_name}</Text>
<Text variant="bodySmall" style={[styles.subText, { color: isDarkTheme ? theme.colors.pureWhite : theme.colors.blue }]}>{incident.join.project_charter_icn} - {incident.join.project_charter_sicn}</Text>
</View>
<View style={styles.rightContent}>
<Icon name="right" size={25} color={colors.blue} />
<Icon name="right" size={25} color={isDarkTheme ? theme.colors.pureWhite : theme.colors.blue} />
</View>
</View>
</Card>
@ -60,22 +124,19 @@ const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 20,
backgroundColor: colors.pureWhite
},
Text: {
fontSize: 16,
fontWeight: 'bold',
color: colors.blue
},
card: {
flex: 1,
marginHorizontal: 8,
marginVertical: 5,
backgroundColor: colors.pureWhite,
},
subText: {
fontSize: 12,
color: colors.blue
},
cardContent: {
flexDirection: 'row',

228
src/screens/incident-page/stepComponent/chronology.js

@ -1,6 +1,6 @@
import React, { useState, useEffect, useRef, useMemo, useCallback } from 'react';
import { List, TouchableRipple, TextInput, Card, Text, Button } from 'react-native-paper';
import { View, StyleSheet, ScrollView } from 'react-native';
import { List, TouchableRipple, TextInput, Card, Text, Button, useTheme } from 'react-native-paper';
import { View, StyleSheet, ScrollView, useWindowDimensions } from 'react-native';
import DateTimePicker from '@react-native-community/datetimepicker';
import moment from 'moment';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
@ -11,12 +11,26 @@ import {
BottomSheetScrollView
} from '@gorhom/bottom-sheet';
import { strings } from '../../../utils/i18n';
import { useDispatch, useSelector } from 'react-redux';
import { RichEditor, RichToolbar, actions } from 'react-native-pell-rich-editor';
import { setIncidentRiskPotential, setRiskLevel, setChronology, setRootCase, setDataPrevention } from '../../../appredux/actions';
export default function ChronologyScreen({ route, navigation }) {
const [chronology, setChronology] = useState('')
const [incidentRiskPotential, setIncidentRiskPotential] = useState({ impact: "", likelihood: "", value: "", impactDescription: "", likelihoodDescription: "" })
const [riskLevel, setRiskLevel] = useState({ level: "", backgroundColor: '', color: '' })
const theme = useTheme();
const isDarkTheme = theme.dark;
const dispatch = useDispatch();
const colorsheet = isDarkTheme ? theme.colors.black : theme.colors.pureWhite;
const typeRiskIncident = useSelector(state => state.incidentReportReducer.typeRiskIncident);
const riskLevel = useSelector(state => state.incidentReportReducer.riskLevel);
const incidentRiskPotential = useSelector(state => state.incidentReportReducer.incidentRiskPotential);
const chronology = useSelector(state => state.incidentReportReducer.chronology);
const rootCase = useSelector(state => state.incidentReportReducer.rootCase);
const dataPrevention = useSelector(state => state.incidentReportReducer.dataPrevention);
const bottomSheetModalImpactRef = useRef(null);
const bottomSheetModalLikelihoodRef = useRef(null);
const chronologyText = useRef();
const rootcaseText = useRef();
const snapPoints = useMemo(() => ['25%', '50%'], []);
@ -28,6 +42,20 @@ export default function ChronologyScreen({ route, navigation }) {
bottomSheetModalLikelihoodRef.current?.present();
}, []);
// useEffect(() => {
// if (route.params?.isSaved) {
// Toast.show({ type: 'success', text1: 'Berhasil di simpan' }); // Show success toast
// }
// }, [route.params?.isSaved]);
const handleEdit = (item) => {
navigation.navigate('ContainedActionScreen', { item });
};
const handleDelete = (id) => {
const updatedData = dataPrevention.filter(prevention => prevention.id !== id);
dispatch(setDataPrevention(updatedData));
};
useEffect(() => {
if (incidentRiskPotential.impact !== "" && incidentRiskPotential.likelihood !== "") {
@ -37,48 +65,39 @@ export default function ChronologyScreen({ route, navigation }) {
const val = impactValue * likelihoodValue;
let newRiskLevel, backgroundColor, color;
if (val >= 1 && val <= 5) {
backgroundColor = '#E3F8E8'
color = '#17C13E'
backgroundColor = colors.semigreen
color = colors.green
newRiskLevel = 'Rendah';
} else if (val >= 6 && val <= 10) {
backgroundColor = "#F8DC49"
backgroundColor = colors.yellow
color = "white"
newRiskLevel = 'Sedang';
} else if (val >= 11 && val <= 15) {
backgroundColor = '#FFD9AF'
color = '#EC9C3D'
backgroundColor = colors.semiRed
color = colors.beanRed
newRiskLevel = 'Tinggi';
} else {
backgroundColor = '#FFC5C3'
color = '#D9534F'
backgroundColor = colors.red
color = colors.white
newRiskLevel = 'Bencana';
}
if (incidentRiskPotential.value !== val.toString() || riskLevel.level !== newRiskLevel || riskLevel.backgroundColor !== backgroundColor || riskLevel.color !== color) {
setIncidentRiskPotential(prevState => ({ ...prevState, value: val.toString() }));
setRiskLevel({ level: newRiskLevel, backgroundColor: backgroundColor, color: color });
dispatch(setIncidentRiskPotential({ ...incidentRiskPotential, value: val.toString() }));
dispatch(setRiskLevel({ level: newRiskLevel, backgroundColor: backgroundColor, color: color }));
}
}
}, [incidentRiskPotential, riskLevel]);
}, [typeRiskIncident, incidentRiskPotential, riskLevel]);
const handleSelectImpact = (impact) => {
setIncidentRiskPotential(prevState => ({
...prevState,
impact: impact.label,
value: impact.value,
impactDescription: impact.description
}));
dispatch(setIncidentRiskPotential({ ...incidentRiskPotential, impact: impact.label, value: impact.value, impactDescription: impact.description }));
bottomSheetModalImpactRef.current?.dismiss();
};
const handleSelectLikelihood = (likelihood) => {
setIncidentRiskPotential(prevState => ({
...prevState,
likelihood: likelihood.label,
likelihoodDescription: likelihood.description
}));
dispatch(setIncidentRiskPotential({ ...incidentRiskPotential, likelihood: likelihood.label, likelihoodDescription: likelihood.description }));
bottomSheetModalLikelihoodRef.current?.dismiss();
};
@ -118,6 +137,7 @@ export default function ChronologyScreen({ route, navigation }) {
<View>
<TouchableRipple key={dataTranslasiImpact[data.label]} onPress={() => handleSelectImpact(data)}>
<List.Item
key={data.label}
title={dataTranslasiImpact[data.label]}
/>
</TouchableRipple>
@ -127,54 +147,77 @@ export default function ChronologyScreen({ route, navigation }) {
<View>
<TouchableRipple key={dataTranslasiLikelihood[data.label]} onPress={() => handleSelectLikelihood(data)}>
<List.Item
key={data.label}
title={dataTranslasiLikelihood[data.label]}
/>
</TouchableRipple>
</View>
);
return (
<>
<Card style={{ backgroundColor: colors.semiRed, paddingVertical: 15, paddingHorizontal: 15, marginHorizontal: 8, marginVertical: 5, borderRadius: 5 }}>
<View>
<Text variant="bodySmall" style={{ color: colors.beanRed, fontWeight: 'bold', fontSize: 16 }}>
<Text variant="bodyLarge" style={{ color: colors.beanRed, fontWeight: 'bold' }}>
Kronologis kejadian
</Text>
<Text variant="bodySmall" style={{ color: colors.beanRed, fontSize: 12 }}>
<Text variant="bodySmall" style={{ color: colors.beanRed }}>
Jelaskan bagaimana terjadinya insiden
</Text>
</View>
</Card>
<ScrollView>
<View style={styles.container}>
<TextInput
dense={true}
underlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
label="Kronologis Singkat Kejadian"
mode="outlined"
placeholder='Isi kronologis'
multiline={true}
numberOfLines={5}
value={chronology}
onChangeText={(text) => {
setChronology(text)
<Text variant="bodyLarge" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }}>
Kronologis Singkat Kejadian
</Text>
<RichEditor
ref={chronologyText}
placeholder='Kronologis Singkat Kejadian'
disabled={false}
containerStyle={{ backgroundColor: colorsheet, borderWidth: 1, borderColor: colors.colorsheet }}
initialContentHTML={chronology}
editorStyle={{ backgroundColor: colorsheet, color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }}
onChange={(text) => {
dispatch(setChronology(text));
}}
/>
<TextInput
dense={true}
underlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
mode="outlined"
label="Penjelasan Permasalahan"
placeholder='Isi Permasalahan'
multiline={true}
numberOfLines={5}
onChangeText={(text) => {
setChronology(text)
<RichToolbar
editor={chronologyText}
actions={[actions.setBold, actions.setItalic, actions.setUnderline, actions.insertOrderedList,
actions.insertBulletsList]}
iconTint={isDarkTheme ? theme.colors.pureWhite : theme.colors.black}
selectedIconTint={isDarkTheme ? theme.colors.pureWhite : theme.colors.black}
selectedButtonStyle={{ backgroundColor: colors.blue }}
style={{ backgroundColor: colorsheet, borderColor: colors.colorsheet, marginBottom: 10 }}
/>
<Text variant="bodyLarge" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }}>
Penjelasan Singkat Kejadian
</Text>
<RichEditor
ref={rootcaseText}
placeholder='Kronologis Singkat Kejadian'
disabled={false}
containerStyle={{ backgroundColor: colorsheet, borderWidth: 1, borderColor: colors.colorsheet }}
initialContentHTML={rootCase}
editorStyle={{ backgroundColor: colorsheet, color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }}
onChange={(text) => {
dispatch(setRootCase(text));
}}
/>
<RichToolbar
editor={rootcaseText}
actions={[actions.setBold, actions.setItalic, actions.setUnderline, actions.insertOrderedList,
actions.insertBulletsList]}
iconTint={isDarkTheme ? theme.colors.pureWhite : theme.colors.black}
selectedIconTint={isDarkTheme ? theme.colors.pureWhite : theme.colors.black}
selectedButtonStyle={{ backgroundColor: colors.blue }}
style={{ backgroundColor: colorsheet, borderColor: colors.colorsheet, marginBottom: 10 }}
/>
<TouchableRipple onPress={handleOpenImpact}>
<TextInput
style={{ marginTop: 10 }}
@ -189,8 +232,8 @@ export default function ChronologyScreen({ route, navigation }) {
/>
</TouchableRipple>
{incidentRiskPotential.impactDescription && (
<Card style={{ backgroundColor: colors.pureWhite, paddingVertical: 15, paddingHorizontal: 15, marginVertical: 5, borderRadius: 5 }}>
<Text variant="bodySmall" style={{ fontSize: 12 }}>
<Card style={{ backgroundColor: isDarkTheme ? theme.colors.background : theme.colors.pureWhite, paddingVertical: 15, paddingHorizontal: 15, marginVertical: 5, borderRadius: 5 }}>
<Text variant="bodySmall" style={{ fontSize: 12, color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }}>
{incidentRiskPotential.impactDescription}
</Text>
</Card>
@ -209,50 +252,54 @@ export default function ChronologyScreen({ route, navigation }) {
</TouchableRipple>
{incidentRiskPotential.likelihoodDescription && (
<Card style={{ backgroundColor: colors.pureWhite, paddingVertical: 15, paddingHorizontal: 15, marginVertical: 5, borderRadius: 5 }}>
<Text variant="bodySmall" style={{ fontSize: 12 }}>
<Card style={{ backgroundColor: isDarkTheme ? theme.colors.background : theme.colors.pureWhite, paddingVertical: 15, paddingHorizontal: 15, marginVertical: 5, borderRadius: 5 }}>
<Text variant="bodySmall" style={{ fontSize: 12, color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }}>
{incidentRiskPotential.likelihoodDescription}
</Text>
</Card>
)}
<View style={styles.row}>
<Card style={{ flex: 1, marginRight: 5, backgroundColor: '#FFC5C3', paddingVertical: 15, paddingHorizontal: 15, marginVertical: 5, borderRadius: 5 }}>
<Text variant="bodySmall" style={{ fontSize: 12, color: '#D9534F' }}>
Critical
</Text>
</Card>
<Card style={{ flex: 1, marginLeft: 5, backgroundColor: riskLevel.backgroundColor, paddingVertical: 15, paddingHorizontal: 15, marginVertical: 5, borderRadius: 5 }}>
<Text variant="bodySmall" style={{ fontSize: 12, color: riskLevel.color }}>
{riskLevel.level} {incidentRiskPotential.value}
</Text>
</Card>
{typeRiskIncident &&
<Card style={{ flex: 1, marginRight: 5, backgroundColor: typeRiskIncident === 'Critical' ? colors.beanRed : typeRiskIncident === 'Major' ? colors.yellow : 'black', paddingVertical: 15, paddingHorizontal: 15, marginVertical: 5, borderRadius: 5 }}>
<Text variant="bodySmall" style={{ fontSize: 12, color: typeRiskIncident === 'Critical' ? colors.red : typeRiskIncident === 'Major' ? colors.black : 'black' }}>
{typeRiskIncident}
</Text>
</Card>
}
{incidentRiskPotential.value && riskLevel.level &&
<Card style={{ flex: 1, marginLeft: 5, backgroundColor: riskLevel.backgroundColor, paddingVertical: 15, paddingHorizontal: 15, marginVertical: 5, borderRadius: 5 }}>
<Text variant="bodySmall" style={{ fontSize: 12, color: riskLevel.color }}>
{riskLevel.level} {incidentRiskPotential.value}
</Text>
</Card>
}
</View>
<Text variant="bodySmall" style={{ color: colors.black, fontSize: 14 }}>
<Text variant="bodySmall" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black, fontSize: 14 }}>
Rencana tindakan pencegahan
</Text>
<Card elevation={2} style={styles.card}>
<View style={styles.cardContent}>
<View style={styles.leftContent}>
<Icon name="view-list" size={25} color={colors.blue} />
{dataPrevention.map(item => (
<Card elevation={2} style={[styles.card, { backgroundColor: isDarkTheme ? theme.colors.background : theme.colors.pureWhite }]}>
<View style={styles.cardContent}>
<View style={styles.leftContent}>
<Icon name="view-list" size={25} color={colors.blue} />
</View>
<View style={styles.midContent}>
<Text variant="bodySmall" style={[styles.subText, { color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }]}>{moment(item.date).format('DD-MM-YYYY')}</Text>
<Text variant="bodyMedium" style={[styles.subText, { color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }]}>{item.status}</Text>
<Text variant="headlineMedium" style={[styles.Text, { color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }]}>{item.who}</Text>
<Text variant="bodySmall" style={[styles.subText, { color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }]}>{item.plan}</Text>
</View>
</View>
<View style={styles.midContent}>
<Text variant="bodySmall" style={styles.subText}>01-03-2024</Text>
<Text variant="headlineMedium" style={styles.Text}>Farhan</Text>
<Text variant="bodySmall" style={styles.subText}>Melakukan pengamatan dan patroli area pagar luar Depo MRT</Text>
<View style={styles.buttonContainer}>
<Button mode="outlined" style={styles.button} textColor={colors.beanRed} onPress={() => handleEdit(item)}>
Edit
</Button>
<Button mode="contained" style={[styles.button, { backgroundColor: colors.beanRed }]} textColor={isDarkTheme ? theme.colors.black : theme.colors.pureWhite} onPress={() => handleDelete(item.id)}>
Hapus
</Button>
</View>
</View>
<View style={styles.buttonContainer}>
<Button mode="outlined" style={styles.button} textColor={colors.beanRed} onPress={() => { navigation.goBack() }} >
Edit
</Button>
<Button mode="contained" style={[styles.button, { backgroundColor: colors.beanRed }]} onPress={() => console.log('Handle Saved')}>
Hapus
</Button>
</View>
</Card>
{/* color: (typeRiskIncident === 'Critical' ? '#D9534F' : (typeRiskIncident === 'Major' ? '#EC9C3D' : 'black')) */}
</Card>
))}
</View>
</ScrollView>
<Button icon="plus" style={{ borderRadius: 10, backgroundColor: colors.semiBlue, marginHorizontal: 8, }} textColor={colors.blue} mode="contained-tonal" onPress={() => { navigation.navigate('ContainedActionScreen') }}>
@ -263,6 +310,7 @@ export default function ChronologyScreen({ route, navigation }) {
ref={bottomSheetModalImpactRef}
index={1}
snapPoints={snapPoints}
backgroundStyle={{ backgroundColor: colorsheet }}
>
<BottomSheetScrollView contentContainerStyle={styles.scrollView}>
{dataSelectImpact.map(item => renderImpact(item))}
@ -274,6 +322,7 @@ export default function ChronologyScreen({ route, navigation }) {
ref={bottomSheetModalLikelihoodRef}
index={1}
snapPoints={snapPoints}
backgroundStyle={{ backgroundColor: colorsheet }}
>
<BottomSheetScrollView contentContainerStyle={styles.scrollView}>
{dataSelectLikelihood.map(item => renderLikelihood(item))}
@ -308,17 +357,14 @@ const styles = StyleSheet.create({
Text: {
fontSize: 16,
fontWeight: 'bold',
color: colors.blue
},
card: {
flex: 1,
marginHorizontal: 8,
marginVertical: 5,
backgroundColor: colors.pureWhite,
},
subText: {
fontSize: 12,
color: colors.blue
},
row: {
flexDirection: 'row',

107
src/screens/incident-page/stepComponent/containedAction.js

@ -1,47 +1,89 @@
import React, { useState, useRef, useMemo, useCallback } from 'react';
import { TouchableRipple, TextInput, Appbar, List, Button } from 'react-native-paper';
import React, { useState, useRef, useCallback, useEffect } from 'react';
import { TouchableRipple, TextInput, Appbar, List, Button, useTheme } from 'react-native-paper';
import { View, StyleSheet, ScrollView } from 'react-native';
import DateTimePicker from '@react-native-community/datetimepicker';
import moment from 'moment';
import { colors } from '../../../utils/color';
import { strings } from '../../../utils/i18n';
import {
BottomSheetModal,
BottomSheetModalProvider,
BottomSheetView
} from '@gorhom/bottom-sheet';
import { BottomSheetModal, BottomSheetModalProvider, BottomSheetView } from '@gorhom/bottom-sheet';
import { useDispatch, useSelector } from 'react-redux';
import { setDataPrevention } from '../../../appredux/actions';
export default function ReportScreen({ route, navigation }) {
const theme = useTheme();
const isDarkTheme = theme.dark;
const dispatch = useDispatch();
const colorsheet = isDarkTheme ? theme.colors.black : theme.colors.pureWhite;
const dataPrevention = useSelector(state => state.incidentReportReducer.dataPrevention);
const [showIncidentDatePicker, setShowIncidentDatePicker] = useState(false);
const [date, setDate] = useState('');
const [status, setStatus] = useState('')
const [date, setDate] = useState(null);
const [status, setStatus] = useState('');
const [preventionPlan, setPreventionPlan] = useState('');
const [who, setWho] = useState('');
const [isEdit, setIsEdit] = useState(false);
const [editId, setEditId] = useState(null);
const bottomSheetModal = useRef(null);
useEffect(() => {
if (route.params?.item) {
const { item } = route.params;
console.log("item", item);
setPreventionPlan(item.plan);
setStatus(item.status);
setWho(item.who)
setDate(item.date)
setEditId(item.id);
setIsEdit(true)
}
}, [route.params?.item]);
const showIncidentDatePickerFunc = () => {
setShowIncidentDatePicker(true);
};
// const snapPoints = useMemo(() => ['10%', ], []);
const handleOpenSheet = useCallback(() => {
bottomSheetModal.current?.present();
}, []);
const handleStatus = (data) => {
setStatus(data)
setStatus(data);
bottomSheetModal.current?.dismiss();
}
};
const handleIncidentDateChange = (event, selectedDate) => {
const currentDate = selectedDate;
setShowIncidentDatePicker(false);
setDate(currentDate);
if (selectedDate) {
setDate(selectedDate);
}
};
const handleSave = () => {
const newPreventionData = {
id: editId || dataPrevention.length + 1,
plan: preventionPlan,
who: who,
date: date,
status: status
};
if (isEdit) {
const updatedData = dataPrevention.map(item => item.id === editId ? newPreventionData : item);
dispatch(setDataPrevention(updatedData));
} else {
dispatch(setDataPrevention([...dataPrevention, newPreventionData]));
}
navigation.goBack();
};
return (
<>
<Appbar.Header mode='center-aligned' style={{ backgroundColor: colors.beanRed }}>
<Appbar.BackAction color={colors.pureWhite} onPress={() => { navigation.goBack() }} />
<Appbar.Content titleStyle={{ fontWeight: 'bold' }} color={colors.pureWhite} title='Rencana pencegahan' />
</Appbar.Header>
<View style={styles.container}>
<ScrollView>
<ScrollView style={{ backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.pureWhite }}>
<View style={[styles.container, { backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.pureWhite }]}>
<TextInput
dense={true}
underlineColor={colors.amethystSmoke}
@ -50,8 +92,9 @@ export default function ReportScreen({ route, navigation }) {
mode="outlined"
multiline={true}
numberOfLines={5}
value={preventionPlan}
onChangeText={setPreventionPlan}
/>
<TextInput
style={{ marginTop: 10, marginBottom: 15 }}
dense={true}
@ -60,6 +103,8 @@ export default function ReportScreen({ route, navigation }) {
mode="outlined"
label='Who'
placeholder='Who'
value={who}
onChangeText={setWho}
/>
<TouchableRipple onPress={showIncidentDatePickerFunc}>
<TextInput
@ -68,7 +113,7 @@ export default function ReportScreen({ route, navigation }) {
outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
mode="outlined"
label=" When"
label="When"
value={date ? moment(date).format("DD-MM-YYYY") : ''}
editable={false}
right={<TextInput.Icon icon="calendar" onPress={showIncidentDatePickerFunc} />}
@ -81,24 +126,22 @@ export default function ReportScreen({ route, navigation }) {
outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
mode="outlined"
label=" Status"
label="Status"
value={status ? status : ''}
editable={false}
right={<TextInput.Icon icon="list-status" onPress={handleOpenSheet} />}
/>
</TouchableRipple>
</ScrollView >
</View>
<View style={styles.buttonContainer}>
<Button mode="outlined" style={styles.button} textColor={colors.mistBlue} onPress={() => { navigation.goBack() }} >
</View>
</ScrollView>
<View style={[styles.buttonContainer, { backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.pureWhite }]}>
<Button mode="outlined" style={styles.button} textColor={colors.mistBlue} onPress={() => { navigation.goBack() }}>
Kembali
</Button>
<Button mode="contained" style={[styles.button, { backgroundColor: colors.beanRed }]} onPress={() => console.log('Handle Saved')}>
<Button mode="contained" style={[styles.button, { backgroundColor: colors.beanRed }]} textColor={isDarkTheme ? theme.colors.black : theme.colors.pureWhite} onPress={handleSave}>
Simpan
</Button>
</View>
{
showIncidentDatePicker && (
<DateTimePicker
@ -109,7 +152,6 @@ export default function ReportScreen({ route, navigation }) {
/>
)
}
<BottomSheetModalProvider>
<BottomSheetModal
ref={bottomSheetModal}
@ -117,26 +159,27 @@ export default function ReportScreen({ route, navigation }) {
snapPoints={['20%']}
bottomInset={10}
detached={true}
style={{ marginHorizontal: 15 }}
backgroundStyle={{ backgroundColor: colorsheet }}
style={{ marginHorizontal: 5 }}
>
<BottomSheetView >
<BottomSheetView>
<TouchableRipple onPress={() => handleStatus("Open")}>
<List.Item
key='Open'
title="OPEN"
left={props => <List.Icon {...props} icon="" />}
/>
</TouchableRipple>
<TouchableRipple onPress={() => handleStatus("Close")}>
<List.Item
key='Close'
title="CLOSE"
left={props => <List.Icon {...props} icon="" />}
/>
</TouchableRipple>
</BottomSheetView>
</BottomSheetModal>
</BottomSheetModalProvider>
</>
)
);
}
const styles = StyleSheet.create({

182
src/screens/incident-page/stepComponent/incident.js

@ -1,63 +1,193 @@
import React, { useState } from 'react';
import { TouchableRipple, Chip, Card, Text } from 'react-native-paper';
import React, { useCallback, useRef, useState } from 'react';
import { TouchableRipple, Chip, Card, Text, useTheme, Searchbar, List, Button } from 'react-native-paper';
import { View, StyleSheet, ScrollView } from 'react-native';
import DateTimePicker from '@react-native-community/datetimepicker';
import moment from 'moment';
import { colors } from '../../../utils/color';
import { jenisKejadian } from '../../../config/ApiConst'
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
import { setDataIncident, setDataAchievement, setDataTypeRisk } from '../../../appredux/actions';
import { useDispatch, useSelector } from 'react-redux';
import {
BottomSheetModal,
BottomSheetModalProvider,
BottomSheetScrollView
} from '@gorhom/bottom-sheet';
import { strings } from '../../../utils/i18n';
export default function IncidentScreen() {
const [selectedItems, setSelectedItems] = useState([]);
const [dataIncidentReport, setDataIncidentReport] = useState(jenisKejadian[0].data)
const [typeRiskIncident, setTypeRiskIncident] = useState("")
const theme = useTheme();
const isDarkTheme = theme.dark;
const dispatch = useDispatch();
const [filter, setFilter] = useState('');
const bottomSheetIncindentModal = useRef(null);
const bottomSheetAchievementModal = useRef(null);
const dataIncidentReport = useSelector(state => state.incidentReportReducer.dataIncidentReport);
const dataAchievement = useSelector(state => state.incidentReportReducer.dataAchievement);
const colorsheet = isDarkTheme ? theme.colors.black : theme.colors.pureWhite;
const handleCheckboxChange = (item) => {
const handleOpenSheetIncident = useCallback(() => {
bottomSheetIncindentModal.current?.present();
}, []);
const handleOpenSheetAchievement = useCallback(() => {
bottomSheetAchievementModal.current?.present();
}, []);
const handleSelectAchievement = (item) => {
const updatedDataAchievement = dataAchievement.map(dataItem => {
if (dataItem.label === item.label) {
return { ...dataItem, checked: !dataItem.checked };
}
return dataItem;
});
dispatch(setDataAchievement(updatedDataAchievement));
setFilter('');
bottomSheetAchievementModal.current?.dismiss();
}
const handleSelectIncident = (item) => {
const updatedDataIncidentReport = dataIncidentReport.map(dataItem => {
if (dataItem.label === item.label) {
return { ...dataItem, checked: !dataItem.checked };
}
return dataItem;
});
setDataIncidentReport(updatedDataIncidentReport);
const hasCritical = updatedDataIncidentReport.some(item => item.level === 'Critical' && item.checked);
setTypeRiskIncident(updatedDataIncidentReport.some(item => item.checked) ? (hasCritical ? 'Critical' : 'Major') : '');
};
dispatch(setDataTypeRisk(updatedDataIncidentReport.some(item => item.checked) ? (hasCritical ? 'Critical' : 'Major') : ''));
dispatch(setDataIncident(updatedDataIncidentReport));
setFilter('');
bottomSheetIncindentModal.current?.dismiss();
}
const dataFilterIncident = dataIncidentReport.filter(item => item.label.toLowerCase().includes(filter.toLowerCase()));
const dataFilterAchievement = dataAchievement.filter(item => item.label.toLowerCase().includes(filter.toLowerCase()));
const isItemSelected = (label) => {
return dataIncidentReport.some(item => item.label === label && item.checked);
};
const renderAchievement = (data) => (
<View key={data.label}>
<TouchableRipple onPress={() => handleSelectAchievement(data)}>
<List.Item
title={data.label}
/>
</TouchableRipple>
</View>
);
const renderIncident = (data) => (
<View key={data.label}>
<TouchableRipple onPress={() => handleSelectIncident(data)}>
<List.Item
title={data.label}
/>
</TouchableRipple>
</View>
);
return (
<>
<Card style={{ backgroundColor: colors.semiRed, paddingVertical: 15, paddingHorizontal: 15, marginHorizontal: 8, marginVertical: 5, borderRadius: 5 }}>
<View>
<Text variant="bodySmall" style={{ color: colors.beanRed, fontWeight: 'bold', fontSize: 16 }}>
Jenis kejadian
{strings('incidentReport.achievement')} & {strings('incidentReport.incident')}
</Text>
<Text variant="bodySmall" style={{ color: colors.beanRed, fontSize: 12 }}>
Kejadian apa saja yang terjadi di lokasi, bisa pilih lebih dari satu
Capaian/Kejadian apa saja yang terjadi di lokasi, bisa pilih lebih dari satu
</Text>
</View>
</Card>
<View style={styles.container}>
<Text variant="bodySmall" style={{ color: colors.black, fontSize: 16 }}>
Pilih Jenis Kejadian
<Text variant="bodySmall" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black, fontSize: 16 }}>
{strings('incidentReport.achievement')}
</Text>
<View style={{ width: '100%', marginTop: 10, marginBottom: 5 }}>
<Button icon="plus" style={{ borderRadius: 10, backgroundColor: colors.semiBlue, paddingVertical: 1, marginHorizontal: 5, }} textColor={colors.blue} mode="contained-tonal" onPress={handleOpenSheetAchievement}>
{strings('incidentReport.achievementSelect')}
</Button>
</View>
<ScrollView style={styles.listData}>
<View>
{dataAchievement.filter(item => item.checked).map(item => (
<Chip
key={item.label}
icon={() => (
<Icon name='circle-slice-8' size={20} color={colors.blue} />
)} textStyle={{ color: colors.blue }} onPress={() => handleSelectAchievement(item)} style={{ backgroundColor: colors.semiBlue, marginBottom: 5 }}>{item.label}</Chip>
))}
</View>
</ScrollView>
<Text variant="bodySmall" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black, fontSize: 16, marginTop: 5 }}>
{strings('incidentReport.incident')}
</Text>
<View style={{ width: '100%', marginTop: 10, marginBottom: 5 }}>
<Button icon="plus" style={{ borderRadius: 10, backgroundColor: colors.semiBlue, paddingVertical: 1, marginHorizontal: 5, }} textColor={colors.blue} mode="contained-tonal" onPress={handleOpenSheetIncident}>
{strings('incidentReport.incidentSelect')}
</Button>
</View>
<ScrollView style={styles.listData}>
<View>
{dataIncidentReport.map(item => (
<>
<Chip
icon={() => (
<Icon name={isItemSelected(item.label) ? 'circle-slice-8' : 'circle-outline'} size={20} color={isItemSelected(item.label) ? colors.pureWhite : colors.blue} />
)} textStyle={{ color: isItemSelected(item.label) ? colors.pureWhite : colors.blue }} onPress={() => handleCheckboxChange(item)} style={{ backgroundColor: isItemSelected(item.label) ? colors.beanRed : colors.semiBlue, marginBottom: 5 }}>{item.label}</Chip >
</>
{dataIncidentReport.filter(item => item.checked).map(item => (
<Chip
key={item.label}
icon={() => (
<Icon name='circle-slice-8' size={20} color={colors.blue} />
)} textStyle={{ color: colors.blue }} onPress={() => handleSelectIncident(item)} style={{ backgroundColor: colors.semiBlue, marginBottom: 5 }}>{item.label}</Chip>
))}
</View>
</ScrollView >
</View >
</ScrollView>
</View>
<BottomSheetModalProvider>
<BottomSheetModal
animateOnMount={true}
ref={bottomSheetIncindentModal}
index={0}
snapPoints={['90%']}
detached={true}
keyboardBehavior="fillParent"
backgroundStyle={{ backgroundColor: colorsheet }}
style={{ marginHorizontal: 5 }}
>
<Searchbar
mode='bar'
placeholder={strings('global.search')}
onChangeText={text => setFilter(text)}
value={filter}
traileringIconColor={isDarkTheme ? theme.colors.pureWhite : theme.colors.surface}
style={{ marginHorizontal: 5, backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.background }}
showDivider={true}
elevation={1}
/>
<BottomSheetScrollView contentContainerStyle={{ marginHorizontal: 5, marginTop: 3 }}>
{dataFilterIncident.map(item => renderIncident(item))}
</BottomSheetScrollView>
</BottomSheetModal>
<BottomSheetModal
animateOnMount={true}
ref={bottomSheetAchievementModal}
index={0}
snapPoints={['90%']}
detached={true}
keyboardBehavior="fillParent"
backgroundStyle={{ backgroundColor: colorsheet }}
style={{ marginHorizontal: 5 }}
>
<Searchbar
mode='bar'
placeholder={strings('global.search')}
onChangeText={text => setFilter(text)}
value={filter}
traileringIconColor={isDarkTheme ? theme.colors.pureWhite : theme.colors.surface}
style={{ marginHorizontal: 5, backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.background }}
showDivider={true}
elevation={1}
/>
<BottomSheetScrollView contentContainerStyle={{ marginHorizontal: 5, marginTop: 3 }}>
{dataFilterAchievement.map(item => renderAchievement(item))}
</BottomSheetScrollView>
</BottomSheetModal>
</BottomSheetModalProvider>
</>
)
}
@ -71,5 +201,5 @@ const styles = StyleSheet.create({
listData: {
flex: 1,
marginTop: 10,
},
}
});

147
src/screens/incident-page/stepComponent/location.js

@ -1,58 +1,44 @@
import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react';
import { TextInput, Card, Checkbox, Text, TouchableRipple } from 'react-native-paper';
import { TextInput, Card, Checkbox, Text, TouchableRipple, useTheme } from 'react-native-paper';
import { StyleSheet, View, ScrollView } from 'react-native';
import { colors } from '../../../utils/color'
import { useNavigation } from '@react-navigation/native';
import { useDispatch, useSelector } from 'react-redux';
import { setArea, setIncidentLocation, setReportLocation } from '../../../appredux/modules/incidentReport/actions';
export default function LocationScreen() {
const navigation = useNavigation();
const [selectedProject, setSelectedProject] = useState(null);
const [area, setArea] = useState({ external: false, internal: false })
const handleProjectPress = () => {
navigation.navigate('SearchPage', { dummyData, onSelect: handleProjectSelect });
};
const theme = useTheme();
const dispatch = useDispatch();
const { user } = useSelector(state => state.userReducer);
const area = useSelector(state => state.incidentReportReducer.area);
const incidentLocation = useSelector(state => state.incidentReportReducer.incidentLocation);
const reportLocation = useSelector(state => state.incidentReportReducer.reportLocation);
const isDarkTheme = theme.dark;
console.log("area", area);
const handleCheckboxArea = (data) => {
const { name } = data;
setArea(prevState => ({
...prevState,
[name]: !prevState[name]
}));
const updatedArea = { ...area, [name]: !area[name] };
dispatch(setArea(updatedArea));
};
const handleIncidentLocationChange = (location) => {
dispatch(setIncidentLocation({ location }));
};
console.log("Area :", area);
const handleProjectSelect = (project) => {
setSelectedProject(project);
const handleIncidentSubLocationChange = (subLocation) => {
dispatch(setIncidentLocation({ subLocation }));
};
const handleReportProjectLocationChange = (projectLocation) => {
dispatch(setReportLocation({ projectLocation }));
};
const dummyData = [
{ id: '1', name: 'MRT', icn: 'test1', sicn: 'test"1' },
{ id: '2', name: 'PLN', icn: 'test1', sicn: 'test"1' },
{ id: '3', name: 'Pertamina', icn: 'test1', sicn: 'test"1' },
{ id: '4', name: 'MD Entertaiment', icn: 'test1', sicn: 'test"1' },
{ id: '5', name: 'Jhonny', icn: 'test1', sicn: 'test"1' },
{ id: '6', name: 'AIA', icn: 'test1', sicn: 'test"1' },
{ id: '7', name: 'PLN Pulogadung', icn: 'test1', sicn: 'test"1' },
{ id: '8', name: 'Google', icn: 'test1', sicn: 'test"1' },
{ id: '9', name: 'Amazon', icn: 'test1', sicn: 'test"1' },
{ id: '10', name: 'Microsoft', icn: 'test1', sicn: 'test"1' },
{ id: '11', name: 'Facebook', icn: 'test1', sicn: 'test"1' },
{ id: '12', name: 'Apple', icn: 'test1', sicn: 'test"1' },
{ id: '13', name: 'Tesla', icn: 'test1', sicn: 'test"1' },
{ id: '14', name: 'Netflix', icn: 'test1', sicn: 'test"1' },
{ id: '15', name: 'Twitter', icn: 'test1', sicn: 'test"1' },
{ id: '16', name: 'LinkedIn', icn: 'test1', sicn: 'test"1' },
{ id: '17', name: 'Instagram', icn: 'test1', sicn: 'test"1' },
{ id: '18', name: 'Snapchat', icn: 'test1', sicn: 'test"1' },
{ id: '19', name: 'WhatsApp', icn: 'test1', sicn: 'test"1' },
{ id: '20', name: 'Uber', icn: 'test1', sicn: 'test"1' },
{ id: '21', name: 'Airbnb', icn: 'test1', sicn: 'test"1' },
{ id: '22', name: 'Spotify', icn: 'test1', sicn: 'test"1' },
{ id: '23', name: 'Pinterest', icn: 'test1', sicn: 'test"1' },
{ id: '24', name: 'Reddit', icn: 'test1', sicn: 'test"1' },
{ id: '25', name: 'Dropbox', icn: 'test1', sicn: 'test"1' },
{ id: '26', name: 'Zoom', icn: 'test1', sicn: 'test"1' },
{ id: '27', name: 'Etsy' }
];
const handleReportLocationChange = (reportLocation) => {
dispatch(setReportLocation({ reportLocation }));
};
const handleReportSubLocationChange = (subLocation) => {
dispatch(setReportLocation({ subLocation }));
};
return (
<>
@ -68,22 +54,20 @@ export default function LocationScreen() {
</Card>
<ScrollView>
<View style={styles.container}>
<Text variant="bodySmall" style={{ color: colors.black, fontSize: 16, marginBottom: 6 }}>
<Text variant="bodySmall" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black, fontSize: 16, marginBottom: 6 }}>
Lokasi Kejadian
</Text>
<TouchableRipple onPress={handleProjectPress}>
<TextInput
dense={true}
outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
mode="outlined"
editable={false}
label='Pilih Proyek'
placeholder='Pilih Proyek'
value={selectedProject ? selectedProject.name : ''}
right={<TextInput.Icon icon="chevron-down" />}
/>
</TouchableRipple>
<TextInput
dense={true}
outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
mode="outlined"
editable={false}
label='Proyek'
placeholder='Pilih Proyek'
value={user?.assigment_hr ? user?.assigment_hr?.join.project_charter_project_name : ''}
/>
<TextInput
style={{ marginTop: 10 }}
@ -93,6 +77,8 @@ export default function LocationScreen() {
mode="outlined"
label='Lokasi Kejadian'
placeholder='Lokasi Kejadian'
value={incidentLocation.location}
onChangeText={handleIncidentLocationChange}
/>
<TextInput
@ -103,49 +89,50 @@ export default function LocationScreen() {
mode="outlined"
label='Sub Lokasi Kejadian'
placeholder='Sub Lokasi Kejadian'
value={incidentLocation.subLocation}
onChangeText={handleIncidentSubLocationChange}
/>
<View style={styles.row}>
<Checkbox
status={area.internal ? 'checked' : 'unchecked'}
status={area?.internal ? 'checked' : 'unchecked'}
color={colors.blue}
uncheckedColor={colors.amethystSmoke}
onPress={() => handleCheckboxArea({ name: 'internal', checked: !area.internal })}
/>
<TouchableRipple rippleColor={colors.pureWhite} onPress={() => handleCheckboxArea({ name: 'internal', checked: !area.internal })}>
<Text variant="bodySmall" style={{ color: colors.black, fontSize: 14, marginBottom: 6, marginTop: 10 }}>
<Text variant="bodySmall" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black, fontSize: 14, marginBottom: 6, marginTop: 10 }}>
Internal (Didalam area/kawasan/parimeter Project)
</Text>
</TouchableRipple>
</View>
<View style={styles.row}>
<Checkbox
status={area.external ? 'checked' : 'unchecked'}
status={area?.external ? 'checked' : 'unchecked'}
color={colors.blue}
uncheckedColor={colors.amethystSmoke}
onPress={() => handleCheckboxArea({ name: 'external', checked: !area.external })}
/>
<TouchableRipple rippleColor={colors.pureWhite} onPress={() => handleCheckboxArea({ name: 'external', checked: !area.internal })}>
<Text variant="bodySmall" style={{ color: colors.black, fontSize: 14, marginBottom: 6, marginTop: 10 }}>
<Text variant="bodySmall" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black, fontSize: 14, marginBottom: 6, marginTop: 10 }}>
External (Diluar area/kawasan/parimeter Project)
</Text>
</TouchableRipple>
</View>
<Text variant="bodySmall" style={{ color: colors.black, fontSize: 16, marginBottom: 6, marginTop: 10 }}>
<Text variant="bodySmall" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black, fontSize: 16, marginBottom: 6, marginTop: 10 }}>
Lokasi Pelaporan
</Text>
<TouchableRipple onPress={handleProjectPress}>
<TextInput
dense={true}
outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
mode="outlined"
label='Pilih Proyek'
placeholder='Pilih Proyek'
/>
</TouchableRipple>
<TextInput
dense={true}
outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
mode="outlined"
label='Pilih Proyek'
placeholder='Pilih Proyek'
value={reportLocation.projectLocation}
onChangeText={handleReportProjectLocationChange}
/>
<TextInput
style={{ marginTop: 10 }}
@ -155,8 +142,8 @@ export default function LocationScreen() {
mode="outlined"
label='Lokasi Laporan'
placeholder='Lokasi Laporan'
value={reportLocation.reportLocation}
onChangeText={handleReportLocationChange}
/>
<TextInput
@ -167,11 +154,13 @@ export default function LocationScreen() {
mode="outlined"
label='Sub Lokasi Laporan'
placeholder='Sub Lokasi Laporan'
value={reportLocation.subLocation}
onChangeText={handleReportSubLocationChange}
/>
</View>
</ScrollView>
</>
)
);
}
const styles = StyleSheet.create({

208
src/screens/incident-page/stepComponent/media.js

@ -1,4 +1,4 @@
import React, { useRef, useCallback, useState, useMemo } from 'react';
import React, { useRef, useCallback, useState, useEffect } from 'react';
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
import {
BottomSheetModal,
@ -6,29 +6,41 @@ import {
BottomSheetView
} from '@gorhom/bottom-sheet';
import ImageMarker, { Position, TextBackgroundType } from 'react-native-image-marker';
import { TextInput, IconButton, Button } from 'react-native-paper';
import { TextInput, IconButton, Button, useTheme } from 'react-native-paper';
import { StyleSheet, View, ScrollView, PermissionsAndroid, Image } from 'react-native';
import { colors } from '../../../utils/color';
import { strings } from '../../../utils/i18n';
import { requestAccessStoragePermission } from '../../../utils/storage';
import { useDispatch, useSelector } from 'react-redux';
import uuid from 'react-native-uuid';
import { setImages } from '../../../appredux/actions';
import { getCoords } from '../../../utils/geolocation';
export default function MediaScreen() {
const [images, setImages] = useState([]);
export default function MediaScreen() {
const images = useSelector(state => state.incidentReportReducer.dataImage || []);
const theme = useTheme();
const isDarkTheme = theme.dark;
const dispatch = useDispatch();
const colorsheet = isDarkTheme ? theme.colors.black : theme.colors.pureWhite;
const [existingAttachmentNumber, setExistingAttachmentNumber] = useState('');
const bottomSheetModal = useRef(null);
console.log("images", useSelector(state => state.incidentReportReducer.dataImage));
const handleSetImageUri = (uri, description) => {
const newImage = { uri: uri, description: description || "" };
setImages(prevImages => [...prevImages, newImage]);
}
const handleSetImageUri = (newImage) => {
const updatedImages = [...images, newImage];
dispatch(setImages(updatedImages));
};
const handleDeleteImage = (index) => {
const updatedImages = [...images];
updatedImages.splice(index, 1);
setImages(updatedImages);
dispatch(setImages(updatedImages));
};
useEffect(() => {
if (existingAttachmentNumber === '') {
setExistingAttachmentNumber(uuid.v4())
}
}, [])
const handleOpenSheet = useCallback(() => {
bottomSheetModal.current?.present();
}, []);
@ -38,21 +50,21 @@ export default function MediaScreen() {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.CAMERA,
{
title: strings('takePicture.cameraPermissionTitle'),
message: strings('takePicture.cameraPermissionMessage'),
buttonNeutral: strings('takePicture.cameraPermissionBtnNeutral'),
buttonNegative: strings('takePicture.cameraPermissionBtnCancel'),
buttonPositive: strings('takePicture.cameraPermissionBtnPositive'),
title: 'Camera Permission',
message: 'App needs camera permission to take pictures.',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
},
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
handleLaunchCamera()
handleLaunchCamera();
} else {
console.log('Camera permission denied');
}
} catch (err) {
console.warn(err);
}
bottomSheetModal.current?.dismiss();
};
const handleLaunchCamera = () => {
@ -61,93 +73,68 @@ export default function MediaScreen() {
skipBackup: true,
path: 'images',
},
cameraType: 'front',
cameraType: 'back',
maxWidth: 768,
maxHeight: 1024,
saveToPhotos: false,
includeBase64: true
};
launchCamera(options, (response) => {
launchCamera(options, async (response) => {
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
} else if (response.customButton) {
} else {
if (response.assets && response.assets.length > 0) {
handleSetImageUri(response.assets[0].uri);
getCoords(loc => {
console.log('ImagePicker Error: ', response.error);
} else if (response.assets && response.assets.length > 0) {
try {
getCoords(async (loc) => {
if (loc) {
let imageObject = {
"image_uri": response.assets[0].uri,
"image_blob": response.assets[0].base64,
"lat": loc.lat,
"lon": loc.lon
}
addOverlay(imageObject)
const timestamp = new Date().toLocaleString();
const location = { latitude: loc.lat, longitude: loc.lon };
const overlayText = `${timestamp}\nLatitude: ${location.latitude}\nLongitude: ${location.longitude}\nCopyright Nawakara`;
const markedImage = await ImageMarker.markText({
backgroundImage: {
src: { uri: response.assets[0].uri }
},
watermarkTexts: [{
text: overlayText,
positionOptions: {
position: Position.bottomLeft,
},
style: {
color: '#ffffff',
fontSize: 9,
fontName: 'Arial',
textBackgroundStyle: {
padding: 12,
type: TextBackgroundType.none,
color: '#00000080'
}
},
}],
position: 'bottomLeft',
color: '#ffffff',
fontName: 'Arial-BoldMT',
fontSize: 16,
scale: 1,
});
const newImageData = {
id: 0,
attachment_number: existingAttachmentNumber,
file: `file://${markedImage}`,
data: response.assets[0].uri,
type: response.assets[0].type,
name: response.assets[0].fileName
};
handleSetImageUri(newImageData);
}
})
});
} catch (error) {
console.error('Error adding overlay:', error);
}
}
});
}
const addOverlay = async (imageObject) => {
try {
const timestamp = new Date().toLocaleString();
const location = { latitude: imageObject.lat, longitude: imageObject.lon };
const overlayText = `${timestamp}\nLatitude: ${location.latitude}\nLongitude: ${location.longitude}`;
if (imageObject.image_uri) {
const markedImage = await ImageMarker.markText({
backgroundImage: {
src: { uri: imageObject.image_uri }
},
watermarkTexts: [{
text: overlayText,
positionOptions: {
position: Position.bottomLeft,
},
style: {
color: '#ffffff',
fontSize: 8,
fontName: 'Arial',
textBackgroundStyle: {
padding: 10,
type: TextBackgroundType.none,
color: '#00000080'
}
},
}],
position: 'bottomLeft',
color: '#ffffff',
fontName: 'Arial-BoldMT',
fontSize: 16,
scale: 1,
});
await saveToTemporaryFolder(markedImage, imageObject);
}
} catch (error) {
console.error('Error adding overlay:', error);
}
}
const saveToTemporaryFolder = async (markedImage, imageObject) => {
try {
const tempPath = `file://${RNFS.TemporaryDirectoryPath}/presensi/${moment().format('YYYYMMDDHHmmss')}.jpg`;
if (!requestAccessStoragePermission()) {
return;
}
await RNFS.copyFile(markedImage, tempPath);
const imageBase64 = await RNFS.readFile(tempPath, 'base64');
storePhoto(imageObject.user_id, imageObject.drop_point_id, tempPath, imageBase64, imageObject.lat, imageObject.lon)
reloadPhotos();
} catch (error) {
console.error('Error saving image to temporary folder:', error);
}
}
};
const handleLaunchGallery = () => {
let options = {
@ -157,16 +144,26 @@ export default function MediaScreen() {
launchImageLibrary(options, (response) => {
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
} else if (response.customButton) {
console.log('ImagePicker Error: ', response.error);
} else {
handleSetImageUri(response.assets[0].uri);
if (response.assets && response.assets.length > 0) {
const newImage = {
uri: response.assets[0].uri,
attachment_number: existingAttachmentNumber,
data: response.assets[0].uri,
type: response.assets[0].type,
name: response.assets[0].fileName
};
handleSetImageUri(newImage);
}
}
});
bottomSheetModal.current?.dismiss();
}
};
const renderImages = useMemo(() => images.map((image, index) => (
const renderImages = images.map((image, index) => (
<View key={index} style={styles.imageBlock}>
<View style={styles.imageContainer}>
<Image
@ -175,7 +172,6 @@ export default function MediaScreen() {
resizeMode="cover"
/>
<IconButton
iconColor={colors.beanRed}
icon="delete"
style={styles.deleteButton}
size={30}
@ -185,8 +181,8 @@ export default function MediaScreen() {
<TextInput
mode='outlined'
style={styles.descriptionInput}
outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
outlineColor="#CCC"
activeOutlineColor="#000"
placeholder="Deskripsi gambar"
label="Deskripsi gambar"
multiline={true}
@ -194,11 +190,11 @@ export default function MediaScreen() {
onChangeText={(text) => {
const updatedImages = [...images];
updatedImages[index].description = text;
setImages(updatedImages);
dispatch(setImages(updatedImages));
}}
/>
</View>
)), [images]);
));
return (
<>
@ -207,7 +203,6 @@ export default function MediaScreen() {
style={styles.addButton}
mode="contained-tonal"
onPress={handleOpenSheet}
textColor={colors.blue}
>
Tambah Gambar
</Button>
@ -243,7 +238,7 @@ export default function MediaScreen() {
</BottomSheetModal>
</BottomSheetModalProvider>
</>
)
);
}
const styles = StyleSheet.create({
@ -263,16 +258,15 @@ const styles = StyleSheet.create({
image: {
width: 100,
height: 100,
borderRadius: 7
borderRadius: 7,
},
descriptionInput: {
flex: 1
flex: 1,
},
addButton: {
marginHorizontal: 8,
marginVertical: 10,
borderRadius: 10,
backgroundColor: colors.semiBlue,
},
bottomSheet: {
marginHorizontal: 15,

71
src/screens/incident-page/stepComponent/report.js

@ -1,11 +1,40 @@
import React, { useState } from 'react';
import { TouchableRipple, TextInput, Card, Text } from 'react-native-paper';
import React from 'react';
import { TextInput, Card, Text, useTheme } from 'react-native-paper';
import { View, StyleSheet, ScrollView } from 'react-native';
import DateTimePicker from '@react-native-community/datetimepicker';
import moment from 'moment';
import { useDispatch, useSelector } from 'react-redux';
import { setDataRecepient, setDataReporter } from '../../../appredux/modules/incidentReport/actions';
import { colors } from '../../../utils/color';
export default function ReportScreen() {
const theme = useTheme();
const isDarkTheme = theme.dark;
const dispatch = useDispatch();
const dataReporter = useSelector(state => state.incidentReportReducer.dataReporter);
const dataRecipient = useSelector(state => state.incidentReportReducer.dataRecipient);
const handleReporterNameChange = (name) => {
dispatch(setDataReporter({ name }));
};
const handleReporterPositionChange = (position) => {
dispatch(setDataReporter({ position }));
};
const handleReporterContactChange = (noContact) => {
dispatch(setDataReporter({ noContact }));
};
const handleRecipientNameChange = (name) => {
dispatch(setDataRecepient({ name }));
};
const handleRecipientPositionChange = (position) => {
dispatch(setDataRecepient({ position }));
};
const handleRecipientContactChange = (noContact) => {
dispatch(setDataRecepient({ noContact }));
};
return (
<>
@ -21,77 +50,89 @@ export default function ReportScreen() {
</Card>
<ScrollView>
<View style={styles.container}>
<Text variant="bodySmall" style={{ color: colors.black, fontSize: 16, marginBottom: 6 }}>
<Text variant="bodySmall" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black, fontSize: 16, marginBottom: 6 }}>
Pelapor
</Text>
<TextInput
style={{ marginTop: 10 }}
dense={true}
dense
outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
mode="outlined"
label=" Nama Pelapor"
placeholder='Nama'
value={dataReporter.name || ''}
onChangeText={handleReporterNameChange}
/>
<TextInput
style={{ marginTop: 10 }}
dense={true}
dense
outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
mode="outlined"
label='Posisi/Jabatan'
placeholder='Posisi/Jabatan'
value={dataReporter.position || ''}
onChangeText={handleReporterPositionChange}
/>
<TextInput
style={{ marginTop: 10 }}
dense={true}
dense
outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
mode="outlined"
label='No Contact'
placeholder='No Contact'
value={dataReporter.noContact || ''}
keyboardType='number-pad'
onChangeText={handleReporterContactChange}
/>
<Text variant="bodySmall" style={{ color: colors.black, fontSize: 16, marginBottom: 6, marginTop: 10 }}>
<Text variant="bodySmall" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black, fontSize: 16, marginBottom: 6, marginTop: 10 }}>
Penerima Laporan
</Text>
<TextInput
dense={true}
dense
outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
mode="outlined"
label='Nama'
placeholder='Nama'
value={dataRecipient.name || ''}
onChangeText={handleRecipientNameChange}
/>
<TextInput
style={{ marginTop: 10 }}
dense={true}
dense
outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
mode="outlined"
label='Posisi/Jabatan'
placeholder='Posisi/Jabatan'
value={dataRecipient.position || ''}
onChangeText={handleRecipientPositionChange}
/>
<TextInput
style={{ marginTop: 10 }}
dense={true}
dense
outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue}
mode="outlined"
label='No Contact'
placeholder='No Contact'
value={dataRecipient.noContact || ''}
keyboardType='number-pad'
onChangeText={handleRecipientContactChange}
/>
</View>
</ScrollView>
</>
)
);
}
const styles = StyleSheet.create({

35
src/screens/incident-page/stepComponent/time.js

@ -3,40 +3,49 @@ import { TouchableRipple, TextInput, Card, Text } from 'react-native-paper';
import { View, StyleSheet } from 'react-native';
import DateTimePicker from '@react-native-community/datetimepicker';
import moment from 'moment';
import { useSelector, useDispatch } from 'react-redux';
import { setIncidentDate, setIncidentTime, setReportDate, setReportTime } from '../../../appredux/modules/incidentReport/actions';
import { colors } from '../../../utils/color';
export default function TimeScreen() {
const [incidentDate, setIncidentDate] = useState('');
const [incidentTime, setIncidentTime] = useState('');
const [reportDate, setReportDate] = useState('');
const [reportTime, setReportTime] = useState('');
const dispatch = useDispatch();
const incidentDate = useSelector(state => state.incidentReportReducer.incidentDate);
const incidentTime = useSelector(state => state.incidentReportReducer.incidentTime);
const reportDate = useSelector(state => state.incidentReportReducer.reportDate);
const reportTime = useSelector(state => state.incidentReportReducer.reportTime);
const [showIncidentDatePicker, setShowIncidentDatePicker] = useState(false);
const [showIncidentTimePicker, setShowIncidentTimePicker] = useState(false);
const [showReportDatePicker, setShowReportDatePicker] = useState(false);
const [showReportTimePicker, setShowReportTimePicker] = useState(false);
console.log("incidentDate", incidentDate ? moment(incidentDate).format("YYYY-MM-DD HH:mm:ss Z") : 'null');
console.log("reportDate", reportDate ? moment(reportDate).format("YYYY-MM-DD HH:mm:ss Z") : 'null');
const handleIncidentDateChange = (event, selectedDate) => {
const currentDate = selectedDate;
setShowIncidentDatePicker(false);
setIncidentDate(currentDate);
if (selectedDate) {
dispatch(setIncidentDate(selectedDate));
}
};
const handleIncidentTimeChange = (event, selectedDate) => {
const currentDate = selectedDate;
setShowIncidentTimePicker(false);
setIncidentTime(currentDate);
if (selectedDate) {
dispatch(setIncidentTime(selectedDate));
}
};
const handleReportDateChange = (event, selectedDate) => {
const currentDate = selectedDate;
setShowReportDatePicker(false);
setReportDate(currentDate);
if (selectedDate) {
dispatch(setReportDate(selectedDate));
}
};
const handleReportTimeChange = (event, selectedDate) => {
const currentDate = selectedDate;
setShowReportTimePicker(false);
setReportTime(currentDate);
if (selectedDate) {
dispatch(setReportTime(selectedDate));
}
};
const showIncidentDatePickerFunc = () => {

Loading…
Cancel
Save