burntab

mail@pastecode.io avatar
unknown
plain_text
a month ago
25 kB
1
Indexable
Never
import React, { useEffect, useRef, useState } from "react"
import { useFocusEffect, useNavigation } from "@react-navigation/native"
import { View, Platform, FlatList, TouchableOpacity, Text, StyleSheet, PermissionsAndroid, } from "react-native"
import Geolocation from 'react-native-geolocation-service';
import MapView, { Polyline } from "react-native-maps"
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
import moment from "moment";
import haversine from 'haversine';


import HistoryIcon from '../../assets/Icons/stats-burn/history.svg'
import InviteIcon from '../../assets/Icons/stats-burn/profile-add-yellow.svg'
import LocationIcon from '../../assets/Icons/stats-burn/location-map.svg'
import PauseIcon from '../../assets/Icons/stats-burn/pause.svg'
import ResumeIcon from '../../assets/Icons/stats-burn/resume.svg'
import RoutingIcon from '../../assets/Icons/stats-burn/routing.svg'
import StopIcon from '../../assets/Icons/stats-burn/stop.svg'

import { SheetModal } from "../common/SheetModal"
import { StartButton } from "../common/StartButton"
import { StatsItem } from "./StatsItem"
import { StepsHistoryCard } from "../common/StepsHistoryCard"
import { BurnTrackers } from "./BurnTrackers";

import { colors } from "../../theme"
import { endBurnTracking, getBurnTrackingData, startBurnTracking } from "../../api";
import fonts from "../../assets/fonts"
import routes from "../../routes/routes"
import { storeCurrentTrackerData } from "../../redux/actions/stats";
import { useDispatch, useSelector } from "react-redux"
import useTimer from "../../helpers/useTimer";
import { LatLngTypes, height, width } from "../../constants/constants"
import getDirections from "../../utils/getDirections";
import useHardwareBackButton from "../../utils/backHandler";


export const BurnTab = () => {

    interface HistoryItem {
        id: number;
        date: string;
        stepsCount: number;
        increase: boolean;
    }
    interface RenderHistoryItemsProps {
        item: HistoryItem;
    }

    const { currentTracker } = useSelector(store => store?.stats)
    const historyData = currentTracker?.trackerData?.chart?.day
    const navigation = useNavigation()
    const LATITUDE = 23.2418;
    const LONGITUDE = 77.3797;
    const LATITUDE_DELTA = 0.02;
    const ASPECT_RATIO = width / height;
    const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;
    const dispatch = useDispatch()
    const mapRef = useRef(null);
    const { timer, handleStart, handlePause, handleResume, handleReset } = useTimer(0);

    const [historyModal, setHistoryModal] = useState<boolean>(false)
    const [inviteModal, setInviteModal] = useState<boolean>(false)
    const [lat, setLat] = useState<number>(23.2418);
    const [lon, setLon] = useState<number>(77.3797);
    const [isPause, setIsPause] = useState(false);

    const [startWatchPosition, setStartWatchPosition] = useState(false);
    const [userStartTime, setUserStartTime] = useState('');
    const [isStart, setIsStart] = useState<boolean>(false);
    const [isMapLoaded, setIsMapLoaded] = useState(false);
    const [polyLineCoords, setPolyLineCoords] = useState<LatLngTypes[]>([
        { latitude: LATITUDE, longitude: LONGITUDE },
    ]);
    const [userInitialPosition, setUserInitialPosition] = useState<LatLngTypes>();
    const [animatedCount, setShowAnimatedCount] = useState(false);
    const [timeLeft, setTimeLeft] = useState<number | null>(null);
    const [printTime, setPrintTime] = useState<number | string | null>(null);

    const [location, setLocation] = useState<{
        speed: number;
        stepsWalked: number;
        latitude: number;
        longitude: number;
        distanceTravelled: number;
        prevLatLng: {};
    }>({
        speed: 0,
        stepsWalked: 0,
        latitude: LATITUDE,
        longitude: LONGITUDE,
        distanceTravelled: 0,
        prevLatLng: {},
    });

    // time format
    const formatTime = (time: any) => {
        const getSeconds = `0${time % 60}`.slice(-2);
        const minutes: any = `${Math.floor(time / 60)}`;
        const getMinutes = `0${minutes % 60}`.slice(-2);
        const getHours = `0${Math.floor(time / 3600)}`.slice(-2);
        return `${getMinutes} : ${getSeconds}`;
    };

    // walk pause
    const onPause = async () => {
        setIsPause(true);
        handlePause();
        setStartWatchPosition(false);
    };

    // resume
    const handleResumeWalk = () => {
        setIsPause(false);
        handleResume();
        setStartWatchPosition(true);
    };

    // finish the walk
    const handleFinishWalk = async () => {
        handleReset();
        let formData = new FormData()

        formData.append('lat', location?.latitude)
        formData.append('long', location?.longitude)
        formData.append('speed', location?.speed)
        formData.append('calories_burn', 0)
        formData.append('steps', location?.stepsWalked)
        formData.append('distance', location?.distanceTravelled)
        formData.append('polyline_coords', JSON.stringify(polyLineCoords))

        endBurnTracking(formData).then(value => {
            if (value?.data) {
                let paramsObj = {
                    current_date: moment().format('YYYY-MM-DD')
                }
                getBurnTrackingData(paramsObj).then(trackingData => {
                    if (trackingData?.data) {
                        const valuesData = trackingData?.data?.data?.steps_chart?.day?.map(entry => entry.value)
                        const titlesData = trackingData?.data?.data?.steps_chart?.day?.map(entry => moment(entry.title).format('MMM-DD'))
                        const modifiedTitles = [titlesData[0]]
                        for (let i = 1; i < titlesData.length; i++) {
                            const day = parseInt(titlesData[i].split("-")[1]);
                            modifiedTitles.push(day);
                        }

                        dispatch(storeCurrentTrackerData({
                            titlesData: modifiedTitles,
                            valuesData: valuesData,
                            trackerType: 'steps',
                            trackerData: {
                                chart: {
                                    ...trackingData?.data?.data?.steps_chart
                                },
                                data: {
                                    ...trackingData?.data?.data?.burn_tracking
                                }
                            }
                        }))
                        navigation.navigate(routes.trackerHistoryScreen, {origin:'burn-session',selectedTracker:'steps'})
                    }
                })
            }
        }).catch(err => console.log(err))
        setStartWatchPosition(false);
    };

    const renderStatsItem = ({ item }) => (
        <StatsItem
            title={item?.title}
            value={item?.value}
            unit={item?.unit}
            leading
        />
    )
    const renderHistoryCards: React.FC<RenderHistoryItemsProps> = ({ item }) => (
        <StepsHistoryCard
            title={'Steps'}
            date={item?.title}
            stepsCount={item?.value}
            increase={item?.value > 0}
            timer={item?.time}
            icon={<MaterialCommunityIcons name="shoe-print" color={colors.purple} size={20} />}
        />)

    const InviteFriendButton = ({
        onpress,
        requests,
    }) => {
        return (
            <TouchableOpacity
                style={styles.inviteButtonStyles}
                onPress={onpress}>
                <View style={styles.notificationIndicator}>
                    <Text style={styles.notificationCountText}>{requests}</Text>
                </View>
                <InviteIcon />
                <Text style={{ ...styles.fs12ppReg666, color: colors.white }}>Invite Friend</Text>
            </TouchableOpacity>
        )
    }

    const requestLocationPermission = async () => {
        if (Platform.OS === 'ios') {
            const auth = await Geolocation.requestAuthorization('whenInUse');
            if (auth === 'granted') {
                return true;
            }
            return false;
        }
        if (Platform.OS === 'android') {
            try {
                const granted = await PermissionsAndroid.request(
                    PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
                    {
                        title: 'Location Access Required',
                        message: 'App Require to Access your location',
                        buttonPositive: 'OK',
                    },
                );
                return granted === PermissionsAndroid.RESULTS.GRANTED;
            } catch (err) {
                return false;
            }
        } else {
            return true;
        }
    };

    const calcUserDistance = (newLatLng: object) =>
        haversine(userInitialPosition, newLatLng, { unit: 'km' }) || 0;

    // get current lat and long
    const getLocation = async () => {
        const isLocationPermited = await requestLocationPermission();
        if (isLocationPermited) {
            Geolocation.getCurrentPosition(
                position => {
                    const { latitude, longitude } = position.coords;
                    const newCoordinate = {
                        latitude,
                        longitude,
                    };
                    setLocation({
                        ...location,
                        latitude,
                        longitude,
                    });
                    setUserInitialPosition(newCoordinate);
                    setUserStartTime(moment()?.toString());
                },
                error => {
                },
                { enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 },
            );
        }
    };

    useFocusEffect(
        React.useCallback(() => {
            getLocation();
        }, []),
    );

    // count animation
    useEffect(() => {
        if (timeLeft === 0) {
            setIsStart(true);
            handleStart();
            setTimeLeft(null);
            setPrintTime(null);
            setStartWatchPosition(true);
        } else if (timeLeft === 1) {
            setPrintTime('GO');
        } else {
            setPrintTime(timeLeft);
        }

        if (!timeLeft) return;

        const intervalId = setInterval(() => {
            setTimeLeft(timeLeft - 1);
        }, 1000);

        return () => clearInterval(intervalId);
    }, [timeLeft]);

    useEffect(() => {
        if (startWatchPosition) {
            Geolocation.getCurrentPosition(position => {
                const { latitude, longitude } = position.coords;
                // setUserInitialPosition({ latitude, longitude });  // for future use
                setPolyLineCoords([{ latitude, longitude }]);
                let dataObj = {
                    lat: latitude,
                    long: longitude
                }
                startBurnTracking(dataObj).then(val => {})
            });
        } else {
            // setUserInitialPosition({ latitude: LATITUDE, longitude: LONGITUDE });
        }

        const watchId = Geolocation.watchPosition(
            async position => {
                const { latitude, longitude, speed } = position.coords;

                if (startWatchPosition && speed > 0) {
                    try {
                        const { coords, stepCount } = await getDirections({
                            startLoc: `${userInitialPosition?.latitude},${userInitialPosition?.longitude}`,
                            destinationLoc: `${latitude},${longitude}`,
                        });
                        setPolyLineCoords(prevState => [...prevState, ...coords]);
                        const newCoordinate = {
                            latitude,
                            longitude,
                        };
                        setLocation(prevState => ({
                            ...prevState,
                            latitude,
                            longitude,
                            speed,
                            stepsWalked: prevState.stepsWalked + stepCount,
                            prevLatLng: newCoordinate,
                            distanceTravelled: calcUserDistance(newCoordinate),
                        }));
                    } catch (error) {
                        // add logic to log error message
                    }
                }
            },
            err => {
                // add logic to log error message
            },
            {
                enableHighAccuracy: true,
                distanceFilter: 1,
            },
        );

        return () => {
            Geolocation.clearWatch(watchId);
        };
    }, [startWatchPosition, dispatch]);

    //BURN TAB - STATS DATA\\
    const mapStatsData = [
        {
            id: 1,
            title: 'Steps',
            value: location?.stepsWalked
        },
        {
            id: 2,
            title: 'Time',
            value: formatTime(timer)
        },
        {
            id: 3,
            title: 'Speed',
            value: location?.speed?.toFixed(3),
            unit: 'Kmph'
        },
        {
            id: 4,
            title: 'Distance',
            value: location?.distanceTravelled?.toFixed(3),
            unit: 'km'
        },
        {
            id: 5,
            title: 'Calories',
            value: 0,  // may come from watch apis
            unit: 'Kcal'
        },
        {
            id: 6,
            title: 'Heart Rate',
            value: 0,  // may come from watch apis
            unit: 'BPM'
        },
    ]

    return (
        <>
            {animatedCount && timeLeft !== null && (
                <View style={styles.animatedCountContainer}>
                    <View>
                        <Text style={styles.animatedCountText}>
                            {printTime === 'GO' ? printTime : `0${printTime}`}
                        </Text>
                    </View>
                </View>
            )}
            <MapView
                initialRegion={{
                    latitude: lat,
                    longitude: lon,
                    latitudeDelta: 0.0922,
                    longitudeDelta: 0.0421,
                }}
                loadingEnabled
                onMapLoaded={() => setIsMapLoaded(true)}
                ref={mapRef}
                style={styles.mapStyles}
                showsUserLocation
                showsMyLocationButton={false}
                followsUserLocation
                region={{
                    latitude: location.latitude,
                    longitude: location.longitude,
                    latitudeDelta: LATITUDE_DELTA,
                    longitudeDelta: LONGITUDE_DELTA,
                }}>
                <Polyline
                    coordinates={polyLineCoords}
                    strokeColor="#7e81e9"
                    strokeWidth={4}
                />


            </MapView>
            <TouchableOpacity style={styles.locationIcon}
                onPress={() => {
                    mapRef.current.animateToRegion({
                        latitude: location?.latitude,
                        longitude: location?.longitude,
                        latitudeDelta: LATITUDE_DELTA,
                        longitudeDelta: LONGITUDE_DELTA,
                    });
                }}>
                <LocationIcon />
            </TouchableOpacity>
            <View style={styles.burnBottomContainer}>

                {/*INITIAL LAUNCH TABS*/}
                {!isStart ?
                    <>
                        <View style={styles.p16}>
                            <BurnTrackers />
                        </View>

                        <View style={{
                            ...styles.rowCenterApart,
                            width: '100%',
                            padding: 16,
                            marginBottom: 10
                        }}>
                            <TouchableOpacity
                                style={{
                                    ...styles.burnButtonStyles,
                                    backgroundColor: colors.white,
                                    gap: 4,
                                }}
                                onPress={() => setHistoryModal(true)}>
                                <HistoryIcon />
                                <Text style={styles.fs12ppReg666}>History</Text>
                            </TouchableOpacity>
                            <StartButton
                                onStart={() => {
                                    setShowAnimatedCount(true);
                                    setTimeLeft(5);
                                    // navigation.navigate(routes.challengeReportScreen)  for reference
                                }}
                                style={{ position: 'absolute', }}
                            />
                            <InviteFriendButton
                                onpress={() => setInviteModal(true)}
                                key={'invite-frnd-btn'}
                                requests={1}
                            />
                        </View>
                    </>
                    :
                    <>
                        <FlatList
                            data={mapStatsData}
                            renderItem={renderStatsItem}
                            horizontal
                            showsHorizontalScrollIndicator={false}
                            contentContainerStyle={{ gap: 8 }}
                            keyExtractor={item => item?.id}
                        />

                        <View style={{
                            ...styles.rowCenterApart,
                            width: '75%',
                            alignSelf: 'center',
                            marginTop: 22,
                            marginBottom: 12
                        }}>

                            {!isPause ?
                                <TouchableOpacity
                                    onPress={onPause}
                                    style={{
                                        ...styles.burnTrackerActionButtons,
                                        backgroundColor: colors.mangoYellow
                                    }}>
                                    <PauseIcon />
                                    <Text style={{ ...styles.fs14ppMed, color: colors.white }}>Pause</Text>
                                </TouchableOpacity>
                                :
                                <TouchableOpacity
                                    onPress={handleResumeWalk}
                                    style={{
                                        ...styles.burnTrackerActionButtons,
                                        backgroundColor: colors.orange
                                    }}>
                                    <ResumeIcon />
                                    <Text style={{ ...styles.fs14ppMed, color: colors.white }}>Resume</Text>
                                </TouchableOpacity>}

                            <TouchableOpacity style={{
                                ...
                                styles.burnTrackerActionButtons,
                                backgroundColor: colors.green
                            }}
                                onPress={handleFinishWalk}>
                                <StopIcon />
                                <Text style={{ ...styles.fs14ppMed, color: colors.white }}>Finish</Text>
                            </TouchableOpacity>
                        </View>
                    </>
                }
                {/*INITIAL LAUNCH TABS*/}

                <View style={styles.newChallengeBanner}>
                    <View style={styles.rowCenter}>
                        <RoutingIcon />
                        <Text style={styles.newChallengeBannerText}>You have a New Run Challenge at 06:00 PM</Text>
                    </View>
                    <TouchableOpacity onPress={() => navigation.navigate(routes.runChallenge)}>
                        <Text style={{ ...styles.fs12ppSb666, color: colors.white }}>Join Now</Text>
                    </TouchableOpacity>
                </View>

            </View >

            {historyModal &&
                <SheetModal
                    visible={historyModal}
                    setVisible={setHistoryModal}
                    style={{ justifyContent: 'flex-end', margin: 0 }}
                    key={'history-modal-sheet'}>
                    <View style={styles.modalView}>
                        <FlatList
                            data={historyData}
                            keyExtractor={item => item?.id}
                            renderItem={renderHistoryCards}
                            contentContainerStyle={{ gap: 12 }}
                            style={{
                                marginVertical: 20,
                                height: height - height * .3,
                            }}
                            showsVerticalScrollIndicator={false}
                        />
                    </View>

                </SheetModal>
            }
        </>
    )
}

const styles = StyleSheet.create({
    animatedCountContainer: {
        alignItems: 'center',
        backgroundColor: 'rgba(52, 52, 52, 0.8)',
        bottom: 0,
        justifyContent: 'center',
        left: 0,
        position: 'absolute',
        right: 0,
        top: 0,
        width: '100%',
        zIndex: 999,
    },
    animatedCountText: {
        color: colors.white,
        fontFamily: 'Poppins-SemiBold',
        fontSize: 46,
    },
    burnBottomContainer: {
        marginTop: 'auto',
        position: 'absolute',
        width: width,
        bottom: 0,
    },
    burnTrackerActionButtons: {
        padding: 10,
        paddingHorizontal: 20,
        borderRadius: 57,
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'center',
        gap: 4
    },
    burnButtonStyles: {
        padding: 6,
        borderRadius: 70,
        paddingRight: 12,
        flexDirection: 'row',
        alignItems: 'center',
    },
    fs12ppReg666: {
        fontSize: 12,
        fontFamily: fonts.PoppinsRegular,
        fontWeight: '400',
        color: colors.c666666
    },
    fs14ppMed: {
        fontSize: 14,
        fontFamily: fonts.PoppinsMedium,
        fontWeight: '500'
    },
    fs12ppSb666: {
        fontSize: 12,
        fontFamily: fonts.PoppinsSemiBold,
        fontWeight: '600',
        color: colors.c666666
    },
    inviteButtonStyles: {
        padding: 6,
        borderRadius: 70,
        paddingRight: 12,
        flexDirection: 'row',
        alignItems: 'center',
        backgroundColor: colors.mangoYellow,
        gap: 4,
        position: 'relative',
    },
    locationIcon: {
        position: 'absolute',
        right: 20,
        top: width - width * .50,
    },
    mapStyles: {
        height: height - height * 0.325,
        width: '100%',
        position: 'relative'
    },
    modalView: {
        backgroundColor: colors.white,
        padding: 16,
        borderTopLeftRadius: 24,
        borderTopRightRadius: 24,
    },
    notificationIndicator: {
        width: 24,
        height: 24,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: colors.cEC6E6E,
        borderRadius: 40,
        position: 'absolute',
        top: -10,
        right: 0,
    },
    newChallengeBanner: {
        width: '100%',
        padding: 12,
        backgroundColor: colors.purple,
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'space-between',
        marginTop: 'auto'
    },
    newChallengeBannerText: {
        fontSize: 12,
        fontFamily: fonts.PoppinsMedium,
        color: colors.cf9f9f9
    },
    notificationCountText: {
        fontSize: 12,
        fontFamily: fonts.PoppinsSemiBold,
        color: colors.white
    },
    p16: {
        padding: 16,
    },
    rowCenter: {
        flexDirection: 'row',
        alignItems: 'center',
    },
    rowCenterApart: {
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'space-between'
    },

})
Leave a Comment