From 70b1907ace2a8c51dd0490885ccbe52479906cf7 Mon Sep 17 00:00:00 2001 From: stelselim Date: Mon, 20 Jul 2026 17:26:15 +0200 Subject: [PATCH 1/3] feat: migrate to new geolocation library and update related functionality --- configs/jsactions/rollup.config.mjs | 3 +- .../nanoflow-actions-native/package.json | 5 +- .../src/geolocation/GetCurrentLocation.ts | 101 ++------------ .../GetCurrentLocationMinimumAccuracy.ts | 132 +++--------------- .../src/geolocation/utils.ts | 49 +++++++ .../typings/Geolocation.d.ts | 22 --- pnpm-lock.yaml | 45 ++++-- 7 files changed, 118 insertions(+), 239 deletions(-) create mode 100644 packages/jsActions/nanoflow-actions-native/src/geolocation/utils.ts delete mode 100644 packages/jsActions/nanoflow-actions-native/typings/Geolocation.d.ts diff --git a/configs/jsactions/rollup.config.mjs b/configs/jsactions/rollup.config.mjs index d8691fac1..115f7c3db 100644 --- a/configs/jsactions/rollup.config.mjs +++ b/configs/jsactions/rollup.config.mjs @@ -34,7 +34,8 @@ export default async args => { types: ["mendix-client", "react-native"], allowSyntheticDefaultImports: true, compilerOptions: { - newLine: "CRLF" + newLine: "CRLF", + jsx: "react-native" } }); diff --git a/packages/jsActions/nanoflow-actions-native/package.json b/packages/jsActions/nanoflow-actions-native/package.json index a1b788d35..c74decb91 100644 --- a/packages/jsActions/nanoflow-actions-native/package.json +++ b/packages/jsActions/nanoflow-actions-native/package.json @@ -1,7 +1,7 @@ { "name": "nanoflow-actions-native", "moduleName": "Nanoflow Commons", - "version": "7.1.0", + "version": "7.2.0", "license": "Apache-2.0", "copyright": "© Mendix Technology BV 2022. All rights reserved.", "repository": { @@ -27,9 +27,10 @@ }, "dependencies": { "@react-native-async-storage/async-storage": "2.2.0", - "@react-native-community/geolocation": "3.4.0", "invariant": "^2.2.4", "js-base64": "~3.7.2", + "react-native-nitro-geolocation": "1.4.3", + "react-native-nitro-modules": "0.22.0", "react-native-permissions": "5.5.1", "react-native-geocoder": "0.5.0" }, diff --git a/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocation.ts b/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocation.ts index b333c81d4..e2691e192 100644 --- a/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocation.ts +++ b/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocation.ts @@ -5,15 +5,9 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. -import { Big } from "big.js"; -import Geolocation, { - GeolocationError, - GeolocationOptions, - GeolocationResponse -} from "@react-native-community/geolocation"; +import { getCurrentPosition } from "react-native-nitro-geolocation"; -import type { Platform, NativeModules } from "react-native"; -import type { GeoError, GeoPosition, GeoOptions } from "../../typings/Geolocation"; +import { buildLocationOptions, mapPositionToMxObject } from "./utils"; // BEGIN EXTRA CODE // END EXTRA CODE @@ -39,94 +33,23 @@ export async function GetCurrentLocation( ): Promise { // BEGIN USER CODE - let reactNativeModule: { NativeModules: typeof NativeModules; Platform: typeof Platform } | undefined; - let geolocationModule: typeof import("@react-native-community/geolocation").default | Geolocation; - - if (navigator && navigator.product === "ReactNative") { - reactNativeModule = require("react-native"); - - if (!reactNativeModule) { - return Promise.reject(new Error("React Native module could not be found")); - } - - if (reactNativeModule.NativeModules.RNFusedLocation) { - geolocationModule = (await import("@react-native-community/geolocation")).default; - } else if (reactNativeModule.NativeModules.RNCGeolocation) { - geolocationModule = Geolocation; - } else { - return Promise.reject(new Error("Geolocation module could not be found")); - } - } else if (navigator && navigator.geolocation) { - geolocationModule = navigator.geolocation; - } else { - return Promise.reject(new Error("Geolocation module could not be found")); - } - - return new Promise((resolve, reject) => { - const options = getOptions(); - geolocationModule?.getCurrentPosition(onSuccess, onError, options); - - function onSuccess(position: GeolocationResponse | GeoPosition): void { + const options = buildLocationOptions(timeout, maximumAge, highAccuracy); + try { + const position = await getCurrentPosition(options); + return new Promise((resolve, reject) => { mx.data.create({ entity: "NanoflowCommons.Geolocation", callback: mxObject => { - const geolocation = mapPositionToMxObject(mxObject, position); - resolve(geolocation); + resolve(mapPositionToMxObject(mxObject, position)); }, error: () => reject(new Error("Could not create 'NanoflowCommons.Geolocation' object to store location")) }); - } - - function onError(error: GeolocationError | GeoError): void { - return reject(new Error(error.message)); - } - - function getOptions(): GeolocationOptions | GeoOptions { - let timeoutNumber = timeout && Number(timeout.toString()); - const maximumAgeNumber = maximumAge && Number(maximumAge.toString()); - - // If the timeout is 0 or undefined (empty), it causes a crash on iOS. - // If the timeout is undefined (empty); we set timeout to 30 sec (default timeout) - // If the timeout is 0; we set timeout to 1 hour (no timeout) - if (reactNativeModule?.Platform.OS === "ios") { - if (timeoutNumber === undefined) { - timeoutNumber = 30000; - } else if (timeoutNumber === 0) { - timeoutNumber = 3600000; - } - } - - return { - timeout: timeoutNumber, - maximumAge: maximumAgeNumber, - enableHighAccuracy: highAccuracy - }; - } - - function mapPositionToMxObject( - mxObject: mendix.lib.MxObject, - position: GeolocationResponse | GeoPosition - ): mendix.lib.MxObject { - mxObject.set("Timestamp", new Date(position.timestamp)); - mxObject.set("Latitude", new Big(position.coords.latitude.toFixed(8))); - mxObject.set("Longitude", new Big(position.coords.longitude.toFixed(8))); - mxObject.set("Accuracy", new Big(position.coords.accuracy.toFixed(8))); - if (position.coords.altitude != null) { - mxObject.set("Altitude", new Big(position.coords.altitude.toFixed(8))); - } - if (position.coords.altitudeAccuracy != null && position.coords.altitudeAccuracy !== -1) { - mxObject.set("AltitudeAccuracy", new Big(position.coords.altitudeAccuracy.toFixed(8))); - } - if (position.coords.heading != null && position.coords.heading !== -1) { - mxObject.set("Heading", new Big(position.coords.heading.toFixed(8))); - } - if (position.coords.speed != null && position.coords.speed !== -1) { - mxObject.set("Speed", new Big(position.coords.speed.toFixed(8))); - } - return mxObject; - } - }); + }); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + return Promise.reject(new Error(`Could not get current location: ${message}`)); + } // END USER CODE } diff --git a/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocationMinimumAccuracy.ts b/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocationMinimumAccuracy.ts index 7756b3e1b..48fbd130d 100644 --- a/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocationMinimumAccuracy.ts +++ b/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocationMinimumAccuracy.ts @@ -5,15 +5,8 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. -import { Big } from "big.js"; -import Geolocation, { - GeolocationError, - GeolocationOptions, - GeolocationResponse -} from "@react-native-community/geolocation"; - -import type { Platform, NativeModules } from "react-native"; -import type { GeoError, GeoPosition, GeoOptions } from "../../typings/Geolocation"; +import { watchPosition, unwatch, LocationError, GeolocationResponse } from "react-native-nitro-geolocation"; +import { buildLocationOptions, mapPositionToMxObject } from "./utils"; // BEGIN EXTRA CODE // END EXTRA CODE @@ -25,7 +18,7 @@ import type { GeoError, GeoPosition, GeoOptions } from "../../typings/Geolocatio * * On hybrid and native platforms the permission should be requested with the `RequestLocationPermission` action. * - * For good user experience, disable the nanoflow during action using property `Disabled during action` if you’re using `Call a nanoflow button` to run JS Action `Get current location with minimum accuracy`. + * For good user experience, disable the nanoflow during action using property `Disabled during action` if you're using `Call a nanoflow button` to run JS Action `Get current location with minimum accuracy`. * * Best practices: * https://developers.google.com/web/fundamentals/native-hardware/user-location/ @@ -43,63 +36,16 @@ export async function GetCurrentLocationMinimumAccuracy( ): Promise { // BEGIN USER CODE - let reactNativeModule: { NativeModules: typeof NativeModules; Platform: typeof Platform } | undefined; - let geolocationModule: typeof import("@react-native-community/geolocation").default | Geolocation; - - if (navigator && navigator.product === "ReactNative") { - reactNativeModule = require("react-native"); - - if (!reactNativeModule) { - return Promise.reject(new Error("React Native module could not be found")); - } - - if (reactNativeModule.NativeModules.RNFusedLocation) { - geolocationModule = (await import("@react-native-community/geolocation")).default; - } else if (reactNativeModule.NativeModules.RNCGeolocation) { - geolocationModule = Geolocation; - } else { - return Promise.reject(new Error("Geolocation module could not be found")); - } - } else if (navigator && navigator.geolocation) { - geolocationModule = navigator.geolocation; - } else { - return Promise.reject(new Error("Geolocation module could not be found")); - } - return new Promise((resolve, reject) => { - if (!geolocationModule) { - return reject(new Error("Geolocation module could not be found")); - } - - const options = getOptions(); + const options = buildLocationOptions(timeout, maximumAge, highAccuracy); + let lastAccruedPosition: GeolocationResponse | undefined; - // This action is only required while running in PWA or hybrid. - if (navigator && (!navigator.product || navigator.product !== "ReactNative")) { - // This ensures the browser will not ignore the maximumAge https://stackoverflow.com/questions/3397585/navigator-geolocation-getcurrentposition-sometimes-works-sometimes-doesnt/31916631#31916631 - geolocationModule.getCurrentPosition( - // eslint-disable-next-line @typescript-eslint/no-empty-function - () => {}, - // eslint-disable-next-line @typescript-eslint/no-empty-function - () => {}, - {} - ); - } - - const timeoutId = setTimeout(onTimeout, Number(timeout)); - const watchId: number = geolocationModule.watchPosition(onSuccess, onError, options); - let lastAccruedPosition: GeolocationResponse | GeoPosition; - - function createGeolocationObject(position: GeolocationResponse | GeoPosition): void { - mx.data.create({ - entity: "NanoflowCommons.Geolocation", - callback: mxObject => resolve(mapPositionToMxObject(mxObject, position)), - error: () => - reject(new Error("Could not create 'NanoflowCommons.Geolocation' object to store location")) - }); - } + const timeoutMs = timeout ? timeout.toNumber() : 30000; + const timeoutId = setTimeout(onTimeout, timeoutMs); + const token = watchPosition(onSuccess, onError, options); function onTimeout(): void { - geolocationModule?.clearWatch(watchId); + unwatch(token); if (lastAccruedPosition) { createGeolocationObject(lastAccruedPosition); @@ -108,10 +54,10 @@ export async function GetCurrentLocationMinimumAccuracy( } } - function onSuccess(position: GeolocationResponse | GeoPosition): void { + function onSuccess(position: GeolocationResponse): void { if (!minimumAccuracy || Number(minimumAccuracy) >= position.coords.accuracy) { clearTimeout(timeoutId); - geolocationModule?.clearWatch(watchId); + unwatch(token); createGeolocationObject(position); } else { if (!lastAccruedPosition || position.coords.accuracy < lastAccruedPosition.coords.accuracy) { @@ -120,53 +66,19 @@ export async function GetCurrentLocationMinimumAccuracy( } } - function onError(error: GeolocationError | GeoError): void { - return reject(new Error(error.message)); + function onError(error: LocationError): void { + clearTimeout(timeoutId); + unwatch(token); + reject(new Error(error.message)); } - function getOptions(): GeolocationOptions | GeoOptions { - let timeoutNumber = timeout && Number(timeout.toString()); - const maximumAgeNumber = maximumAge && Number(maximumAge.toString()); - - // If the timeout is 0 or undefined (empty), it causes a crash on iOS. - // If the timeout is undefined (empty); we set timeout to 30 sec (default timeout) - // If the timeout is 0; we set timeout to 1 hour (no timeout) - if (reactNativeModule?.Platform.OS === "ios") { - if (timeoutNumber === undefined) { - timeoutNumber = 30000; - } else if (timeoutNumber === 0) { - timeoutNumber = 3600000; - } - } - - return { - timeout: timeoutNumber, - maximumAge: maximumAgeNumber, - enableHighAccuracy: highAccuracy - }; - } - - function mapPositionToMxObject( - mxObject: mendix.lib.MxObject, - position: GeolocationResponse | GeoPosition - ): mendix.lib.MxObject { - mxObject.set("Timestamp", new Date(position.timestamp)); - mxObject.set("Latitude", new Big(position.coords.latitude.toFixed(8))); - mxObject.set("Longitude", new Big(position.coords.longitude.toFixed(8))); - mxObject.set("Accuracy", new Big(position.coords.accuracy.toFixed(8))); - if (position.coords.altitude != null) { - mxObject.set("Altitude", new Big(position.coords.altitude.toFixed(8))); - } - if (position.coords.altitudeAccuracy != null && position.coords.altitudeAccuracy !== -1) { - mxObject.set("AltitudeAccuracy", new Big(position.coords.altitudeAccuracy.toFixed(8))); - } - if (position.coords.heading != null && position.coords.heading !== -1) { - mxObject.set("Heading", new Big(position.coords.heading.toFixed(8))); - } - if (position.coords.speed != null && position.coords.speed !== -1) { - mxObject.set("Speed", new Big(position.coords.speed.toFixed(8))); - } - return mxObject; + function createGeolocationObject(position: GeolocationResponse): void { + mx.data.create({ + entity: "NanoflowCommons.Geolocation", + callback: mxObject => resolve(mapPositionToMxObject(mxObject, position)), + error: () => + reject(new Error("Could not create 'NanoflowCommons.Geolocation' object to store location")) + }); } }); diff --git a/packages/jsActions/nanoflow-actions-native/src/geolocation/utils.ts b/packages/jsActions/nanoflow-actions-native/src/geolocation/utils.ts new file mode 100644 index 000000000..de6d142b8 --- /dev/null +++ b/packages/jsActions/nanoflow-actions-native/src/geolocation/utils.ts @@ -0,0 +1,49 @@ +import { Big } from "big.js"; +import { Platform } from "react-native"; +import { GeolocationResponse, LocationRequestOptions } from "react-native-nitro-geolocation"; + +export function buildLocationOptions( + timeout: Big | undefined, + maximumAge: Big | undefined, + highAccuracy: boolean | undefined +): LocationRequestOptions { + let timeoutNumber = timeout ? timeout.toNumber() : undefined; + const maximumAgeNumber = maximumAge ? maximumAge.toNumber() : undefined; + + // If the timeout is 0 or undefined (empty), it causes a crash on iOS. + // If the timeout is undefined (empty); we set timeout to 30 sec (default timeout) + // If the timeout is 0; we set timeout to 1 hour (no timeout) + if (Platform.OS === "ios") { + if (timeoutNumber === undefined) { + timeoutNumber = 30000; + } else if (timeoutNumber === 0) { + timeoutNumber = 3600000; + } + } + + return { + timeout: timeoutNumber, + maximumAge: maximumAgeNumber, + accuracy: highAccuracy ? { android: "high", ios: "best" } : { android: "balanced", ios: "hundredMeters" } + }; +} + +export function mapPositionToMxObject(mxObject: mendix.lib.MxObject, pos: GeolocationResponse): mendix.lib.MxObject { + mxObject.set("Timestamp", new Date(pos.timestamp)); + mxObject.set("Latitude", new Big(pos.coords.latitude.toFixed(8))); + mxObject.set("Longitude", new Big(pos.coords.longitude.toFixed(8))); + mxObject.set("Accuracy", new Big(pos.coords.accuracy.toFixed(8))); + if (pos.coords.altitude != null) { + mxObject.set("Altitude", new Big(pos.coords.altitude.toFixed(8))); + } + if (pos.coords.altitudeAccuracy != null && pos.coords.altitudeAccuracy !== -1) { + mxObject.set("AltitudeAccuracy", new Big(pos.coords.altitudeAccuracy.toFixed(8))); + } + if (pos.coords.heading != null && pos.coords.heading !== -1) { + mxObject.set("Heading", new Big(pos.coords.heading.toFixed(8))); + } + if (pos.coords.speed != null && pos.coords.speed !== -1) { + mxObject.set("Speed", new Big(pos.coords.speed.toFixed(8))); + } + return mxObject; +} diff --git a/packages/jsActions/nanoflow-actions-native/typings/Geolocation.d.ts b/packages/jsActions/nanoflow-actions-native/typings/Geolocation.d.ts deleted file mode 100644 index c92f243d4..000000000 --- a/packages/jsActions/nanoflow-actions-native/typings/Geolocation.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { - AuthorizationLevel, - AuthorizationResult, - GeoError, - GeoPosition, - GeoOptions, - getCurrentPosition, - requestAuthorization, - watchPosition, - clearWatch, - stopObserving -} from "@react-native-community/geolocation"; - -type GeolocationServiceStatic = { - getCurrentPosition: typeof getCurrentPosition; - requestAuthorization: typeof requestAuthorization; - watchPosition: typeof watchPosition; - clearWatch: typeof clearWatch; - stopObserving: typeof stopObserving; -}; - -export type { GeolocationServiceStatic, AuthorizationLevel, AuthorizationResult, GeoError, GeoPosition, GeoOptions }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8d5c6189..74f723a2f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -194,9 +194,6 @@ importers: '@react-native-async-storage/async-storage': specifier: 2.2.0 version: 2.2.0(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3)) - '@react-native-community/geolocation': - specifier: 3.4.0 - version: 3.4.0(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) invariant: specifier: ^2.2.4 version: 2.2.4 @@ -206,6 +203,12 @@ importers: react-native-geocoder: specifier: 0.5.0 version: 0.5.0 + react-native-nitro-geolocation: + specifier: 1.4.3 + version: 1.4.3(react-native-nitro-modules@0.22.0(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3))(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) + react-native-nitro-modules: + specifier: 0.22.0 + version: 0.22.0(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) react-native-permissions: specifier: 5.5.1 version: 5.5.1(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) @@ -2059,13 +2062,6 @@ packages: peerDependencies: react-native: 0.84.1 - '@react-native-community/geolocation@3.4.0': - resolution: {integrity: sha512-bzZH89/cwmpkPMKKveoC72C4JH0yF4St5Ceg/ZM9pA1SqX9MlRIrIrrOGZ/+yi++xAvFDiYfihtn9TvXWU9/rA==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: 19.2.3 - react-native: 0.84.1 - '@react-native-community/netinfo@11.5.2': resolution: {integrity: sha512-/g0m65BtX9HU+bPiCH2517bOHpEIUsGrWFXDzi1a5nNKn5KujQgm04WhL7/OSXWKHyrT8VVtUoJA0XKRxueBpQ==} peerDependencies: @@ -6088,6 +6084,19 @@ packages: react: 19.2.3 react-native: 0.84.1 + react-native-nitro-geolocation@1.4.3: + resolution: {integrity: sha512-8r09M6fjf7krCXRuF3RskuJpcxE8dvwQtRJnlrk+U3tO4v+ltyXhRRGmAMlO2Y/PEv1II8sgnIgil58RaLPI4A==} + peerDependencies: + react: 19.2.3 + react-native: 0.84.1 + react-native-nitro-modules: '*' + + react-native-nitro-modules@0.22.0: + resolution: {integrity: sha512-3obSYG8dgg3D8lEU/xMKL/0r1A3FrKB2tIKa+LWfBaXnMfWwg5n1o2GRcLpbLtmgFPx903JjVuxhFDRAtslW0Q==} + peerDependencies: + react: 19.2.3 + react-native: 0.84.1 + react-native-permissions@5.5.1: resolution: {integrity: sha512-nTKFoj47b6EXNqbbg+8VFwBWMpxF1/UTbrNBLpXkWpt005pH4BeFv/NwpcC1iNhToKBrxQD+5kI0z6+kTYoYWA==} peerDependencies: @@ -8924,11 +8933,6 @@ snapshots: dependencies: react-native: 0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3) - '@react-native-community/geolocation@3.4.0(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)': - dependencies: - react: 19.2.3 - react-native: 0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3) - '@react-native-community/netinfo@11.5.2(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)': dependencies: react: 19.2.3 @@ -13871,6 +13875,17 @@ snapshots: react-native: 0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3) react-native-animatable: 1.3.3 + react-native-nitro-geolocation@1.4.3(react-native-nitro-modules@0.22.0(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3))(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3): + dependencies: + react: 19.2.3 + react-native: 0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3) + react-native-nitro-modules: 0.22.0(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) + + react-native-nitro-modules@0.22.0(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3): + dependencies: + react: 19.2.3 + react-native: 0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3) + react-native-permissions@5.5.1(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3): dependencies: react: 19.2.3 From c34370baca1655851a10c53a7b9a2ead6b796099 Mon Sep 17 00:00:00 2001 From: stelselim Date: Tue, 21 Jul 2026 10:19:36 +0200 Subject: [PATCH 2/3] fix: update react-native-nitro-modules to version 0.36.1 --- .../nanoflow-actions-native/package.json | 2 +- pnpm-lock.yaml | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/jsActions/nanoflow-actions-native/package.json b/packages/jsActions/nanoflow-actions-native/package.json index c74decb91..bfcd77854 100644 --- a/packages/jsActions/nanoflow-actions-native/package.json +++ b/packages/jsActions/nanoflow-actions-native/package.json @@ -30,7 +30,7 @@ "invariant": "^2.2.4", "js-base64": "~3.7.2", "react-native-nitro-geolocation": "1.4.3", - "react-native-nitro-modules": "0.22.0", + "react-native-nitro-modules": "0.36.1", "react-native-permissions": "5.5.1", "react-native-geocoder": "0.5.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 74f723a2f..c78e01966 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -205,10 +205,10 @@ importers: version: 0.5.0 react-native-nitro-geolocation: specifier: 1.4.3 - version: 1.4.3(react-native-nitro-modules@0.22.0(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3))(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) + version: 1.4.3(react-native-nitro-modules@0.36.1(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3))(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) react-native-nitro-modules: - specifier: 0.22.0 - version: 0.22.0(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) + specifier: 0.36.1 + version: 0.36.1(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) react-native-permissions: specifier: 5.5.1 version: 5.5.1(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) @@ -6091,8 +6091,8 @@ packages: react-native: 0.84.1 react-native-nitro-modules: '*' - react-native-nitro-modules@0.22.0: - resolution: {integrity: sha512-3obSYG8dgg3D8lEU/xMKL/0r1A3FrKB2tIKa+LWfBaXnMfWwg5n1o2GRcLpbLtmgFPx903JjVuxhFDRAtslW0Q==} + react-native-nitro-modules@0.36.1: + resolution: {integrity: sha512-kBv/VvKqAmkXAvP1DxJMC9b/fRhh7JdSO4EUnPP46hJjrIFeFR8AwKm8mYaKZEuF014M/TVdv2vomVUW0umsQQ==} peerDependencies: react: 19.2.3 react-native: 0.84.1 @@ -13875,13 +13875,13 @@ snapshots: react-native: 0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3) react-native-animatable: 1.3.3 - react-native-nitro-geolocation@1.4.3(react-native-nitro-modules@0.22.0(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3))(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3): + react-native-nitro-geolocation@1.4.3(react-native-nitro-modules@0.36.1(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3))(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3): dependencies: react: 19.2.3 react-native: 0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3) - react-native-nitro-modules: 0.22.0(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) + react-native-nitro-modules: 0.36.1(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) - react-native-nitro-modules@0.22.0(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3): + react-native-nitro-modules@0.36.1(react-native@0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3))(react@19.2.3): dependencies: react: 19.2.3 react-native: 0.84.1(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.16)(react@19.2.3) From 111feb451b47b55f15bb470f224d6b9d30d02969 Mon Sep 17 00:00:00 2001 From: stelselim Date: Wed, 22 Jul 2026 16:02:36 +0200 Subject: [PATCH 3/3] feat: refactor location handling functions --- .../src/geolocation/GetCurrentLocation.ts | 51 ++++++++++++++++- .../GetCurrentLocationMinimumAccuracy.ts | 56 ++++++++++++++++++- .../src/geolocation/utils.ts | 49 ---------------- 3 files changed, 102 insertions(+), 54 deletions(-) delete mode 100644 packages/jsActions/nanoflow-actions-native/src/geolocation/utils.ts diff --git a/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocation.ts b/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocation.ts index e2691e192..73d714d60 100644 --- a/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocation.ts +++ b/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocation.ts @@ -5,9 +5,9 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. -import { getCurrentPosition } from "react-native-nitro-geolocation"; - -import { buildLocationOptions, mapPositionToMxObject } from "./utils"; +import { Big } from "big.js"; +import { Platform } from "react-native"; +import { getCurrentPosition, GeolocationResponse, LocationRequestOptions } from "react-native-nitro-geolocation"; // BEGIN EXTRA CODE // END EXTRA CODE @@ -51,5 +51,50 @@ export async function GetCurrentLocation( return Promise.reject(new Error(`Could not get current location: ${message}`)); } + function buildLocationOptions( + timeout: Big | undefined, + maximumAge: Big | undefined, + highAccuracy: boolean | undefined + ): LocationRequestOptions { + let timeoutNumber = timeout ? timeout.toNumber() : undefined; + const maximumAgeNumber = maximumAge ? maximumAge.toNumber() : undefined; + + // If the timeout is 0 or undefined (empty), it causes a crash on iOS. + // If the timeout is undefined (empty); we set timeout to 30 sec (default timeout) + // If the timeout is 0; we set timeout to 1 hour (no timeout) + if (Platform.OS === "ios") { + if (timeoutNumber === undefined) { + timeoutNumber = 30000; + } else if (timeoutNumber === 0) { + timeoutNumber = 3600000; + } + } + + return { + timeout: timeoutNumber, + maximumAge: maximumAgeNumber, + accuracy: highAccuracy ? { android: "high", ios: "best" } : { android: "balanced", ios: "hundredMeters" } + }; + } + function mapPositionToMxObject(mxObject: mendix.lib.MxObject, pos: GeolocationResponse): mendix.lib.MxObject { + mxObject.set("Timestamp", new Date(pos.timestamp)); + mxObject.set("Latitude", new Big(pos.coords.latitude.toFixed(8))); + mxObject.set("Longitude", new Big(pos.coords.longitude.toFixed(8))); + mxObject.set("Accuracy", new Big(pos.coords.accuracy.toFixed(8))); + if (pos.coords.altitude != null) { + mxObject.set("Altitude", new Big(pos.coords.altitude.toFixed(8))); + } + if (pos.coords.altitudeAccuracy != null && pos.coords.altitudeAccuracy !== -1) { + mxObject.set("AltitudeAccuracy", new Big(pos.coords.altitudeAccuracy.toFixed(8))); + } + if (pos.coords.heading != null && pos.coords.heading !== -1) { + mxObject.set("Heading", new Big(pos.coords.heading.toFixed(8))); + } + if (pos.coords.speed != null && pos.coords.speed !== -1) { + mxObject.set("Speed", new Big(pos.coords.speed.toFixed(8))); + } + return mxObject; + } + // END USER CODE } diff --git a/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocationMinimumAccuracy.ts b/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocationMinimumAccuracy.ts index 48fbd130d..ffc270b4d 100644 --- a/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocationMinimumAccuracy.ts +++ b/packages/jsActions/nanoflow-actions-native/src/geolocation/GetCurrentLocationMinimumAccuracy.ts @@ -5,8 +5,15 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. -import { watchPosition, unwatch, LocationError, GeolocationResponse } from "react-native-nitro-geolocation"; -import { buildLocationOptions, mapPositionToMxObject } from "./utils"; +import { Big } from "big.js"; +import { Platform } from "react-native"; +import { + watchPosition, + unwatch, + LocationError, + GeolocationResponse, + LocationRequestOptions +} from "react-native-nitro-geolocation"; // BEGIN EXTRA CODE // END EXTRA CODE @@ -82,5 +89,50 @@ export async function GetCurrentLocationMinimumAccuracy( } }); + function buildLocationOptions( + timeout: Big | undefined, + maximumAge: Big | undefined, + highAccuracy: boolean | undefined + ): LocationRequestOptions { + let timeoutNumber = timeout ? timeout.toNumber() : undefined; + const maximumAgeNumber = maximumAge ? maximumAge.toNumber() : undefined; + + // If the timeout is 0 or undefined (empty), it causes a crash on iOS. + // If the timeout is undefined (empty); we set timeout to 30 sec (default timeout) + // If the timeout is 0; we set timeout to 1 hour (no timeout) + if (Platform.OS === "ios") { + if (timeoutNumber === undefined) { + timeoutNumber = 30000; + } else if (timeoutNumber === 0) { + timeoutNumber = 3600000; + } + } + + return { + timeout: timeoutNumber, + maximumAge: maximumAgeNumber, + accuracy: highAccuracy ? { android: "high", ios: "best" } : { android: "balanced", ios: "hundredMeters" } + }; + } + function mapPositionToMxObject(mxObject: mendix.lib.MxObject, pos: GeolocationResponse): mendix.lib.MxObject { + mxObject.set("Timestamp", new Date(pos.timestamp)); + mxObject.set("Latitude", new Big(pos.coords.latitude.toFixed(8))); + mxObject.set("Longitude", new Big(pos.coords.longitude.toFixed(8))); + mxObject.set("Accuracy", new Big(pos.coords.accuracy.toFixed(8))); + if (pos.coords.altitude != null) { + mxObject.set("Altitude", new Big(pos.coords.altitude.toFixed(8))); + } + if (pos.coords.altitudeAccuracy != null && pos.coords.altitudeAccuracy !== -1) { + mxObject.set("AltitudeAccuracy", new Big(pos.coords.altitudeAccuracy.toFixed(8))); + } + if (pos.coords.heading != null && pos.coords.heading !== -1) { + mxObject.set("Heading", new Big(pos.coords.heading.toFixed(8))); + } + if (pos.coords.speed != null && pos.coords.speed !== -1) { + mxObject.set("Speed", new Big(pos.coords.speed.toFixed(8))); + } + return mxObject; + } + // END USER CODE } diff --git a/packages/jsActions/nanoflow-actions-native/src/geolocation/utils.ts b/packages/jsActions/nanoflow-actions-native/src/geolocation/utils.ts deleted file mode 100644 index de6d142b8..000000000 --- a/packages/jsActions/nanoflow-actions-native/src/geolocation/utils.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Big } from "big.js"; -import { Platform } from "react-native"; -import { GeolocationResponse, LocationRequestOptions } from "react-native-nitro-geolocation"; - -export function buildLocationOptions( - timeout: Big | undefined, - maximumAge: Big | undefined, - highAccuracy: boolean | undefined -): LocationRequestOptions { - let timeoutNumber = timeout ? timeout.toNumber() : undefined; - const maximumAgeNumber = maximumAge ? maximumAge.toNumber() : undefined; - - // If the timeout is 0 or undefined (empty), it causes a crash on iOS. - // If the timeout is undefined (empty); we set timeout to 30 sec (default timeout) - // If the timeout is 0; we set timeout to 1 hour (no timeout) - if (Platform.OS === "ios") { - if (timeoutNumber === undefined) { - timeoutNumber = 30000; - } else if (timeoutNumber === 0) { - timeoutNumber = 3600000; - } - } - - return { - timeout: timeoutNumber, - maximumAge: maximumAgeNumber, - accuracy: highAccuracy ? { android: "high", ios: "best" } : { android: "balanced", ios: "hundredMeters" } - }; -} - -export function mapPositionToMxObject(mxObject: mendix.lib.MxObject, pos: GeolocationResponse): mendix.lib.MxObject { - mxObject.set("Timestamp", new Date(pos.timestamp)); - mxObject.set("Latitude", new Big(pos.coords.latitude.toFixed(8))); - mxObject.set("Longitude", new Big(pos.coords.longitude.toFixed(8))); - mxObject.set("Accuracy", new Big(pos.coords.accuracy.toFixed(8))); - if (pos.coords.altitude != null) { - mxObject.set("Altitude", new Big(pos.coords.altitude.toFixed(8))); - } - if (pos.coords.altitudeAccuracy != null && pos.coords.altitudeAccuracy !== -1) { - mxObject.set("AltitudeAccuracy", new Big(pos.coords.altitudeAccuracy.toFixed(8))); - } - if (pos.coords.heading != null && pos.coords.heading !== -1) { - mxObject.set("Heading", new Big(pos.coords.heading.toFixed(8))); - } - if (pos.coords.speed != null && pos.coords.speed !== -1) { - mxObject.set("Speed", new Big(pos.coords.speed.toFixed(8))); - } - return mxObject; -}