Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: onUpdate doesn't update the value in a ref #3557

Closed
sulemanbutt10 opened this issue Jul 1, 2024 · 1 comment
Closed

[Bug]: onUpdate doesn't update the value in a ref #3557

sulemanbutt10 opened this issue Jul 1, 2024 · 1 comment
Labels
bug 🪲 Something isn't working reopen-on-code-fixed

Comments

@sulemanbutt10
Copy link

Mapbox Implementation

Mapbox

Mapbox Version

10.17.0

React Native Version

0.70.15

Platform

iOS, Android

@rnmapbox/maps version

10.0.15

Standalone component to reproduce

import { useEffect, useRef, useState } from 'react';
import { Platform } from 'react-native';
import MapboxGL, { UserLocationRenderMode } from '@rnmapbox/maps';
import { MapState } from '@rnmapbox/maps/lib/typescript/components/MapView';
import { area } from '@turf/turf';
import { isEmpty } from 'lodash';
import { useTranslation } from 'react-i18next';
import {
SearchIcon,
CurrentLocationIcon,
HelpCircleIcon,
ResetIcon,
OnePinIcon,
} from '@ricultx/assets';
import { ConfirmationModal } from '@ricultx/components/Farmer';
import { OutOfAreaModal, WhitePointer } from '@ricultx/components/Field';
import {
DistanceLabels,
NearbyFields,
PolygonDrawing,
PolygonJoints,
MAP_STYLE_SATELLITE,
} from '@ricultx/components/MapComponents';
import { drawFieldNearbyFieldFillLayerStyle } from '@ricultx/components/MapComponents/NearbyBoundaries/NearbyBoundaries.styled';
import {
SearchLocationsHandler,
SearchLocations,
} from '@ricultx/components/SearchLocations';
import { SVGImage } from '@ricultx/components/SVGImage';
import useOrgSpecificConfig from '@ricultx/pattern/ui/hooks/useOrgSpecificConfig';
import { getIsConnected } from '@ricultx/store/nodes/networking';
import {
useDeleteRecentUserSearchesMutation,
useSaveRecentUserSearchMutation,
} from '@ricultx/store/nodes/userSearch';
import { useSelector } from '@ricultx/store/root';
import { useCountryData } from '@ricultx/store/utils';
import { useModalVisible } from '@ricultx/utils/hooks';
import {
mapStyle,
OptionsContainer,
HelpTextContainer,
TopOptions,
TopOptionItem,
CustomControl,
HelpTextStyle,
AreaTextContainer,
} from './DrawFieldFeature.styled';
import { DrawFieldFeatureProps } from './DrawFieldFeature.types';
import { MapButtons } from './MapButtons';
import { useMapDrawing } from './useMapDrawing';

/**
*

  • @param onPressHelpIcon callback for help icon
  • @param isModalVisible boolean for modal visibility
  • @param onModalCancel callback for modal cancel button press
  • @param onModalConfirm callback for modal confirm button press
  • @returns DrawFieldFeature
    */
    export const DrawFieldFeature = ({
    onPressHelpIcon,
    isModalVisible,
    onModalCancel,
    onModalConfirm,
    ...params
    }: Required) => {
    // Hooks
    const {
    polygons,
    onPressAddPoint,
    onDragPoint,
    onPressUndo,
    onPressFinish,
    setPolygons,
    isOutOFAreaModalVisible,
    setIsOutOFAreaModalVisible,
    isOverlapping,
    isFinishDrawing,
    fieldDetail,
    isFetchingRecentFieldSearches,
    recentFieldSearches,
    setRecentFieldSearches,
    nearbyFieldsCollection,
    onRegionChange,
    viewportCoordinates,
    isFieldAreaInRange,
    helpTextMessage,
    isAddPointButtonDisable,
    isPolygonInvalid,
    onConfirmedReset,
    isOnePinButtonDisabled,
    onOnePinPress,
    onePinFarmCreateConfig,
    fieldArea,
    setFieldArea,
    } = useMapDrawing(params);

const {
country: {
fallbackCoordinates: { lat, lng },
},
helperFunctions,
} = useCountryData();

const isConnected = useSelector(getIsConnected);

const { field_draw_map_style } = useOrgSpecificConfig();

const { isResetModalVisible, showResetModal, hideResetModal } =
useModalVisible('reset');

const { isRedrawModalVisible, showRedrawModal, hideRedrawModal } =
useModalVisible('redraw');

const searchRef = useRef(null);
const { t } = useTranslation('translation', {
keyPrefix: 'portfolio_page.field.fields',
});

const mapViewRef = useRef<MapboxGL.MapView>(null);
const cameraRef = useRef<MapboxGL.Camera>(null);
const currentPosition = useRef<number[] | null>(null);
const currentSpeed = useRef(5);
const [isLocationFetched, setLocationFetched] = useState(false);

// Moving to current location is handled by enabling isFollowingUserLocation
const isFollowingUserLocation = useRef(true);

/*
1. This state is forcefully rendering the moveCameraTo function while onUpdate is triggered
2. onUpdate doesn't update the value in currentPosition
3. To update it, the component needs to be rerendered
4. Its a quick-fix for now, we'll update the library to see if that
works fine with built-in follow location according to our requirements
*/
const [shouldRenderForcefullyOnUpdate, setShouldRenderForcefullyOnUpdate] =
useState(false);

const [deleteRecentFieldSearches] = useDeleteRecentUserSearchesMutation();
const [saveRecentFieldSearch] = useSaveRecentUserSearchMutation();

// Function to open bottom sheet
const handleSearchSheet = () => {
isFollowingUserLocation.current = false;
searchRef?.current?.openBottomSheet?.();
};

const hideModal = () => {
setIsOutOFAreaModalVisible(false);
};

const onPressResetIcon = () => {
showResetModal();
};

const onPressRedrawFinish = () => {
showRedrawModal();
};

// Function to handle modal confirm button press
const onPressOk = () => {
setPolygons([]);
hideModal();
};

// Runs when current field to edit is changed in edit field flow
useEffect(() => {
if (fieldDetail?.boundary_status === 'incomplete') {
setPolygons([fieldDetail?.boundaries?.coordinates[0][0]] || []);
}
setPolygons(fieldDetail?.boundaries?.coordinates[0] || []);
if (fieldDetail?.boundaries) {
setFieldArea(
helperFunctions.toFormattedArea(area(fieldDetail?.boundaries))
);
}
}, [fieldDetail?.id]);

/**
*

  • @param coordinates moves the camera to given coordinates
  • @param shouldStopFollowLocation This parameter stops follow location in cases
  • where we don't need to follow the location e.g. edit field or search location
  • Note: setCamera doesn't work while followLocation is true, so we have to
  • make it false before using setCamera. And we make it true again in default case
  • where we need to follow the location.

*/

const moveCameraTo = (coordinates) => {
cameraRef.current?.setCamera({
centerCoordinate: coordinates,
zoomLevel: 17,
animationDuration: 1500,
});

// moving to current location is handled by enabling isFollowingUserLocation

};

/**

  • For Android, we have to explicitly ask for permissions first
    */
    async function getLocationPermission() {
    if (Platform.OS === 'android') {
    MapboxGL.requestAndroidLocationPermissions().then((isGranted) => {
    if (isGranted && mapViewRef.current && currentPosition.current) {
    setLocationFetched(true);
    moveCameraTo(currentPosition.current);
    } else {
    moveCameraTo([lng, lat]);
    }
    });
    } else if (
    Platform.OS === 'ios' &&
    mapViewRef.current &&
    currentPosition.current
    ) {
    setLocationFetched(true);
    moveCameraTo(currentPosition.current);
    }
    }

const onPressDeleteRecentFieldSearch = async () => {
await deleteRecentFieldSearches({ search_feature_type: 'portfolio_field' });
setRecentFieldSearches([]);
};

const onRegionIsChanging = (state: MapState) => {
onRegionChange(state.properties.center);
};

const addPoint = () => {
onPressAddPoint(currentPosition.current ?? [0, 0]);
};

const saveRecentSearch = async (query) => {
const payload = {
search_query: query,
search_feature_type: 'portfolio_field',
};

await saveRecentFieldSearch(payload).unwrap();

};

const setSelectedCoordinates = ({ lat, lng, query }) => {
saveRecentSearch(query);
moveCameraTo([lng, lat]);
};

// This callback triggers when the map is moved manually by touch
// So we have to disable follow location
const onTouchMove = () => {
isFollowingUserLocation.current = false;
};

useEffect(() => {
if (isEmpty(fieldDetail)) {
getLocationPermission();
} else {
moveCameraTo(fieldDetail?.boundaries?.coordinates[0][0]);
}
}, [mapViewRef.current, fieldDetail?.id]);

// This useEffect handles the movement of camera while following location
useEffect(() => {
if (isFollowingUserLocation.current && !fieldDetail?.id) {
moveCameraTo(currentPosition.current);
}
}, [currentPosition.current, shouldRenderForcefullyOnUpdate]);

const onConfirmReset = () => {
onConfirmedReset();
hideResetModal();
};

const onConfirmRedraw = () => {
hideRedrawModal();
onPressFinish();
};

return (
<>

<MapboxGL.MapView
ref={mapViewRef}
style={mapStyle.default}
onCameraChanged={onRegionIsChanging}
logoEnabled={false}
attributionEnabled={false}
styleURL={isConnected ? field_draw_map_style : MAP_STYLE_SATELLITE}
onTouchMove={onTouchMove}
>
<MapboxGL.Camera
ref={cameraRef}
allowUpdates
animationMode="flyTo"
zoomLevel={17}
followZoomLevel={17}
defaultSettings={{
zoomLevel: 17,
centerCoordinate: currentPosition.current ?? [lng, lat],
}}
/>




<MapboxGL.UserLocation
minDisplacement={1}
animated
androidRenderMode="gps"
showsUserHeadingIndicator
renderMode={UserLocationRenderMode.Native}
onUpdate={({ coords: { longitude, latitude } }) => {
const newCords = [longitude, latitude];
if (!currentPosition.current) {
if (fieldDetail?.id) {
moveCameraTo(fieldDetail.center_point);
} else {
moveCameraTo(newCords);
}
}
currentPosition.current = newCords;
setShouldRenderForcefullyOnUpdate((prev) => !prev);
setLocationFetched(true);
}}
/>
</MapboxGL.MapView>

<HelpTextContainer
type={
isOutOFAreaModalVisible
? 'out_of_area'
: isOverlapping
? 'overlapping_boundary'
: !isFieldAreaInRange
? 'out_of_range'
: 'normal'
}
>
{t(helpTextMessage)}

{!isFinishDrawing && fieldArea && (


{t('field_area_message', {
fieldArea,
})}


)}





<TopOptionItem
onPress={() => {
isFollowingUserLocation.current = true;
moveCameraTo(currentPosition.current);
}}
>








{!fieldDetail?.id && onePinFarmCreateConfig.enabled && (


<SVGImage
SVG={OnePinIcon}
color={isOnePinButtonDisabled ? 'disabled' : 'primary'}
height={20}
width={20}
/>


)}

<TopOptionItem
onPress={onPressResetIcon}
disabled={polygons.length === 0 || isFinishDrawing}
>
0 && isFinishDrawing ? 'disabled' : 'primary'
}
/>



<MapButtons
polygons={polygons}
onPressFinish={
fieldDetail?.id && !isFinishDrawing
? onPressRedrawFinish
: onPressFinish
}
onPressAddPoint={addPoint}
onPressUndo={onPressUndo}
isFinishDrawing={isFinishDrawing}
isFinishButtonDisable={isPolygonInvalid || !isFieldAreaInRange}
isAddPointButtonDisable={isAddPointButtonDisable || !isLocationFetched}
/>
{!isFetchingRecentFieldSearches && (
<SearchLocations
ref={searchRef}
onBackDropCloseHandler={() => {
isFollowingUserLocation.current = true;
}}
searchedHistory={recentFieldSearches}
clearHistory={onPressDeleteRecentFieldSearch}
getSelectedLocationCoordinates={(latLngQuery) => {
setSelectedCoordinates(latLngQuery);
}}
/>
)}


<ConfirmationModal
isVisible={!!(fieldDetail?.id && isRedrawModalVisible)}
onCancelPress={hideRedrawModal}
onConfirmPress={onConfirmRedraw}
confirmButtonKey="proceed"
headingKey="redraw_confirmation"
descriptionKey="redraw_warning_text"
/>
</>
);
};

Observed behavior and steps to reproduce

I have made a follow location feature. The camera follows the user if he/she is moving.
During the movement, the onUpdate is triggered but it doesnot uPdates the value in "currentPosition.current".
Instead it passes some previous value in the function which came across the movement.

Expected behavior

"currentPosition.current" must be updated properly and should give the exact current value of "currentPosition.current" whenever the addPoint function is called.

Notes / preliminary analysis

I have also tried this on newer versions (10.1.1 to 10.1.15) and the latest version (10.1.27) but no luck.
When i hanged "minDisplacement" value to 5, it started updating the "curretPosition.current" after moving some meters. But i need that to add that point right where i clicked the button (means right where my current location was displayed)

Additional links and references

No response

@sulemanbutt10 sulemanbutt10 added the bug 🪲 Something isn't working label Jul 1, 2024
Copy link

github-actions bot commented Jul 1, 2024

No code example found in issue body - More info

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🪲 Something isn't working reopen-on-code-fixed
Projects
None yet
Development

No branches or pull requests

1 participant