Compare commits

..

No commits in common. '7d4250654e0a36ea394dc66227f8eac33cc7847a' and '69d45cbcd8b39c5871d021a63620cef651d10bf8' have entirely different histories.

  1. 70
      index.js
  2. 24
      src/App.js
  3. 25
      src/appredux/actions.js
  4. 115
      src/appredux/modules/incidentReport/actions.js
  5. 89
      src/appredux/modules/incidentReport/reducers.js
  6. 8
      src/appredux/modules/user/actions.js
  7. 17
      src/appredux/modules/user/reducers.js
  8. 6
      src/appredux/reducers.js
  9. 68
      src/config/ApiConst.js
  10. 12
      src/navigation/AppRoutes.js
  11. 4
      src/navigation/BottomTabNavigator.js
  12. 138
      src/screens/incident-page/dialogForm.js
  13. 117
      src/screens/incident-page/index.js
  14. 228
      src/screens/incident-page/stepComponent/chronology.js
  15. 107
      src/screens/incident-page/stepComponent/containedAction.js
  16. 182
      src/screens/incident-page/stepComponent/incident.js
  17. 147
      src/screens/incident-page/stepComponent/location.js
  18. 208
      src/screens/incident-page/stepComponent/media.js
  19. 71
      src/screens/incident-page/stepComponent/report.js
  20. 35
      src/screens/incident-page/stepComponent/time.js
  21. 2
      src/screens/presence/index.js
  22. 115
      src/screens/registerPage/index.js
  23. 2
      src/utils/color.js
  24. 19
      src/utils/i18n.js
  25. 38
      src/utils/locales/en.json
  26. 32
      src/utils/locales/id.json

70
index.js

@ -1,69 +1,25 @@
import React from 'react'; /**
import { AppRegistry, StatusBar, View, StyleSheet, useColorScheme } from 'react-native'; * @format
import { Provider, useSelector } from 'react-redux'; */
import { PersistGate } from 'redux-persist/integration/react';
import { PaperProvider, MD3DarkTheme, MD3LightTheme } from 'react-native-paper'; import { AppRegistry } from 'react-native';
import App from './src/App'; import App from './src/App';
import { name as appName } from './app.json'; import { name as appName } from './app.json';
import { persistor, store } from './src/appredux/store'; import { LogBox } from 'react-native';
import { PaperProvider, useTheme } from 'react-native-paper';
const Main = () => {
const systemTheme = useColorScheme();
const { theme, useSystemTheme } = useSelector(state => state.themeReducer);
const customColors = {
blue: '#3876BF',
semiBlue: '#DCECFF',
beanRed: '#EF6262',
semiRed: '#FFC5C3',
semiYellow: '#FFE7A3',
orange: '#FAA300',
green: '#17C13E',
semigreen: '#E3F8E8',
black: '#333333',
mistBlue: '#667085',
amethystSmoke: '#9A99AB',
mercury: '#E4E4E7',
catskillWhite: '#F2F4F6',
white: '#F9F9F9',
pureWhite: '#FFFFFF',
};
const lightTheme = { LogBox.ignoreLogs(['Warning: Failed prop type: Invalid prop `role`']); // Ignore log notification by message
...MD3LightTheme, LogBox.ignoreAllLogs();
colors: {
...MD3LightTheme.colors,
...customColors,
background: customColors.white,
text: customColors.black,
},
};
const darkTheme = {
...MD3DarkTheme,
colors: {
...MD3DarkTheme.colors,
...customColors,
background: customColors.black,
text: customColors.white,
},
};
const appliedTheme = useSystemTheme ? (systemTheme === 'dark' ? darkTheme : lightTheme) : (theme === 'dark' ? darkTheme : lightTheme);
export default function Main() {
return ( return (
<PaperProvider theme={appliedTheme}> <PaperProvider>
<App /> <App />
</PaperProvider> </PaperProvider>
); );
}; }
const AppWrapper = () => (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<Main />
</PersistGate>
</Provider>
);
AppRegistry.registerComponent(appName, () => AppWrapper); AppRegistry.registerComponent(appName, () => App);

24
src/App.js

@ -1,24 +1,23 @@
import React from 'react'; import React from 'react';
import { StyleSheet, View, ActivityIndicator } from 'react-native';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react'; import { PersistGate } from 'redux-persist/integration/react';
import { store, persistor } from './appredux/store'; import { StyleSheet, View } from 'react-native';
import AppRoutes from './navigation/AppRoutes'; import { ActivityIndicator } from 'react-native-paper';
import { persistor, store } from './appredux/store';
import AppRoutes from './navigation/AppRoutes'
import Toast from 'react-native-toast-message'; import Toast from 'react-native-toast-message';
import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { colors } from '../src/utils/color'; import { colors } from '../src/utils/color'
const App = () => { const App = () => {
return ( return (
<Provider store={store}> <Provider store={store}>
<PersistGate <PersistGate loading={
loading={ <View style={styles.container}>
<View style={styles.container}> <ActivityIndicator size='large' style={{ backgroundColor: colors.pureWhite }} animating={true} color={colors.blue} />
<ActivityIndicator size='large' style={{ backgroundColor: colors.pureWhite }} animating={true} color={colors.blue} /> </View>
</View> } persistor={persistor}>
}
persistor={persistor}
>
<GestureHandlerRootView style={{ flex: 1 }}> <GestureHandlerRootView style={{ flex: 1 }}>
<AppRoutes /> <AppRoutes />
<Toast position='bottom' visibilityTime={5000} /> <Toast position='bottom' visibilityTime={5000} />
@ -28,6 +27,7 @@ const App = () => {
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,

25
src/appredux/actions.js

@ -1,7 +1,22 @@
// user actions /*
export * from './modules/user/actions'; * All actions should be import and exported first
* to make components / pages are easy to use
*/
// theme actions import {
export * from './modules/theme/actions'; setIsLogin,
setUser,
setFcmToken,
setChosenLanguage,
setRegister
} from './modules/user/actions';
export * from './modules/incidentReport/actions'
export {
setIsLogin,
setUser,
setFcmToken,
setChosenLanguage,
setRegister
}

115
src/appredux/modules/incidentReport/actions.js

@ -1,115 +0,0 @@
// Action Types
export const SET_INCIDENT_DATE = 'SET_INCIDENT_DATE';
export const SET_INCIDENT_TIME = 'SET_INCIDENT_TIME';
export const SET_REPORT_DATE = 'SET_REPORT_DATE';
export const SET_REPORT_TIME = 'SET_REPORT_TIME';
export const SET_AREA = 'SET_AREA';
export const SET_DATA_RECEPIENT = 'SET_DATA_RECEPIENT';
export const SET_DATA_REPORTER = 'SET_DATA_REPORTER';
export const SET_INCIDENT_LOCATION = 'SET_INCIDENT_LOCATION';
export const SET_REPORT_LOCATION = 'SET_REPORT_LOCATION';
export const SET_DATA_INCIDENT = 'SET_DATA_INCIDENT';
export const SET_DATA_ACHIEVEMENT = 'SET_DATA_ACHIEVEMENT';
export const SET_DATA_TYPE_RISK = 'SET_DATA_TYPE_RISK';
export const SET_INCIDENT_RISK_POTENTIAL = 'SET_INCIDENT_RISK_POTENTIAL';
export const SET_RISK_LEVEL = 'SET_RISK_LEVEL';
export const SET_ROOT_CASE = 'SET_ROOT_CASE';
export const SET_CHRONOLOGY = 'SET_CHRONOLOGY';
export const SET_DATA_PREVENTION = 'SET_DATA_PREVENTION';
export const SET_DATA_IMAGES = 'SET_DATA_IMAGES';
export const RESET_INCIDENT_REPORT = 'RESET_INCIDENT_REPORT';
// Action Creators
export const setIncidentDate = (date) => ({
type: SET_INCIDENT_DATE,
payload: date,
});
export const setIncidentTime = (time) => ({
type: SET_INCIDENT_TIME,
payload: time,
});
export const setReportDate = (date) => ({
type: SET_REPORT_DATE,
payload: date,
});
export const setReportTime = (time) => ({
type: SET_REPORT_TIME,
payload: time,
});
export const setArea = (area) => ({
type: SET_AREA,
payload: area,
});
export const setDataRecepient = (data) => ({
type: SET_DATA_RECEPIENT,
payload: data,
});
export const setDataReporter = (data) => ({
type: SET_DATA_REPORTER,
payload: data,
});
export const setIncidentLocation = (location) => ({
type: SET_INCIDENT_LOCATION,
payload: location,
});
export const setReportLocation = (location) => ({
type: SET_REPORT_LOCATION,
payload: location,
});
export const setDataIncident = (data) => ({
type: SET_DATA_INCIDENT,
payload: data,
});
export const setDataAchievement = (data) => ({
type: SET_DATA_ACHIEVEMENT,
payload: data,
});
export const setDataTypeRisk = (data) => ({
type: SET_DATA_TYPE_RISK,
payload: data,
});
export const setIncidentRiskPotential = (data) => ({
type: SET_INCIDENT_RISK_POTENTIAL,
payload: data,
});
export const setRiskLevel = (data) => ({
type: SET_RISK_LEVEL,
payload: data,
});
export const setChronology = (data) => ({
type: SET_CHRONOLOGY,
payload: data,
});
export const setRootCase = (data) => ({
type: SET_ROOT_CASE,
payload: data,
});
export const setDataPrevention = (data) => ({
type: SET_DATA_PREVENTION,
payload: data,
});
export const setImages = (images) => ({
type: SET_DATA_IMAGES,
payload: images,
});
export const resetIncidentReport = () => ({
type: RESET_INCIDENT_REPORT,
});

89
src/appredux/modules/incidentReport/reducers.js

@ -1,89 +0,0 @@
import {
SET_INCIDENT_DATE,
SET_INCIDENT_TIME,
SET_REPORT_DATE,
SET_REPORT_TIME,
SET_AREA,
SET_DATA_RECEPIENT,
SET_DATA_REPORTER,
SET_INCIDENT_LOCATION,
SET_REPORT_LOCATION,
SET_DATA_INCIDENT,
SET_DATA_ACHIEVEMENT,
SET_DATA_TYPE_RISK,
RESET_INCIDENT_REPORT,
SET_CHRONOLOGY,
SET_ROOT_CASE,
SET_INCIDENT_RISK_POTENTIAL,
SET_RISK_LEVEL,
SET_DATA_PREVENTION,
SET_DATA_IMAGES
} from './actions';
const initialState = {
area: { external: false, internal: false },
chronology: null,
dataAchievement: [],
dataIncidentReport: [],
dataPrevention: [],
dataRecipient: { name: "", noContact: "", position: "" },
dataReporter: { name: "", noContact: "", position: "" },
incidentDate: null,
incidentLocation: { location: "", subLocation: "" },
incidentRiskPotential: { impact: "", impactDescription: "", likelihood: "", likelihoodDescription: "", value: "" },
incidentTime: null,
dataImage: [],
reportDate: null,
reportLocation: { projectLocation: "", reportLocation: "", subLocation: "" },
reportTime: null,
riskLevel: { backgroundColor: "", color: "", level: "" },
rootCase: null,
typeRiskIncident: null,
};
export default function incidentReportReducer(state = initialState, action) {
switch (action.type) {
case SET_INCIDENT_DATE:
return { ...state, incidentDate: action.payload };
case SET_INCIDENT_TIME:
return { ...state, incidentTime: action.payload };
case SET_REPORT_DATE:
return { ...state, reportDate: action.payload };
case SET_REPORT_TIME:
return { ...state, reportTime: action.payload };
case SET_AREA:
return { ...state, area: action.payload };
case SET_DATA_RECEPIENT:
return { ...state, dataRecipient: { ...state.dataRecipient, ...action.payload } };
case SET_DATA_REPORTER:
return { ...state, dataReporter: { ...state.dataReporter, ...action.payload } };
case SET_INCIDENT_LOCATION:
return { ...state, incidentLocation: { ...state.incidentLocation, ...action.payload } };
case SET_REPORT_LOCATION:
return { ...state, reportLocation: { ...state.reportLocation, ...action.payload } };
case SET_DATA_INCIDENT:
return { ...state, dataIncidentReport: action.payload };
case SET_DATA_ACHIEVEMENT:
return { ...state, dataAchievement: action.payload };
case SET_DATA_TYPE_RISK:
return { ...state, typeRiskIncident: action.payload };
case SET_INCIDENT_RISK_POTENTIAL:
return { ...state, incidentRiskPotential: action.payload };
case SET_RISK_LEVEL:
return { ...state, riskLevel: action.payload };
case SET_CHRONOLOGY:
return { ...state, chronology: action.payload };
case SET_ROOT_CASE:
return { ...state, rootCase: action.payload };
case SET_DATA_PREVENTION:
return { ...state, dataPrevention: action.payload };
case SET_DATA_IMAGES:
return { ...state, dataImage: action.payload };
case RESET_INCIDENT_REPORT:
return initialState;
default:
return state;
}
}

8
src/appredux/modules/user/actions.js

@ -25,12 +25,12 @@ export const setFcmToken = obj => dispatch => {
}) })
} }
export const setChosenLanguage = (language) => dispatch => { export const setChosenLanguage = obj => dispatch => {
dispatch({ dispatch({
type: SET_CHOSEN_LANGUAGE, type: SET_CHOSEN_LANGUAGE,
payload: language payload: obj
}); })
}; }
export const setRegister = obj => dispatch => { export const setRegister = obj => dispatch => {
dispatch({ dispatch({

17
src/appredux/modules/user/reducers.js

@ -6,26 +6,27 @@ import {
SET_REGISTER SET_REGISTER
} from "./actions"; } from "./actions";
const initialState = { const initialState = {
isLogin: false, isLogin: false,
user: null, user: null, // the payload after request login to API
fcmToken: null, fcmToken: null,
chosenLanguage: 'id', chosenLanguage: 'en', // id / en
isRegister: false isRegister: false
}; }
function userReducer(state = initialState, action) { function userReducer(state = initialState, action) {
switch (action.type) { switch (action.type) {
case SET_IS_LOGIN: case SET_IS_LOGIN:
return { ...state, isLogin: action.payload }; return { ...state, isLogin: action.payload }
case SET_USER: case SET_USER:
return { ...state, user: action.payload }; return { ...state, user: action.payload }
case SET_FCM_TOKEN: case SET_FCM_TOKEN:
return { ...state, fcmToken: action.payload }; return { ...state, fcmToken: action.payload }
case SET_CHOSEN_LANGUAGE: case SET_CHOSEN_LANGUAGE:
return { ...state, chosenLanguage: action.payload }; return { ...state, chosenLanguage: action.payload }
case SET_REGISTER: case SET_REGISTER:
return { ...state, isRegister: action.payload }; return { ...state, isRegister: action.payload }
default: default:
return state; return state;
} }

6
src/appredux/reducers.js

@ -4,14 +4,10 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
// modules // modules
import userReducer from './modules/user/reducers'; import userReducer from './modules/user/reducers';
import themeReducer from './modules/theme/reducers';
import incidentReportReducer from './modules/incidentReport/reducers'
const rootReducer = combineReducers({ const rootReducer = combineReducers({
userReducer, userReducer
themeReducer,
incidentReportReducer
}); });
const appReducer = (state, action) => { const appReducer = (state, action) => {

68
src/config/ApiConst.js

@ -18,49 +18,41 @@ export const ERROR_LOGIN = "ERROR_LOGIN"
export const jenisKejadian = [ export const jenisKejadian = [
{ {
"data": [ "data": [
{ label: "Vandalisme aset perusahaan", "level": "Critical", "checked": false }, { "label": "Vandalisme aset perusahaan", "level": "Critical", "checked": false },
{ label: "Perusakan aset", "level": "Critical", "checked": false }, { "label": "Perusakan aset", "level": "Critical", "checked": false },
{ label: "Pencurian", "level": "Critical", "checked": false }, { "label": "Pencurian", "level": "Critical", "checked": false },
{ label: "Penerobosan", "level": "Critical", "checked": false }, { "label": "Penerobosan", "level": "Critical", "checked": false },
{ label: "Kehilangan", "level": "Critical", "checked": false }, { "label": "Kehilangan", "level": "Critical", "checked": false },
{ label: "Peledakan", "level": "Critical", "checked": false }, { "label": "Peledakan", "level": "Critical", "checked": false },
{ label: "Pembakaran", "level": "Critical", "checked": false }, { "label": "Pembakaran", "level": "Critical", "checked": false },
{ label: "Pencemaran lingkungan", "level": "Critical", "checked": false }, { "label": "Pencemaran lingkungan", "level": "Critical", "checked": false },
{ label: "Perampokan", "level": "Critical", "checked": false }, { "label": "Perampokan", "level": "Critical", "checked": false },
{ label: "Pemalakan / Pemerasan", "level": "Critical", "checked": false }, { "label": "Pemalakan / Pemerasan", "level": "Critical", "checked": false },
{ label: "Kerusuhan sosial", "level": "Critical", "checked": false }, { "label": "Kerusuhan sosial", "level": "Critical", "checked": false },
{ label: "Pemogokan kerja", "level": "Critical", "checked": false }, { "label": "Pemogokan kerja", "level": "Critical", "checked": false },
{ label: "Keluhan User", "level": "Critical", "checked": false }, { "label": "Keluhan User", "level": "Critical", "checked": false },
{ label: "Serangan kekerasan", "level": "Critical", "checked": false }, { "label": "Serangan kekerasan", "level": "Critical", "checked": false },
{ label: "Gangguan masyarakat", "level": "Critical", "checked": false }, { "label": "Gangguan masyarakat", "level": "Critical", "checked": false },
{ label: "Sabotase", "level": "Critical", "checked": false }, { "label": "Sabotase", "level": "Critical", "checked": false },
{ label: "Narkoba", "level": "Critical", "checked": false }, { "label": "Narkoba", "level": "Critical", "checked": false },
{ label: "Minuman berakohol", "level": "Critical", "checked": false }, { "label": "Minuman berakohol", "level": "Critical", "checked": false },
{ label: "Perselisihan ketenagakerjaan", "level": "Critical", "checked": false }, { "label": "Perselisihan ketenagakerjaan", "level": "Critical", "checked": false },
{ label: "Tidak ada tindakan/respond", "level": "Critical", "checked": false }, { "label": "Tidak ada tindakan/respond", "level": "Critical", "checked": false },
{ label: "Pelanggaran SOP", "level": "Major", "checked": false }, { "label": "Pelanggaran SOP", "level": "Major", "checked": false },
{ label: "Indisipliner kerja anggota", "level": "Major", "checked": false }, { "label": "Indisipliner kerja anggota", "level": "Major", "checked": false },
{ label: "Kelengkapan seragam", "level": "Major", "checked": false }, { "label": "Kelengkapan seragam", "level": "Major", "checked": false },
{ label: "Kecelakaan kerja", "level": "Major", "checked": false }, { "label": "Kecelakaan kerja", "level": "Major", "checked": false },
{ label: "Kecelakaan Lalu Lintas", "level": "Major", "checked": false }, { "label": "Kecelakaan Lalu Lintas", "level": "Major", "checked": false },
{ label: "Kerusakan Kendaraan Project", "level": "Major", "checked": false }, { "label": "Kerusakan Kendaraan Project", "level": "Major", "checked": false },
{ label: "Kerusakan Equipment Project", "level": "Major", "checked": false }, { "label": "Kerusakan Equipment Project", "level": "Major", "checked": false },
{ label: "Keterlambatan Pembayaran Vendor", "level": "Major", "checked": false }, { "label": "Keterlambatan Pembayaran Vendor", "level": "Major", "checked": false },
{ label: "Keterlambatan Penggajian", "level": "Major", "checked": false }, { "label": "Keterlambatan Penggajian", "level": "Major", "checked": false },
{ label: "Lain-lain", "level": "Major", "checked": false } { "label": "Lain-lain", "level": "Major", "checked": false }
] ]
} }
] ]
export const achievement = [
{ label: "Penghargaan", "checked": false },
{ label: "Penangkapan", "checked": false },
{ label: "Penemuan Barang", "checked": false },
{ label: "Penggagalan Pencurian", "checked": false },
{ label: "Lain-lain", "checked": false }
]
export const dummyDataTraining = [ export const dummyDataTraining = [
{ name: 'Gada Pratama', value: false, label: 'Gada Pratama' }, { name: 'Gada Pratama', value: false, label: 'Gada Pratama' },
{ name: 'Gada Madya', value: false, label: 'Gada Madya' }, { name: 'Gada Madya', value: false, label: 'Gada Madya' },

12
src/navigation/AppRoutes.js

@ -55,8 +55,6 @@ import DialogFormPost from '../screens/activity/projectAset/post/dialogForm';
import ProjectScreen from '../screens/activity/projectAset/project/index'; import ProjectScreen from '../screens/activity/projectAset/project/index';
import DialogFormProject from '../screens/activity/projectAset/project/dialogForm'; import DialogFormProject from '../screens/activity/projectAset/project/dialogForm';
import ProfileScreen from '../screens/Profile'; import ProfileScreen from '../screens/Profile';
import ThemeScreen from '../components/theme'
import LanguageScreen from '../components/language'
const Stack = createNativeStackNavigator(); const Stack = createNativeStackNavigator();
@ -321,16 +319,6 @@ const AppRoutes = () => {
name="ProfileScreen" name="ProfileScreen"
component={ProfileScreen} component={ProfileScreen}
/> />
<Stack.Screen
options={{ headerShown: false }}
name="ThemeScreen"
component={ThemeScreen}
/>
<Stack.Screen
options={{ headerShown: false }}
name="LanguageScreen"
component={LanguageScreen}
/>
</> </>
) )
} }

4
src/navigation/BottomTabNavigator.js

@ -16,9 +16,9 @@ const Tab = createBottomTabNavigator();
export default function BottomTabNavigator() { export default function BottomTabNavigator() {
const { theme, useSystemTheme } = useSelector(state => state.themeReducer); const { theme, useSystemTheme } = useSelector(state => state.themeReducer);
const systemTheme = useColorScheme();
const tabBarColor = useSystemTheme ? (systemTheme === 'dark' ? colors.black : colors.pureWhite) : (theme === 'dark' ? colors.black : colors.pureWhite);
const tabBarColor = theme === 'dark' ? colors.black : colors.pureWhite;
const activeColor = colors.blue; const activeColor = colors.blue;
return ( return (

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

@ -1,6 +1,6 @@
import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react'; import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react';
import { BackHandler, StatusBar } from 'react-native'; import { StatusBar } from 'react-native';
import { Button, Dialog, Appbar, useTheme, Text, } from 'react-native-paper'; import { Button, Text, Appbar, } from 'react-native-paper';
import { StyleSheet, View, } from 'react-native'; import { StyleSheet, View, } from 'react-native';
import { colors } from '../../utils/color'; import { colors } from '../../utils/color';
import { strings } from '../../utils/i18n'; import { strings } from '../../utils/i18n';
@ -11,97 +11,10 @@ import ReportScreen from './stepComponent/report';
import IncidentScreen from './stepComponent/incident'; import IncidentScreen from './stepComponent/incident';
import ChronologyScreen from './stepComponent/chronology'; import ChronologyScreen from './stepComponent/chronology';
import MediaScreen from './stepComponent/media'; 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 }) { export default function DialogForm({ route, navigation }) {
const theme = useTheme()
const dispatch = useDispatch()
const isDarkTheme = theme.dark
const [active, setActive] = useState(0); const [active, setActive] = useState(0);
const [visible, setVisible] = useState(false); const labels = ["Waktu", "Lokasi", "Pelapor", "Kejadian", "Kronologis", "Media"];
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(() => { const renderStepContent = useMemo(() => {
switch (active) { switch (active) {
@ -134,13 +47,13 @@ export default function DialogForm({ route, navigation }) {
} }
}; };
return ( return (
<View style={[styles.container, { backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.pureWhite }]}> <View style={styles.container}>
<StatusBar backgroundColor={colors.beanRed} barStyle="light-content" /> <StatusBar backgroundColor={colors.beanRed} barStyle="light-content" />
<Appbar.Header mode='center-aligned' style={{ backgroundColor: colors.beanRed }}> <Appbar.Header mode='center-aligned' style={{ backgroundColor: colors.beanRed }}>
<Appbar.BackAction color={colors.pureWhite} onPress={showDialog} /> <Appbar.BackAction color={colors.pureWhite} onPress={() => { navigation.goBack() }} />
<Appbar.Content titleStyle={{ fontWeight: 'bold' }} color={colors.pureWhite} title={strings('incidentReport.title')} /> <Appbar.Content titleStyle={{ fontWeight: 'bold' }} color={colors.pureWhite} title={strings('incidentReport.title')} />
</Appbar.Header> </Appbar.Header>
<View style={{ width: '100%', marginTop: 15, marginBottom: 2, backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.pureWhite }}> <View style={{ width: '100%', marginTop: 15, marginBottom: 2, backgroundColor: colors.pureWhite }}>
<StepIndicator <StepIndicator
stepCount={labels.length} stepCount={labels.length}
customStyles={stepIndicatorStyles} customStyles={stepIndicatorStyles}
@ -158,34 +71,17 @@ export default function DialogForm({ route, navigation }) {
</Button> </Button>
{active === labels.length - 1 ? {active === labels.length - 1 ?
( (
<Button mode="contained" textColor={isDarkTheme ? theme.colors.surface : theme.colors.pureWhite} style={[styles.button, { backgroundColor: colors.beanRed }]} onPress={() => console.log('Handle Saved')}> <Button mode="contained" style={[styles.button, { backgroundColor: colors.beanRed }]} onPress={() => console.log('Handle Saved')}>
Simpan Simpan
</Button> </Button>
) )
: ( : (
<Button mode="contained" textColor={isDarkTheme ? theme.colors.surface : theme.colors.pureWhite} style={[styles.button, { backgroundColor: colors.beanRed }]} onPress={handleNext}> <Button mode="contained" style={[styles.button, { backgroundColor: colors.beanRed }]} onPress={handleNext}>
Lanjut Lanjut
</Button> </Button>
)} )}
</View> </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 > </View >
) )
} }
@ -194,6 +90,7 @@ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
marginTop: 20, marginTop: 20,
backgroundColor: colors.pureWhite
}, },
cardView: { cardView: {
marginTop: 10, marginTop: 10,
@ -217,14 +114,7 @@ const styles = StyleSheet.create({
padding: 10, padding: 10,
paddingBottom: 20, paddingBottom: 20,
}, },
dialog: {
marginVertical: 20,
padding: 20,
marginHorizontal: 20,
borderRadius: 10,
justifyContent: "center",
alignItems: "center"
}
}) })
const stepIndicatorStyles = { const stepIndicatorStyles = {
@ -243,12 +133,12 @@ const stepIndicatorStyles = {
stepIndicatorFinishedColor: colors.beanRed, stepIndicatorFinishedColor: colors.beanRed,
stepIndicatorUnFinishedColor: colors.semiRed, stepIndicatorUnFinishedColor: colors.semiRed,
stepIndicatorCurrentColor: colors.beanRed, stepIndicatorCurrentColor: colors.beanRed,
stepIndicatorLabelFontSize: 11, stepIndicatorLabelFontSize: 12,
currentStepIndicatorLabelFontSize: 11, currentStepIndicatorLabelFontSize: 12,
stepIndicatorLabelCurrentColor: colors.pureWhite, stepIndicatorLabelCurrentColor: colors.pureWhite,
stepIndicatorLabelFinishedColor: colors.pureWhite, stepIndicatorLabelFinishedColor: colors.pureWhite,
stepIndicatorLabelUnFinishedColor: colors.beanRed, stepIndicatorLabelUnFinishedColor: colors.beanRed,
labelColor: colors.semiRed, labelColor: colors.semiRed,
labelSize: 11, labelSize: 12,
currentStepLabelColor: colors.beanRed currentStepLabelColor: colors.beanRed
} }

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

@ -4,77 +4,24 @@ import { RefreshControl, StyleSheet, View, ScrollView, Image, Dimensions, Status
import { colors } from '../../utils/color'; import { colors } from '../../utils/color';
import Icon from 'react-native-vector-icons/AntDesign'; import Icon from 'react-native-vector-icons/AntDesign';
import { strings } from '../../utils/i18n'; 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 }) { export default function IncidentScreen({ route, navigation }) {
const theme = useTheme(); const incidentData = [
const isDarkTheme = theme.dark; { id: 1, date: "Senin, 02-05-2024 21:03", location: "Kangean Site Indonesia", company: "Kangean Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "KEI2301M" },
const { user } = useSelector(state => state.userReducer); { id: 2, date: "Selasa, 03-05-2024 10:15", location: "Sumatra Site Indonesia", company: "Sumatra Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "SEI2402M" },
const request = new RequestModule('incident-report'); { id: 3, date: "Rabu, 04-05-2024 15:20", location: "Java Site Indonesia", company: "Java Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "JEI2503M" },
const [refreshing, setRefreshing] = useState(false); { id: 4, date: "Kamis, 05-05-2024 18:30", location: "Bali Site Indonesia", company: "Bali Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "BEI2604M" },
const [page, setPage] = useState(0); { id: 5, date: "Jumat, 06-05-2024 08:00", location: "Sulawesi Site Indonesia", company: "Sulawesi Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "SEI2705M" },
const [dataIncident, setDataIncident] = useState([]); { id: 5, date: "Sabtu, 07-05-2024 08:00", location: "Sulawesi Site Indonesia", company: "Sulawesi Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "SEI2705M" },
const [loading, setLoading] = useState(false); { id: 5, date: "Minggu, 08-05-2024 08:00", location: "Sulawesi Site Indonesia", company: "Sulawesi Energy Indonesia, BUT. Ltd.", icn: "KEI2301M", sicn: "SEI2705M" }
];
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 ( return (
<View style={[styles.container, { backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.pureWhite }]}> <View style={styles.container}>
<StatusBar backgroundColor={isDarkTheme ? theme.colors.background : theme.colors.pureWhite} barStyle={isDarkTheme ? 'light-content' : 'dark-content'} translucent={true} /> <StatusBar backgroundColor={colors.white} barStyle='dark-content' translucent={true} />
<Appbar.Header mode='center-aligned' style={{ backgroundColor: isDarkTheme ? theme.colors.background : theme.colors.pureWhite, elevation: 4 }}> <Appbar.Header mode='center-aligned' style={{ backgroundColor: colors.pureWhite, elevation: 4 }}>
<Appbar.BackAction onPress={() => { navigation.goBack() }} /> <Appbar.BackAction onPress={() => { navigation.goBack() }} />
<Appbar.Content titleStyle={{ fontWeight: 'bold' }} color={isDarkTheme ? theme.colors.pureWhite : theme.colors.black} title={strings('incidentReport.title')} /> <Appbar.Content titleStyle={{ fontWeight: 'bold' }} title={strings('incidentReport.title')} />
</Appbar.Header> </Appbar.Header>
<View style={{ width: '100%', marginTop: 10, marginBottom: 5 }}> <View style={{ width: '100%', marginTop: 10, marginBottom: 5 }}>
@ -82,34 +29,23 @@ export default function IncidentScreen({ route, navigation }) {
{strings('incidentReport.add')} {strings('incidentReport.add')}
</Button> </Button>
</View> </View>
<ScrollView
style={{ flex: 1, marginTop: 5, backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.pureWhite }} <ScrollView style={{ backgroundColor: colors.pureWhite }}>
refreshControl={ {incidentData.map((incident) => (
<RefreshControl <TouchableRipple key={incident.id} onPress={() => { navigation.navigate('DialogFormIncident') }}>
refreshing={refreshing} <Card key={incident.id} elevation={2} style={styles.card}>
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.cardContent}>
<View style={styles.leftContent}> <View style={styles.leftContent}>
<Icon name="warning" size={25} color={isDarkTheme ? theme.colors.pureWhite : theme.colors.blue} /> <Icon name="warning" size={25} color={colors.blue} />
</View> </View>
<View style={styles.midContent}> <View style={styles.midContent}>
<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="bodySmall" style={styles.subText}>{incident.date}</Text>
<Text variant="headlineMedium" style={[styles.Text, { color: isDarkTheme ? theme.colors.pureWhite : theme.colors.blue }]}>{incident.join.project_charter_project_name}</Text> <Text variant="headlineMedium" style={styles.Text}>{incident.location}</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}>{incident.company}</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> <Text variant="bodySmall" style={styles.subText}>{incident.icn} - {incident.sicn}</Text>
</View> </View>
<View style={styles.rightContent}> <View style={styles.rightContent}>
<Icon name="right" size={25} color={isDarkTheme ? theme.colors.pureWhite : theme.colors.blue} /> <Icon name="right" size={25} color={colors.blue} />
</View> </View>
</View> </View>
</Card> </Card>
@ -124,19 +60,22 @@ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
marginTop: 20, marginTop: 20,
backgroundColor: colors.pureWhite
}, },
Text: { Text: {
fontSize: 16, fontSize: 16,
fontWeight: 'bold', fontWeight: 'bold',
color: colors.blue
}, },
card: { card: {
flex: 1, flex: 1,
marginHorizontal: 8, marginHorizontal: 8,
marginVertical: 5, marginVertical: 5,
backgroundColor: colors.pureWhite,
}, },
subText: { subText: {
fontSize: 12, fontSize: 12,
color: colors.blue
}, },
cardContent: { cardContent: {
flexDirection: 'row', flexDirection: 'row',

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

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

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

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

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

@ -1,193 +1,63 @@
import React, { useCallback, useRef, useState } from 'react'; import React, { useState } from 'react';
import { TouchableRipple, Chip, Card, Text, useTheme, Searchbar, List, Button } from 'react-native-paper'; import { TouchableRipple, Chip, Card, Text } from 'react-native-paper';
import { View, StyleSheet, ScrollView } from 'react-native'; import { View, StyleSheet, ScrollView } from 'react-native';
import DateTimePicker from '@react-native-community/datetimepicker'; import DateTimePicker from '@react-native-community/datetimepicker';
import moment from 'moment'; import moment from 'moment';
import { colors } from '../../../utils/color'; import { colors } from '../../../utils/color';
import { jenisKejadian } from '../../../config/ApiConst' import { jenisKejadian } from '../../../config/ApiConst'
import Icon from 'react-native-vector-icons/MaterialCommunityIcons' 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() { export default function IncidentScreen() {
const theme = useTheme(); const [selectedItems, setSelectedItems] = useState([]);
const isDarkTheme = theme.dark; const [dataIncidentReport, setDataIncidentReport] = useState(jenisKejadian[0].data)
const dispatch = useDispatch(); const [typeRiskIncident, setTypeRiskIncident] = useState("")
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 handleOpenSheetIncident = useCallback(() => { const handleCheckboxChange = (item) => {
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 => { const updatedDataIncidentReport = dataIncidentReport.map(dataItem => {
if (dataItem.label === item.label) { if (dataItem.label === item.label) {
return { ...dataItem, checked: !dataItem.checked }; return { ...dataItem, checked: !dataItem.checked };
} }
return dataItem; return dataItem;
}); });
setDataIncidentReport(updatedDataIncidentReport);
const hasCritical = updatedDataIncidentReport.some(item => item.level === 'Critical' && item.checked); const hasCritical = updatedDataIncidentReport.some(item => item.level === 'Critical' && item.checked);
dispatch(setDataTypeRisk(updatedDataIncidentReport.some(item => item.checked) ? (hasCritical ? 'Critical' : 'Major') : '')); setTypeRiskIncident(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 renderAchievement = (data) => ( const isItemSelected = (label) => {
<View key={data.label}> return dataIncidentReport.some(item => item.label === label && item.checked);
<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 ( return (
<> <>
<Card style={{ backgroundColor: colors.semiRed, paddingVertical: 15, paddingHorizontal: 15, marginHorizontal: 8, marginVertical: 5, borderRadius: 5 }}> <Card style={{ backgroundColor: colors.semiRed, paddingVertical: 15, paddingHorizontal: 15, marginHorizontal: 8, marginVertical: 5, borderRadius: 5 }}>
<View> <View>
<Text variant="bodySmall" style={{ color: colors.beanRed, fontWeight: 'bold', fontSize: 16 }}> <Text variant="bodySmall" style={{ color: colors.beanRed, fontWeight: 'bold', fontSize: 16 }}>
{strings('incidentReport.achievement')} & {strings('incidentReport.incident')} Jenis kejadian
</Text> </Text>
<Text variant="bodySmall" style={{ color: colors.beanRed, fontSize: 12 }}> <Text variant="bodySmall" style={{ color: colors.beanRed, fontSize: 12 }}>
Capaian/Kejadian apa saja yang terjadi di lokasi, bisa pilih lebih dari satu Kejadian apa saja yang terjadi di lokasi, bisa pilih lebih dari satu
</Text> </Text>
</View> </View>
</Card> </Card>
<View style={styles.container}> <View style={styles.container}>
<Text variant="bodySmall" style={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black, fontSize: 16 }}> <Text variant="bodySmall" style={{ color: colors.black, fontSize: 16 }}>
{strings('incidentReport.achievement')} Pilih Jenis Kejadian
</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> </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}> <ScrollView style={styles.listData}>
<View> <View>
{dataIncidentReport.filter(item => item.checked).map(item => ( {dataIncidentReport.map(item => (
<Chip <>
key={item.label} <Chip
icon={() => ( icon={() => (
<Icon name='circle-slice-8' size={20} color={colors.blue} /> <Icon name={isItemSelected(item.label) ? 'circle-slice-8' : 'circle-outline'} size={20} color={isItemSelected(item.label) ? colors.pureWhite : colors.blue} />
)} textStyle={{ color: colors.blue }} onPress={() => handleSelectIncident(item)} style={{ backgroundColor: colors.semiBlue, marginBottom: 5 }}>{item.label}</Chip> )} 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 >
</>
))} ))}
</View> </View>
</ScrollView> </ScrollView >
</View> </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>
</> </>
) )
} }
@ -201,5 +71,5 @@ const styles = StyleSheet.create({
listData: { listData: {
flex: 1, flex: 1,
marginTop: 10, marginTop: 10,
} },
}); });

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

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

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

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

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

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

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

@ -3,49 +3,40 @@ import { TouchableRipple, TextInput, Card, Text } from 'react-native-paper';
import { View, StyleSheet } from 'react-native'; import { View, StyleSheet } from 'react-native';
import DateTimePicker from '@react-native-community/datetimepicker'; import DateTimePicker from '@react-native-community/datetimepicker';
import moment from 'moment'; 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'; import { colors } from '../../../utils/color';
export default function TimeScreen() { export default function TimeScreen() {
const dispatch = useDispatch(); const [incidentDate, setIncidentDate] = useState('');
const [incidentTime, setIncidentTime] = useState('');
const incidentDate = useSelector(state => state.incidentReportReducer.incidentDate); const [reportDate, setReportDate] = useState('');
const incidentTime = useSelector(state => state.incidentReportReducer.incidentTime); const [reportTime, setReportTime] = useState('');
const reportDate = useSelector(state => state.incidentReportReducer.reportDate);
const reportTime = useSelector(state => state.incidentReportReducer.reportTime);
const [showIncidentDatePicker, setShowIncidentDatePicker] = useState(false); const [showIncidentDatePicker, setShowIncidentDatePicker] = useState(false);
const [showIncidentTimePicker, setShowIncidentTimePicker] = useState(false); const [showIncidentTimePicker, setShowIncidentTimePicker] = useState(false);
const [showReportDatePicker, setShowReportDatePicker] = useState(false); const [showReportDatePicker, setShowReportDatePicker] = useState(false);
const [showReportTimePicker, setShowReportTimePicker] = 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 handleIncidentDateChange = (event, selectedDate) => {
const currentDate = selectedDate;
setShowIncidentDatePicker(false); setShowIncidentDatePicker(false);
if (selectedDate) { setIncidentDate(currentDate);
dispatch(setIncidentDate(selectedDate));
}
}; };
const handleIncidentTimeChange = (event, selectedDate) => { const handleIncidentTimeChange = (event, selectedDate) => {
const currentDate = selectedDate;
setShowIncidentTimePicker(false); setShowIncidentTimePicker(false);
if (selectedDate) { setIncidentTime(currentDate);
dispatch(setIncidentTime(selectedDate));
}
}; };
const handleReportDateChange = (event, selectedDate) => { const handleReportDateChange = (event, selectedDate) => {
const currentDate = selectedDate;
setShowReportDatePicker(false); setShowReportDatePicker(false);
if (selectedDate) { setReportDate(currentDate);
dispatch(setReportDate(selectedDate));
}
}; };
const handleReportTimeChange = (event, selectedDate) => { const handleReportTimeChange = (event, selectedDate) => {
const currentDate = selectedDate;
setShowReportTimePicker(false); setShowReportTimePicker(false);
if (selectedDate) { setReportTime(currentDate);
dispatch(setReportTime(selectedDate));
}
}; };
const showIncidentDatePickerFunc = () => { const showIncidentDatePickerFunc = () => {

2
src/screens/presence/index.js

@ -109,7 +109,7 @@ export default function PresenceScreen({ route, navigation }) {
<Appbar.Content titleStyle={{ fontWeight: 'bold' }} color={colors.pureWhite} title={strings('presence.attendanceHistory')} /> <Appbar.Content titleStyle={{ fontWeight: 'bold' }} color={colors.pureWhite} title={strings('presence.attendanceHistory')} />
</Appbar.Header> </Appbar.Header>
<ScrollView <ScrollView
style={{ flex: 1, marginTop: 5, backgroundColor: isDarkTheme ? theme.colors.surface : theme.colors.pureWhite }} style={{ flex: 1, marginTop: 5, backgroundColor: theme.colors.surface }}
refreshControl={ refreshControl={
<RefreshControl <RefreshControl
refreshing={refreshing} refreshing={refreshing}

115
src/screens/registerPage/index.js

@ -115,28 +115,21 @@ export default function DialogForm() {
}; };
try { try {
if (image && image.imageFile == null) { const resultImage = await handleUploadImage([image], PATH_ID);
const result = await requestAssign.addData(payload);
if (result.status === 201) {
store.dispatch(setRegister(true));
Toast.show({ Toast.show({
type: 'error', type: 'success',
text1: strings('global.imageNull'), text1: strings('register.dataSentSuccessfully'),
}); });
navigation.navigate('App');
clearForm()
} else { } else {
const resultImage = await handleUploadImage([image], PATH_ID); Toast.show({
const result = await requestAssign.addData(payload); type: 'error',
if (result.status === 201) { text1: strings('presence.failedSendData'),
store.dispatch(setRegister(true)); });
Toast.show({
type: 'success',
text1: strings('register.dataSentSuccessfully'),
});
navigation.navigate('App');
clearForm()
} else {
Toast.show({
type: 'error',
text1: strings('presence.failedSendData'),
});
}
} }
} catch (error) { } catch (error) {
console.error("Network error sending presence data:", error); console.error("Network error sending presence data:", error);
@ -353,6 +346,7 @@ export default function DialogForm() {
// const tempPath = `file://${RNFS.TemporaryDirectoryPath}/prsensi/${moment().format('YYYYMMDDHHmmss')}.jpg`; // const tempPath = `file://${RNFS.TemporaryDirectoryPath}/prsensi/${moment().format('YYYYMMDDHHmmss')}.jpg`;
// await RNFS.copyFile(markedImage, tempPath); // await RNFS.copyFile(markedImage, tempPath);
console.log("markedImage", markedImage);
const newImageData = { const newImageData = {
id: 0, id: 0,
attachment_number: existingAttachmentNumber, attachment_number: existingAttachmentNumber,
@ -374,38 +368,26 @@ export default function DialogForm() {
}); });
}; };
const renderImage = useMemo(() => { const renderImage = useMemo(() => (
if (!image?.imageFile) { <>
return null; // Don't render anything if imageFile is null or undefined <View style={styles.imageBlock}>
} <TouchableRipple onPress={() => handleOpenSheetImage(image?.imageFile)}>
<View style={styles.imageContainer}>
return ( <Image
<> source={{ uri: image?.imageFile }}
<View style={styles.imageBlock}> style={styles.image}
<TouchableRipple onPress={() => handleOpenSheetImage(image?.imageFile)}> resizeMode="cover"
<View style={styles.imageContainer}> />
<Image </View>
source={{ uri: image.imageFile }} </TouchableRipple>
style={styles.image} </View>
resizeMode="cover"
/>
</View>
</TouchableRipple>
</View>
<Button <Button icon="delete" style={{ borderRadius: 10, backgroundColor: colors.semiRed, marginHorizontal: 5, marginBottom: 10 }} textColor={colors.beanRed} mode="contained-tonal" onPress={handleDeleteImage}>
icon="delete" {strings('global.delete')}
style={{ borderRadius: 10, backgroundColor: colors.semiRed, marginHorizontal: 5, marginBottom: 10 }} </Button>
textColor={colors.beanRed}
mode="contained-tonal"
onPress={handleDeleteImage}
>
{strings('global.delete')}
</Button>
</>
);
}, [image, handleOpenSheetImage, handleDeleteImage]);
</>
), [image, handleOpenSheetImage, handleDeleteImage]);
@ -469,22 +451,21 @@ export default function DialogForm() {
right={<TextInput.Icon icon="chevron-down" />} right={<TextInput.Icon icon="chevron-down" />}
/> />
</TouchableRipple> </TouchableRipple>
{position !== 'spv' &&
<TouchableRipple rippleColor={isDarkTheme ? theme.colors.blue : theme.colors.pureWhite} onPress={handleOpenSheet}> <TouchableRipple rippleColor={isDarkTheme ? theme.colors.blue : theme.colors.pureWhite} onPress={handleOpenSheet}>
<TextInput <TextInput
style={{ marginTop: 10 }} style={{ marginTop: 10 }}
dense={true} dense={true}
editable={false} editable={false}
value={shift ? shift : ''} value={shift ? shift : ''}
outlineColor={colors.amethystSmoke} outlineColor={colors.amethystSmoke}
activeOutlineColor={colors.blue} activeOutlineColor={colors.blue}
mode="outlined" mode="outlined"
label='Shift' label='Shift'
placeholder='Shift' placeholder='Shift'
right={<TextInput.Icon icon="chevron-down" />} right={<TextInput.Icon icon="chevron-down" />}
/> />
</TouchableRipple> </TouchableRipple>
}
{position !== 'spv' && {position !== 'spv' &&
<TouchableRipple rippleColor={isDarkTheme ? theme.colors.blue : theme.colors.pureWhite} onPress={handleOpenSheetArea}> <TouchableRipple rippleColor={isDarkTheme ? theme.colors.blue : theme.colors.pureWhite} onPress={handleOpenSheetArea}>
<TextInput <TextInput
@ -530,11 +511,11 @@ export default function DialogForm() {
placeholder='Masa Berlaku KTA' placeholder='Masa Berlaku KTA'
/> />
</TouchableRipple> </TouchableRipple>
{!image && image?.imageFile !== null && renderImage} {image !== null && renderImage}
</ScrollView> </ScrollView>
<View style={{ width: '100%', marginTop: 10, marginBottom: 5 }}> <View style={{ width: '100%', marginTop: 10, marginBottom: 5 }}>
<Button icon="camera-plus" style={{ borderRadius: 10, backgroundColor: colors.semiBlue, paddingVertical: 5, marginHorizontal: 5, }} textColor={colors.blue} mode="contained-tonal" onPress={handleTakePicture}> <Button icon="camera-plus" style={{ borderRadius: 10, backgroundColor: colors.semiBlue, paddingVertical: 5, marginHorizontal: 5, }} textColor={colors.blue} mode="contained-tonal" onPress={handleTakePicture}>
{strings('global.addImage')} KTA {strings('global.addImage')}
</Button> </Button>
</View> </View>
</View > </View >

2
src/utils/color.js

@ -14,6 +14,4 @@ export const colors = {
catskillWhite: '#F2F4F6', catskillWhite: '#F2F4F6',
white: '#F9F9F9', white: '#F9F9F9',
pureWhite: '#fFFFFF', pureWhite: '#fFFFFF',
yellow: "#F8DC49",
red: "#AE110C"
}; };

19
src/utils/i18n.js

@ -1,14 +1,13 @@
import { I18n } from "i18n-js"; import { I18n } from "i18n-js";
import * as RNLocalize from "react-native-localize"; import * as RNLocalize from "react-native-localize";
import en from "./locales/en"; import en from "./locales/en";
import id from "./locales/id"; import id from "./locales/id";
import LocalizedStrings from "react-native-localization";
const locales = RNLocalize.getLocales(); const locales = RNLocalize.getLocales();
const i18n = new I18n({ const i18n = new I18n({ en, id });
en,
id,
});
if (Array.isArray(locales)) { if (Array.isArray(locales)) {
i18n.locale = locales[0].languageCode; i18n.locale = locales[0].languageCode;
@ -18,9 +17,13 @@ i18n.fallbacks = true;
export const strings = (name, params = {}) => { export const strings = (name, params = {}) => {
return i18n.t(name, params); return i18n.t(name, params);
}; }
const localStr = new LocalizedStrings({
en,
id
});
export const changeLanguage = (languageKey) => { export const changeLanguage = (languageKey) => {
i18n.locale = languageKey; localStr.setLanguage(languageKey)
console.log("languageKey", languageKey); }
};

38
src/utils/locales/en.json

@ -25,16 +25,13 @@
"send": "Send", "send": "Send",
"sending": "Sending", "sending": "Sending",
"errorConnectionMsg": "Failed to connect internet", "errorConnectionMsg": "Failed to connect internet",
"backMessage": "Are you sure you want to back ?",
"areYouSure": "Are you sure?", "areYouSure": "Are you sure?",
"noData": "No data found", "noData": "No data found",
"register": "Register",
"fill": "FILL", "fill": "FILL",
"press": "PRESS", "press": "PRESS",
"search": "Search",
"panicButton": "PANIC BUTTON", "panicButton": "PANIC BUTTON",
"panicButtonMessage": "Press this button in case of an incident", "panicButtonMessage": "Press this button in case of an incident"
"message": "Data inputted will be lost",
"imageNull": "Image cannot be null"
}, },
"profile": { "profile": {
"profile": "Profile", "profile": "Profile",
@ -47,15 +44,13 @@
"signout": "Sign Out", "signout": "Sign Out",
"signoutMessage": "Are you sure you want to log out of this account?", "signoutMessage": "Are you sure you want to log out of this account?",
"about": "About", "about": "About",
"languageSetting": "Language Setting", "languageSetting": "Language Setting"
"changeTheme": "Theme Setting",
"personnelList": "Personel List"
}, },
"loginPage": { "login": {
"headMessage": "Welcome back!", "welcomeMessage": "Welcome back!",
"signInBtn": "SIGN IN", "scanuserid": "Scan User ID",
"passwordErrorMsg": "Pleas fill the password", "userlogin": "Login User",
"successLogin": "welcome to Neops" "usernamenotexist": "Username does not exist!"
}, },
"home": { "home": {
"welcomeMessage": "Welcome" "welcomeMessage": "Welcome"
@ -86,14 +81,7 @@
"incidentReport": { "incidentReport": {
"title": "Incident Report", "title": "Incident Report",
"add": "Add Incident Report", "add": "Add Incident Report",
"containedAction": "Add Contained Action", "containedAction": "Add Contained Action"
"incidentSelect": "Select Incident",
"achievementSelect": "Select Achievement",
"incidentStep": "Capaian & Kejadian",
"timeStep": "Time",
"locationStep": "Location",
"reportStep": "Reporter",
"chronologyStep": "Chronology"
}, },
"patrol": { "patrol": {
"title": "Patrol", "title": "Patrol",
@ -108,13 +96,7 @@
"failedSendDataPresence": "Failed to send presence data", "failedSendDataPresence": "Failed to send presence data",
"presenceOutMessage": "Thank you for your dedication and work today", "presenceOutMessage": "Thank you for your dedication and work today",
"dataSentSuccessfully": "Presence Data Successfully Saved", "dataSentSuccessfully": "Presence Data Successfully Saved",
"dataSentOutSuccessfully": "Out attendance data is successfully saved", "dataSentOutSuccessfully": "Out attendance data is successfully saved"
"attendanceHistory": "Presence History"
},
"register": {
"title": "Registration",
"dataSentSuccessfully": "Register Data Successfully Saved",
"failedSendData": "Failed to send register data"
}, },
"activity": { "activity": {
"title": "Report Activity", "title": "Report Activity",

32
src/utils/locales/id.json

@ -24,25 +24,22 @@
"close": "Tutup", "close": "Tutup",
"send": "Kirim", "send": "Kirim",
"sending": "Mengirim", "sending": "Mengirim",
"backMessage": "Apakah anda ingin kembali ?",
"errorConnectionMsg": "Gagal menghubungkan ke internet", "errorConnectionMsg": "Gagal menghubungkan ke internet",
"reject": "Tolak", "reject": "Tolak",
"areYouSure": "Apakah anda yakin?", "areYouSure": "Apakah anda yakin?",
"noData": "Tidak ada data ditemukan", "noData": "Tidak ada data ditemukan",
"register": "Pendaftaran",
"fill": "ISI", "fill": "ISI",
"press": "TEKAN", "press": "TEKAN",
"search": "Cari",
"panicButton": "TOMBOL PANIK", "panicButton": "TOMBOL PANIK",
"panicButtonMessage": "Press this button in case of an incident", "panicButtonMessage": "Press this button in case of an incident"
"message": "Data yang di input akan hilang",
"imageNull": "Gambar Tidak Boleh Kosong"
}, },
"loginPage": { "loginPage": {
"headMessage": "Selamat datang!", "headMessage": "Selamat datang!",
"signInBtn": "MASUK", "signInBtn": "MASUK",
"usernameErrorMsg": "Username harus di antara 3-30 karakter", "usernameErrorMsg": "Username harus di antara 3-30 karakter",
"passwordErrorMsg": "Password tidak boleh kosong", "passwordErrorMsg": "Password tidak boleh kosong",
"successLogin": "Selamat Datang di Neops" "successLogin": "Berhasil login aplikasi"
}, },
"profile": { "profile": {
"profile": "Profil", "profile": "Profil",
@ -55,9 +52,7 @@
"signout": "Keluar Aplikasi", "signout": "Keluar Aplikasi",
"signoutMessage": "Apakah anda yakin ingin keluar dari akun ini?", "signoutMessage": "Apakah anda yakin ingin keluar dari akun ini?",
"about": "Tentang", "about": "Tentang",
"languageSetting": "Pengaturan Bahasa", "languageSetting": "Pengaturan Bahasa"
"changeTheme": "Ganti Tampilan",
"personnelList": "Daftar Personel"
}, },
"home": { "home": {
"welcomeMessage": "Selamat datang", "welcomeMessage": "Selamat datang",
@ -72,13 +67,7 @@
"failedSendDataPresence": "Gagal mengirim data kehadiran", "failedSendDataPresence": "Gagal mengirim data kehadiran",
"errorFetchingLocation": "Gagal Mendapatkan Titik Lokasi", "errorFetchingLocation": "Gagal Mendapatkan Titik Lokasi",
"dataSentSuccessfully": "Data Presensi Berhasil Disimpan", "dataSentSuccessfully": "Data Presensi Berhasil Disimpan",
"dataSentOutSuccessfully": "Data Presensi Keluar Berhasil Disimpan", "dataSentOutSuccessfully": "Data Presensi Keluar Berhasil Disimpan"
"attendanceHistory": "Riwayat Kehadiran"
},
"register": {
"title": "Pendaftaran",
"dataSentSuccessfully": "Data Pendaftaran Berhasil Disimpan",
"failedSendData": "Gagal mengirim data pendaftaran"
}, },
"takePicture": { "takePicture": {
"select": "Pilih", "select": "Pilih",
@ -106,16 +95,7 @@
"incidentReport": { "incidentReport": {
"title": "Laporan Kejadian", "title": "Laporan Kejadian",
"add": "Tambah Laporan", "add": "Tambah Laporan",
"containedAction": "Tambah Rencana Pencegahan", "containedAction": "Tambah Rencana Pencegahan"
"incidentSelect": "Pilih Kejadian",
"achievementSelect": "Pilih Capaian",
"incident": "Kejadian",
"achievement": "Capaian",
"incidentStep": "Capaian & Kejadian",
"timeStep": "Waktu",
"locationStep": "Lokasi",
"reportStep": "Pelapor",
"chronologyStep": "Kronologis"
}, },
"patrol": { "patrol": {
"title": "Patroli", "title": "Patroli",

Loading…
Cancel
Save