|
|
|
@ -1,6 +1,6 @@
|
|
|
|
|
import React, { useEffect, useCallback, useMemo, useState, useRef } from 'react'; |
|
|
|
|
import { Icon, Card, Text, Avatar, useTheme, IconButton, FAB, Button, Tooltip } from 'react-native-paper'; |
|
|
|
|
import { RefreshControl, StyleSheet, View, Alert, PermissionsAndroid, Platform, ToastAndroid } from 'react-native'; |
|
|
|
|
import { Card, Text, Avatar, useTheme, IconButton, FAB, Button, Tooltip, TouchableRipple } from 'react-native-paper'; |
|
|
|
|
import { RefreshControl, StyleSheet, View, Alert, PermissionsAndroid, Platform, ToastAndroid, ScrollView, StatusBar } from 'react-native'; |
|
|
|
|
import { launchCamera } from 'react-native-image-picker'; |
|
|
|
|
import { useFocusEffect } from '@react-navigation/native'; |
|
|
|
|
import ImageMarker, { Position, TextBackgroundType } from 'react-native-image-marker'; |
|
|
|
@ -8,26 +8,25 @@ import { useDispatch, useSelector } from 'react-redux';
|
|
|
|
|
import { setShipmentData } from '../appredux/actions'; |
|
|
|
|
import { store } from '../appredux/store'; |
|
|
|
|
import RNFS from 'react-native-fs'; |
|
|
|
|
import { getCoords } from '../utils/geolocation'; |
|
|
|
|
import { strings } from '../utils/i18n'; |
|
|
|
|
import moment from 'moment'; |
|
|
|
|
import 'moment/locale/id'; |
|
|
|
|
moment.locale('id'); |
|
|
|
|
import person from '../assets/images/courier_man.png' |
|
|
|
|
import BottomSheet, { BottomSheetScrollView } from '@gorhom/bottom-sheet'; |
|
|
|
|
import { |
|
|
|
|
BottomSheetModal, |
|
|
|
|
BottomSheetModalProvider, |
|
|
|
|
BottomSheetView |
|
|
|
|
} from '@gorhom/bottom-sheet'; |
|
|
|
|
import Icon from 'react-native-vector-icons/AntDesign'; |
|
|
|
|
import { requestAccessStoragePermission } from '../utils/storage'; |
|
|
|
|
import { colors } from '../utils/color'; |
|
|
|
|
|
|
|
|
|
const HomeScreen = ({ route, navigation }) => { |
|
|
|
|
const theme = useTheme(); |
|
|
|
|
const [currentTime, setCurrentTime] = useState(moment(new Date())); |
|
|
|
|
const [historyPresensi, setHistoryPresensi] = useState([]); |
|
|
|
|
const [state, setState] = React.useState({ open: false }); |
|
|
|
|
|
|
|
|
|
const onStateChange = ({ open }) => setState({ open }); |
|
|
|
|
|
|
|
|
|
const { open } = state; |
|
|
|
|
const [bottomSheetIndex, setBottomSheetIndex] = useState(0); |
|
|
|
|
const [zIndex, setZIndex] = useState(1); |
|
|
|
|
|
|
|
|
|
const bottomSheetModal = useRef(null); |
|
|
|
|
useFocusEffect( |
|
|
|
|
useCallback(() => { |
|
|
|
|
let homeTimer = setInterval(() => { |
|
|
|
@ -40,29 +39,19 @@ const HomeScreen = ({ route, navigation }) => {
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
const dummyData = [ |
|
|
|
|
{ id: '1', date: '2024-02-09', timeIn: '08:00', timeOut: '17:00', duration: new Date(0, 0, 0, 8, 0, 0) }, |
|
|
|
|
{ id: '2', date: '2024-02-10', timeIn: '08:15', timeOut: '17:30', duration: new Date(0, 0, 0, 8, 30, 0) }, |
|
|
|
|
{ id: '3', date: '2024-02-11', timeIn: '08:10', timeOut: '17:20', duration: new Date(0, 0, 0, 9, 0, 0) }, |
|
|
|
|
{ id: '4', date: '2024-02-12', timeIn: '08:10', timeOut: '17:20', duration: new Date(0, 0, 0, 10, 0, 0) }, |
|
|
|
|
{ id: '5', date: '2024-02-13', timeIn: '08:10', timeOut: '17:20', duration: new Date(0, 0, 0, 11, 0, 0) }, |
|
|
|
|
{ id: '6', date: '2024-02-14', timeIn: '08:10', timeOut: '17:20', duration: new Date(0, 0, 0, 9, 30, 0) }, |
|
|
|
|
{ id: '7', date: '2024-02-15', timeIn: '08:10', timeOut: '17:20', duration: new Date(0, 0, 0, 12, 0, 0) }, |
|
|
|
|
{ id: '1', date: '2024-02-09', timeIn: '08:00', timeOut: '17:00', shift: "Pagi", duration: new Date(0, 0, 0, 8, 0, 0) }, |
|
|
|
|
{ id: '2', date: '2024-02-10', timeIn: '08:15', timeOut: '17:30', shift: "Pagi", duration: new Date(0, 0, 0, 8, 30, 0) }, |
|
|
|
|
{ id: '3', date: '2024-02-11', timeIn: '08:10', timeOut: '17:20', shift: "Pagi", duration: new Date(0, 0, 0, 9, 0, 0) }, |
|
|
|
|
{ id: '4', date: '2024-02-12', timeIn: '08:10', timeOut: '17:20', shift: "Pagi", duration: new Date(0, 0, 0, 10, 0, 0) }, |
|
|
|
|
{ id: '5', date: '2024-02-13', timeIn: '08:10', timeOut: '17:20', shift: "Pagi", duration: new Date(0, 0, 0, 11, 0, 0) }, |
|
|
|
|
{ id: '6', date: '2024-02-14', timeIn: '08:10', timeOut: '17:20', shift: "Pagi", duration: new Date(0, 0, 0, 9, 30, 0) }, |
|
|
|
|
{ id: '7', date: '2024-02-15', timeIn: '08:10', timeOut: '17:20', shift: "Pagi", duration: new Date(0, 0, 0, 12, 0, 0) }, |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const handleSheetChanges = useCallback((index) => { |
|
|
|
|
console.log('index', index); |
|
|
|
|
if (index > 0) { |
|
|
|
|
setZIndex(0) |
|
|
|
|
} else { |
|
|
|
|
setZIndex(1) |
|
|
|
|
} |
|
|
|
|
const handlePresensiPress = useCallback(() => { |
|
|
|
|
bottomSheetModal.current?.present(); |
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
const handlePresensiPress = () => { |
|
|
|
|
setZIndex(0) |
|
|
|
|
setBottomSheetIndex(1); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const handlePresensiConfirm = async () => { |
|
|
|
|
try { |
|
|
|
@ -77,15 +66,13 @@ const HomeScreen = ({ route, navigation }) => {
|
|
|
|
|
}, |
|
|
|
|
); |
|
|
|
|
if (granted === PermissionsAndroid.RESULTS.GRANTED) { |
|
|
|
|
// console.log('You can use the camera');
|
|
|
|
|
handleLaunchCamera() |
|
|
|
|
} else { |
|
|
|
|
// console.log('Camera permission denied');
|
|
|
|
|
} |
|
|
|
|
} catch (err) { |
|
|
|
|
console.warn(err); |
|
|
|
|
} |
|
|
|
|
setBottomSheetIndex(0); |
|
|
|
|
bottomSheetModal.current?.dismiss(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const handleLaunchCamera = () => { |
|
|
|
@ -213,61 +200,14 @@ const HomeScreen = ({ route, navigation }) => {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const handlePresensiCancel = () => { |
|
|
|
|
setZIndex(1) |
|
|
|
|
setBottomSheetIndex(0); |
|
|
|
|
bottomSheetModal.current?.dismiss(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const renderItem = ({ id, date, timeIn, timeOut, duration }) => ( |
|
|
|
|
<View key={id} > |
|
|
|
|
<View style={[styles.row, { justifyContent: 'space-between', paddingBottom: 5, paddingLeft: 15 }]}> |
|
|
|
|
<Text>{moment(date).format('dddd, DD MMMM - YYYY')}</Text> |
|
|
|
|
</View> |
|
|
|
|
<View style={[styles.row, { justifyContent: 'space-between', paddingRight: 30, paddingLeft: 20 }]}> |
|
|
|
|
<Icon |
|
|
|
|
source="login" |
|
|
|
|
color={theme.colors.onPrimaryContainer} |
|
|
|
|
size={20} |
|
|
|
|
/> |
|
|
|
|
<Text>{timeIn}</Text> |
|
|
|
|
<Icon |
|
|
|
|
source="arrow-right" |
|
|
|
|
color={theme.colors.onPrimaryContainer} |
|
|
|
|
size={20} |
|
|
|
|
/> |
|
|
|
|
<Text>{timeOut}</Text> |
|
|
|
|
<Icon |
|
|
|
|
source="timer-outline" |
|
|
|
|
color={theme.colors.onPrimaryContainer} |
|
|
|
|
size={20} |
|
|
|
|
/> |
|
|
|
|
<Text>{moment(duration).format('HH:mm')}</Text> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<View style={styles.container}> |
|
|
|
|
<FAB.Group |
|
|
|
|
open={open} |
|
|
|
|
mode='elevated' |
|
|
|
|
icon={open ? 'alert' : 'plus'} |
|
|
|
|
style={[styles.fab, { zIndex: zIndex }]} |
|
|
|
|
backdropColor={'transparent'} |
|
|
|
|
actions={[ |
|
|
|
|
{ |
|
|
|
|
icon: 'plus', |
|
|
|
|
onPress: () => console.log('Daily Report'), |
|
|
|
|
}, |
|
|
|
|
]} |
|
|
|
|
onStateChange={onStateChange} |
|
|
|
|
onPress={() => { |
|
|
|
|
if (open) { |
|
|
|
|
navigation.navigate('DialogFormIncident') |
|
|
|
|
} |
|
|
|
|
}} |
|
|
|
|
/> |
|
|
|
|
<View style={[styles.header, { backgroundColor: '#1C1B40' }]}> |
|
|
|
|
<StatusBar backgroundColor={colors.blue} barStyle='ligth-content' translucent={true} /> |
|
|
|
|
<View style={[styles.header, { backgroundColor: colors.blue }]}> |
|
|
|
|
<Avatar.Image style={styles.avatar} source={person} /> |
|
|
|
|
<View style={styles.textContainer}> |
|
|
|
|
<Text style={[styles.welcomeText, { color: theme.colors.surface }]}> |
|
|
|
@ -281,22 +221,23 @@ const HomeScreen = ({ route, navigation }) => {
|
|
|
|
|
|
|
|
|
|
<Card elevation={4} style={[styles.card, { backgroundColor: 'white' }]}> |
|
|
|
|
<Card.Content> |
|
|
|
|
<Text variant='displaySmall' style={[styles.boldText, { paddingBottom: 10, textAlign: 'center' }]}>{moment(currentTime).format('HH:mm')} </Text> |
|
|
|
|
<Text variant='displaySmall' style={[styles.boldText, { paddingBottom: 10, textAlign: 'center', color: colors.blue }]}>{moment(currentTime).format('HH:mm')} </Text> |
|
|
|
|
<Text variant='titleSmall' style={{ paddingBottom: 10 }}>{moment(currentTime).format('dddd, DD MMMM - YYYY')} </Text> |
|
|
|
|
<View style={[styles.row, { justifyContent: 'space-between' }]}> |
|
|
|
|
<Text variant='titleMedium' style={[styles.boldText, { textAlign: 'center' }]}>Masuk </Text> |
|
|
|
|
<Text variant='titleMedium' style={[styles.boldText, { textAlign: 'center' }]}>Keluar </Text> |
|
|
|
|
<Text variant='titleMedium' style={[styles.boldText, { textAlign: 'center', color: colors.amethystSmoke }]}>Masuk </Text> |
|
|
|
|
<Text variant='titleMedium' style={[styles.boldText, { textAlign: 'center', color: colors.amethystSmoke }]}>Keluar </Text> |
|
|
|
|
</View> |
|
|
|
|
<View style={[styles.row, { justifyContent: 'space-between' }]}> |
|
|
|
|
<Text variant='bodyMedium' style={{ textAlign: 'center' }}>Jam </Text> |
|
|
|
|
<Text variant='bodyMedium' style={{ textAlign: 'center' }}>Jam </Text> |
|
|
|
|
<Text variant='bodyMedium' style={{ textAlign: 'center', color: colors.blue }}>Jam </Text> |
|
|
|
|
<Text variant='bodyMedium' style={{ textAlign: 'center', color: colors.blue }}>Jam </Text> |
|
|
|
|
</View> |
|
|
|
|
<View style={styles.row}> |
|
|
|
|
<View style={styles.iconButtonContainer}> |
|
|
|
|
<IconButton |
|
|
|
|
containerColor={colors.blue} |
|
|
|
|
mode='contained' |
|
|
|
|
icon="fingerprint" |
|
|
|
|
iconColor={'#1C1B40'} |
|
|
|
|
iconColor={colors.pureWhite} |
|
|
|
|
size={80} |
|
|
|
|
onPress={handlePresensiPress} |
|
|
|
|
style={styles.iconButton} |
|
|
|
@ -305,51 +246,89 @@ const HomeScreen = ({ route, navigation }) => {
|
|
|
|
|
</View> |
|
|
|
|
<View style={styles.row}> |
|
|
|
|
<View style={styles.iconButtonContainer}> |
|
|
|
|
<Text variant='bodySmall'>Ketuk Untuk Presensi </Text> |
|
|
|
|
<Text variant='bodySmall' style={{ color: colors.amethystSmoke }}>Ketuk Untuk Presensi </Text> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
</Card.Content> |
|
|
|
|
</Card> |
|
|
|
|
|
|
|
|
|
{bottomSheetIndex === 1 && ( |
|
|
|
|
<BottomSheet |
|
|
|
|
index={bottomSheetIndex === 1 ? 0 : -1} |
|
|
|
|
snapPoints={['30%']} |
|
|
|
|
style={styles.bottomSheet} |
|
|
|
|
bottomInset={20} |
|
|
|
|
<View style={[styles.row, { justifyContent: 'space-between', paddingBottom: 5, paddingHorizontal: 15 }]}> |
|
|
|
|
<Text style={{ color: colors.black, fontWeight: 'bold' }}>Riwayat Kehadiran</Text> |
|
|
|
|
<TouchableRipple onPress={() => { navigation.navigate('PresenceScreen') }}> |
|
|
|
|
<Text style={{ color: colors.amethystSmoke }}>Lihat Semua</Text> |
|
|
|
|
</TouchableRipple> |
|
|
|
|
</View> |
|
|
|
|
<ScrollView style={{ flex: 1 }}> |
|
|
|
|
{dummyData.map((item) => ( |
|
|
|
|
<Card key={item.id} style={styles.cardPrecense}> |
|
|
|
|
<Card.Content> |
|
|
|
|
<View style={[styles.row, { justifyContent: 'space-between' }]}> |
|
|
|
|
<View style={[styles.row, styles.precenseDate]}> |
|
|
|
|
<Icon name="calendar" size={20} color={colors.blue} /> |
|
|
|
|
<Text style={{ color: colors.blue, fontWeight: 'bold', paddingLeft: 3 }}> |
|
|
|
|
{moment(item.date).format('dddd, DD MMMM - YYYY')} |
|
|
|
|
</Text> |
|
|
|
|
</View> |
|
|
|
|
<View style={[styles.precenseDate, { backgroundColor: colors.semigreen }]}> |
|
|
|
|
<Text style={{ color: colors.green, fontWeight: 'bold', paddingLeft: 3 }}> |
|
|
|
|
Shift {item.shift} |
|
|
|
|
</Text> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
<View style={[styles.row, { justifyContent: 'space-between' }]}> |
|
|
|
|
<View style={styles.row}> |
|
|
|
|
<Icon name="clockcircleo" size={20} color={colors.black} /> |
|
|
|
|
<Text style={{ color: colors.amethystSmoke, fontWeight: 'bold', paddingLeft: 3 }}> |
|
|
|
|
Durasi Kerja |
|
|
|
|
</Text> |
|
|
|
|
</View> |
|
|
|
|
<View style={styles.row}> |
|
|
|
|
<Text style={{ color: colors.amethystSmoke }}>Masuk</Text> |
|
|
|
|
<Icon name="minus" size={20} color={colors.amethystSmoke} /> |
|
|
|
|
<Text style={{ color: colors.amethystSmoke }}>Keluar</Text> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
<View style={[styles.row, { justifyContent: 'space-between' }]}> |
|
|
|
|
<View style={styles.row}> |
|
|
|
|
<Text style={{ color: colors.black, paddingLeft: 5 }}>{item.timeIn} Jam</Text> |
|
|
|
|
</View> |
|
|
|
|
<View style={styles.row}> |
|
|
|
|
<Text>{item.timeIn}</Text> |
|
|
|
|
<Icon name="minus" size={20} color={colors.black} /> |
|
|
|
|
<Text>{item.timeOut}</Text> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
</Card.Content> |
|
|
|
|
</Card> |
|
|
|
|
))} |
|
|
|
|
</ScrollView> |
|
|
|
|
|
|
|
|
|
<BottomSheetModalProvider> |
|
|
|
|
<BottomSheetModal |
|
|
|
|
ref={bottomSheetModal} |
|
|
|
|
index={0} |
|
|
|
|
snapPoints={['25%']} |
|
|
|
|
bottomInset={10} |
|
|
|
|
detached={true} |
|
|
|
|
> |
|
|
|
|
<View style={styles.cardContent}> |
|
|
|
|
<View style={[styles.row, { justifyContent: 'space-between' }]}> |
|
|
|
|
<Text variant='titleMedium' style={[styles.boldText, { textAlign: 'center' }]}>Ingin presensi sekarang? </Text> |
|
|
|
|
<BottomSheetView > |
|
|
|
|
<View style={styles.cardContent}> |
|
|
|
|
<View style={[styles.row, { justifyContent: 'space-between' }]}> |
|
|
|
|
<Text variant='titleMedium' style={[styles.boldText, { textAlign: 'center', color: colors.black }]}>Ingin presensi sekarang? </Text> |
|
|
|
|
</View> |
|
|
|
|
<Text variant='bodyMedium' style={{ textAlign: 'center', padding: 3, color: colors.amethystSmoke }}>Semoga harimu menyenangkan dengan penuh produktivitas dan semangat </Text> |
|
|
|
|
<Button mode="contained" buttonColor={colors.blue} onPress={handlePresensiConfirm} style={{ borderRadius: 15 }}> |
|
|
|
|
Presensi Sekarang |
|
|
|
|
</Button> |
|
|
|
|
<Button onPress={handlePresensiCancel} textColor={colors.amethystSmoke}> |
|
|
|
|
Batal |
|
|
|
|
</Button> |
|
|
|
|
</View> |
|
|
|
|
<Text variant='bodyMedium' style={{ textAlign: 'center', padding: 3 }}>Semoga harimu menyenangkan dengan penuh produktivitas dan semangat </Text> |
|
|
|
|
<Button mode="contained" buttonColor='#1C1B40' onPress={handlePresensiConfirm}> |
|
|
|
|
Presensi Sekarang |
|
|
|
|
</Button> |
|
|
|
|
<Button onPress={handlePresensiCancel} textColor={theme.colors.secondary}> |
|
|
|
|
Batal |
|
|
|
|
</Button> |
|
|
|
|
</View> |
|
|
|
|
</BottomSheet> |
|
|
|
|
)} |
|
|
|
|
{bottomSheetIndex === 0 && ( |
|
|
|
|
<BottomSheet |
|
|
|
|
index={bottomSheetIndex === 0 ? 0 : -1} |
|
|
|
|
snapPoints={['10%', '25%', '50%']} |
|
|
|
|
style={styles.bottomSheet} |
|
|
|
|
onChange={handleSheetChanges} |
|
|
|
|
> |
|
|
|
|
<View> |
|
|
|
|
<Text variant='titleMedium' style={[styles.boldText, { textAlign: 'center' }]}>Presensi Minggu ini</Text> |
|
|
|
|
</View> |
|
|
|
|
<BottomSheetScrollView contentContainerStyle={styles.scrollView}> |
|
|
|
|
{dummyData.map(item => renderItem(item))} |
|
|
|
|
</BottomSheetScrollView> |
|
|
|
|
</BottomSheet> |
|
|
|
|
)} |
|
|
|
|
|
|
|
|
|
</View> |
|
|
|
|
</BottomSheetView> |
|
|
|
|
</BottomSheetModal> |
|
|
|
|
</BottomSheetModalProvider> |
|
|
|
|
</View > |
|
|
|
|
); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -361,6 +340,11 @@ const styles = StyleSheet.create({
|
|
|
|
|
flex: 1, |
|
|
|
|
marginTop: 20 |
|
|
|
|
}, |
|
|
|
|
precenseDate: { |
|
|
|
|
backgroundColor: colors.semiBlue, |
|
|
|
|
borderRadius: 10, |
|
|
|
|
padding: 5, |
|
|
|
|
}, |
|
|
|
|
header: { |
|
|
|
|
flexDirection: 'row', |
|
|
|
|
alignItems: 'center', |
|
|
|
@ -408,15 +392,11 @@ const styles = StyleSheet.create({
|
|
|
|
|
scrollView: { |
|
|
|
|
paddingBottom: 20, |
|
|
|
|
}, |
|
|
|
|
presensiItem: { |
|
|
|
|
padding: 10, |
|
|
|
|
borderBottomWidth: 1, |
|
|
|
|
borderBottomColor: '#ccc', |
|
|
|
|
}, |
|
|
|
|
fab: { |
|
|
|
|
position: 'absolute', |
|
|
|
|
|
|
|
|
|
bottom: 44, |
|
|
|
|
cardPrecense: { |
|
|
|
|
marginHorizontal: 10, |
|
|
|
|
marginVertical: 2, |
|
|
|
|
elevation: 4, |
|
|
|
|
backgroundColor: colors.pureWhite |
|
|
|
|
}, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|