From ffd2acf3f26e114cf6e90cd946f3da644e214abc Mon Sep 17 00:00:00 2001 From: farhantock Date: Thu, 20 Jun 2024 13:01:45 +0700 Subject: [PATCH] feat(dark mode): add dark mode --- src/components/SearchPage.js | 13 +- src/components/renderSkeleton.js | 93 ++++++---- src/navigation/BottomTabNavigator.js | 19 +- src/screens/Home.js | 53 +++--- src/screens/Login.js | 87 +++++----- src/screens/Profile.js | 154 ++++++++--------- src/screens/Service.js | 13 +- src/screens/presence/index.js | 80 +++++---- src/screens/registerPage/index.js | 248 ++++++++++++++++++--------- 9 files changed, 445 insertions(+), 315 deletions(-) diff --git a/src/components/SearchPage.js b/src/components/SearchPage.js index 1b21889..1c1b7d1 100644 --- a/src/components/SearchPage.js +++ b/src/components/SearchPage.js @@ -1,11 +1,12 @@ import React from 'react'; -import { List, Searchbar, TouchableRipple } from 'react-native-paper'; +import { List, Searchbar, TouchableRipple, useTheme } from 'react-native-paper'; import { StyleSheet, View, ScrollView } from 'react-native'; import { useRoute } from '@react-navigation/native'; import { colors } from '../utils/color'; import Icon from 'react-native-vector-icons/AntDesign'; export default function SearchPage({ navigation }) { + const theme = useTheme(); const [searchQuery, setSearchQuery] = React.useState(''); const route = useRoute(); const { dataListProjectCharters, onSelect } = route.params; @@ -20,21 +21,21 @@ export default function SearchPage({ navigation }) { ); return ( - + - + {filteredData.map(item => ( handleProjectSelect(item)}> } + left={() => } right={() => } /> @@ -48,8 +49,6 @@ export default function SearchPage({ navigation }) { const styles = StyleSheet.create({ container: { flex: 1, - marginTop: 50, - marginHorizontal: 10, }, listData: { flex: 1, diff --git a/src/components/renderSkeleton.js b/src/components/renderSkeleton.js index ef79dbe..5a50e0a 100644 --- a/src/components/renderSkeleton.js +++ b/src/components/renderSkeleton.js @@ -2,49 +2,72 @@ import React from 'react'; import { View, StyleSheet } from 'react-native'; import { Card } from 'react-native-paper'; import SkeletonPlaceholder from 'react-native-skeleton-placeholder'; +import { colors } from '../utils/color'; -const renderSkeletonPresence = (length) => { - return Array.from({ length }).map((_, index) => ( - - - - - - - - - - - - - - - - - - - - - - - - - - )); +const renderSkeletonPresence = (length, theme) => { + return ( + + {Array.from({ length }).map((_, index) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ))} + + ); }; const styles = StyleSheet.create({ + presenceDate: { + borderRadius: 10, + }, + row: { flexDirection: 'row', alignItems: 'center', + marginBottom: 5, }, - cardPrecense: { - margin: 10, - padding: 10, - }, - presenceDate: { - padding: 5, - borderRadius: 5, + + cardPresence: { + marginHorizontal: 10, + marginVertical: 2 }, }); diff --git a/src/navigation/BottomTabNavigator.js b/src/navigation/BottomTabNavigator.js index 6b930a8..a7b9f40 100644 --- a/src/navigation/BottomTabNavigator.js +++ b/src/navigation/BottomTabNavigator.js @@ -1,5 +1,5 @@ import React from 'react'; -import { View, StatusBar } from 'react-native'; +import { StatusBar, View, useColorScheme } from 'react-native'; import { CommonActions } from '@react-navigation/native'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { BottomNavigation } from 'react-native-paper'; @@ -10,10 +10,17 @@ import NotifikasiScreen from '../screens/Notification'; import ProfileScreen from '../screens/Profile'; import ServiceScreen from '../screens/Service'; import { colors } from '../utils/color'; +import { useSelector } from 'react-redux'; const Tab = createBottomTabNavigator(); export default function BottomTabNavigator() { + const { theme, useSystemTheme } = useSelector(state => state.themeReducer); + + + const tabBarColor = theme === 'dark' ? colors.black : colors.pureWhite; + const activeColor = colors.blue; + return ( ({ focus: () => { if (route.name === 'Home') { - StatusBar.setBackgroundColor(colors.blue); + StatusBar.setBackgroundColor(theme === 'dark' ? colors.black : colors.blue); StatusBar.setBarStyle('light-content'); } else { StatusBar.setBackgroundColor('white'); @@ -56,14 +63,14 @@ export default function BottomTabNavigator() { renderIcon={({ route, focused }) => { const { options } = descriptors[route.key]; if (options.tabBarIcon) { - return options.tabBarIcon({ focused, color: colors.blue, size: 24 }); + return options.tabBarIcon({ focused, color: activeColor, size: 24 }); } return null; }} renderIndicator={({ route, focused }) => { if (focused) { - return ; + return ; } return null; }} @@ -79,10 +86,10 @@ export default function BottomTabNavigator() { return label; }} - style={{ backgroundColor: colors.pureWhite, borderTopWidth: 0, elevation: 8 }} + style={{ backgroundColor: tabBarColor, borderTopWidth: 0, elevation: 8 }} labeled={false} compact={true} - activeColor={colors.beanRed} + activeColor={activeColor} /> )} > diff --git a/src/screens/Home.js b/src/screens/Home.js index d7b1dff..c56c3f6 100644 --- a/src/screens/Home.js +++ b/src/screens/Home.js @@ -7,7 +7,7 @@ import { PermissionsAndroid, RefreshControl } from 'react-native'; -import { Card, Avatar, IconButton, Button, Text, TouchableRipple, ActivityIndicator } from 'react-native-paper'; +import { Card, Avatar, IconButton, Button, Text, TouchableRipple, ActivityIndicator, useTheme } from 'react-native-paper'; import { launchCamera } from 'react-native-image-picker'; import { useFocusEffect } from '@react-navigation/native'; import ImageMarker, { Position, TextBackgroundType } from 'react-native-image-marker'; @@ -24,18 +24,19 @@ import { import Icon from 'react-native-vector-icons/AntDesign'; import Toast from 'react-native-toast-message'; -import person from '../assets/images/courier_man.png'; import { colors } from '../utils/color'; import { getCoords } from '../utils/geolocation'; import { strings } from '../utils/i18n'; import { PATH_PRESENCE } from '../config/imageFolder'; -import { storeData, resendFailedAttachments } from '../services/sqlite/attachment'; +// import { storeData, resendFailedAttachments } from '../services/sqlite/attachment'; import RequestModule from '../services/api/request'; import { requestAccessStoragePermission } from '../utils/storage'; -// import renderSkeleton from '../components/renderSkeleton'; +import renderSkeleton from '../components/renderSkeleton'; moment.locale('id'); const HomeScreen = ({ route, navigation }) => { + const theme = useTheme(); + const isDarkTheme = theme.dark; const request = new RequestModule('presence') const { user } = useSelector(state => state.userReducer) const [currentTime, setCurrentTime] = useState(moment(new Date())); @@ -74,7 +75,7 @@ const HomeScreen = ({ route, navigation }) => { } getPresenceHistory() getLastPresence() - resendFailedAttachments(); + // resendFailedAttachments(); }, []) @@ -173,7 +174,7 @@ const HomeScreen = ({ route, navigation }) => { console.error("Error sending presence data:", error); Toast.show({ type: 'error', - text1: strings('presence.errorMessage'), + text1: strings('global.errorConnectionMsg'), }); setLoading(false) } @@ -377,13 +378,13 @@ const HomeScreen = ({ route, navigation }) => { return ( - - - + + + - {strings('home.welcomeMessage')}, {user?.name} + {strings('home.welcomeMessage')}, {user?.name.length > 5 ? `${user?.name.substring(0, 5)}...` : user?.name} penuh semangat dan produktivitas @@ -397,7 +398,7 @@ const HomeScreen = ({ route, navigation }) => { /> - + {moment(currentTime).format('HH:mm')} {moment(currentTime).format('dddd, DD MMMM - YYYY')} @@ -431,12 +432,12 @@ const HomeScreen = ({ route, navigation }) => { - Riwayat Kehadiran + Riwayat Kehadiran { navigation.navigate('PresenceScreen') }}> Lihat Semua - { } > {loadingSkeleton ? ( - // renderSkeleton(2) - null + renderSkeleton(2, theme) ) : ( dataPresence.map((item) => ( - + + {moment(item.datePresence).format('dddd, DD MMMM - YYYY')} @@ -469,28 +470,29 @@ const HomeScreen = ({ route, navigation }) => { - - + + Durasi Kerja - Masuk - - Keluar + Masuk + + Keluar - {item.duration ? convertDuration(item.duration) : ''} + {item.duration ? convertDuration(item.duration) : ''} - {moment(item.in_time).format('HH:mm')} - - {item.out_time ? moment(item.out_time).format('HH:mm') : ''} + {moment(item.in_time).format('HH:mm')} + + {item.out_time ? moment(item.out_time).format('HH:mm') : ''} + )) )} @@ -593,7 +595,6 @@ const styles = StyleSheet.create({ marginHorizontal: 10, marginVertical: 2, elevation: 4, - backgroundColor: colors.pureWhite }, loading: { position: 'absolute', diff --git a/src/screens/Login.js b/src/screens/Login.js index b845528..048232c 100644 --- a/src/screens/Login.js +++ b/src/screens/Login.js @@ -1,21 +1,19 @@ import React, { useEffect, useState } from 'react'; import { useForm, Controller } from 'react-hook-form'; -import { KeyboardAvoidingView, ScrollView, StatusBar, View, StyleSheet, Image, Platform, Dimensions, Alert } from 'react-native'; -import { Button, TextInput, HelperText, Text, Modal } from 'react-native-paper'; +import { KeyboardAvoidingView, ScrollView, StatusBar, View, StyleSheet, Image, Platform, Dimensions } from 'react-native'; +import { Button, TextInput, HelperText, Text, useTheme } from 'react-native-paper'; +import { useDispatch } from 'react-redux'; import { setIsLogin, setUser, setRegister } from '../appredux/actions'; -import { store } from '../appredux/store'; -import { colors } from '../utils/color'; import LOGIN_BANNER from '../assets/images/logo_nawakara.png'; import { strings } from '../utils/i18n'; import { initFirebase } from '../utils/Auth'; import RequestModule from '../services/api/request'; import Toast from 'react-native-toast-message'; -const LoginScreen = ({ route, navigation }) => { +const LoginScreen = ({ navigation }) => { + const theme = useTheme(); + const dispatch = useDispatch(); const request = new RequestModule(''); - const [visible, setVisible] = useState(false); - const showModal = () => setVisible(true); - const hideModal = () => setVisible(false); const [loginProcess, setLoginProcess] = useState(false); const [showPassword, setShowPassword] = useState(false); const { control, handleSubmit, formState: { errors, isDirty, isValid, isSubmitting } } = useForm({ @@ -30,19 +28,18 @@ const LoginScreen = ({ route, navigation }) => { initFirebase(); }, []); - const onSubmitLogin = async (payload) => { setLoginProcess(true); try { const result = await request.login(payload); if (result && result.status === 200 && result.data.data) { - store.dispatch(setIsLogin(true)); - store.dispatch(setUser(result.data.data)); + dispatch(setIsLogin(true)); + dispatch(setUser(result.data.data)); if (result.data.data.assigment_hr) { - store.dispatch(setRegister(true)); + dispatch(setRegister(true)); navigation.navigate('App'); } else { - store.dispatch(setRegister(false)); + dispatch(setRegister(false)); navigation.navigate('RegisterScreen'); } } else { @@ -65,29 +62,27 @@ const LoginScreen = ({ route, navigation }) => { return ( <> - + - + login-image - {strings('loginPage.headMessage')} - Silahkan isi Username dan kata sandi anda + {strings('loginPage.headMessage')} + Silahkan isi Username dan kata sandi anda + ( { )} name="username" /> - {errors.username && + {errors.username && ( {strings('loginPage.usernameErrorMsg')} - } + + )} + ( { )} name="password" /> - {errors.password && + {errors.password && ( {strings('loginPage.passwordErrorMsg')} - } + + )} - + - - ) } @@ -161,12 +154,24 @@ const styles = StyleSheet.create({ flex: 1, padding: 20, justifyContent: 'center', - backgroundColor: colors.white, paddingBottom: 100 }, eyeIcon: { marginTop: 12 + }, + loginBanner: { + width: '100%', + height: Dimensions.get('window').height / 5, + marginTop: 30, + marginBottom: 20 + }, + headMessage: { + fontFamily: 'Roboto-Bold' + }, + signInButton: { + marginTop: 15, + borderRadius: 10 } -}) +}); export default LoginScreen; diff --git a/src/screens/Profile.js b/src/screens/Profile.js index 656fa8b..2ac12e6 100644 --- a/src/screens/Profile.js +++ b/src/screens/Profile.js @@ -1,110 +1,115 @@ -import React, { useState } from 'react'; -import { Alert, View, ScrollView, StyleSheet, TouchableOpacity, StatusBar } from 'react-native'; -import { Avatar, Text, Appbar, List, Button, Switch, Modal, Dialog, TouchableRipple } from 'react-native-paper'; -import AntDesign from 'react-native-vector-icons/AntDesign'; -import Ionicons from 'react-native-vector-icons/Ionicons'; -import { clearAllState } from '../utils/Auth'; +import React, { useEffect, useState } from 'react'; +import { Alert, View, ScrollView, StyleSheet, StatusBar } from 'react-native'; +import { Avatar, Text, Appbar, List, Button, Dialog, TouchableRipple, PaperProvider, useTheme } from 'react-native-paper'; import { strings } from '../utils/i18n'; -import person from '../assets/images/courier_man.png' import { colors } from '../utils/color'; import { useSelector } from 'react-redux'; +import { clearAllState } from '../utils/Auth'; const ProfileScreen = ({ navigation }) => { - const [isSwitchOn, setIsSwitchOn] = React.useState(false); - const { user } = useSelector(state => state.userReducer) - const onToggleSwitch = () => setIsSwitchOn(!isSwitchOn); - + const theme = useTheme(); + const isDarkTheme = theme.dark; + const { user } = useSelector(state => state.userReducer); const [visible, setVisible] = useState(false); - - const showModal = () => setVisible(true); - const hideModal = () => setVisible(false); - console.log("user", user.join); + const showDialog = () => setVisible(true); + const hideDialog = () => setVisible(false); return ( - <> + - - - { navigation.goBack() }} /> - + + + { navigation.goBack() }} /> + - + - + {user.name} - - {user.join.m_role_name} + + {user.assigment_hr.position} - + - { navigation.navigate('DailyReportScreen') }}> + { navigation.navigate('DailyReportScreen') }}> } - right={() => } + title={strings('dailyReport.title')} + titleStyle={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }} + left={() => } + right={() => } /> { navigation.navigate('PresenceScreen') }}> } - right={() => } + title={strings('presence.attendanceHistory')} + titleStyle={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }} + left={() => } + right={() => } /> { navigation.navigate('RegisterScreen') }}> } - right={() => } + title={strings('register.title')} + titleStyle={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }} + left={() => } + right={() => } /> - { navigation.navigate('RegisterScreen') }}> + {user.assigment_hr.position !== 'Guard' && + { navigation.navigate('RegisterScreen') }}> + } + right={() => } + /> + + } + { navigation.navigate('ThemeScreen') }}> } - right={() => } + title={strings('profile.changeTheme')} + titleStyle={{ color: isDarkTheme ? theme.colors.pureWhite : theme.colors.black }} + left={() => } + right={() => } + /> + + { navigation.navigate('LanguageScreen') }}> + } + right={() => } /> - } - right={() => - - {isSwitchOn ? "ID" : "EN"} - - - } - /> - + + + + + {strings('global.confirm')} + + {strings('profile.signoutMessage')} + + + + + - - Konfirmasi - {strings('profile.signoutMessage')} - - - - + ) } @@ -112,14 +117,12 @@ const styles = StyleSheet.create({ container: { flex: 1, marginTop: 20, - backgroundColor: colors.pureWhite }, header: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 10, paddingVertical: 20, - backgroundColor: colors.pureWhite }, avatar: { marginRight: 10, @@ -144,7 +147,6 @@ const styles = StyleSheet.create({ marginTop: 10, marginHorizontal: 10, marginVertical: 2, - backgroundColor: colors.pureWhite }, button: { margin: 10, @@ -156,17 +158,9 @@ const styles = StyleSheet.create({ padding: 20, marginHorizontal: 20, borderRadius: 10, - backgroundColor: colors.pureWhite - }, - switchContainer: { - flexDirection: "row", justifyContent: "center", alignItems: "center" - }, - switch: { - marginLeft: 10 } - }) export default ProfileScreen \ No newline at end of file diff --git a/src/screens/Service.js b/src/screens/Service.js index fb6687f..2b004d6 100644 --- a/src/screens/Service.js +++ b/src/screens/Service.js @@ -1,6 +1,6 @@ import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react'; import { Icon, Card, Text, Avatar, useTheme, IconButton, MD3Colors, Button, TouchableRipple } from 'react-native-paper'; -import { RefreshControl, StyleSheet, View, ScrollView, Image, Dimensions } from 'react-native'; +import { RefreshControl, StyleSheet, View, ScrollView, Image, Dimensions, StatusBar } from 'react-native'; import ilustration from '../assets/images/checked.png'; import danger from '../assets/images/danger.png'; import activity from '../assets/images/activity.png'; @@ -12,8 +12,10 @@ import { strings } from '../utils/i18n'; export default function ServiceScreen({ route, navigation }) { const theme = useTheme(); + const isDarkTheme = theme.dark return ( - + + { navigation.navigate('IncidentScreen') }}> @@ -102,8 +104,8 @@ export default function ServiceScreen({ route, navigation }) { /> Kehadiran Lihat riwayat kehadiran - @@ -134,8 +136,7 @@ export default function ServiceScreen({ route, navigation }) { const styles = StyleSheet.create({ container: { flex: 1, - marginTop: 30, - backgroundColor: colors.pureWhite + marginTop: 30 }, Text: { fontSize: 16, diff --git a/src/screens/presence/index.js b/src/screens/presence/index.js index 0810927..5c191c8 100644 --- a/src/screens/presence/index.js +++ b/src/screens/presence/index.js @@ -1,4 +1,4 @@ -import { TouchableRipple, TextInput, Card, Text, Appbar } from 'react-native-paper'; +import { TouchableRipple, TextInput, Card, Text, Appbar, Avatar, ActivityIndicator, useTheme } from 'react-native-paper'; import { View, StyleSheet, ScrollView, RefreshControl, StatusBar, Image } from 'react-native'; import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react'; import { colors } from '../../utils/color' @@ -12,10 +12,13 @@ import { BottomSheetModalProvider, BottomSheetView } from '@gorhom/bottom-sheet'; +import { strings } from '../../utils/i18n'; moment.locale('id'); const PAGE_SIZE = 25; export default function PresenceScreen({ route, navigation }) { + const theme = useTheme(); + const isDarkTheme = theme.dark const request = new RequestModule('presence'); const [refreshing, setRefreshing] = useState(false); const [page, setPage] = useState(0); @@ -23,10 +26,16 @@ export default function PresenceScreen({ route, navigation }) { const [loading, setLoading] = useState(false); const bottomSheetImage = useRef(null); const [selectedImageUri, setSelectedImageUri] = useState(null); + const [loadingImage, setLoadingImage] = useState(false); + + const handleOpenSheetImage = useCallback((uri) => { - console.log('URI received:', uri); - setSelectedImageUri(uri); - bottomSheetImage.current?.present(); + setLoadingImage(true); + setTimeout(() => { + setSelectedImageUri(uri); + setLoadingImage(false); + bottomSheetImage.current?.present(); + }, 1000); }, []); const onRefresh = useCallback(() => { @@ -73,27 +82,34 @@ export default function PresenceScreen({ route, navigation }) { const isCloseToBottom = ({ layoutMeasurement, contentOffset, contentSize }) => { return layoutMeasurement.height + contentOffset.y >= contentSize.height - 20; }; + const renderImage = useMemo(() => { - console.log('Rendering image with URI:', selectedImageUri); return ( - + <> + {loadingImage ? ( + + ) : ( + <> + + + )} + ); - }, [selectedImageUri]); + }, [selectedImageUri, loadingImage]); return ( <> - - + + { navigation.goBack() }} /> - + - {loading ? ( - // renderSkeleton(10) - null + renderSkeleton(10, theme) ) : ( dataPresence.map((item) => ( item.attachments && item.attachments[0] && handleOpenSheetImage(item.attachments[0].url)} key={item.id}> - + @@ -130,35 +145,34 @@ export default function PresenceScreen({ route, navigation }) { - - + + Durasi Kerja - Masuk - - Keluar + Masuk + + Keluar - {item.duration ? convertDuration(item.duration) : ''} + {item.duration ? convertDuration(item.duration) : ''} - {moment(item.in_time).format('HH:mm')} - - {item.out_time ? moment(item.out_time).format('HH:mm') : ''} + {moment(item.in_time).format('HH:mm')} + + {item.out_time ? moment(item.out_time).format('HH:mm') : ''} - {item.attachments && item.attachments.length > 0 ? item.attachments[0].url : 'No attachments'} )) )} - + state.userReducer) - const [images, setImages] = useState([]); + const [image, setImage] = useState(null); const [selectedImageUri, setSelectedImageUri] = useState(null); const bottomSheetImage = useRef(null); const [selectedProject, setSelectedProject] = useState(null); @@ -59,10 +64,11 @@ export default function DialogForm() { }, []); useEffect(() => { + handleGetProjectCharter() + handleGetAssignHR() if (existingAttachmentNumber === '') { setExistingAttachmentNumber(uuid.v4()) } - handleGetProjectCharter() }, []) @@ -70,41 +76,98 @@ export default function DialogForm() { navigation.navigate('SearchPage', { dataListProjectCharters, onSelect: handleProjectSelect }); }; + const handleGetAssignHR = async () => { + const payload = { + paging: { start: 0, length: 1 }, + columns: [ + { name: 'user_id', logic_operator: '=', operator: 'AND', value: user?.id.toString() }, + { name: 'deleted_at', logic_operator: 'IS NULL', operator: 'AND' }, + ], + orders: { columns: ['created_at', 'id'], ascending: false } + }; + const result = await requestAssign.getDataSearch(payload); + if (result && result.status === 200) { + let projectName + if (result.data.data[0]?.project_charter_id) { + projectName = await getProjectName(result.data.data[0]?.project_charter_id); + } + + setImage({ imageFile: result.data.data[0]?.attachments[0]?.url }) + setSelectedProject({ id: result.data.data[0]?.project_charter_id, project_name: projectName || '' }); + setShift(result.data?.data[0]?.shift) + setPosition(result.data?.data[0]?.position) + setExpDate(result.data?.data[0]?.created_at) + setArea(result.data?.data[0]?.area) + setSelectedPost(result.data?.data[0]?.pos) + setExistingAttachmentNumber(result.data?.data[0]?.attachment_number) + } + } const handleSendRegisterData = async () => { const payload = { project_charter_id: selectedProject.id, hr_id: user.id, - Position: position, - Area: area, - Post: selectedPost, + position: position, + area: area, + post: selectedPost, + shift: shift, attachment_number: existingAttachmentNumber }; + try { + const resultImage = await handleUploadImage([image], PATH_ID); const result = await requestAssign.addData(payload); if (result.status === 201) { + store.dispatch(setRegister(true)); Toast.show({ type: 'success', - text1: strings('presence.dataSentSuccessfully'), + text1: strings('register.dataSentSuccessfully'), }); navigation.navigate('App'); + clearForm() } else { Toast.show({ type: 'error', - text1: strings('presence.failedSendDataPresence'), + text1: strings('presence.failedSendData'), }); } } catch (error) { console.error("Network error sending presence data:", error); Toast.show({ type: 'error', - text1: strings('presence.errorMessage'), + text1: strings('global.errorConnectionMsg'), }); } finally { - setLoading(false); // Ensure setLoading is called once in the end + // setLoading(false); // Ensure setLoading is called once in the end } }; + const getProjectName = async (projectCharterId) => { + const payload = { + paging: { start: 0, length: 1 }, + columns: [ + { name: 'id', logic_operator: '=', operator: 'AND', value: projectCharterId.toString() }, + { name: 'deleted_at', logic_operator: 'IS NULL', operator: 'AND' }, + ], + orders: { columns: ['created_at', 'id'], ascending: false } + }; + const result = await request.getDataSearch(payload); + if (result && result.status === 200 && result.data.data.length > 0) { + return result.data.data[0].project_name; + } + return ''; + }; + + const clearForm = () => { + setImage(null) + setSelectedProject(null) + setShift('') + setPosition('') + setExpDate('') + setArea('') + setSelectedPost('') + setExistingAttachmentNumber('') + } const handleProjectSelect = (project) => { handleGetDataManPowers(project.id) @@ -185,18 +248,11 @@ export default function DialogForm() { } }; - - const handleSetImageUri = (uri, description) => { - const newImage = { uri: uri, description: description || "" }; - setImages(prevImages => [...prevImages, newImage]); - } - - const handleDeleteImage = (index) => { - const updatedImages = [...images]; - updatedImages.splice(index, 1); - setImages(updatedImages); + const handleDeleteImage = () => { + setImage(null); }; + const handleTakePicture = async () => { try { const granted = await PermissionsAndroid.request( @@ -253,7 +309,7 @@ export default function DialogForm() { console.log('ImagePicker Error: ', response.error); } else { if (response.assets && response.assets.length > 0) { - setLoading(true) + // setLoading(true) try { getCoords(async (loc) => { if (loc) { @@ -290,7 +346,7 @@ export default function DialogForm() { // const tempPath = `file://${RNFS.TemporaryDirectoryPath}/prsensi/${moment().format('YYYYMMDDHHmmss')}.jpg`; // await RNFS.copyFile(markedImage, tempPath); - + console.log("markedImage", markedImage); const newImageData = { id: 0, attachment_number: existingAttachmentNumber, @@ -300,27 +356,25 @@ export default function DialogForm() { type: response.assets[0].type, name: response.assets[0].fileName }; - - const resultImage = await handleUploadImage([newImageData], PATH_ID); - handleSendRegisterData(); + setImage(newImageData); } }); } catch (error) { console.error('Error adding overlay:', error); - setLoading(false) + // setLoading(false) } } } }); }; - const renderImages = useMemo(() => images.map((image, index) => ( + const renderImage = useMemo(() => ( <> - - { handleOpenSheetImage(image.uri) }}> + + handleOpenSheetImage(image?.imageFile)}> @@ -328,11 +382,14 @@ export default function DialogForm() { - + - )), [images]); + ), [image, handleOpenSheetImage, handleDeleteImage]); + + const renderArea = useMemo(() => listArea?.manpower_planning?.info?.data.map((data, index) => ( <> @@ -356,15 +413,15 @@ export default function DialogForm() { return ( <> - - + + { navigation.goBack() }} /> - + - + - + - - } - /> - - + + } /> - - } - /> - - + + } /> - + {position !== 'spv' && + + } + /> + + } + {position !== 'Danru' && position !== 'spv' && + + } + /> + + } + - {renderImages} + {image !== null && renderImage} - @@ -474,9 +537,14 @@ export default function DialogForm() { snapPoints={['30%']} bottomInset={10} detached={true} - style={{ marginHorizontal: 15, shadowOpacity: 10 }} + style={{ marginHorizontal: 15, shadowOpacity: 10, }} > - + handleSelectPosition("Guard")}> - + handleSelectShift("pagi")}> - + {renderArea} @@ -549,7 +627,12 @@ export default function DialogForm() { detached={true} style={{ marginHorizontal: 15 }} > - + {renderPost} @@ -611,7 +694,6 @@ const styles = StyleSheet.create({ justifyContent: 'space-between', padding: 10, paddingBottom: 20, - backgroundColor: colors.pureWhite, }, imageBlock: { marginTop: 10,