From a437302c5ddb6a66a9f0c8b15b659056db8350cc Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Tue, 8 Oct 2024 13:15:26 -0400 Subject: [PATCH 1/4] on timeline refresh, recompute "past week" date range Within one app session, the constants TODAY_DATE and INITIAL_DATE_RANGE do not change. On app resume, we call refreshTimeline which sets dateRange to INITIAL_DATE_RANGE. But this is a problem if the app stays running for multiple days because INITIAL_DATE_RANGE is old. Instead we need to recompute the date range, using an up-to-date "today" date. Thus, TODAY_DATE and INITIAL_DATE_RANGE are replaced with functions: getTodayDate and getPastWeekDateRange. --- www/js/TimelineContext.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/www/js/TimelineContext.ts b/www/js/TimelineContext.ts index 9b53d2a27..855f8958f 100644 --- a/www/js/TimelineContext.ts +++ b/www/js/TimelineContext.ts @@ -25,9 +25,12 @@ import useAppStateChange from './useAppStateChange'; import { isoDateRangeToTsRange, isoDateWithOffset } from './datetimeUtil'; import { base_modes } from 'e-mission-common'; -const TODAY_DATE = DateTime.now().toISODate(); +const getTodayDate = () => DateTime.now().toISODate(); // initial date range is the past week: [TODAY - 6 days, TODAY] -const INITIAL_DATE_RANGE: [string, string] = [isoDateWithOffset(TODAY_DATE, -6), TODAY_DATE]; +const getPastWeekDateRange = (): [string, string] => { + const todayDate = getTodayDate(); + return [isoDateWithOffset(todayDate, -6), todayDate]; +}; type ContextProps = { labelOptions: LabelOptions | null; @@ -60,7 +63,7 @@ export const useTimelineContext = (): ContextProps => { // date range (inclusive) that has been loaded into the UI [YYYY-MM-DD, YYYY-MM-DD] const [queriedDateRange, setQueriedDateRange] = useState<[string, string] | null>(null); // date range (inclusive) chosen by datepicker [YYYY-MM-DD, YYYY-MM-DD] - const [dateRange, setDateRange] = useState<[string, string]>(INITIAL_DATE_RANGE); + const [dateRange, setDateRange] = useState<[string, string]>(getPastWeekDateRange); // map of timeline entries (trips, places, untracked time), ids to objects const [timelineMap, setTimelineMap] = useState(null); const [timelineIsLoading, setTimelineIsLoading] = useState('replace'); @@ -184,7 +187,7 @@ export const useTimelineContext = (): ContextProps => { // clamp range to ensure it is within [pipelineStartDate, TODAY_DATE] const clampedDateRange: [string, string] = [ new Date(range[0]) < new Date(pipelineStartDate) ? pipelineStartDate : range[0], - new Date(range[1]) > new Date(TODAY_DATE) ? TODAY_DATE : range[1], + new Date(range[1]) > new Date(getTodayDate()) ? getTodayDate() : range[1], ]; if (clampedDateRange[0] != dateRange?.[0] || clampedDateRange[1] != dateRange?.[1]) { logDebug('Timeline: loadDateRange setting new date range = ' + clampedDateRange); @@ -257,7 +260,7 @@ export const useTimelineContext = (): ContextProps => { try { logDebug('timelineContext: refreshTimeline'); setTimelineIsLoading('replace'); - setDateRange(INITIAL_DATE_RANGE); + setDateRange(getPastWeekDateRange()); setQueriedDateRange(null); setTimelineMap(null); setRefreshTime(new Date()); From 667a726b46727a43a16ace5116f55f478d9b88c9 Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Tue, 8 Oct 2024 15:31:46 -0400 Subject: [PATCH 2/4] fix errors on pipelineRange with null start_ts and end_ts For a new user where the pipeline has not yet processed, pipelineRange will be `{ start_ts: null, end_ts: null }`. We should handle this appropriately: -in TimelineScrollList, pipelineEndDate should be undefined instead of trying to call DateTime.fromSeconds with null -loadDateRange should return early and do nothing -The early return from fetchTripsInRange should return empty arrays, not void --- www/js/TimelineContext.ts | 10 ++++++---- www/js/diary/list/TimelineScrollList.tsx | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/www/js/TimelineContext.ts b/www/js/TimelineContext.ts index 9b53d2a27..885db8d2f 100644 --- a/www/js/TimelineContext.ts +++ b/www/js/TimelineContext.ts @@ -176,8 +176,8 @@ export const useTimelineContext = (): ContextProps => { function loadDateRange(range: [string, string]) { logDebug('Timeline: loadDateRange with newDateRange = ' + range); - if (!pipelineRange) { - logWarn('No pipelineRange yet - early return from loadDateRange'); + if (!pipelineRange?.start_ts) { + logWarn('No pipelineRange start_ts yet - early return from loadDateRange'); return; } const pipelineStartDate = DateTime.fromSeconds(pipelineRange.start_ts).toISODate(); @@ -220,8 +220,10 @@ export const useTimelineContext = (): ContextProps => { } async function fetchTripsInRange(dateRange: [string, string]) { - if (!pipelineRange?.start_ts || !pipelineRange?.end_ts) - return logWarn('No pipelineRange yet - early return'); + if (!pipelineRange?.start_ts || !pipelineRange?.end_ts) { + logDebug('No pipelineRange yet, returning empty lists'); + return [[], []]; + } logDebug('Timeline: fetchTripsInRange from ' + dateRange[0] + ' to ' + dateRange[1]); const [startTs, endTs] = isoDateRangeToTsRange(dateRange); diff --git a/www/js/diary/list/TimelineScrollList.tsx b/www/js/diary/list/TimelineScrollList.tsx index e640b2b11..577df712e 100644 --- a/www/js/diary/list/TimelineScrollList.tsx +++ b/www/js/diary/list/TimelineScrollList.tsx @@ -57,7 +57,8 @@ const TimelineScrollList = ({ listEntries }: Props) => { ); - const pipelineEndDate = pipelineRange && DateTime.fromSeconds(pipelineRange.end_ts).toISODate(); + const pipelineEndDate = + pipelineRange?.end_ts && DateTime.fromSeconds(pipelineRange.end_ts).toISODate(); const noTravelBanner = ( }> From 661ba415a5c15cec7689035ca445248ffbafbb78 Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Tue, 8 Oct 2024 18:58:21 -0400 Subject: [PATCH 3/4] fix re-prompting of notifications permission after denied --- www/js/usePermissionStatus.ts | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/www/js/usePermissionStatus.ts b/www/js/usePermissionStatus.ts index 636d9c5e9..63ee47e55 100644 --- a/www/js/usePermissionStatus.ts +++ b/www/js/usePermissionStatus.ts @@ -5,6 +5,9 @@ import { useTranslation } from 'react-i18next'; import { useAppTheme } from './appTheme'; import { logDebug, logWarn } from './plugin/logger'; import { AlertManager } from './components/AlertBar'; +import { storageGet } from './plugin/storage'; + +const HAS_REQUESTED_NOTIFS_KEY = 'HasRequestedNotificationPermission'; let DEVICE_PLATFORM: 'android' | 'ios'; let DEVICE_VERSION: number; @@ -224,7 +227,7 @@ const usePermissionStatus = () => { } } - function setupNotificationChecks() { + function setupNotificationChecks(hasRequestedNotifs) { let fixPerms = () => { logDebug('fix and refresh notification permissions'); appAndChannelNotificationsCheck.wasRequested = true; @@ -252,7 +255,7 @@ const usePermissionStatus = () => { fix: fixPerms, refresh: checkPerms, isOptional: true, - wasRequested: false, + wasRequested: hasRequestedNotifs, }; let tempChecks = checkList; tempChecks.push(appAndChannelNotificationsCheck); @@ -344,7 +347,7 @@ const usePermissionStatus = () => { logDebug('Explanation = ' + explanationList); } - function createChecklist() { + function createChecklist(hasRequestedNotifs) { setupLocChecks(); setupFitnessChecks(); if (DEVICE_PLATFORM == 'android') { @@ -353,7 +356,7 @@ const usePermissionStatus = () => { } setupAndroidBackgroundRestrictionChecks(); } - setupNotificationChecks(); + setupNotificationChecks(hasRequestedNotifs); refreshAllChecks(checkList); } @@ -365,11 +368,13 @@ const usePermissionStatus = () => { //load when ready useEffect(() => { if (appConfig && window['device']?.platform) { - DEVICE_PLATFORM = window['device'].platform.toLowerCase(); - DEVICE_VERSION = window['device'].version.split('.')[0]; - setupPermissionText(); - logDebug('setting up permissions'); - createChecklist(); + storageGet(HAS_REQUESTED_NOTIFS_KEY).then((hasRequestedNotifs) => { + DEVICE_PLATFORM = window['device'].platform.toLowerCase(); + DEVICE_VERSION = window['device'].version.split('.')[0]; + setupPermissionText(); + logDebug('setting up permissions'); + createChecklist(hasRequestedNotifs); + }); } }, [appConfig]); From 6d1fcad4b37b6ac17d1701ccc2423c04b90e3ab3 Mon Sep 17 00:00:00 2001 From: "K. Shankari" Date: Tue, 8 Oct 2024 20:47:41 -0700 Subject: [PATCH 4/4] Bump up the plugin version to support storage in native code --- package.cordovabuild.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.cordovabuild.json b/package.cordovabuild.json index c8fa65973..bc2a3f15b 100644 --- a/package.cordovabuild.json +++ b/package.cordovabuild.json @@ -122,7 +122,7 @@ "cordova-plugin-app-version": "0.1.14", "cordova-plugin-customurlscheme": "5.0.2", "cordova-plugin-device": "2.1.0", - "cordova-plugin-em-datacollection": "git+https://github.com/e-mission/e-mission-data-collection.git#v1.9.2", + "cordova-plugin-em-datacollection": "git+https://github.com/e-mission/e-mission-data-collection.git#v1.9.3", "cordova-plugin-em-opcodeauth": "git+https://github.com/e-mission/cordova-jwt-auth.git#v1.7.2", "cordova-plugin-em-server-communication": "git+https://github.com/e-mission/cordova-server-communication.git#v1.2.7", "cordova-plugin-em-serversync": "git+https://github.com/e-mission/cordova-server-sync.git#v1.3.3",