feat: optout sentry reporting
This commit is contained in:
parent
754e14946c
commit
c1b220f007
6 changed files with 276 additions and 53 deletions
|
@ -6,7 +6,7 @@ import { ErrorUtils } from "react-native";
|
|||
import { createLogger } from "~/lib/logger";
|
||||
import { SYSTEM_SCOPES } from "~/lib/logger/scopes";
|
||||
|
||||
import { authActions, permissionWizardActions } from "~/stores";
|
||||
import { authActions, permissionWizardActions, paramsActions } from "~/stores";
|
||||
import { secureStore } from "~/storage/memorySecureStore";
|
||||
import memoryAsyncStorage from "~/storage/memoryAsyncStorage";
|
||||
|
||||
|
@ -62,6 +62,7 @@ const initializeStores = () => {
|
|||
// Then initialize other stores sequentially
|
||||
initializeStore("authActions", authActions.init);
|
||||
initializeStore("permissionWizard", permissionWizardActions.init);
|
||||
initializeStore("paramsActions", paramsActions.init);
|
||||
initializeStore("storeSubscriptions", storeSubscriptions.init);
|
||||
|
||||
appLogger.info("Core initialization complete");
|
||||
|
|
78
src/scenes/Params/SentryOptOut.js
Normal file
78
src/scenes/Params/SentryOptOut.js
Normal file
|
@ -0,0 +1,78 @@
|
|||
import React, { useCallback } from "react";
|
||||
import { View } from "react-native";
|
||||
import { Title, Switch } from "react-native-paper";
|
||||
import { createStyles } from "~/theme";
|
||||
import { useParamsState, paramsActions } from "~/stores";
|
||||
import Text from "~/components/Text";
|
||||
import { setSentryEnabled } from "~/sentry";
|
||||
|
||||
function SentryOptOut() {
|
||||
const styles = useStyles();
|
||||
const { sentryEnabled } = useParamsState(["sentryEnabled"]);
|
||||
|
||||
const handleToggle = useCallback(async () => {
|
||||
const newValue = !sentryEnabled;
|
||||
await paramsActions.setSentryEnabled(newValue);
|
||||
|
||||
// Dynamically enable/disable Sentry
|
||||
setSentryEnabled(newValue);
|
||||
}, [sentryEnabled]);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Title style={styles.title}>Rapport d'erreurs</Title>
|
||||
<View style={styles.content}>
|
||||
<View style={styles.switchContainer}>
|
||||
<Text style={styles.label}>Envoyer les rapports d'erreurs</Text>
|
||||
<Switch
|
||||
value={sentryEnabled}
|
||||
onValueChange={handleToggle}
|
||||
style={styles.switch}
|
||||
/>
|
||||
</View>
|
||||
<Text style={styles.description}>
|
||||
Les rapports d'erreurs nous aident à améliorer l'application en nous
|
||||
permettant de mieux identifier et corriger les problèmes techniques.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const useStyles = createStyles(({ theme: { colors } }) => ({
|
||||
container: {
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
},
|
||||
title: {
|
||||
fontSize: 20,
|
||||
fontWeight: "bold",
|
||||
marginVertical: 15,
|
||||
},
|
||||
content: {
|
||||
width: "100%",
|
||||
},
|
||||
switchContainer: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
marginBottom: 5,
|
||||
paddingVertical: 5,
|
||||
},
|
||||
label: {
|
||||
fontSize: 16,
|
||||
flex: 1,
|
||||
marginRight: 15,
|
||||
},
|
||||
switch: {
|
||||
flexShrink: 0,
|
||||
},
|
||||
description: {
|
||||
fontSize: 14,
|
||||
color: colors.onSurfaceVariant,
|
||||
textAlign: "left",
|
||||
lineHeight: 20,
|
||||
},
|
||||
}));
|
||||
|
||||
export default SentryOptOut;
|
|
@ -6,6 +6,7 @@ import ParamsRadius from "./Radius";
|
|||
import ParamsEmergencyCall from "./EmergencyCall";
|
||||
import ThemeSwitcher from "./ThemeSwitcher";
|
||||
import Permissions from "./Permissions";
|
||||
import SentryOptOut from "./SentryOptOut";
|
||||
|
||||
export default function ParamsView({ data }) {
|
||||
const styles = useStyles();
|
||||
|
@ -25,6 +26,9 @@ export default function ParamsView({ data }) {
|
|||
<View style={styles.section}>
|
||||
<ParamsRadius data={data} />
|
||||
</View>
|
||||
<View style={styles.section}>
|
||||
<SentryOptOut />
|
||||
</View>
|
||||
<View style={styles.section}>
|
||||
<Permissions />
|
||||
</View>
|
||||
|
|
|
@ -3,6 +3,15 @@ import { Platform } from "react-native";
|
|||
|
||||
import env from "~/env";
|
||||
import packageJson from "../../package.json";
|
||||
import memoryAsyncStorage from "~/storage/memoryAsyncStorage";
|
||||
import { STORAGE_KEYS } from "~/storage/storageKeys";
|
||||
import { createLogger } from "~/lib/logger";
|
||||
import { SYSTEM_SCOPES } from "~/lib/logger/scopes";
|
||||
|
||||
const sentryLogger = createLogger({
|
||||
module: SYSTEM_SCOPES.APP,
|
||||
feature: "sentry",
|
||||
});
|
||||
|
||||
// Get the build number from native code
|
||||
const getBuildNumber = () => {
|
||||
|
@ -23,8 +32,54 @@ const getReleaseVersion = () => {
|
|||
return `com.alertesecours@${version}+${buildNumber}`;
|
||||
};
|
||||
|
||||
Sentry.init({
|
||||
// Check if Sentry is enabled by user preference
|
||||
const checkSentryEnabled = async () => {
|
||||
try {
|
||||
// Wait for memory storage to be initialized
|
||||
let retries = 0;
|
||||
const maxRetries = 10;
|
||||
|
||||
while (retries < maxRetries) {
|
||||
try {
|
||||
const stored = await memoryAsyncStorage.getItem(
|
||||
STORAGE_KEYS.SENTRY_ENABLED,
|
||||
);
|
||||
if (stored !== null) {
|
||||
return JSON.parse(stored);
|
||||
}
|
||||
break; // Storage is ready, no preference stored
|
||||
} catch (error) {
|
||||
if (
|
||||
error.message?.includes("not initialized") &&
|
||||
retries < maxRetries - 1
|
||||
) {
|
||||
// Wait a bit and retry if storage not initialized
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
retries++;
|
||||
continue;
|
||||
}
|
||||
sentryLogger.warn("Failed to check Sentry preference", {
|
||||
error: error.message,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
sentryLogger.warn("Failed to check Sentry preference", {
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
// Default to enabled if no preference stored or error occurred
|
||||
return true;
|
||||
};
|
||||
|
||||
// Initialize Sentry with user preference check
|
||||
const initializeSentry = async () => {
|
||||
const isEnabled = await checkSentryEnabled();
|
||||
|
||||
Sentry.init({
|
||||
dsn: env.SENTRY_DSN,
|
||||
enabled: isEnabled,
|
||||
tracesSampleRate: 0.1,
|
||||
debug: __DEV__,
|
||||
// Configure release to match ios-archive.sh format
|
||||
|
@ -79,4 +134,37 @@ Sentry.init({
|
|||
// maskAllVectors: false,
|
||||
// }),
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
// Initialize Sentry asynchronously
|
||||
initializeSentry().catch((error) => {
|
||||
sentryLogger.warn("Failed to initialize Sentry", {
|
||||
error: error.message,
|
||||
});
|
||||
});
|
||||
|
||||
// Export function to dynamically control Sentry
|
||||
export const setSentryEnabled = (enabled) => {
|
||||
try {
|
||||
// Use the newer Sentry API
|
||||
const client = Sentry.getClient();
|
||||
if (client) {
|
||||
const options = client.getOptions();
|
||||
options.enabled = enabled;
|
||||
if (!enabled) {
|
||||
// Clear any pending events when disabling
|
||||
Sentry.withScope((scope) => {
|
||||
scope.clear();
|
||||
});
|
||||
}
|
||||
sentryLogger.info("Sentry state toggled", { enabled });
|
||||
} else {
|
||||
sentryLogger.warn("Sentry client not available for toggling");
|
||||
}
|
||||
} catch (error) {
|
||||
sentryLogger.warn("Failed to toggle Sentry state", {
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -80,4 +80,5 @@ export const STORAGE_KEYS = {
|
|||
LAST_KNOWN_LOCATION: registerAsyncStorageKey("@last_known_location"),
|
||||
EULA_ACCEPTED_SIMPLE: registerAsyncStorageKey("eula_accepted"),
|
||||
EMULATOR_MODE_ENABLED: registerAsyncStorageKey("emulator_mode_enabled"),
|
||||
SENTRY_ENABLED: registerAsyncStorageKey("@sentry_enabled"),
|
||||
};
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
import { createAtom } from "~/lib/atomic-zustand";
|
||||
import memoryAsyncStorage from "~/storage/memoryAsyncStorage";
|
||||
import { STORAGE_KEYS } from "~/storage/storageKeys";
|
||||
import { createLogger } from "~/lib/logger";
|
||||
import { SYSTEM_SCOPES } from "~/lib/logger/scopes";
|
||||
|
||||
const paramsLogger = createLogger({
|
||||
module: SYSTEM_SCOPES.APP,
|
||||
feature: "params",
|
||||
});
|
||||
|
||||
export default createAtom(({ merge, reset }) => {
|
||||
const setDevModeEnabled = (b) => {
|
||||
|
@ -37,6 +46,45 @@ export default createAtom(({ merge, reset }) => {
|
|||
});
|
||||
};
|
||||
|
||||
const setSentryEnabled = async (sentryEnabled) => {
|
||||
merge({
|
||||
sentryEnabled,
|
||||
});
|
||||
|
||||
// Persist to storage
|
||||
try {
|
||||
await memoryAsyncStorage.setItem(
|
||||
STORAGE_KEYS.SENTRY_ENABLED,
|
||||
JSON.stringify(sentryEnabled),
|
||||
);
|
||||
} catch (error) {
|
||||
paramsLogger.warn("Failed to persist Sentry preference", {
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const initSentryEnabled = async () => {
|
||||
try {
|
||||
const stored = await memoryAsyncStorage.getItem(
|
||||
STORAGE_KEYS.SENTRY_ENABLED,
|
||||
);
|
||||
if (stored !== null) {
|
||||
const sentryEnabled = JSON.parse(stored);
|
||||
merge({ sentryEnabled });
|
||||
return sentryEnabled;
|
||||
}
|
||||
} catch (error) {
|
||||
paramsLogger.warn("Failed to load Sentry preference", {
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const init = async () => {
|
||||
await initSentryEnabled();
|
||||
};
|
||||
|
||||
return {
|
||||
default: {
|
||||
// devModeEnabled: false,
|
||||
|
@ -46,6 +94,7 @@ export default createAtom(({ merge, reset }) => {
|
|||
mapColorScheme: "auto",
|
||||
hasRegisteredRelatives: null,
|
||||
alertListSortBy: "location",
|
||||
sentryEnabled: true,
|
||||
},
|
||||
actions: {
|
||||
reset,
|
||||
|
@ -55,6 +104,8 @@ export default createAtom(({ merge, reset }) => {
|
|||
setMapColorScheme,
|
||||
setHasRegisteredRelatives,
|
||||
setAlertListSortBy,
|
||||
setSentryEnabled,
|
||||
init,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue