diff --git a/src/config/ApiConst.js b/src/config/ApiConst.js
index 3d4cdb6..e425ab4 100644
--- a/src/config/ApiConst.js
+++ b/src/config/ApiConst.js
@@ -8,4 +8,45 @@ export const BASE_URL_IMAGE = `${BASE_URL_API_V1}/attachments`
export const LOGIN_STATE_CHANGED = 'LOGIN_STATE_CHANGED';
-export const ERROR_LOGIN = "ERROR_LOGIN"
\ No newline at end of file
+export const ERROR_LOGIN = "ERROR_LOGIN"
+
+
+
+
+export const jenisKejadian = [
+ {
+ "data": [
+ { "label": "Vandalisme aset perusahaan", "level": "Critical", "checked": false },
+ { "label": "Perusakan aset", "level": "Critical", "checked": false },
+ { "label": "Pencurian", "level": "Critical", "checked": false },
+ { "label": "Penerobosan", "level": "Critical", "checked": false },
+ { "label": "Kehilangan", "level": "Critical", "checked": false },
+ { "label": "Peledakan", "level": "Critical", "checked": false },
+ { "label": "Pembakaran", "level": "Critical", "checked": false },
+ { "label": "Pencemaran lingkungan", "level": "Critical", "checked": false },
+ { "label": "Perampokan", "level": "Critical", "checked": false },
+ { "label": "Pemalakan / Pemerasan", "level": "Critical", "checked": false },
+ { "label": "Kerusuhan sosial", "level": "Critical", "checked": false },
+ { "label": "Pemogokan kerja", "level": "Critical", "checked": false },
+ { "label": "Keluhan User", "level": "Critical", "checked": false },
+ { "label": "Serangan kekerasan", "level": "Critical", "checked": false },
+ { "label": "Gangguan masyarakat", "level": "Critical", "checked": false },
+ { "label": "Sabotase", "level": "Critical", "checked": false },
+ { "label": "Narkoba", "level": "Critical", "checked": false },
+ { "label": "Minuman berakohol", "level": "Critical", "checked": false },
+ { "label": "Perselisihan ketenagakerjaan", "level": "Critical", "checked": false },
+ { "label": "Tidak ada tindakan/respond", "level": "Critical", "checked": false },
+ { "label": "Pelanggaran SOP", "level": "Major", "checked": false },
+ { "label": "Indisipliner kerja anggota", "level": "Major", "checked": false },
+ { "label": "Kelengkapan seragam", "level": "Major", "checked": false },
+ { "label": "Kecelakaan kerja", "level": "Major", "checked": false },
+ { "label": "Kecelakaan Lalu Lintas", "level": "Major", "checked": false },
+ { "label": "Kerusakan Kendaraan Project", "level": "Major", "checked": false },
+ { "label": "Kerusakan Equipment Project", "level": "Major", "checked": false },
+ { "label": "Keterlambatan Pembayaran Vendor", "level": "Major", "checked": false },
+ { "label": "Keterlambatan Penggajian", "level": "Major", "checked": false },
+ { "label": "Lain-lain", "level": "Major", "checked": false }
+ ]
+
+ }
+]
\ No newline at end of file
diff --git a/src/screens/Login.js b/src/screens/Login.js
index 9d081a6..571ef5c 100644
--- a/src/screens/Login.js
+++ b/src/screens/Login.js
@@ -5,12 +5,11 @@ import { Button, TextInput, useTheme, Text, IconButton } from 'react-native-pape
import { useDispatch, useSelector } from 'react-redux';
import { setIsLogin, setUser } from '../appredux/actions';
import { store } from '../appredux/store';
+import { colors } from '../utils/color';
import LOGIN_BANNER from '../assets/images/logo_nawakara.png';
import { strings } from '../utils/i18n';
import { initFirebase } from '../utils/Auth';
-
const LoginScreen = ({ route, navigation }) => {
- const theme = useTheme();
const { scannedCode } = useSelector(state => state.userReducer)
const [loginProcess, setLoginProcess] = useState(false);
const [showPassword, setShowPassword] = useState(false);
@@ -32,7 +31,7 @@ const LoginScreen = ({ route, navigation }) => {
return (
<>
-
+
@@ -43,8 +42,8 @@ const LoginScreen = ({ route, navigation }) => {
resizeMode="contain"
/>
- {strings('loginPage.headMessage')}
- Silahkan isi Username dan kata sandi anda
+ {strings('loginPage.headMessage')}
+ Silahkan isi Username dan kata sandi anda
{
}}
render={({ field: { onChange, onBlur, value } }) => (
{
}}
render={({ field: { onChange, onBlur, value } }) => (
{
diff --git a/src/screens/incident-page/dialogFrom.js b/src/screens/incident-page/dialogFrom.js
index 5e698b0..c2b87c1 100644
--- a/src/screens/incident-page/dialogFrom.js
+++ b/src/screens/incident-page/dialogFrom.js
@@ -1,37 +1,83 @@
import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react';
-import { Icon, Card, Text, Avatar, useTheme, IconButton, Appbar, Button } from 'react-native-paper';
-import { RefreshControl, StyleSheet, View, ScrollView, Image, Dimensions } from 'react-native';
+import { StatusBar } from 'react-native';
+import { Button, Text, Appbar, } from 'react-native-paper';
+import { StyleSheet, View, } from 'react-native';
+import { colors } from '../../utils/color';
+import { strings } from '../../utils/i18n';
+import StepIndicator from 'react-native-step-indicator';
+import TimeComponent from './stepComponent/time'
+import LocationScreen from './stepComponent/location';
+import ReportScreen from './stepComponent/report';
+import IncidentScreen from './stepComponent/incident';
+import ChronologyScreen from './stepComponent/chronology';
+import MediaScreen from './stepComponent/media';
+
export default function DialogForm({ route, navigation }) {
+ const [active, setActive] = useState(0);
+ const labels = ["Waktu", "Lokasi", "Pelapor", "Kejadian", "Kronologis", "Media"];
+
+ const renderStepContent = (step) => {
+ switch (step) {
+ case 0:
+ return ;
+ case 1:
+ return ;
+ case 2:
+ return
+ case 3:
+ return ;
+ case 4:
+ return ;
+ case 5:
+ return ;
+ }
+ };
+ const handleBack = () => {
+ if (active > 0) {
+ setActive(active - 1);
+ }
+ };
+
+ const handleNext = () => {
+ if (active < labels.length - 1) {
+ setActive(active + 1);
+ }
+ };
return (
-
- { navigation.goBack() }} />
-
+
+
+ { navigation.goBack() }} />
+
-
-
- } />
-
-
-
- } />
-
-
-
- } />
-
-
- } />
-
-
- } />
-
-
- } />
-
-
- } />
-
+
+ setActive(position)}
+ />
+
+
+ {renderStepContent(active)}
+
+
+
+ {active === labels.length - 1 ?
+ (
+
+ )
+ : (
+
+ )}
+
)
@@ -41,6 +87,7 @@ const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 20,
+ backgroundColor: colors.pureWhite
},
cardView: {
marginTop: 10,
@@ -50,5 +97,45 @@ const styles = StyleSheet.create({
marginHorizontal: 10,
backgroundColor: '#1C1B40',
},
+ button: {
+ flex: 1,
+ margin: 5,
+ borderRadius: 5
+ },
+ contentContainer: {
+ flex: 1,
+ },
+ buttonContainer: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ padding: 10,
+ paddingBottom: 20,
+ },
+
+})
+
+const stepIndicatorStyles = {
-})
\ No newline at end of file
+ stepIndicatorSize: 25,
+ currentStepIndicatorSize: 30,
+ separatorStrokeWidth: 2,
+ currentStepStrokeWidth: 2,
+ stepIndicatorCurrentColor: colors.beanRed,
+ stepStrokeCurrentColor: colors.beanRed,
+ stepStrokeWidth: 1,
+ stepStrokeFinishedColor: colors.beanRed,
+ stepStrokeUnFinishedColor: colors.semiRed,
+ separatorFinishedColor: colors.beanRed,
+ separatorUnFinishedColor: colors.semiRed,
+ stepIndicatorFinishedColor: colors.beanRed,
+ stepIndicatorUnFinishedColor: colors.semiRed,
+ stepIndicatorCurrentColor: colors.beanRed,
+ stepIndicatorLabelFontSize: 12,
+ currentStepIndicatorLabelFontSize: 12,
+ stepIndicatorLabelCurrentColor: colors.pureWhite,
+ stepIndicatorLabelFinishedColor: colors.pureWhite,
+ stepIndicatorLabelUnFinishedColor: colors.beanRed,
+ labelColor: colors.semiRed,
+ labelSize: 12,
+ currentStepLabelColor: colors.beanRed
+}
\ No newline at end of file
diff --git a/src/screens/incident-page/index.js b/src/screens/incident-page/index.js
index 15e0763..3fa7047 100644
--- a/src/screens/incident-page/index.js
+++ b/src/screens/incident-page/index.js
@@ -1,35 +1,54 @@
import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react';
-import { Icon, Card, Text, Avatar, useTheme, IconButton, Appbar, Button } from 'react-native-paper';
-import { RefreshControl, StyleSheet, View, ScrollView, Image, Dimensions } from 'react-native';
+import { Card, Text, Avatar, useTheme, IconButton, Appbar, Button } from 'react-native-paper';
+import { RefreshControl, StyleSheet, View, ScrollView, Image, Dimensions, StatusBar } from 'react-native';
+import { colors } from '../../utils/color';
+import Icon from 'react-native-vector-icons/AntDesign';
+import { strings } from '../../utils/i18n';
+
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" }
+ ];
+
return (
-
+
+
{ navigation.goBack() }} />
-
- { }} />
- { }} />
+
-
-
-
-
- Jenis Insiden
- SICN
-
-
-
-
-
-
-
+
+
+
+
+
+ {incidentData.map((incident) => (
+
+
+
+
+
+
+ {incident.date}
+ {incident.location}
+ {incident.company}
+ {incident.icn} - {incident.sicn}
+
+
+
+
+
+
+ ))}
)
@@ -39,22 +58,44 @@ const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 20,
+ backgroundColor: colors.pureWhite
+ },
+ Text: {
+ fontSize: 16,
+ fontWeight: 'bold',
+ color: colors.blue
},
card: {
- marginTop: 15,
- marginHorizontal: 10,
- marginVertical: 2,
- backgroundColor: '#1C1B40',
+ flex: 1,
+ marginHorizontal: 8,
+ marginVertical: 5,
+ backgroundColor: colors.pureWhite,
},
- cardActions: {
- justifyContent: 'space-between',
- backgroundColor: '#1C1B40',
- borderBottomRightRadius: 20,
- borderBottomLeftRadius: 20,
- marginVertical: 4,
+ subText: {
+ fontSize: 12,
+ color: colors.blue
},
cardContent: {
- paddingHorizontal: 10,
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ paddingVertical: 10,
+ },
+ leftContent: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'flex-start',
+ marginLeft: 15
+ },
+ midContent: {
+ flex: 7,
+ justifyContent: 'flex-start',
+ alignItems: 'flex-start',
+ },
+ rightContent: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'flex-end',
+ marginRight: 15,
},
row: {
flexDirection: 'row',
diff --git a/src/screens/incident-page/stepComponent/chronology.js b/src/screens/incident-page/stepComponent/chronology.js
new file mode 100644
index 0000000..9e1cf1e
--- /dev/null
+++ b/src/screens/incident-page/stepComponent/chronology.js
@@ -0,0 +1,361 @@
+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 DateTimePicker from '@react-native-community/datetimepicker';
+import moment from 'moment';
+import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
+import { colors } from '../../../utils/color';
+import {
+ BottomSheetModal,
+ BottomSheetModalProvider,
+ BottomSheetScrollView
+} from '@gorhom/bottom-sheet';
+import { strings } from '../../../utils/i18n';
+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 bottomSheetModalImpactRef = useRef(null);
+ const bottomSheetModalLikelihoodRef = useRef(null);
+
+ const snapPoints = useMemo(() => ['25%', '50%'], []);
+
+ const handleOpenImpact = useCallback(() => {
+ bottomSheetModalImpactRef.current?.present();
+ }, []);
+
+ const handleOpenLikelihood = useCallback(() => {
+ bottomSheetModalLikelihoodRef.current?.present();
+ }, []);
+
+
+ useEffect(() => {
+ if (incidentRiskPotential.impact !== "" && incidentRiskPotential.likelihood !== "") {
+ const impactValue = dataSelectImpact.find(item => item.label === incidentRiskPotential.impact)?.value || 0;
+ const likelihoodValue = dataSelectLikelihood.find(item => item.label === incidentRiskPotential.likelihood)?.value || 0;
+
+ const val = impactValue * likelihoodValue;
+ let newRiskLevel, backgroundColor, color;
+ if (val >= 1 && val <= 5) {
+ backgroundColor = '#E3F8E8'
+ color = '#17C13E'
+ newRiskLevel = 'Rendah';
+ } else if (val >= 6 && val <= 10) {
+ backgroundColor = "#F8DC49"
+ color = "white"
+ newRiskLevel = 'Sedang';
+ } else if (val >= 11 && val <= 15) {
+ backgroundColor = '#FFD9AF'
+ color = '#EC9C3D'
+ newRiskLevel = 'Tinggi';
+ } else {
+ backgroundColor = '#FFC5C3'
+ color = '#D9534F'
+ 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 });
+ }
+ }
+ }, [incidentRiskPotential, riskLevel]);
+
+
+
+ const handleSelectImpact = (impact) => {
+ setIncidentRiskPotential(prevState => ({
+ ...prevState,
+ impact: impact.label,
+ value: impact.value,
+ impactDescription: impact.description
+ }));
+ bottomSheetModalImpactRef.current?.dismiss();
+ };
+
+ const handleSelectLikelihood = (likelihood) => {
+ setIncidentRiskPotential(prevState => ({
+ ...prevState,
+ likelihood: likelihood.label,
+ likelihoodDescription: likelihood.description
+ }));
+ bottomSheetModalLikelihoodRef.current?.dismiss();
+ };
+
+ const dataSelectImpact = [
+ { label: 'Insignificant', value: 1, description: 'Tidak ada Gangguan Operasional Perusahaan' },
+ { label: 'Minor', value: 2, description: 'Operasional Perusahaan Terganggu Namun tidak terlalu signifikan dapat berjalan 75%' },
+ { label: 'Moderate', value: 3, description: 'Operasional Perusahaan Terganggu Namun tidak dapat berjalan 50%' },
+ { label: 'Major', value: 4, description: 'Operasional Perusahaan Terganggu, Namun tidak dapat berjalan 25%' },
+ { label: 'Extreme', value: 5, description: 'Operasional Perusahaan Terhenti akibat Gangguan Yang Ada' }
+ ];
+
+ const dataTranslasiImpact = {
+ Insignificant: 'Tidak signifikan',
+ Minor: 'Kecil',
+ Moderate: 'Sedang',
+ Major: 'Besar',
+ Extreme: 'Ekstrim',
+ }
+
+ const dataSelectLikelihood = [
+ { label: 'Rare', value: 1, description: '< 5%, Terjadi dalam 1x lebih 20 Tahun' },
+ { label: 'Unlikely', value: 2, description: '5% - 29%, Terjadi dalam 1x dalam setiap 20 Tahun' },
+ { label: 'Possible', value: 3, description: '30% - 59%, Terjadi dalam 1x dalam setiap 5 Tahun' },
+ { label: 'Likely', value: 4, description: '60% - 89%, Terjadi dalam 1x dalam setiap tahun' },
+ { label: 'Almost Certain', value: 5, description: '90%, Terjadi dalam 1x dalam setiap bulan' }
+ ]
+
+ const dataTranslasiLikelihood = {
+ Rare: 'Langka',
+ Unlikely: 'Jarang',
+ Possible: 'Mungkin terjadi',
+ Likely: 'Sangat memungkinkan',
+ "Almost Certain": 'Sudah pasti',
+ }
+
+ console.log("incidentRiskPotential", incidentRiskPotential);
+
+ const renderImpact = (data) => (
+
+ handleSelectImpact(data)}>
+
+
+
+ );
+ const renderLikelihood = (data) => (
+
+ handleSelectLikelihood(data)}>
+
+
+
+ );
+
+ return (
+ <>
+
+
+
+ Kronologis kejadian
+
+
+ Jelaskan bagaimana terjadinya insiden
+
+
+
+
+
+ {
+ setChronology(text)
+ }}
+ />
+
+ {
+ setChronology(text)
+ }}
+ />
+
+ }
+ />
+
+ {incidentRiskPotential.impactDescription && (
+
+
+ {incidentRiskPotential.impactDescription}
+
+
+ )}
+
+ }
+ />
+
+
+ {incidentRiskPotential.likelihoodDescription && (
+
+
+ {incidentRiskPotential.likelihoodDescription}
+
+
+ )}
+
+
+
+ Critical
+
+
+
+
+ {riskLevel.level} {incidentRiskPotential.value}
+
+
+
+
+ Rencana tindakan pencegahan
+
+
+
+
+
+
+
+
+ 01-03-2024
+ Farhan
+ Melakukan pengamatan dan patroli area pagar luar Depo MRT
+
+
+
+
+
+
+
+
+ {/* color: (typeRiskIncident === 'Critical' ? '#D9534F' : (typeRiskIncident === 'Major' ? '#EC9C3D' : 'black')) */}
+
+
+
+
+
+
+ {dataSelectImpact.map(item => renderImpact(item))}
+
+
+
+
+
+
+ {dataSelectLikelihood.map(item => renderLikelihood(item))}
+
+
+
+ >
+ )
+}
+
+const styles = StyleSheet.create({
+ containerModal: {
+ flex: 1,
+ padding: 24,
+ justifyContent: 'center',
+ backgroundColor: 'grey',
+ },
+
+ contentContainer: {
+ flex: 1,
+ alignItems: 'center',
+ },
+ buttonContainer: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ padding: 10,
+ paddingBottom: 20,
+ },
+ button: {
+ flex: 1,
+ margin: 5,
+ borderRadius: 5
+ },
+ container: {
+ flex: 1,
+ marginVertical: 10,
+ marginHorizontal: 10
+ },
+
+ 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',
+ justifyContent: 'space-between',
+ marginBottom: 5
+ },
+ cardContent: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ paddingVertical: 10,
+ },
+ leftContent: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'flex-start',
+ marginLeft: 15
+ },
+ midContent: {
+ flex: 7,
+ justifyContent: 'flex-start',
+ alignItems: 'flex-start',
+ },
+ rightContent: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'flex-end',
+ marginRight: 15,
+ },
+});
diff --git a/src/screens/incident-page/stepComponent/containedAction.js b/src/screens/incident-page/stepComponent/containedAction.js
new file mode 100644
index 0000000..2fb8a9a
--- /dev/null
+++ b/src/screens/incident-page/stepComponent/containedAction.js
@@ -0,0 +1,159 @@
+import React, { useState, useRef, useMemo, useCallback } from 'react';
+import { TouchableRipple, TextInput, Appbar, 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 { strings } from '../../../utils/i18n';
+import {
+ BottomSheetModal,
+ BottomSheetModalProvider,
+ BottomSheetView
+} from '@gorhom/bottom-sheet';
+
+export default function ReportScreen({ route, navigation }) {
+ const [showIncidentDatePicker, setShowIncidentDatePicker] = useState(false);
+ const [date, setDate] = useState('');
+ const [status, setStatus] = useState('')
+ const bottomSheetModal = useRef(null);
+ const showIncidentDatePickerFunc = () => {
+ setShowIncidentDatePicker(true);
+ };
+ // const snapPoints = useMemo(() => ['10%', ], []);
+ const handleOpenSheet = useCallback(() => {
+ bottomSheetModal.current?.present();
+ }, []);
+
+ const handleStatus = (data) => {
+ setStatus(data)
+ bottomSheetModal.current?.dismiss();
+ }
+
+ const handleIncidentDateChange = (event, selectedDate) => {
+ const currentDate = selectedDate;
+ setShowIncidentDatePicker(false);
+ setDate(currentDate);
+ };
+ return (
+ <>
+
+ { navigation.goBack() }} />
+
+
+
+
+
+
+
+
+ }
+ />
+
+
+ }
+ />
+
+
+
+
+
+
+
+
+
+ {
+ showIncidentDatePicker && (
+
+ )
+ }
+
+
+
+
+ handleStatus("Open")}>
+ }
+ />
+
+ handleStatus("Close")}>
+ }
+ />
+
+
+
+
+ >
+ )
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ marginVertical: 10,
+ marginHorizontal: 10
+ },
+ button: {
+ flex: 1,
+ margin: 5,
+ borderRadius: 5
+ },
+ buttonContainer: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ padding: 10,
+ paddingBottom: 20,
+ },
+});
diff --git a/src/screens/incident-page/stepComponent/incident.js b/src/screens/incident-page/stepComponent/incident.js
new file mode 100644
index 0000000..bb3df9c
--- /dev/null
+++ b/src/screens/incident-page/stepComponent/incident.js
@@ -0,0 +1,75 @@
+import React, { useState } from 'react';
+import { TouchableRipple, Chip, Card, Text } 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'
+
+export default function IncidentScreen() {
+ const [selectedItems, setSelectedItems] = useState([]);
+ const [dataIncidentReport, setDataIncidentReport] = useState(jenisKejadian[0].data)
+ const [typeRiskIncident, setTypeRiskIncident] = useState("")
+
+ const handleCheckboxChange = (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') : '');
+ };
+
+
+ const isItemSelected = (label) => {
+ return dataIncidentReport.some(item => item.label === label && item.checked);
+ };
+
+ return (
+ <>
+
+
+
+ Jenis kejadian
+
+
+ Kejadian apa saja yang terjadi di lokasi, bisa pilih lebih dari satu
+
+
+
+
+
+ Pilih Jenis Kejadian
+
+
+
+ {dataIncidentReport.map(item => (
+ <>
+ (
+
+ )} 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}
+ >
+ ))}
+
+
+
+ >
+ )
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ marginVertical: 10,
+ marginHorizontal: 10
+ },
+ listData: {
+ flex: 1,
+ marginTop: 10,
+ },
+});
diff --git a/src/screens/incident-page/stepComponent/location.js b/src/screens/incident-page/stepComponent/location.js
new file mode 100644
index 0000000..37222e5
--- /dev/null
+++ b/src/screens/incident-page/stepComponent/location.js
@@ -0,0 +1,187 @@
+import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react';
+import { TextInput, Card, Checkbox, Text, TouchableRipple } from 'react-native-paper';
+import { StyleSheet, View, ScrollView } from 'react-native';
+import { colors } from '../../../utils/color'
+import { useNavigation } from '@react-navigation/native';
+
+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 handleCheckboxArea = (data) => {
+ const { name } = data;
+ setArea(prevState => ({
+ ...prevState,
+ [name]: !prevState[name]
+ }));
+ setBottomSheetIndex(0);
+ };
+ console.log("Area :", area);
+ const handleProjectSelect = (project) => {
+ setSelectedProject(project);
+ };
+
+ 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' }
+ ];
+
+ return (
+ <>
+
+
+
+ Lokasi kejadian
+
+
+ Harap memasukan lokasi kejadian yang sesuai
+
+
+
+
+
+
+ Lokasi Kejadian
+
+
+ }
+ />
+
+
+
+
+
+
+ handleCheckboxArea({ name: 'internal', checked: !area.internal })}
+ />
+
+ Internal (Didalam area/kawasan/parimeter Project)
+
+
+
+ handleCheckboxArea({ name: 'external', checked: !area.external })}
+ />
+
+ External (Diluar area/kawasan/parimeter Project)
+
+
+
+
+ Lokasi Pelaporan
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ marginVertical: 10,
+ marginHorizontal: 10
+ },
+ row: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ marginBottom: 5,
+ marginRight: 15,
+ marginLeft: 5
+ },
+});
\ No newline at end of file
diff --git a/src/screens/incident-page/stepComponent/media.js b/src/screens/incident-page/stepComponent/media.js
new file mode 100644
index 0000000..9c5aa94
--- /dev/null
+++ b/src/screens/incident-page/stepComponent/media.js
@@ -0,0 +1,288 @@
+import React, { useRef, useCallback, useState, useMemo } from 'react';
+import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
+import {
+ BottomSheetModal,
+ BottomSheetModalProvider,
+ BottomSheetView
+} from '@gorhom/bottom-sheet';
+import ImageMarker, { Position, TextBackgroundType } from 'react-native-image-marker';
+import { TextInput, IconButton, Button } 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 { getCoords } from '../../../utils/geolocation';
+
+export default function MediaScreen() {
+ const [images, setImages] = useState([]);
+
+ const bottomSheetModal = useRef(null);
+
+ const handleSetImageUri = (uri, description) => {
+ const newImage = { uri: uri, description: description || "" };
+ setImages(prevImages => [...prevImages, newImage]);
+ }
+
+ const handleDeleteImage = (index) => {
+ const updatedImages = [...images];
+ updatedImages.splice(index, 1);
+ setImages(updatedImages);
+ };
+
+ const handleOpenSheet = useCallback(() => {
+ bottomSheetModal.current?.present();
+ }, []);
+
+ const handleTakePicture = async () => {
+ try {
+ 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'),
+ },
+ );
+ if (granted === PermissionsAndroid.RESULTS.GRANTED) {
+ handleLaunchCamera()
+ } else {
+ }
+ } catch (err) {
+ console.warn(err);
+ }
+ bottomSheetModal.current?.dismiss();
+ };
+
+ const handleLaunchCamera = () => {
+ let options = {
+ storageOptions: {
+ skipBackup: true,
+ path: 'images',
+ },
+ cameraType: 'front',
+ maxWidth: 768,
+ maxHeight: 1024,
+ saveToPhotos: false,
+ includeBase64: true
+ };
+
+ launchCamera(options, (response) => {
+ if (response.didCancel) {
+ } else if (response.error) {
+ } else if (response.customButton) {
+ } else {
+ if (response.assets && response.assets.length > 0) {
+ handleSetImageUri(response.assets[0].uri);
+ getCoords(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 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/${imageObject.drop_point_id}_${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 = {
+ mediaType: 'photo',
+ includeBase64: true
+ };
+
+ launchImageLibrary(options, (response) => {
+ if (response.didCancel) {
+ } else if (response.error) {
+ } else if (response.customButton) {
+ } else {
+ handleSetImageUri(response.assets[0].uri);
+ }
+ });
+ bottomSheetModal.current?.dismiss();
+ }
+
+ const renderImages = useMemo(() => images.map((image, index) => (
+
+
+
+ handleDeleteImage(index)}
+ />
+
+ {
+ const updatedImages = [...images];
+ updatedImages[index].description = text;
+ setImages(updatedImages);
+ }}
+ />
+
+ )), [images]);
+
+ return (
+ <>
+
+
+
+
+ {renderImages}
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ marginVertical: 10,
+ marginHorizontal: 10,
+ },
+ imageBlock: {
+ marginBottom: 20,
+ flexDirection: 'row',
+ },
+ imageContainer: {
+ flexDirection: 'column',
+ alignItems: 'center',
+ marginHorizontal: 5
+ },
+ image: {
+ width: 100,
+ height: 100,
+ borderRadius: 7
+ },
+ descriptionInput: {
+ flex: 1,
+ marginRight: 10,
+ },
+ addButton: {
+ marginHorizontal: 8,
+ marginVertical: 10,
+ borderRadius: 10,
+ backgroundColor: colors.semiBlue,
+ },
+ bottomSheet: {
+ marginHorizontal: 15,
+ },
+ sheetButtonContainer: {
+ flexDirection: 'row',
+ justifyContent: 'space-around',
+ padding: 10,
+ paddingBottom: 20,
+ },
+});
diff --git a/src/screens/incident-page/stepComponent/report.js b/src/screens/incident-page/stepComponent/report.js
new file mode 100644
index 0000000..aa7f7b6
--- /dev/null
+++ b/src/screens/incident-page/stepComponent/report.js
@@ -0,0 +1,103 @@
+import React, { useState } from 'react';
+import { TouchableRipple, TextInput, Card, Text } 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';
+
+export default function ReportScreen() {
+
+ return (
+ <>
+
+
+
+ Pelapor dan penerima laporan
+
+
+ Siapa yang membuat laporan dan siapa yang membuat laporan
+
+
+
+
+
+
+ Pelapor
+
+
+
+
+
+
+
+
+ Penerima Laporan
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ marginVertical: 10,
+ marginHorizontal: 10
+ },
+});
diff --git a/src/screens/incident-page/stepComponent/time.js b/src/screens/incident-page/stepComponent/time.js
new file mode 100644
index 0000000..5c6fb7f
--- /dev/null
+++ b/src/screens/incident-page/stepComponent/time.js
@@ -0,0 +1,168 @@
+import React, { useState } from 'react';
+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 { 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 [showIncidentDatePicker, setShowIncidentDatePicker] = useState(false);
+ const [showIncidentTimePicker, setShowIncidentTimePicker] = useState(false);
+ const [showReportDatePicker, setShowReportDatePicker] = useState(false);
+ const [showReportTimePicker, setShowReportTimePicker] = useState(false);
+
+ const handleIncidentDateChange = (event, selectedDate) => {
+ const currentDate = selectedDate;
+ setShowIncidentDatePicker(false);
+ setIncidentDate(currentDate);
+ };
+
+ const handleIncidentTimeChange = (event, selectedDate) => {
+ const currentDate = selectedDate;
+ setShowIncidentTimePicker(false);
+ setIncidentTime(currentDate);
+ };
+
+ const handleReportDateChange = (event, selectedDate) => {
+ const currentDate = selectedDate;
+ setShowReportDatePicker(false);
+ setReportDate(currentDate);
+ };
+
+ const handleReportTimeChange = (event, selectedDate) => {
+ const currentDate = selectedDate;
+ setShowReportTimePicker(false);
+ setReportTime(currentDate);
+ };
+
+ const showIncidentDatePickerFunc = () => {
+ setShowIncidentDatePicker(true);
+ };
+
+ const showIncidentTimePickerFunc = () => {
+ setShowIncidentTimePicker(true);
+ };
+
+ const showReportDatePickerFunc = () => {
+ setShowReportDatePicker(true);
+ };
+
+ const showReportTimePickerFunc = () => {
+ setShowReportTimePicker(true);
+ };
+
+ return (
+ <>
+
+
+
+
+ Laporan Awal Insiden
+
+
+ Wajib melaporkan maksimal 1x3 jam setelah kejadian
+
+
+
+
+
+ }
+ />
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+ }
+ />
+
+
+ {showIncidentDatePicker && (
+
+ )}
+ {showIncidentTimePicker && (
+
+ )}
+ {showReportDatePicker && (
+
+ )}
+ {showReportTimePicker && (
+
+ )}
+ >
+ )
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ marginVertical: 10,
+ marginHorizontal: 10
+ },
+});