You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

691 lines
26 KiB

import { useEffect, useRef, useState } from 'react';
import {View,Text, StyleSheet, ScrollView, TouchableOpacity, Image, Animated, TextInput, Button, Alert, StatusBar, Pressable, FlatList} from 'react-native';
import MapLibreGL from '@maplibre/maplibre-react-native';
import { MapView,ShapeSource,Camera,UserLocation,PointAnnotation,FillLayer,LineLayer,VectorSource } from "@maplibre/maplibre-react-native";
import { SelectList } from 'react-native-dropdown-select-list';
import { RadioButton } from 'react-native-paper';
import DatePicker from 'react-native-date-picker';
import Moment from 'moment';
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
import NetInfo from "@react-native-community/netinfo";
import AwesomeAlert from 'react-native-awesome-alerts';
import AsyncStorage from '@react-native-async-storage/async-storage';
import turfcenter from '@turf/center';
const {points,polygon,lineString} = require('@turf/helpers');
import RNFetchBlob from 'rn-fetch-blob';
import Modal from "react-native-modal";
import {useIsFocused} from '@react-navigation/native';
import { PDAM_API_URL } from "../../urlConfig";
import React from 'react';
type collectLineScreenProps = {route: any,navigation: any};
export default function CollectLineScreen({route,navigation}:collectLineScreenProps) {
console.log("route",route.params);
const apiKey = "JoJs2pcDv5o0yQlQLMfI";
const [basemap, setBasemap] = useState("streets-v2");
const styleURL = `https://api.maptiler.com/maps/${basemap}/style.json?key=${apiKey}`;
const Pipe_Type = [
{key:'Pipa 24"', value:'Pipa 24"'},
{key:'Pipa 20"', value:'Pipa 20"'},
{key:'Pipa 16"', value:'Pipa 16"'},
{key:'Pipa 10"', value:'Pipa 10"'},
]
const [centerCoords,setCenterCoords] = useState<number[]>([]);
const isFocused = useIsFocused();
const [userID,setUserID] = useState();
useEffect(()=>{
if(isFocused){
const getKey = async () =>{
const jsonValue = await AsyncStorage.getItem('USER_DATA')
console.log(JSON.parse(jsonValue!));
const data = JSON.parse(jsonValue!);
console.log("user_data",data.id);
setUserID(data.id)
};
getKey()
let centCord = turfcenter(points(route.params.coordinates));
// console.log('center');
// console.log(centCord.geometry.coordinates);
setCenterCoords(centCord.geometry.coordinates);
const unsubscribe = NetInfo.addEventListener((state) => {
setConnected(state.isConnected!)
});
return () => {
unsubscribe();
};
};
},[isFocused])
const ref = useRef();
const [connected, setConnected] = useState(true);
const [currentIndex, setCurrentIndex] = useState(0);
const [imgUrl, setImgUrl] = useState([]);
const [files, setFiles] = useState([]);
const [pipeName, setPipeName] = useState('');
const [selectedPipeType, setselectedPipeType] = useState("");
const [checkedStatus, setCheckedStatus] = useState('Baik');
const [Information, setInformation] = useState('');
const [open, setOpen] = useState(false);
const [install_date, setInstallDate] = useState(new Date());
const momentDate = Moment(install_date).format('YYYY-MM-DD');
const [alertOnline, setAlertOnline] = useState(false);
const [alertOffline, setAlertOffline] = useState(false);
const [pipeNameError, setPipeNameError] = useState(false);
const [pipeTyeError, setPipeTypeError] = useState(false);
const [pipeStatusError, setPipeStatusError] = useState(false);
const [pipeInfoError, setPipeInfoError] = useState(false);
const [ModalAttachment, setModalAttachment] = useState(false);
const openCameraLib = async () => {
const result = await launchCamera({
mediaType: 'photo',
quality: 1,
includeBase64: true,
saveToPhotos: true
});
const newObj = {
file_type: result?.assets![0]?.type,
file: result?.assets![0]?.base64,
fileSize: result?.assets![0]?.fileSize,
}
setFiles([...files,newObj]);
setImgUrl([...imgUrl,result?.assets![0]?.base64]);
};
const openLib = async () => {
const result = await launchImageLibrary({
quality: 1,
mediaType: 'photo',
selectionLimit: 0,
includeExtra: true,
includeBase64: true
});
result?.assets?.forEach(asset => {
const newObj = {
file_type: asset.type,
file: asset.base64,
fileSize: asset.fileSize
}
setFiles(oldArray => [...oldArray,newObj]);
setImgUrl(oldArray => [...oldArray,asset.base64]);
});
};
const PrevImg = ({isIndex}) => {
if(isIndex===0){
return (
<TouchableOpacity disabled style={{width:'10%',alignSelf:'center'}}>
<Image source={require('../../assets/icon/left-arrow.png')} />
</TouchableOpacity>
)
}
return (
<TouchableOpacity style={{width:'10%',alignSelf:'center'}} onPress={()=> {
setCurrentIndex(currentIndex-1)
ref.current.scrollToIndex({
animated: true,
index: currentIndex-1
});
}}>
<Image source={require('../../assets/icon/left-arrow.png')} />
</TouchableOpacity>
)
};
const NextImg = ({isIndex}) => {
if(imgUrl.length<=1){
return (
<TouchableOpacity disabled style={{width:'10%',alignSelf:'center'}}>
<Image style={{alignSelf:'flex-end'}} source={require('../../assets/icon/right-arrow.png')} />
</TouchableOpacity>
)
}
else{
if (isIndex === (imgUrl.length-1)) {
return (
<TouchableOpacity disabled style={{width:'10%',alignSelf:'center'}}>
<Image style={{alignSelf:'flex-end'}} source={require('../../assets/icon/right-arrow.png')} />
</TouchableOpacity>
)
}
else{
return (
<TouchableOpacity style={{width:'10%',alignSelf:'center'}} onPress={()=> {
setCurrentIndex(currentIndex+1)
ref.current.scrollToIndex({
animated: true,
index: currentIndex+1
});
}}>
<Image style={{alignSelf:'flex-end'}} source={require('../../assets/icon/right-arrow.png')} />
</TouchableOpacity>
)
}
}
};
const showDialog = () => {
if(!pipeName){
setPipeNameError(true)
}else{
setPipeNameError(false)
}
if(!selectedPipeType){
setPipeTypeError(true)
}else{
setPipeTypeError(false)
}
if(!checkedStatus){
setPipeStatusError(true)
}else{
setPipeStatusError(false)
}
if(!Information){
setPipeInfoError(true)
}else{
setPipeInfoError(false)
}
if(!pipeName || !selectedPipeType || !checkedStatus || !Information) {
return false
}
if(connected){
setAlertOnline(true);
}
else{
setAlertOffline(true)
}
};
const handleCancelAlertOnline = () => {
setAlertOnline(false);
};
const handleCancelAlertOffline = () => {
setAlertOffline(false);
};
const collectDataOnline = async() => {
try {
const result = {
status: 0,
body: {},
}
let date = new Date();
const milliseconds = Date.UTC(
date.getFullYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds(),
);
const localTime = new Date(milliseconds);
const geom = route.params.coordinates.map((item:any)=>{
return String(item).replace(',',' ')
})
const obj = {
nama: pipeName,
jenis: selectedPipeType,
tanggal_installasi: momentDate,
status: checkedStatus,
keterangan: Information,
geom: `MULTILINESTRING((${geom}))`,
created_by: userID,
created_at: localTime
}
await RNFetchBlob.config({
trusty : true
}).fetch('POST', `${PDAM_API_URL}/addData`,{
"Accept": 'application/json',
"Content-Type": "application/json",
},
JSON.stringify(obj)
).then(async (resp) => {
const json = resp.json()
const status = resp.respInfo.status;
result.status = status;
result.body = json;
if (status == 201) {
insertAttachment(json,files)
const storeData = async () => {
try {
await AsyncStorage.setItem(json[0].id+" / "+pipeName+" / "+selectedPipeType+" / "+momentDate+" / "+checkedStatus+" / "+Information+" / "+geom+" / sentPDAM","Value");
} catch (e) {
}
};
storeData()
}
})
} catch (error) {
}
};
const collectDataOffline = () => {
const geom = route.params.coordinates.map((item:any)=>{
return String(item).replace(',',' ')
})
const storeData = async () => {
try {
await AsyncStorage.setItem(pipeName+" / "+selectedPipeType+" / "+momentDate+" / "+checkedStatus+" / "+Information+" / "+geom+" / draftPDAM","Value");
} catch (e) {
}
};
storeData()
setAlertOffline(false);
navigation.navigate('Survey Pipa PDAM', { screen: 'Survey Pipa PDAM'})
};
const insertAttachment = async (json: any,files: any) => {
try {
files.forEach(async function(file:any) {
const url = `${PDAM_API_URL}/addAttachment`;
await RNFetchBlob.config({
trusty : true
}).fetch('POST', url,{
"Content-Type": "application/json",
},
JSON.stringify({pdam_id:json[0].id, file:file.file, mimetype:file.file_type, size:file.fileSize})
).then(async (resp) => {
Alert.alert("Success")
navigation.navigate('Survey Pipa PDAM', { screen: 'Survey Pipa PDAM'})
setAlertOnline(false);
}
)
});
} catch (error) {
console.log(error);
}
};
const renderItem = ({item,index}:any) => {
return (
<View key={index} style={{width:100,height:100,borderRadius:10,borderWidth:1,borderStyle:"dashed",flexDirection:'row'}}>
<Image style={{width: '100%',height: '100%',borderRadius:10}}
source={{uri: `data:image/jpeg;base64,${imgUrl[index]}`}}
/>
</View>
);
};
return (
<View style={styles.mainContainer}>
<StatusBar backgroundColor="#34A6F8" barStyle={'light-content'} />
<View key={"mainBackground"} style={{backgroundColor:'#34A6F8',width:'100%',height:'93%'}} />
<View key={"background"} style={{backgroundColor:'#FFFFFF',width:'100%',height:'100%',position:'absolute',borderTopRightRadius:50,borderTopLeftRadius:35,paddingTop:25}}>
<ScrollView style={styles.container}>
<View style={{flexDirection:'column'}}>
<MapView
style={{width:352,height:200,borderWidth:1,borderColor:'#A6A6A6',overflow:'hidden',alignSelf:'center',borderTopRightRadius:10,borderTopLeftRadius:10}}
mapStyle={styleURL}
rotateEnabled={false}
zoomEnabled={false}
pitchEnabled={false}
scrollEnabled={false}
>
<Camera
centerCoordinate={centerCoords}
zoomLevel={15}
minZoomLevel={5}
maxZoomLevel={20}
/>
<ShapeSource
id="line"
shape={{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": route.params.coordinates
}
}
]
}}
>
<LineLayer
id="linelayer1"
style={{lineColor:'red',lineWidth:3}}
/>
</ShapeSource>
{
route.params.coordinates.map((item:any,index:number)=>(
<PointAnnotation
children={<></>}
key={index}
id={String(index)}
coordinate={item}
draggable={false}
/>
))
}
</MapView>
{/* </Pressable> */}
<TouchableOpacity style={{alignSelf:'center',backgroundColor:'#F9F9F9',width:352,height:50,borderBottomLeftRadius:10,borderBottomRightRadius:10,justifyContent:'center',borderWidth:1,borderColor:'#A6A6A6'}} onPress={()=>navigation.navigate('PDAM Map Collect', { screen: 'PDAM Map Collect'})}>
<Text style={{alignSelf:'center',fontWeight:'semibold',fontSize:16,color:'#434343'}}>Change Location</Text>
</TouchableOpacity>
</View>
<View
style={{
marginTop: 15
}}
/>
<View style={{alignSelf:'center'}}>
{/* <Text style={styles.label}>Name<Text style={{color:'red',fontWeight:'bold'}}>*</Text></Text> */}
<Text style={styles.label}>Pipe Name</Text>
<TextInput
style={styles.input}
onChangeText={(text) => {
setPipeName(text)
}}
onChange={()=> {
setPipeNameError(false)
}}
/>
{pipeNameError ? <Text style={styles.errorInput}>Pipe Name is Required!</Text>:null}
</View>
<View
style={{
marginTop: 15
}}
/>
<View style={{alignSelf:'center'}}>
{/* <Text style={styles.label}>PJU Type <Text style={{color:'red',fontWeight:'bold'}}>*</Text></Text> */}
<Text style={styles.label}>Pipe Type</Text>
<SelectList
search={false}
placeholder="Select Pipe Type"
boxStyles={{borderRadius:10,borderWidth:1,borderColor:'#A6A6A6',width:352,height:45}}
inputStyles={{color:'#6B5E5E'}}
dropdownTextStyles={{color:'#6B5E5E'}}
data={Pipe_Type}
setSelected={setselectedPipeType}
onSelect={()=> (
[setPipeTypeError(false)]
)}
/>
{pipeTyeError ? <Text style={styles.errorInput}>Pipe Type is Required!</Text>:null}
</View>
<View
style={{
marginTop: 15
}}
/>
<View style={{alignSelf:'center',width:352,height:45}}>
{/* <Text style={styles.label}>Status<Text style={{color:'red',fontWeight:'bold'}}>*</Text></Text> */}
<Text style={styles.label}>Status</Text>
<View style={{flexDirection:'row',alignItems:'center'}}>
<RadioButton
color='#434343'
value="Baik"
status={ checkedStatus === 'Baik' ? 'checked' : 'unchecked' }
onPress={() => {setCheckedStatus('Baik'); setPipeStatusError(false)}}
/>
<Text style={{color:"#434343",fontWeight:'semibold',fontSize:16}}>Baik</Text>
</View>
<View style={{flexDirection:'row',alignItems:'center'}}>
<RadioButton
color='#434343'
value="Rusak"
status={ checkedStatus === 'Rusak' ? 'checked' : 'unchecked' }
onPress={() => {setCheckedStatus('Rusak'); setPipeStatusError(false); }}
/>
<Text style={{color:"#434343",fontWeight:'semibold',fontSize:16}}>Rusak</Text>
</View>
{pipeStatusError ? <Text style={styles.errorInput}>Status is Required!</Text>:null}
</View>
<View
style={{
marginTop: 60
}}
/>
<View style={{alignSelf:'center'}}>
<Text style={styles.label}>Information</Text>
<TextInput style={{borderWidth:1,borderRadius:20,padding: 10,color:'#6B5E5E',borderColor:'#A6A6A6',textAlignVertical:'top',width:352,height:135}}
multiline
numberOfLines={5}
maxLength={255}
onChangeText={(text) => {
setInformation(text)
}}
onChange={()=> {
setPipeInfoError(false)
}}
/>
{pipeInfoError ? <Text style={styles.errorInput}>Information is Required!</Text>:null}
</View>
<View
style={{
marginTop: 15
}}
/>
<View style={{alignSelf:'center'}}>
<Text style={styles.label}>Installation Date</Text>
<TextInput
style={styles.input}
onPress={() => setOpen(true)}
value={String(momentDate)}
/>
<DatePicker
locale='en'
theme='light'
mode='date'
modal
open={open}
date={install_date}
onConfirm={(survey_date) => {
setOpen(false)
setInstallDate(survey_date)
}}
onCancel={() => {
setOpen(false)
}}
/>
</View>
<View
style={{
marginTop: 15
}}
/>
<View style={{alignSelf:'center',width:352}}>
<Text style={styles.label}>Attachment</Text>
<Text style={{fontStyle:'italic',color:'#434343',fontSize:14}}>Lampirkan foto / gambar</Text>
{
imgUrl.length === 0 ?
<Pressable onPress={()=>setModalAttachment(true)}>
<View style={{width:352,height:70,borderRadius:10,borderStyle:'dashed',borderWidth:2,borderCurve:'continuous',borderColor:'#434343',alignItems:'center',justifyContent:'center',flexDirection:'row',columnGap:5}}>
<Image
source={require('../../assets/icon/camorlib.png')}
/>
<Text style={{fontStyle:'italic',color:'#434343'}}>Klik untuk menambahkan foto / gambar</Text>
</View>
</Pressable>
:
<FlatList
horizontal={false}
showsHorizontalScrollIndicator={false}
scrollEnabled={false}
ListFooterComponent={()=>
<Pressable onPress={()=>setModalAttachment(true)}>
<View style={{width:100,height:100,borderRadius:10,borderWidth:1,borderStyle:"dashed",flexDirection:'row',alignItems:'center',justifyContent:'center'}}>
<Image
source={require('../../assets/icon/camorlib.png')}
/>
</View>
</Pressable>
}
contentContainerStyle={{flexDirection:'row',flexWrap:'wrap',columnGap:25,rowGap:10}}
data={imgUrl}
renderItem={({item,index})=>renderItem({item,index})}
/>
}
</View>
<View
style={{
marginTop: 30
}}
/>
</ScrollView>
<TouchableOpacity style={{width:'100%',height:50,backgroundColor:'#34A6F8',alignItems:'center',justifyContent:'center'}} onPress={showDialog}>
<Text style={{fontSize:18,fontWeight:'bold',color:'#FFFFFF'}}>SEND</Text>
</TouchableOpacity>
</View>
<AwesomeAlert
show={alertOnline}
showProgress={false}
title="Collecting Data"
message="Are you sure for Collecting PDAM data?"
closeOnTouchOutside={false}
closeOnHardwareBackPress={false}
showCancelButton={true}
showConfirmButton={true}
cancelText="No, cancel"
confirmText="Yes, Collect it"
confirmButtonColor="#137997"
onCancelPressed={() => {
handleCancelAlertOnline();
}}
onConfirmPressed={() => {
collectDataOnline();
}}
overlayStyle={{width:'100%'}}
contentContainerStyle={{width:'70%',borderRadius:10}}
titleStyle={{fontSize:20}}
messageStyle={{fontSize:16}}
/>
{/* Offline Mode Alert */}
<AwesomeAlert
show={alertOffline}
showProgress={false}
title="You are offline"
message="You want to add data to the draft?"
closeOnTouchOutside={false}
closeOnHardwareBackPress={false}
showCancelButton={true}
showConfirmButton={true}
cancelText="No, cancel"
confirmText="Yes, Add it"
confirmButtonColor="#DD6B55"
onCancelPressed={() => {
handleCancelAlertOffline();
}}
onConfirmPressed={() => {
collectDataOffline();
}}
overlayStyle={{width:'100%'}}
contentContainerStyle={{width:'70%',borderRadius:10}}
titleStyle={{fontSize:20}}
messageStyle={{fontSize:16}}
/>
<Modal isVisible={ModalAttachment} animationIn={'fadeInUp'} animationOut={'fadeOutDown'} backdropOpacity={0} onBackdropPress={()=>setModalAttachment(false)} style={{top:'18%',alignSelf:'center'}}>
<View key={"modal container"} style={{width:330,height:220,backgroundColor:'#F9F9F9',borderRadius:25,borderWidth:1,borderColor:'#A6A6A6'}}>
<View style={{flexDirection:'row',alignItems:'center',justifyContent:'space-between',paddingLeft:30,paddingTop:20,paddingRight:10}}>
<Text style={{fontSize:20,fontWeight:'semibold',color: '#434343',}}>
Select Mode
</Text>
<Pressable onPress={()=>setModalAttachment(false)} style={{alignSelf:'flex-end',padding:10}}>
<Image style={{tintColor:'#434343'}}
source={require('../../assets/icon/x.png')}
/>
</Pressable>
</View>
<View style={{padding:30}}>
<TouchableOpacity onPress={()=>{openCameraLib(),setModalAttachment(false)}} style={{height:50,backgroundColor:'#FFFFFF',alignItems:'center',justifyContent:'center',borderTopLeftRadius:10,borderTopRightRadius:10,borderWidth:1,borderColor:'#A6A6A6'}}>
<Text style={{fontSize:20,fontWeight:'light',color:'#434343'}}>Take photo</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{openLib(),setModalAttachment(false)}} style={{height:50,backgroundColor:'#FFFFFF',alignItems:'center',justifyContent:'center',borderBottomLeftRadius:10,borderBottomRightRadius:10,borderWidth:1,borderColor:'#A6A6A6'}}>
<Text style={{fontSize:20,fontWeight:'light',color:'#434343'}}>Choose photo</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</View>
);
};
const styles = StyleSheet.create({
errorInput: {
color: 'red',
marginLeft: 20
},
inputLong: {
height: 40,
borderWidth: 1,
padding: 10,
width: 180,
marginRight: 20
},
inputLat: {
height: 40,
borderWidth: 1,
padding: 10,
borderRadius: 50,
width: 180,
color: 'black'
},
input: {
width:352,
height: 45,
borderWidth: 1,
padding: 10,
borderRadius: 10,
color: '#6B5E5E',
borderColor:'#A6A6A6'
},
container: {
padding: 10,
flexGrow: 1
},
mainContainer: {
flex: 1,
},
label: {
fontSize: 16,
fontWeight:'semibold',
color: '#434343',
// marginBottom: 20
},
title: {
alignItems: 'center',
justifyContent: 'center',
alignSelf: 'center',
fontWeight: 'bold',
fontSize: 22,
color: 'black',
marginBottom: 10
},
borderImg: {
borderColor: 'black',
borderWidth: 1,
borderRadius: 20,
},
img: {
width: 295,
height: 500,
borderRadius: 6,
},
btnCameraContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
top:10,
},
btnCamera: {
alignItems: 'center',
justifyContent: 'center',
alignSelf: 'center',
width: 100,
height: 40,
bottom:20,
borderRadius: 6,
backgroundColor: '#80CBD3'
},
textBtn: {
color: '#fff'
},
buttonImageIconStyle: {
padding: 10,
margin: 5,
height: 25,
width: 25,
resizeMode: 'stretch',
},
});