A personal media tracker built on the AT Protocol opnshelf.xyz
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: improvements to posthog integration

+67 -24
-14
apps/mobile/app/auth/complete.tsx
··· 48 48 router.replace("/(tabs)"); 49 49 } catch (error) { 50 50 console.error("Auth complete failed:", error); 51 - posthog.capture("$exception", { 52 - $exception_list: [ 53 - { 54 - type: error instanceof Error ? error.name : "Error", 55 - value: 56 - error instanceof Error ? error.message : "Auth complete failed", 57 - stacktrace: { 58 - type: "raw", 59 - frames: error instanceof Error ? (error.stack ?? "") : "", 60 - }, 61 - }, 62 - ], 63 - $exception_source: "auth_complete", 64 - }); 65 51 showToast("Sign in failed. Please try again."); 66 52 router.replace("/login"); 67 53 }
+24 -1
apps/web/src/routes/__root.tsx
··· 1 1 import { configureApiClient } from "@opnshelf/api"; 2 - import { PostHogProvider } from "@posthog/react"; 2 + import { usePostHog } from "@posthog/react"; 3 3 import { TanStackDevtools } from "@tanstack/react-devtools"; 4 4 import { type QueryClient, QueryClientProvider } from "@tanstack/react-query"; 5 5 import { ··· 7 7 HeadContent, 8 8 Outlet, 9 9 Scripts, 10 + useLocation, 10 11 } from "@tanstack/react-router"; 11 12 import { TanStackRouterDevtoolsPanel } from "@tanstack/react-router-devtools"; 13 + import React from "react"; 12 14 import { Toaster } from "sonner"; 13 15 import { ThemeProvider } from "@/components/theme-provider"; 14 16 import { env } from "@/env"; ··· 49 51 50 52 configureApiClient(env.VITE_API_URL); 51 53 54 + function ScreenTracker() { 55 + const location = useLocation(); 56 + const posthog = usePostHog(); 57 + const previousPath = React.useRef<string | null>(null); 58 + 59 + React.useEffect(() => { 60 + const currentPath = location.pathname; 61 + if (previousPath.current !== currentPath) { 62 + posthog.capture("$pageview", { 63 + $pathname: currentPath, 64 + $previous_pathname: previousPath.current, 65 + $search: location.search, 66 + }); 67 + previousPath.current = currentPath; 68 + } 69 + }, [location, posthog]); 70 + 71 + return null; 72 + } 73 + 52 74 function RootComponent() { 53 75 const { queryClient } = Route.useRouteContext(); 54 76 55 77 return ( 56 78 <QueryClientProvider client={queryClient}> 57 79 <ThemeProvider> 80 + <ScreenTracker /> 58 81 <div className="min-h-screen flex flex-col"> 59 82 <Header /> 60 83 <main className="flex-1 flex flex-col min-h-0">
+43 -9
apps/web/src/routes/auth/complete.tsx
··· 1 + import { authControllerMeOptions } from "@opnshelf/api"; 1 2 import { usePostHog } from "@posthog/react"; 2 3 import { useQueryClient } from "@tanstack/react-query"; 3 4 import { createFileRoute, useNavigate } from "@tanstack/react-router"; ··· 23 24 const posthog = usePostHog(); 24 25 25 26 useEffect(() => { 26 - queryClient.invalidateQueries({ queryKey: ["auth"] }); 27 - sessionStorage.removeItem("oauth_pending"); 27 + async function completeAuth() { 28 + try { 29 + queryClient.invalidateQueries({ queryKey: ["auth"] }); 30 + sessionStorage.removeItem("oauth_pending"); 28 31 29 - posthog.capture("auth_completed"); 32 + const user = await queryClient.fetchQuery({ 33 + ...authControllerMeOptions(), 34 + staleTime: 0, 35 + }); 30 36 31 - const storedRedirect = sessionStorage.getItem("auth_redirect"); 32 - sessionStorage.removeItem("auth_redirect"); 37 + if (user) { 38 + posthog.identify(user.did, { 39 + $set: { 40 + handle: user.handle, 41 + did: user.did, 42 + }, 43 + $set_once: { 44 + first_login_date: new Date().toISOString(), 45 + }, 46 + }); 47 + posthog.capture("user_logged_in", { 48 + handle: user.handle, 49 + }); 50 + } 51 + 52 + posthog.capture("auth_completed"); 53 + 54 + const storedRedirect = sessionStorage.getItem("auth_redirect"); 55 + sessionStorage.removeItem("auth_redirect"); 33 56 34 - if (storedRedirect && isValidRedirectPath(storedRedirect)) { 35 - navigate({ to: storedRedirect }); 36 - } else { 37 - navigate({ to: "/profile/shelf" }); 57 + if (storedRedirect && isValidRedirectPath(storedRedirect)) { 58 + navigate({ to: storedRedirect }); 59 + } else { 60 + navigate({ to: "/profile/shelf" }); 61 + } 62 + } catch (error) { 63 + console.error("Auth complete failed:", error); 64 + posthog.capture("auth_completed", { 65 + success: false, 66 + error: error instanceof Error ? error.message : "Unknown error", 67 + }); 68 + navigate({ to: "/login" }); 69 + } 38 70 } 71 + 72 + completeAuth(); 39 73 }, [navigate, queryClient, posthog]); 40 74 41 75 return (