From 9e6382d303974a4b575e840b7c13ecbd97e0ffc3 Mon Sep 17 00:00:00 2001 From: farhantock Date: Thu, 6 Jun 2024 12:35:20 +0700 Subject: [PATCH] feat(activity project-personel): personel page --- src/screens/activity/personel/index.js | 176 +++++++ .../activity/projectAset/post/dialogForm.js | 458 ++++++++++++++++++ 2 files changed, 634 insertions(+) create mode 100644 src/screens/activity/personel/index.js create mode 100644 src/screens/activity/projectAset/post/dialogForm.js diff --git a/src/screens/activity/personel/index.js b/src/screens/activity/personel/index.js new file mode 100644 index 0000000..5223130 --- /dev/null +++ b/src/screens/activity/personel/index.js @@ -0,0 +1,176 @@ +import { TouchableRipple, Button, Card, Text, Avatar, List, Appbar } from 'react-native-paper'; +import { View, StyleSheet, ScrollView } from 'react-native'; +import React, { useState } from 'react'; +import { colors } from '../../../utils/color' +import Icon from 'react-native-vector-icons/AntDesign'; +import moment from 'moment'; +import 'moment/locale/id'; +import person from '../../../assets/images/courier_man.png' +import { strings } from '../../../utils/i18n'; +moment.locale('id'); +export default function PersonelScreen({ route, navigation }) { + const role = 'Danru' + + const dummyData = [ + { id: '2', status: "Sakit", position: "Guard", name: "ibnu", date: '2024-02-10', timeIn: '08:15', timeOut: '17:30' }, + { id: '3', status: "Cuti", position: "Guard", name: "ardhi", date: '2024-02-11', timeIn: '08:10', timeOut: '17:20' }, + { id: '4', status: "", position: "Admin", name: "hana", date: '2024-02-12', timeIn: '08:10', timeOut: '17:20' }, + { id: '5', status: "", position: "Guard", name: "satori", date: '2024-02-13', timeIn: '08:10', timeOut: '17:20' }, + { id: '6', status: "", position: "Guard", name: "khaidir", date: '2024-02-14', timeIn: '08:10', timeOut: '17:20' }, + ]; + + const getCardColor = (status) => { + switch (status) { + case 'Sakit': + return colors.mistBlue; + case 'Alpa': + return colors.semiRed; + case 'Izin': + return colors.semiYellow; + case 'Cuti': + return colors.amethystSmoke; + default: + return colors.mercury; + } + }; + + const getTextColor = (status) => { + switch (status) { + case 'Sakit': + return colors.white; + case 'Alpa': + return colors.beanRed; + case 'Izin': + return colors.orange; + case 'Cuti': + return colors.white; + default: + return colors.mistBlue; + } + }; + + const getTextStatusColor = (status) => { + switch (status) { + case 'Sakit': + return colors.mistBlue; + case 'Alpa': + return colors.beanRed; + case 'Izin': + return colors.orange; + case 'Cuti': + return colors.amethystSmoke; + default: + return colors.mercury; + } + }; + + return ( + + + { navigation.goBack() }} /> + + + {role === 'Danru' ? + + {dummyData.map((item) => ( + + }> + + + + + + + + + + + + + + ))} + + : + {dummyData.map((item) => ( + + } + right={() => { + if (item.status !== "") { + return ( + + + {item.status} + + + ); + } else { return null; } + }} + > + + + ))} + } + + + + + + ) +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + marginTop: 20, + backgroundColor: colors.pureWhite + }, + status: { + backgroundColor: colors.semiBlue, + borderRadius: 10, + padding: 5, + }, + row: { + flexDirection: 'row', + paddingLeft: 0, + marginVertical: 5, + }, + card: { + marginHorizontal: 10, + marginVertical: 4, + elevation: 4, + }, + button: { + flex: 1, + margin: 5, + borderRadius: 5 + }, + buttonContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + padding: 10, + paddingBottom: 20, + backgroundColor: colors.pureWhite, + }, +}); \ No newline at end of file diff --git a/src/screens/activity/projectAset/post/dialogForm.js b/src/screens/activity/projectAset/post/dialogForm.js new file mode 100644 index 0000000..c653295 --- /dev/null +++ b/src/screens/activity/projectAset/post/dialogForm.js @@ -0,0 +1,458 @@ +import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react'; +import { StatusBar } from 'react-native'; +import { Button, IconButton, Text, Appbar, TextInput, TouchableRipple, Card, List, Searchbar, RadioButton } from 'react-native-paper'; +import { StyleSheet, View, ScrollView, PermissionsAndroid, Image } from 'react-native'; +import Icon from 'react-native-vector-icons/AntDesign'; +import { colors } from '../../../../utils/color'; +import { strings } from '../../../../utils/i18n'; +import { launchCamera } from 'react-native-image-picker'; +import { requestAccessStoragePermission } from '../../../../utils/storage'; +import { getCoords } from '../../../../utils/geolocation'; +import { + BottomSheetModal, + BottomSheetModalProvider, + BottomSheetView, + BottomSheetScrollView +} from '@gorhom/bottom-sheet'; +import RNFS from 'react-native-fs'; +import ImageMarker, { Position, TextBackgroundType } from 'react-native-image-marker'; +import DateTimePicker from '@react-native-community/datetimepicker'; +import moment from 'moment'; + +export default function DialogForm({ route, navigation }) { + const [images, setImages] = useState([]); + const [equipment, setEquipment] = useState([]); + const [selectedImageUri, setSelectedImageUri] = useState(null); + const [filter, setFilter] = useState('') + const bottomSheetModal = useRef(null); + const bottomSheetImage = useRef(null); + const [showDamageDatePicker, setShowDamageDatePicker] = useState(false); + + const dummyData = [ + { name: 'HT', description: "", status: "", damageDate: "" }, + { name: 'Borgol', description: "", status: "", damageDate: "" }, + { name: 'Mobil', description: "", status: "", damageDate: "" }, + { name: 'Senter', description: "", status: "", damageDate: "" }, + { name: 'Traffic cone (stick)', description: "", status: "", damageDate: "" }, + { name: 'Laptop', description: "", status: "", damageDate: "" }, + ]; + + const handleSelectEquipment = (data) => { + setEquipment(prevEquipment => { + if (prevEquipment.some(item => item.name === data.name)) { + return prevEquipment; + } + return [...prevEquipment, data]; + }); + setFilter('') + bottomSheetModal.current?.dismiss(); + }; + + const handleStatus = (data, newStatus) => { + setEquipment(prevEquipment => { + return prevEquipment.map(item => { + if (item.name === data) { + return { ...item, status: newStatus }; + } + return item; + }); + }); + } + + const handleDamageDateChange = (data, selectedDate) => { + const currentDate = selectedDate; + setShowDamageDatePicker(false); + setEquipment(prevEquipment => { + return prevEquipment.map(item => { + if (item.name === data) { + return { ...item, damageDate: currentDate }; + } + return item; + }); + }); + }; + + const showDamageDatePickerFunc = () => { + setShowDamageDatePicker(true); + }; + + console.log("equipment", equipment); + const handleSetImageUri = (uri, description) => { + const newImage = { uri: uri, description: description || "" }; + setImages(prevImages => [...prevImages, newImage]); + } + + const handleDeleteImage = (index) => { + const updatedImages = [...images]; + updatedImages.splice(index, 1); + setImages(updatedImages); + }; + + const handleOpenSheet = useCallback(() => { + bottomSheetModal.current?.present(); + }, []); + const handleOpenSheetImage = useCallback((uri) => { + + setSelectedImageUri(uri); + bottomSheetImage.current?.present(); + }, []); + + + const handleTakePicture = async () => { + try { + const granted = await PermissionsAndroid.request( + PermissionsAndroid.PERMISSIONS.CAMERA, + { + title: strings('takePicture.cameraPermissionTitle'), + message: strings('takePicture.cameraPermissionMessage'), + buttonNeutral: strings('takePicture.cameraPermissionBtnNeutral'), + buttonNegative: strings('takePicture.cameraPermissionBtnCancel'), + buttonPositive: strings('takePicture.cameraPermissionBtnPositive'), + }, + ); + if (granted === PermissionsAndroid.RESULTS.GRANTED) { + handleLaunchCamera() + } else { + } + } catch (err) { + console.warn(err); + } + }; + + const handleLaunchCamera = () => { + let options = { + storageOptions: { + skipBackup: true, + path: 'images', + }, + cameraType: 'front', + maxWidth: 768, + maxHeight: 1024, + saveToPhotos: false, + includeBase64: true + }; + + launchCamera(options, (response) => { + if (response.didCancel) { + } else if (response.error) { + } else if (response.customButton) { + } else { + if (response.assets && response.assets.length > 0) { + handleSetImageUri(response.assets[0].uri); + getCoords(loc => { + if (loc) { + let imageObject = { + "image_uri": response.assets[0].uri, + "image_blob": response.assets[0].base64, + "lat": loc.lat, + "lon": loc.lon + } + addOverlay(imageObject) + } + }) + } + } + }); + } + + const addOverlay = async (imageObject) => { + try { + const timestamp = new Date().toLocaleString(); + const location = { latitude: imageObject.lat, longitude: imageObject.lon }; + + const overlayText = `${timestamp}\nLatitude: ${location.latitude}\nLongitude: ${location.longitude}`; + + if (imageObject.image_uri) { + const markedImage = await ImageMarker.markText({ + backgroundImage: { + src: { uri: imageObject.image_uri } + }, + watermarkTexts: [{ + text: overlayText, + positionOptions: { + position: Position.bottomLeft, + }, + style: { + color: '#ffffff', + fontSize: 8, + fontName: 'Arial', + textBackgroundStyle: { + padding: 10, + type: TextBackgroundType.none, + color: '#00000080' + } + }, + }], + position: 'bottomLeft', + color: '#ffffff', + fontName: 'Arial-BoldMT', + fontSize: 16, + scale: 1, + }); + await saveToTemporaryFolder(markedImage, imageObject); + } + + } catch (error) { + console.error('Error adding overlay:', error); + } + } + + const saveToTemporaryFolder = async (markedImage, imageObject) => { + try { + const tempPath = `file://${RNFS.TemporaryDirectoryPath}/equipment/${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 renderImages = useMemo(() => images.map((image, index) => ( + <> + + { handleOpenSheetImage(image.uri) }}> + + + + + + + + + )), [images]); + + const renderEquipment = (data) => ( + + handleSelectEquipment(data)}> + + + + ); + + const filteredData = dummyData.filter(item => item.name.toLowerCase().includes(filter.toLowerCase())); + return ( + <> + + + { navigation.goBack() }} /> + + + + + + + + {strings('activity.ppeUse')} + + {equipment.map(item => + + + + handleStatus(item.name, 'Baik')} + color={colors.blue} + uncheckedColor={colors.amethystSmoke} + + /> + handleStatus(item.name, 'Baik')}> + + Baik + + + handleStatus(item.name, 'Rusak')} + color={colors.blue} + uncheckedColor={colors.amethystSmoke} + + /> + handleStatus(item.name, 'Rusak')}> + + Rusak + + + + + {item.status === 'Rusak' && + <> + + + + + + } + + {showDamageDatePicker && ( + + )} + + {renderImages} + + + )} + + + + + + + + + + + + + setFilter(text)} + value={filter} + traileringIconColor={colors.white} + style={{ backgroundColor: colors.white }} + showDivider={true} + elevation={1} + /> + + {filteredData.map(item => renderEquipment(item))} + + + + + + + + + + + ) +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + marginHorizontal: 10 + }, + + scrollViewContainer: { + flex: 1, + marginVertical: 10, + }, + card: { + flex: 1, + marginHorizontal: 8, + marginVertical: 5, + backgroundColor: colors.pureWhite, + }, + subText: { + fontSize: 12, + color: colors.blue + }, + button: { + flex: 1, + margin: 5, + borderRadius: 5 + }, + buttonContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + padding: 10, + paddingBottom: 20, + backgroundColor: colors.pureWhite, + }, + imageBlock: { + marginVertical: 10, + alignItems: 'center', + }, + imageContainer: { + flexDirection: 'row', + alignItems: 'center', + }, + image: { + width: 330, + height: 150, + borderRadius: 7 + }, + imageDetail: { + width: 330, + height: 300, + borderRadius: 7 + }, + accordion: { + backgroundColor: colors.semiBlue, + color: colors.blue, + marginHorizontal: 10, + marginTop: 10, + borderRadius: 5 + }, +}) \ No newline at end of file