From 5727d03b3754fe5413531a72554bccbb3297fd6f Mon Sep 17 00:00:00 2001 From: farhantock Date: Thu, 6 Jun 2024 12:39:57 +0700 Subject: [PATCH] feat(activity project-spesial request): spesial request page --- .../activity/spesialRequest/dialogForm.js | 457 ++++++++++++++++++ src/screens/activity/spesialRequest/index.js | 91 ++++ 2 files changed, 548 insertions(+) create mode 100644 src/screens/activity/spesialRequest/dialogForm.js create mode 100644 src/screens/activity/spesialRequest/index.js diff --git a/src/screens/activity/spesialRequest/dialogForm.js b/src/screens/activity/spesialRequest/dialogForm.js new file mode 100644 index 0000000..b8b4523 --- /dev/null +++ b/src/screens/activity/spesialRequest/dialogForm.js @@ -0,0 +1,457 @@ +import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react'; +import { StatusBar } from 'react-native'; +import { Button, Checkbox, Appbar, TextInput, TouchableRipple, Card, List, Text, RadioButton } from 'react-native-paper'; +import { StyleSheet, View, ScrollView, PermissionsAndroid, Image } from 'react-native'; +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 moment from 'moment'; +import DateTimePicker from '@react-native-community/datetimepicker'; +export default function DialogForm({ route, navigation }) { + const [images, setImages] = useState([]); + const [selectedImageUri, setSelectedImageUri] = useState(null); + const bottomSheetModal = useRef(null); + const bottomSheetImage = useRef(null); + const [area, setArea] = useState({ external: false, internal: false }) + const [spesialRequest, SetSpesialRequest] = useState({ name: '', description: '' }) + const [showStartTimePicker, setShowStartTimePicker] = useState(false); + const [showFinishTimePicker, setShowFinishTimePicker] = useState(false); + const [startTime, setStartTime] = useState(''); + const [finishTime, setFinishTime] = useState(''); + const [checked, setChecked] = useState(''); + const dummySpecialRequest = [ + { name: 'Penambahan Guard Statis', description: "" }, + { name: 'Penambahan Guard Temporary', description: "" }, + { name: 'Pengawalan', description: "" }, + { name: 'Investigasi', description: "" }, + { name: 'Training', description: "" }, + { name: 'Pelaporan Kasus', description: "" }, + { name: 'Sidang Pengadilan', description: "" }, + { name: 'Meeting dengan pihak ketiga', description: "" }, + { name: 'Peralatan/Security Device', description: "" }, + { name: 'Lain-lain', description: "" } + ]; + + const handleStartTimeChange = (event, selectedDate) => { + const currentDate = selectedDate; + setShowStartTimePicker(false); + }; + const handleFinishTimeChange = (event, selectedDate) => { + const currentDate = selectedDate; + setShowFinishTimePicker(false); + }; + + const showStartTimePickerFunc = () => { + setShowStartTimePicker(true); + }; + const showFinishTimePickerFunc = () => { + setShowFinishTimePicker(true); + }; + + 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 handleOpenSheetImage = useCallback((uri) => { + + setSelectedImageUri(uri); + bottomSheetImage.current?.present(); + }, []); + + const handleOpenSheet = useCallback(() => { + bottomSheetModal.current?.present(); + }, []); + const handleSelectSpesialRequest = (data) => { + SetSpesialRequest(prevState => ({ + ...prevState, + name: data.name, + + })); + bottomSheetModal.current?.present(); + }; + + const handleTakePicture = async () => { + try { + const granted = await PermissionsAndroid.request( + PermissionsAndroid.PERMISSIONS.CAMERA, + { + title: strings('takePicture.cameraPermissionTitle'), + message: strings('takePicture.cameraPermissionMessage'), + buttonNeutral: strings('takePicture.cameraPermissionBtnNeutral'), + buttonNegative: strings('takePicture.cameraPermissionBtnCancel'), + buttonPositive: strings('takePicture.cameraPermissionBtnPositive'), + }, + ); + if (granted === PermissionsAndroid.RESULTS.GRANTED) { + handleLaunchCamera() + } else { + } + } catch (err) { + console.warn(err); + } + }; + + 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}/spesial-request/${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 renderCategory = (data) => ( + + handleSelectSpesialRequest(data)}> + + + + ); + + return ( + <> + + + { navigation.goBack() }} /> + + + + + + } + /> + + + setChecked('Komplemen')} + color={colors.blue} + uncheckedColor={colors.amethystSmoke} + + /> + setChecked('Komplemen')}> + + Komplemen + + + setChecked('Provisional Sum')} + color={colors.blue} + uncheckedColor={colors.amethystSmoke} + + /> + setChecked('Provisional Sum')}> + + Provisional Sum + + + + + setChecked('service')} + color={colors.blue} + uncheckedColor={colors.amethystSmoke} + + /> + setChecked('service')}> + + Additional work/service + + + + + + } + /> + + + + } + /> + + + + + {renderImages} + + + + + + + + + + + + + + + + {dummySpecialRequest.map(item => renderCategory(item))} + + + + + + + + + + {showStartTimePicker && ( + + )} + {showFinishTimePicker && ( + + )} + + ) +} + +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 + }, + row: { + flexDirection: 'row', + }, + buttonContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + padding: 10, + paddingBottom: 20, + backgroundColor: colors.pureWhite, + }, + imageBlock: { + marginBottom: 10, + alignItems: 'center', + }, + imageContainer: { + flexDirection: 'row', + alignItems: 'center', + }, + image: { + width: 330, + height: 150, + borderRadius: 7 + }, + imageDetail: { + width: 330, + height: 300, + borderRadius: 7 + } +}) \ No newline at end of file diff --git a/src/screens/activity/spesialRequest/index.js b/src/screens/activity/spesialRequest/index.js new file mode 100644 index 0000000..930565f --- /dev/null +++ b/src/screens/activity/spesialRequest/index.js @@ -0,0 +1,91 @@ +import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react'; +import { Card, Text, TouchableRipple, Button, Appbar } from 'react-native-paper'; +import { RefreshControl, StyleSheet, View, ScrollView, StatusBar } from 'react-native'; +import { colors } from '../../../utils/color'; +import Icon from 'react-native-vector-icons/AntDesign'; +import { strings } from '../../../utils/i18n'; +import moment from 'moment'; +export default function SpesialRequestScreen({ route, navigation }) { + const data = [ + { id: 1, type: "Provisional Sum", position: "Manager", date: "Senin, 02-05-2024", startTime: "21:03", title: "Pengawalan", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce tincidunt fringilla lobortis. Morbi suscipit massa mollis porttitor fringilla. Integer rutrum ipsum lorem, ut convallis nisl consequat nec. Proin vel elit vitae sapien convallis molestie. Donec id feugiat lectus. Aenean ut dui ut mi semper facilisis. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam luctus convallis tellus, quis malesuada felis viverra mattis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Aliquam erat volutpat. Mauris eu posuere sapien. Aliquam in nisi at tortor faucibus interdum eget non quam. Aenean non elit ut leo malesuada porttitor.", visitor: "Farhan" }, + { id: 2, type: "Komplemen", position: "Danru", date: "Selasa, 03-05-2024", startTime: "10:15", title: "Investigasi", description: "Morbi suscipit massa mollis porttitor fringilla. Integer rutrum ipsum lorem, ut convallis nisl consequat nec. Proin vel elit vitae sapien convallis molestie. Donec id feugiat lectus. Aenean ut dui ut mi semper facilisis. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam luctus convallis tellus, quis malesuada felis viverra mattis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Aliquam erat volutpat. Mauris eu posuere sapien. Aliquam in nisi at tortor faucibus interdum eget non quam. Aenean non elit ut leo malesuada porttitor.", visitor: "Ibnu" }, + { id: 3, type: "Tambahan", position: "BKO Kepolisian", date: "Rabu, 04-05-2024", startTime: "15:20", title: "Sidang Pengadilan", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean non elit ut leo malesuada porttitor.", visitor: "Khaidir" }, + ]; + return ( + + + + { navigation.goBack() }} /> + + + + + + + {data.map((item) => ( + { navigation.navigate('DialogFormSpesialRequest') }}> + + + + {item.title} + + Tanggal + {item.date} + + + Waktu + {item.startTime} + + + + + {item.type} + + + + + Deskripsi + + + {item.description} + + + + + ))} + + + ) +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + marginTop: 20, + backgroundColor: colors.pureWhite + }, + card: { + flex: 1, + marginTop: 20, + marginHorizontal: 8, + marginVertical: 5, + backgroundColor: colors.pureWhite, + }, + row: { + flexDirection: 'row', + justifyContent: 'space-between', + paddingVertical: 5, + }, + shift: { + backgroundColor: colors.semiBlue, + borderRadius: 10, + padding: 5, + paddingHorizontal: 10 + }, +}) \ No newline at end of file