From af39ee40f4907941f8826f44041f9de0849d1bea Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Sat, 31 Jan 2026 01:01:54 +0530 Subject: [PATCH] Add Sentry integration for error reporting and user analytics consent - Introduced Sentry for error tracking, initialized in the application to capture errors while respecting user privacy. - Added a new analytics service to manage user consent for data collection, ensuring only non-personal data is sent to Sentry. - Updated Redux state to track user analytics preferences and modified onboarding steps to include analytics consent. - Enhanced the PrivacyPanel component to allow users to toggle analytics sharing. - Removed the AnalyticsStep from onboarding as its functionality is now integrated into the PrivacyPanel. This update improves error reporting capabilities while prioritizing user privacy and consent. --- CLAUDE.md | 1 + package.json | 1 + src/App.tsx | 6 +- .../settings/panels/PrivacyPanel.tsx | 93 ++++++--- src/main.tsx | 4 + src/pages/onboarding/Onboarding.tsx | 20 +- src/pages/onboarding/steps/AnalyticsStep.tsx | 4 +- src/services/analytics.ts | 135 +++++++++++++ src/store/authSlice.ts | 12 +- src/store/index.ts | 2 +- yarn.lock | 188 ++++++++++-------- 11 files changed, 333 insertions(+), 133 deletions(-) create mode 100644 src/services/analytics.ts diff --git a/CLAUDE.md b/CLAUDE.md index f09a96f65..e53321d4f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -152,6 +152,7 @@ Set in `.env` (Vite exposes `VITE_*` prefixed vars): | `VITE_TELEGRAM_API_HASH` | Telegram MTProto API hash | | `VITE_TELEGRAM_BOT_USERNAME` | Telegram bot username | | `VITE_TELEGRAM_BOT_ID` | Telegram bot numeric ID | +| `VITE_SENTRY_DSN` | Sentry DSN for error reporting (optional) | | `VITE_DEBUG` | Debug mode flag | Production defaults are in `src/utils/config.ts`. diff --git a/package.json b/package.json index 9f44e58a5..ee0db2e08 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "@reduxjs/toolkit": "^2.11.2", + "@sentry/react": "^10.38.0", "@tauri-apps/api": "^2", "@tauri-apps/plugin-deep-link": "^2", "@tauri-apps/plugin-opener": "^2", diff --git a/src/App.tsx b/src/App.tsx index 18e6cf991..361c8a0d3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,7 @@ import { HashRouter as Router } from "react-router-dom"; import { Provider } from "react-redux"; import { PersistGate } from "redux-persist/integration/react"; +import * as Sentry from "@sentry/react"; import { store, persistor } from "./store"; import UserProvider from "./providers/UserProvider"; import SocketProvider from "./providers/SocketProvider"; @@ -9,7 +10,7 @@ import AppRoutes from "./AppRoutes"; function App() { return ( - <> + Something went wrong.}> @@ -31,8 +32,7 @@ function App() { - - + ); } diff --git a/src/components/settings/panels/PrivacyPanel.tsx b/src/components/settings/panels/PrivacyPanel.tsx index 914eb9f0a..afa503df8 100644 --- a/src/components/settings/panels/PrivacyPanel.tsx +++ b/src/components/settings/panels/PrivacyPanel.tsx @@ -1,8 +1,25 @@ import { useSettingsNavigation } from "../hooks/useSettingsNavigation"; +import { useAppSelector, useAppDispatch } from "../../../store/hooks"; +import { setAnalyticsForUser } from "../../../store/authSlice"; +import { syncAnalyticsConsent } from "../../../services/analytics"; import SettingsHeader from "../components/SettingsHeader"; const PrivacyPanel = () => { const { navigateBack } = useSettingsNavigation(); + const dispatch = useAppDispatch(); + const user = useAppSelector((state) => state.user.user); + const analyticsEnabled = useAppSelector((state) => { + const userId = state.user.user?._id; + if (!userId) return false; + return state.auth.isAnalyticsEnabledByUser[userId] === true; + }); + + const handleToggleAnalytics = () => { + if (!user?._id) return; + const newValue = !analyticsEnabled; + dispatch(setAnalyticsForUser({ userId: user._id, enabled: newValue })); + syncAnalyticsConsent(newValue); + }; return (
@@ -13,34 +30,64 @@ const PrivacyPanel = () => { />
-
-
-
+
+ {/* Analytics Section */} +
+

+ Analytics +

+
+
+
+

+ Share Anonymized Usage Data +

+

+ Help improve AlphaHuman by sharing anonymous crash reports + and usage analytics. No personal data, messages, or wallet + information is ever collected. +

+
+ +
+
+
+ + {/* Info Box */} +
+
-
-

- Privacy & Security -

-

- Manage your privacy settings, data retention policies, and - security preferences. -

-
- - Coming Soon - +
+

+ When enabled, we collect only crash information, device type, + and the file location of errors. We never access your messages, + session data, wallet keys, or any personally identifiable + information. +

+
diff --git a/src/main.tsx b/src/main.tsx index f9b5e4b33..80ec71649 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -5,6 +5,10 @@ import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; import "./index.css"; +import { initSentry } from "./services/analytics"; + +// Initialize Sentry early (before React renders) +initSentry(); // Deep link listener - lazy import to avoid running before Tauri IPC is ready import("./utils/desktopDeepLinkListener").then((m) => { diff --git a/src/pages/onboarding/Onboarding.tsx b/src/pages/onboarding/Onboarding.tsx index e678bc084..a57f460ae 100644 --- a/src/pages/onboarding/Onboarding.tsx +++ b/src/pages/onboarding/Onboarding.tsx @@ -7,7 +7,6 @@ import ProgressIndicator from "../../components/ProgressIndicator"; import LottieAnimation from "../../components/LottieAnimation"; import FeaturesStep from "./steps/FeaturesStep"; import PrivacyStep from "./steps/PrivacyStep"; -import AnalyticsStep from "./steps/AnalyticsStep"; import ConnectStep from "./steps/ConnectStep"; import GetStartedStep from "./steps/GetStartedStep"; @@ -16,15 +15,14 @@ const Onboarding = () => { const dispatch = useAppDispatch(); const user = useAppSelector((state) => state.user.user); const [currentStep, setCurrentStep] = useState(1); - const totalSteps = 5; + const totalSteps = 4; // Lottie animation files for each step const stepAnimations = [ "/lottie/wave.json", // Step 1 - Features "/lottie/safe3.json", // Step 2 - Privacy - "/lottie/analytics.json", // Step 3 - Analytics - "/lottie/connect2.json", // Step 4 - Connect - "/lottie/trophy.json", // Step 5 - Get Started + "/lottie/connect2.json", // Step 3 - Connect + "/lottie/trophy.json", // Step 4 - Get Started ]; const handleNext = () => { @@ -59,10 +57,8 @@ const Onboarding = () => { case 2: return ; case 3: - return ; - case 4: return ; - case 5: + case 4: return ; default: return ; @@ -81,14 +77,6 @@ const Onboarding = () => {
{renderStep()} - {/* {currentStep > 1 && ( - - )} */}
); diff --git a/src/pages/onboarding/steps/AnalyticsStep.tsx b/src/pages/onboarding/steps/AnalyticsStep.tsx index 3edf9e57e..2a3396696 100644 --- a/src/pages/onboarding/steps/AnalyticsStep.tsx +++ b/src/pages/onboarding/steps/AnalyticsStep.tsx @@ -1,7 +1,7 @@ import { useState } from "react"; interface AnalyticsStepProps { - onNext: () => void; + onNext: (analyticsEnabled: boolean) => void; } const AnalyticsStep = ({ onNext }: AnalyticsStepProps) => { @@ -113,7 +113,7 @@ const AnalyticsStep = ({ onNext }: AnalyticsStepProps) => {