farhantock
7 months ago
2 changed files with 530 additions and 0 deletions
@ -0,0 +1,440 @@ |
|||||||
|
import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react'; |
||||||
|
import { StatusBar } from 'react-native'; |
||||||
|
import { Button, Checkbox, Appbar, TextInput, TouchableRipple, Card, List, Text } 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 DateTimePicker from '@react-native-community/datetimepicker'; |
||||||
|
import moment from 'moment'; |
||||||
|
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 dummySpecialRequest = [ |
||||||
|
{ name: 'Manajemen', description: "" }, |
||||||
|
{ name: 'Pos (Pos Visit)', description: "" }, |
||||||
|
{ name: 'Stakeholders (Polri,TNI,Instansi Pemerintah', description: "" }, |
||||||
|
{ name: 'Komunitas Lokal (Local Community)', 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}/visit/${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) => ( |
||||||
|
<> |
||||||
|
<View key={index} style={styles.imageBlock}> |
||||||
|
<TouchableRipple onPress={() => { handleOpenSheetImage(image.uri) }}> |
||||||
|
<View style={styles.imageContainer}> |
||||||
|
<Image |
||||||
|
source={{ uri: image.uri }} |
||||||
|
style={styles.image} |
||||||
|
resizeMode="cover" |
||||||
|
/> |
||||||
|
</View> |
||||||
|
</TouchableRipple> |
||||||
|
</View> |
||||||
|
|
||||||
|
<Button icon="delete" style={{ borderRadius: 10, backgroundColor: colors.semiRed, marginHorizontal: 5, marginBottom: 10 }} textColor={colors.beanRed} mode="contained-tonal" onPress={() => handleDeleteImage(index)}> |
||||||
|
{strings('global.delete')} |
||||||
|
</Button> |
||||||
|
</> |
||||||
|
)), [images]); |
||||||
|
|
||||||
|
const renderCategory = (data) => ( |
||||||
|
<View> |
||||||
|
<TouchableRipple key={data.name} onPress={() => handleSelectSpesialRequest(data)}> |
||||||
|
<List.Item |
||||||
|
title={data.name} |
||||||
|
/> |
||||||
|
</TouchableRipple> |
||||||
|
</View> |
||||||
|
); |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<StatusBar backgroundColor={colors.blue} barStyle='light-content' translucent={true} /> |
||||||
|
<Appbar.Header mode='center-aligned' style={{ backgroundColor: colors.blue, elevation: 4 }}> |
||||||
|
<Appbar.BackAction color={colors.pureWhite} onPress={() => { navigation.goBack() }} /> |
||||||
|
<Appbar.Content titleStyle={{ fontWeight: 'bold' }} color={colors.pureWhite} title={strings('activity.visit')} /> |
||||||
|
</Appbar.Header> |
||||||
|
<View style={{ flex: 1, backgroundColor: colors.pureWhite }}> |
||||||
|
<View style={styles.container}> |
||||||
|
<ScrollView style={[styles.scrollViewContainer, { backgroundColor: colors.pureWhite }]}> |
||||||
|
<TextInput |
||||||
|
style={{ marginTop: 10 }} |
||||||
|
dense={true} |
||||||
|
value='' |
||||||
|
outlineColor={colors.amethystSmoke} |
||||||
|
activeOutlineColor={colors.blue} |
||||||
|
mode="outlined" |
||||||
|
label='Nama Pengunjung' |
||||||
|
placeholder='Masukan Nama' |
||||||
|
/> |
||||||
|
<TouchableRipple rippleColor={colors.pureWhite} onPress={handleOpenSheet}> |
||||||
|
<TextInput |
||||||
|
style={{ marginTop: 10 }} |
||||||
|
dense={true} |
||||||
|
editable={false} |
||||||
|
value='' |
||||||
|
outlineColor={colors.amethystSmoke} |
||||||
|
activeOutlineColor={colors.blue} |
||||||
|
mode="outlined" |
||||||
|
label='Jenis Kunjungan' |
||||||
|
placeholder='Pilih Jenis Kunjungan' |
||||||
|
right={<TextInput.Icon icon="chevron-down" onPress={handleOpenSheet} />} |
||||||
|
/> |
||||||
|
</TouchableRipple> |
||||||
|
<TextInput |
||||||
|
style={{ marginTop: 10 }} |
||||||
|
dense={true} |
||||||
|
value='' |
||||||
|
outlineColor={colors.amethystSmoke} |
||||||
|
activeOutlineColor={colors.blue} |
||||||
|
mode="outlined" |
||||||
|
label='Jabatan' |
||||||
|
placeholder='Masukan Jabatan' |
||||||
|
/> |
||||||
|
<TouchableRipple onPress={showStartTimePickerFunc}> |
||||||
|
<TextInput |
||||||
|
style={{ marginTop: 10 }} |
||||||
|
dense={true} |
||||||
|
outlineColor={colors.amethystSmoke} |
||||||
|
activeOutlineColor={colors.blue} |
||||||
|
mode="outlined" |
||||||
|
label="Dari Jam" |
||||||
|
value={''} |
||||||
|
editable={false} |
||||||
|
right={<TextInput.Icon icon="clock-time-eight-outline" onPress={showStartTimePickerFunc} />} |
||||||
|
/> |
||||||
|
</TouchableRipple> |
||||||
|
|
||||||
|
<TouchableRipple onPress={showFinishTimePickerFunc}> |
||||||
|
<TextInput |
||||||
|
style={{ marginTop: 10 }} |
||||||
|
dense={true} |
||||||
|
outlineColor={colors.amethystSmoke} |
||||||
|
activeOutlineColor={colors.blue} |
||||||
|
mode="outlined" |
||||||
|
label="Sampai Jam" |
||||||
|
value={''} |
||||||
|
editable={false} |
||||||
|
right={<TextInput.Icon icon="clock-time-eight-outline" onPress={showFinishTimePickerFunc} />} |
||||||
|
/> |
||||||
|
</TouchableRipple> |
||||||
|
<TextInput |
||||||
|
style={{ marginTop: 10 }} |
||||||
|
dense={true} |
||||||
|
value='' |
||||||
|
outlineColor={colors.amethystSmoke} |
||||||
|
activeOutlineColor={colors.blue} |
||||||
|
mode="outlined" |
||||||
|
label='Lokasi Kunjungan' |
||||||
|
placeholder='Lokasi Kunjungan' |
||||||
|
/> |
||||||
|
<TextInput |
||||||
|
style={{ marginTop: 10 }} |
||||||
|
dense={true} |
||||||
|
underlineColor={colors.amethystSmoke} |
||||||
|
activeOutlineColor={colors.blue} |
||||||
|
label="Deskripsi" |
||||||
|
mode="outlined" |
||||||
|
multiline={true} |
||||||
|
numberOfLines={4} |
||||||
|
/> |
||||||
|
|
||||||
|
{renderImages} |
||||||
|
</ScrollView> |
||||||
|
|
||||||
|
</View > |
||||||
|
<View style={{ width: '100%', marginTop: 10, marginBottom: 5 }}> |
||||||
|
<Button icon="camera-plus" style={{ borderRadius: 10, backgroundColor: colors.semiBlue, marginHorizontal: 5, }} textColor={colors.blue} mode="contained-tonal" onPress={handleTakePicture}> |
||||||
|
{strings('global.addImage')} |
||||||
|
</Button> |
||||||
|
</View> |
||||||
|
<View style={styles.buttonContainer}> |
||||||
|
<Button mode="outlined" style={styles.button} textColor={colors.mistBlue} onPress={() => { navigation.goBack() }} > |
||||||
|
Kembali |
||||||
|
</Button> |
||||||
|
<Button mode="contained" style={[styles.button, { backgroundColor: colors.blue }]} onPress={() => console.log('Handle Saved')}> |
||||||
|
Simpan |
||||||
|
</Button> |
||||||
|
</View> |
||||||
|
</View > |
||||||
|
|
||||||
|
<BottomSheetModalProvider> |
||||||
|
<BottomSheetModal |
||||||
|
ref={bottomSheetModal} |
||||||
|
index={0} |
||||||
|
snapPoints={['50%']} |
||||||
|
bottomInset={10} |
||||||
|
detached={true} |
||||||
|
style={{ marginHorizontal: 5 }} |
||||||
|
> |
||||||
|
<BottomSheetScrollView contentContainerStyle={styles.scrollView}> |
||||||
|
{dummySpecialRequest.map(item => renderCategory(item))} |
||||||
|
</BottomSheetScrollView> |
||||||
|
</BottomSheetModal> |
||||||
|
|
||||||
|
<BottomSheetModal |
||||||
|
ref={bottomSheetImage} |
||||||
|
index={0} |
||||||
|
snapPoints={['50%']} |
||||||
|
> |
||||||
|
<BottomSheetView style={{ alignItems: 'center' }} > |
||||||
|
<Image |
||||||
|
source={{ uri: selectedImageUri }} |
||||||
|
style={styles.imageDetail} |
||||||
|
resizeMode="cover" |
||||||
|
/> |
||||||
|
</BottomSheetView> |
||||||
|
</BottomSheetModal> |
||||||
|
</BottomSheetModalProvider> |
||||||
|
|
||||||
|
|
||||||
|
{showStartTimePicker && ( |
||||||
|
<DateTimePicker |
||||||
|
value={new Date()} |
||||||
|
mode="time" |
||||||
|
display="default" |
||||||
|
onChange={handleStartTimeChange} |
||||||
|
/> |
||||||
|
)} |
||||||
|
{showFinishTimePicker && ( |
||||||
|
<DateTimePicker |
||||||
|
value={new Date()} |
||||||
|
mode="time" |
||||||
|
display="default" |
||||||
|
onChange={handleFinishTimeChange} |
||||||
|
/> |
||||||
|
)} |
||||||
|
</> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
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: { |
||||||
|
marginTop: 10, |
||||||
|
marginBottom: 10, |
||||||
|
alignItems: 'center', |
||||||
|
}, |
||||||
|
imageContainer: { |
||||||
|
flexDirection: 'row', |
||||||
|
alignItems: 'center', |
||||||
|
}, |
||||||
|
image: { |
||||||
|
width: 330, |
||||||
|
height: 150, |
||||||
|
borderRadius: 7 |
||||||
|
}, |
||||||
|
imageDetail: { |
||||||
|
width: 330, |
||||||
|
height: 300, |
||||||
|
borderRadius: 7 |
||||||
|
} |
||||||
|
}) |
@ -0,0 +1,90 @@ |
|||||||
|
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 VisitActivityScreen({ route, navigation }) { |
||||||
|
const data = [ |
||||||
|
{ id: 1, location: "Pos 1", position: "Manager", date: "Senin, 02-05-2024", startTime: "21:03", title: "Kunjungan Manajemen", 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, location: "Pos 2", position: "Danru", date: "Selasa, 03-05-2024", startTime: "10:15", title: "Kunjungan Pos", 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, location: "Pos 3", position: "BKO Kepolisian", date: "Rabu, 04-05-2024", startTime: "15:20", title: "Kunjungan Stakeholders", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean non elit ut leo malesuada porttitor.", visitor: "Khaidir" }, |
||||||
|
]; |
||||||
|
return ( |
||||||
|
<View style={styles.container}> |
||||||
|
<StatusBar backgroundColor={colors.blue} barStyle='light-content' translucent={true} /> |
||||||
|
<Appbar.Header mode='center-aligned' style={{ backgroundColor: colors.blue, elevation: 4 }}> |
||||||
|
<Appbar.BackAction color={colors.pureWhite} onPress={() => { navigation.goBack() }} /> |
||||||
|
<Appbar.Content titleStyle={{ fontWeight: 'bold' }} color={colors.pureWhite} title={strings('activity.visit')} /> |
||||||
|
</Appbar.Header> |
||||||
|
<View style={{ width: '100%', marginTop: 10, marginBottom: 5 }}> |
||||||
|
<Button icon="plus" style={{ borderRadius: 10, backgroundColor: colors.semiBlue, marginHorizontal: 5, }} textColor={colors.blue} mode="contained-tonal" onPress={() => { navigation.navigate('DialogFormVisit') }}> |
||||||
|
{strings('activity.addVisit')} |
||||||
|
</Button> |
||||||
|
</View> |
||||||
|
<ScrollView style={{ backgroundColor: colors.pureWhite }}> |
||||||
|
{data.map((item) => ( |
||||||
|
<Card style={styles.card}> |
||||||
|
<Card.Cover source={{ uri: 'https://picsum.photos/700' }} style={{ height: 130 }} resizeMode='cover' /> |
||||||
|
<Card.Content style={{ marginTop: 10 }}> |
||||||
|
<Text variant="titleLarge" style={{ color: colors.black, fontWeight: '695' }}>{item.title}</Text> |
||||||
|
<View style={styles.row}> |
||||||
|
<Text variant="bodyMedium" style={{ color: colors.black, fontWeight: '695' }}>Tanggal</Text> |
||||||
|
<Text variant="bodyMedium" style={{ color: colors.amethystSmoke }}>{item.date}</Text> |
||||||
|
</View> |
||||||
|
<View style={styles.row}> |
||||||
|
<Text variant="bodyMedium" style={{ color: colors.black, fontWeight: '695' }}>Waktu</Text> |
||||||
|
<Text variant="bodyMedium" style={{ color: colors.amethystSmoke }}>{item.startTime} WIB</Text> |
||||||
|
</View> |
||||||
|
<View style={styles.row}> |
||||||
|
<Text variant="bodyMedium" style={{ color: colors.black, fontWeight: '695' }}>Pengunjung</Text> |
||||||
|
<Text variant="bodyMedium" style={{ color: colors.amethystSmoke }}>{item.visitor}</Text> |
||||||
|
</View> |
||||||
|
<View style={styles.row}> |
||||||
|
<Text variant="bodyMedium" style={{ color: colors.black, fontWeight: '695' }}>Jabatan</Text> |
||||||
|
<Text variant="bodyMedium" style={{ color: colors.amethystSmoke }}>{item.position}</Text> |
||||||
|
</View> |
||||||
|
<View style={styles.row}> |
||||||
|
<Text variant="bodyMedium" style={{ color: colors.black, fontWeight: '695' }}>Lokasi Kunjungan</Text> |
||||||
|
<Text variant="bodyMedium" style={{ color: colors.amethystSmoke }}>{item.location}</Text> |
||||||
|
</View> |
||||||
|
<View style={styles.row}> |
||||||
|
<Text variant="bodyMedium" style={{ color: colors.black, fontWeight: '695' }}>Deskripsi</Text> |
||||||
|
</View> |
||||||
|
<View style={styles.row}> |
||||||
|
<Text variant="bodyMedium" style={{ color: colors.amethystSmoke, textAlign: 'justify' }}>{item.description}</Text> |
||||||
|
</View> |
||||||
|
</Card.Content> |
||||||
|
</Card> |
||||||
|
))} |
||||||
|
</ScrollView> |
||||||
|
</View > |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
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 |
||||||
|
}, |
||||||
|
}) |
Loading…
Reference in new issue