From fbaec00a2e69040bfbdad911a5f7f62014306e4a Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Thu, 29 Aug 2024 11:36:41 +0530 Subject: [PATCH 1/5] fix: Use local Onyx key to throttle location permission prompts. Signed-off-by: krishna2323 --- src/ONYXKEYS.ts | 4 ++++ src/libs/DateUtils.ts | 22 +++++++++++++++++++ src/libs/actions/IOU.ts | 5 +++++ .../step/IOURequestStepConfirmation.tsx | 11 ++++++++-- 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 6a1fc8a629ed..5901f5c77292 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -133,6 +133,9 @@ const ONYXKEYS = { /** The NVP with the last payment method used per policy */ NVP_LAST_PAYMENT_METHOD: 'nvp_private_lastPaymentMethod', + /** Last date (yyyy-MM-dd HH:mm:ss) when the location permission prompt was shown. */ + NVP_LAST_LOCATION_PERMISSION_PROMPT: 'nvp_lastLocalPermissionPrompt', + /** This NVP holds to most recent waypoints that a person has used when creating a distance expense */ NVP_RECENT_WAYPOINTS: 'nvp_expensify_recentWaypoints', @@ -825,6 +828,7 @@ type OnyxValuesMapping = { [ONYXKEYS.NVP_DISMISSED_HOLD_USE_EXPLANATION]: boolean; [ONYXKEYS.FOCUS_MODE_NOTIFICATION]: boolean; [ONYXKEYS.NVP_LAST_PAYMENT_METHOD]: OnyxTypes.LastPaymentMethod; + [ONYXKEYS.NVP_LAST_LOCATION_PERMISSION_PROMPT]: string; [ONYXKEYS.LAST_EXPORT_METHOD]: OnyxTypes.LastExportMethod; [ONYXKEYS.NVP_RECENT_WAYPOINTS]: OnyxTypes.RecentWaypoint[]; [ONYXKEYS.NVP_INTRO_SELECTED]: OnyxTypes.IntroSelected; diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index 0b4a847f3733..4937e62b659b 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -3,6 +3,7 @@ import { addHours, addMilliseconds, addMinutes, + differenceInDays, eachDayOfInterval, eachMonthOfInterval, endOfDay, @@ -819,6 +820,25 @@ function isCardExpired(expiryMonth: number, expiryYear: number): boolean { return expiryYear < currentYear || (expiryYear === currentYear && expiryMonth < currentMonth); } +/** + * Returns the difference in the number of days from the provided date to/from now. + * @param - The date to compare. + * @returns The difference in days as an integer. + */ +function getDifferenceInDaysFromNow(date: Date) { + return differenceInDays(new Date(), date); +} + +/** + * Returns a boolean value indicating whether the provided date string can be parsed as a valid date. + * @param dateString string + * @returns True if the date string is valid, otherwise false. + */ +function isValidDateString(dateString: string) { + const date = new Date(dateString); + return !Number.isNaN(date.getTime()); +} + const DateUtils = { isDate, formatToDayOfWeek, @@ -864,6 +884,8 @@ const DateUtils = { getFormattedTransportDate, doesDateBelongToAPastYear, isCardExpired, + getDifferenceInDaysFromNow, + isValidDateString, }; export default DateUtils; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 83e35f2fb420..6992bf99634c 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7965,6 +7965,10 @@ function mergeDuplicates(params: TransactionMergeParams) { API.write(WRITE_COMMANDS.TRANSACTION_MERGE, params, {optimisticData, failureData}); } +function updateLastLocationPermissionPrompt() { + Onyx.set(ONYXKEYS.NVP_LAST_LOCATION_PERMISSION_PROMPT, new Date().toISOString()); +} + export { adjustRemainingSplitShares, approveMoneyRequest, @@ -8034,5 +8038,6 @@ export { updateMoneyRequestTaxAmount, updateMoneyRequestTaxRate, mergeDuplicates, + updateLastLocationPermissionPrompt, }; export type {GPSPoint as GpsPoint, IOURequestType}; diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index c43d537c5bfc..002d2b1ae17d 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -1,7 +1,7 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import {useOnyx, withOnyx} from 'react-native-onyx'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -15,6 +15,7 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import DateUtils from '@libs/DateUtils'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as FileUtils from '@libs/fileDownload/FileUtils'; import getCurrentPosition from '@libs/getCurrentPosition'; @@ -92,6 +93,7 @@ function IOURequestStepConfirmation({ const [receiptFile, setReceiptFile] = useState>(); const requestType = TransactionUtils.getRequestType(transaction); const isDistanceRequest = requestType === CONST.IOU.REQUEST_TYPE.DISTANCE; + const [lastLocationPermissionPrompt] = useOnyx(ONYXKEYS.NVP_LAST_LOCATION_PERMISSION_PROMPT); const receiptFilename = transaction?.filename; const receiptPath = transaction?.receipt?.source; @@ -568,7 +570,12 @@ function IOURequestStepConfirmation({ const onConfirm = (listOfParticipants: Participant[]) => { setSelectedParticipantList(listOfParticipants); - if (gpsRequired) { + const shouldStartLocationPermissionFlow = + !lastLocationPermissionPrompt || + (DateUtils.isValidDateString(lastLocationPermissionPrompt ?? '') && DateUtils.getDifferenceInDaysFromNow(new Date(lastLocationPermissionPrompt ?? '')) > 7); + + if (gpsRequired && shouldStartLocationPermissionFlow) { + IOU.updateLastLocationPermissionPrompt(); setStartLocationPermissionFlow(true); return; } From 8a263632c62ab5760a8c11b1f8dd9a2d3c32dba1 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Thu, 12 Sep 2024 02:48:46 +0530 Subject: [PATCH 2/5] minor fix. Signed-off-by: krishna2323 --- .../iou/request/step/IOURequestStepConfirmation.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 5a6a6d1d1cbd..843c6308071f 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -592,7 +592,6 @@ function IOURequestStepConfirmation({ (DateUtils.isValidDateString(lastLocationPermissionPrompt ?? '') && DateUtils.getDifferenceInDaysFromNow(new Date(lastLocationPermissionPrompt ?? '')) > 7); if (gpsRequired && shouldStartLocationPermissionFlow) { - IOU.updateLastLocationPermissionPrompt(); setStartLocationPermissionFlow(true); return; } @@ -628,8 +627,14 @@ function IOURequestStepConfirmation({ setStartLocationPermissionFlow(false)} - onGrant={() => createTransaction(selectedParticipantList, true)} - onDeny={() => createTransaction(selectedParticipantList, false)} + onGrant={() => { + IOU.updateLastLocationPermissionPrompt(); + createTransaction(selectedParticipantList, true); + }} + onDeny={() => { + IOU.updateLastLocationPermissionPrompt(); + createTransaction(selectedParticipantList, false); + }} /> )} Date: Fri, 13 Sep 2024 22:44:52 +0530 Subject: [PATCH 3/5] calculate shouldStartLocationPermissionFlow only when gpsRequired is true. Signed-off-by: krishna2323 --- .../request/step/IOURequestStepConfirmation.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 843c6308071f..da62a1114005 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -587,13 +587,16 @@ function IOURequestStepConfirmation({ const onConfirm = (listOfParticipants: Participant[]) => { setSelectedParticipantList(listOfParticipants); - const shouldStartLocationPermissionFlow = - !lastLocationPermissionPrompt || - (DateUtils.isValidDateString(lastLocationPermissionPrompt ?? '') && DateUtils.getDifferenceInDaysFromNow(new Date(lastLocationPermissionPrompt ?? '')) > 7); - if (gpsRequired && shouldStartLocationPermissionFlow) { - setStartLocationPermissionFlow(true); - return; + if (gpsRequired) { + const shouldStartLocationPermissionFlow = + !lastLocationPermissionPrompt || + (DateUtils.isValidDateString(lastLocationPermissionPrompt ?? '') && DateUtils.getDifferenceInDaysFromNow(new Date(lastLocationPermissionPrompt ?? '')) > 7); + + if (shouldStartLocationPermissionFlow) { + setStartLocationPermissionFlow(true); + return; + } } createTransaction(listOfParticipants); From 2b100157777bcacdf3e898ebab9aff3db6131abc Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Fri, 20 Sep 2024 05:32:33 +0530 Subject: [PATCH 4/5] minor update. Signed-off-by: krishna2323 --- src/pages/iou/request/step/IOURequestStepConfirmation.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index da62a1114005..60bdbf831842 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -631,7 +631,6 @@ function IOURequestStepConfirmation({ startPermissionFlow={startLocationPermissionFlow} resetPermissionFlow={() => setStartLocationPermissionFlow(false)} onGrant={() => { - IOU.updateLastLocationPermissionPrompt(); createTransaction(selectedParticipantList, true); }} onDeny={() => { From 1530d59a50cac2ffe4ecdeebcc8e1213cf073a31 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Thu, 3 Oct 2024 21:41:17 +0530 Subject: [PATCH 5/5] minor improvements. Signed-off-by: krishna2323 --- src/CONST.ts | 1 + src/pages/iou/request/step/IOURequestStepConfirmation.tsx | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 2af183d9d751..9bed4cb32e42 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -2039,6 +2039,7 @@ const CONST = { OPTIMISTIC_TRANSACTION_ID: '1', // Note: These payment types are used when building IOU reportAction message values in the server and should // not be changed. + LOCATION_PERMISSION_PROMPT_THRESHOLD_DAYS: 7, PAYMENT_TYPE: { ELSEWHERE: 'Elsewhere', EXPENSIFY: 'Expensify', diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 85fcc6660a86..7cbb2327c5c8 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -586,7 +586,8 @@ function IOURequestStepConfirmation({ if (gpsRequired) { const shouldStartLocationPermissionFlow = !lastLocationPermissionPrompt || - (DateUtils.isValidDateString(lastLocationPermissionPrompt ?? '') && DateUtils.getDifferenceInDaysFromNow(new Date(lastLocationPermissionPrompt ?? '')) > 7); + (DateUtils.isValidDateString(lastLocationPermissionPrompt ?? '') && + DateUtils.getDifferenceInDaysFromNow(new Date(lastLocationPermissionPrompt ?? '')) > CONST.IOU.LOCATION_PERMISSION_PROMPT_THRESHOLD_DAYS); if (shouldStartLocationPermissionFlow) { setStartLocationPermissionFlow(true); @@ -625,9 +626,7 @@ function IOURequestStepConfirmation({ setStartLocationPermissionFlow(false)} - onGrant={() => { - createTransaction(selectedParticipantList, true); - }} + onGrant={() => createTransaction(selectedParticipantList, true)} onDeny={() => { IOU.updateLastLocationPermissionPrompt(); createTransaction(selectedParticipantList, false);