chore: add location debug helpers
This commit is contained in:
parent
40b27bff29
commit
5398f94f49
3 changed files with 200 additions and 1 deletions
110
src/location/emulatorService.js
Normal file
110
src/location/emulatorService.js
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
import BackgroundGeolocation from "react-native-background-geolocation";
|
||||||
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||||
|
import { createLogger } from "~/lib/logger";
|
||||||
|
import { BACKGROUND_SCOPES } from "~/lib/logger/scopes";
|
||||||
|
|
||||||
|
const EMULATOR_MODE_KEY = "emulator_mode_enabled";
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
let emulatorIntervalId = null;
|
||||||
|
let isEmulatorModeEnabled = false;
|
||||||
|
|
||||||
|
// Create a logger for the emulator service
|
||||||
|
const emulatorLogger = createLogger({
|
||||||
|
module: BACKGROUND_SCOPES.GEOLOCATION,
|
||||||
|
feature: "emulator",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize emulator mode based on stored preference
|
||||||
|
export const initEmulatorMode = async () => {
|
||||||
|
try {
|
||||||
|
const storedValue = await AsyncStorage.getItem(EMULATOR_MODE_KEY);
|
||||||
|
emulatorLogger.debug("Initializing emulator mode", { storedValue });
|
||||||
|
|
||||||
|
if (storedValue === "true") {
|
||||||
|
await enableEmulatorMode();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
emulatorLogger.error("Failed to initialize emulator mode", {
|
||||||
|
error: error.message,
|
||||||
|
stack: error.stack,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enable emulator mode
|
||||||
|
export const enableEmulatorMode = async () => {
|
||||||
|
emulatorLogger.info("Enabling emulator mode");
|
||||||
|
|
||||||
|
// Clear existing interval if any
|
||||||
|
if (emulatorIntervalId) {
|
||||||
|
clearInterval(emulatorIntervalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Call immediately once
|
||||||
|
await BackgroundGeolocation.changePace(true);
|
||||||
|
emulatorLogger.debug("Initial changePace call successful");
|
||||||
|
|
||||||
|
// Then set up interval
|
||||||
|
emulatorIntervalId = setInterval(
|
||||||
|
() => {
|
||||||
|
BackgroundGeolocation.changePace(true);
|
||||||
|
emulatorLogger.debug("Interval changePace call executed");
|
||||||
|
},
|
||||||
|
30 * 60 * 1000,
|
||||||
|
); // 30 minutes
|
||||||
|
|
||||||
|
isEmulatorModeEnabled = true;
|
||||||
|
|
||||||
|
// Persist the setting
|
||||||
|
await AsyncStorage.setItem(EMULATOR_MODE_KEY, "true");
|
||||||
|
emulatorLogger.debug("Emulator mode setting saved");
|
||||||
|
} catch (error) {
|
||||||
|
emulatorLogger.error("Failed to enable emulator mode", {
|
||||||
|
error: error.message,
|
||||||
|
stack: error.stack,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Disable emulator mode
|
||||||
|
export const disableEmulatorMode = async () => {
|
||||||
|
emulatorLogger.info("Disabling emulator mode");
|
||||||
|
|
||||||
|
if (emulatorIntervalId) {
|
||||||
|
clearInterval(emulatorIntervalId);
|
||||||
|
emulatorIntervalId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmulatorModeEnabled = false;
|
||||||
|
|
||||||
|
// Persist the setting
|
||||||
|
try {
|
||||||
|
await AsyncStorage.setItem(EMULATOR_MODE_KEY, "false");
|
||||||
|
emulatorLogger.debug("Emulator mode setting saved");
|
||||||
|
} catch (error) {
|
||||||
|
emulatorLogger.error("Failed to save emulator mode setting", {
|
||||||
|
error: error.message,
|
||||||
|
stack: error.stack,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get current emulator mode state
|
||||||
|
export const getEmulatorModeState = () => {
|
||||||
|
return isEmulatorModeEnabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Toggle emulator mode
|
||||||
|
export const toggleEmulatorMode = async (enabled) => {
|
||||||
|
emulatorLogger.info("Toggling emulator mode", { enabled });
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
await enableEmulatorMode();
|
||||||
|
} else {
|
||||||
|
await disableEmulatorMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
return isEmulatorModeEnabled;
|
||||||
|
};
|
|
@ -3,6 +3,7 @@ import { TRACK_MOVE } from "~/misc/devicePrefs";
|
||||||
import { createLogger } from "~/lib/logger";
|
import { createLogger } from "~/lib/logger";
|
||||||
import { BACKGROUND_SCOPES } from "~/lib/logger/scopes";
|
import { BACKGROUND_SCOPES } from "~/lib/logger/scopes";
|
||||||
import jwtDecode from "jwt-decode";
|
import jwtDecode from "jwt-decode";
|
||||||
|
import { initEmulatorMode } from "./emulatorService";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getAuthState,
|
getAuthState,
|
||||||
|
@ -271,4 +272,7 @@ export default async function trackLocation() {
|
||||||
|
|
||||||
// Check for pending records after a short delay to ensure everything is initialized
|
// Check for pending records after a short delay to ensure everything is initialized
|
||||||
setTimeout(checkPendingRecords, 5000);
|
setTimeout(checkPendingRecords, 5000);
|
||||||
|
|
||||||
|
// Initialize emulator mode if previously enabled
|
||||||
|
initEmulatorMode();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { View, StyleSheet, ScrollView } from "react-native";
|
import { View, StyleSheet, ScrollView } from "react-native";
|
||||||
import * as Sentry from "@sentry/react-native";
|
import * as Sentry from "@sentry/react-native";
|
||||||
|
import BackgroundGeolocation from "react-native-background-geolocation";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
|
@ -12,6 +13,11 @@ import {
|
||||||
import { createStyles } from "~/theme";
|
import { createStyles } from "~/theme";
|
||||||
import env, { setStaging } from "~/env";
|
import env, { setStaging } from "~/env";
|
||||||
import { authActions } from "~/stores";
|
import { authActions } from "~/stores";
|
||||||
|
import {
|
||||||
|
getEmulatorModeState,
|
||||||
|
toggleEmulatorMode as toggleEmulatorModeService,
|
||||||
|
initEmulatorMode,
|
||||||
|
} from "~/location/emulatorService";
|
||||||
|
|
||||||
const reset = async () => {
|
const reset = async () => {
|
||||||
await authActions.logout();
|
await authActions.logout();
|
||||||
|
@ -29,7 +35,50 @@ const Section = ({ title, children }) => {
|
||||||
|
|
||||||
export default function Developer() {
|
export default function Developer() {
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
|
const { colors } = useTheme();
|
||||||
const [isStaging, setIsStaging] = useState(env.IS_STAGING);
|
const [isStaging, setIsStaging] = useState(env.IS_STAGING);
|
||||||
|
const [emulatorMode, setEmulatorMode] = useState(false);
|
||||||
|
const [syncStatus, setSyncStatus] = useState(null); // null, 'syncing', 'success', 'error'
|
||||||
|
const [syncResult, setSyncResult] = useState("");
|
||||||
|
|
||||||
|
// Initialize emulator mode when component mounts
|
||||||
|
useEffect(() => {
|
||||||
|
// Initialize the emulator service
|
||||||
|
initEmulatorMode();
|
||||||
|
|
||||||
|
// Set the initial state based on the global service
|
||||||
|
setEmulatorMode(getEmulatorModeState());
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Handle toggling emulator mode
|
||||||
|
const handleEmulatorModeToggle = async (enabled) => {
|
||||||
|
const newState = await toggleEmulatorModeService(enabled);
|
||||||
|
setEmulatorMode(newState);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to trigger geolocation sync
|
||||||
|
const triggerGeolocSync = async () => {
|
||||||
|
try {
|
||||||
|
setSyncStatus("syncing");
|
||||||
|
setSyncResult("");
|
||||||
|
|
||||||
|
// Get the count of pending records first
|
||||||
|
const count = await BackgroundGeolocation.getCount();
|
||||||
|
|
||||||
|
// Perform the sync
|
||||||
|
const records = await BackgroundGeolocation.sync();
|
||||||
|
|
||||||
|
const result = `Synced ${
|
||||||
|
records?.length || 0
|
||||||
|
} records (${count} pending)`;
|
||||||
|
setSyncResult(result);
|
||||||
|
setSyncStatus("success");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Geolocation sync failed:", error);
|
||||||
|
setSyncResult(`Sync failed: ${error.message}`);
|
||||||
|
setSyncStatus("error");
|
||||||
|
}
|
||||||
|
};
|
||||||
const triggerNullError = () => {
|
const triggerNullError = () => {
|
||||||
try {
|
try {
|
||||||
// Wrap the null error in try-catch
|
// Wrap the null error in try-catch
|
||||||
|
@ -101,6 +150,13 @@ export default function Developer() {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
<View style={styles.settingRow}>
|
||||||
|
<Text variant="bodyLarge">Emulator Mode</Text>
|
||||||
|
<Switch
|
||||||
|
value={emulatorMode}
|
||||||
|
onValueChange={handleEmulatorModeToggle}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<Section title="Environment URLs">
|
<Section title="Environment URLs">
|
||||||
|
@ -150,6 +206,35 @@ export default function Developer() {
|
||||||
|
|
||||||
<Divider style={styles.divider} />
|
<Divider style={styles.divider} />
|
||||||
|
|
||||||
|
<Section title="Location Controls">
|
||||||
|
<Button
|
||||||
|
onPress={triggerGeolocSync}
|
||||||
|
style={styles.button}
|
||||||
|
contentStyle={styles.buttonContent}
|
||||||
|
labelStyle={styles.buttonLabel}
|
||||||
|
loading={syncStatus === "syncing"}
|
||||||
|
disabled={syncStatus === "syncing"}
|
||||||
|
>
|
||||||
|
Trigger Geolocation Sync
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{syncStatus && syncResult && (
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
styles.statusText,
|
||||||
|
{
|
||||||
|
color: syncStatus === "success" ? colors.primary : colors.error,
|
||||||
|
marginTop: 8,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{syncResult}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
<Divider style={styles.divider} />
|
||||||
|
|
||||||
<Section title="Error Testing">
|
<Section title="Error Testing">
|
||||||
<Button
|
<Button
|
||||||
onPress={triggerNullError}
|
onPress={triggerNullError}
|
||||||
|
|
Loading…
Add table
Reference in a new issue