Skip to content

Commit e662ad1

Browse files
committed
Add PostHog analytics integration and update Discord links
This commit integrates PostHog analytics by adding initialization, provider, and user identification logic throughout the app. It also updates all Discord invite links to use the new URL, improves the 404 Not Found page with a custom design and image, and refines markdown rendering styles. Additionally, it removes hardcoded admin limits in RBAC hooks and fixes order status handling in rebalance and trade order components.
1 parent 755ddcb commit e662ad1

24 files changed

+592
-238
lines changed

.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
VITE_SUPABASE_URL=your_supabase_url_here
33
VITE_SUPABASE_ANON_KEY=your_supabase_anon_key_here
44

5+
# Analytics
6+
VITE_POSTHOG_API_KEY=your_posthog_api_key_here
7+
VITE_POSTHOG_HOST=https://us.i.posthog.com
8+
59
# Development
610
APP_ENV=development
711

index.html

Lines changed: 69 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -55,43 +55,9 @@
5555
window.dataLayer = window.dataLayer || [];
5656
function gtag() { dataLayer.push(arguments); }
5757
gtag('js', new Date());
58-
59-
// Initial config without user_id
60-
gtag('config', 'G-HYXMNMH4WX', {
61-
send_page_view: false, // Prevent automatic pageview
62-
custom_map: {
63-
'dimension1': 'login_status',
64-
'dimension2': 'user_type'
65-
}
66-
});
67-
68-
// Function to track authenticated users
69-
window.trackAuthenticatedUser = function (userId, userType) {
70-
if (userId) {
71-
gtag('config', 'G-HYXMNMH4WX', {
72-
user_id: userId,
73-
user_properties: {
74-
user_type: userType || 'standard'
75-
}
76-
});
77-
78-
// Send custom pageview for authenticated users
79-
gtag('event', 'page_view', {
80-
login_status: 'logged_in',
81-
user_type: userType || 'standard'
82-
});
83-
}
84-
};
85-
86-
// Function to track anonymous pageviews
87-
window.trackAnonymousPageview = function () {
88-
gtag('event', 'page_view', {
89-
login_status: 'anonymous'
90-
});
91-
};
58+
gtag('config', 'G-HYXMNMH4WX');
9259
</script>
9360

94-
9561
</head>
9662

9763
<body>
@@ -101,37 +67,80 @@
10167
<!-- Widgetbot Crate for Discord -->
10268
<script src="https://cdn.jsdelivr.net/npm/@widgetbot/crate@3" async defer></script>
10369
<script>
70+
// Pages where the widget should be hidden
71+
const HIDDEN_PAGES = [
72+
'/login',
73+
'/register',
74+
'/reset-password',
75+
'/admin',
76+
'/settings'
77+
];
78+
79+
// Function to check if widget should be shown on current page
80+
function shouldShowWidget() {
81+
const currentPath = window.location.pathname.toLowerCase();
82+
return !HIDDEN_PAGES.some(page => currentPath.startsWith(page));
83+
}
84+
10485
// Wait for page to fully load before initializing Widgetbot
10586
window.addEventListener('load', function () {
106-
// 3 second delay after page load with fade-in animation
107-
setTimeout(function () {
108-
new Crate({
109-
server: '1410785898273964166', // Replace with your Discord server ID
110-
channel: '1411021392983363616', // Replace with your Discord channel ID
111-
location: ['bottom', 'right'], // Position at bottom right
112-
color: '#ffcc00', // Discord's default color, you can change this
113-
notifications: true, // Show notification badge
114-
indicator: true, // Show unread message indicator
115-
defer: true,
116-
css: `
117-
@keyframes fadeInScale {
118-
0% {
119-
opacity: 0;
120-
transform: scale(0.8);
87+
// Only initialize widget if it should be shown on this page
88+
if (shouldShowWidget()) {
89+
// 3 second delay after page load with fade-in animation
90+
setTimeout(function () {
91+
window.discordCrate = new Crate({
92+
server: '1410785898273964166', // Replace with your Discord server ID
93+
channel: '1411021392983363616', // Replace with your Discord channel ID
94+
location: ['bottom', 'right'], // Position at bottom right
95+
color: '#ffcc00', // Discord's default color, you can change this
96+
notifications: true, // Show notification badge
97+
indicator: true, // Show unread message indicator
98+
defer: true,
99+
css: `
100+
@keyframes fadeInScale {
101+
0% {
102+
opacity: 0;
103+
transform: scale(0.8);
104+
}
105+
100% {
106+
opacity: 1;
107+
transform: scale(1);
108+
}
121109
}
122-
100% {
123-
opacity: 1;
124-
transform: scale(1);
110+
111+
&[open="false"] {
112+
animation: fadeInScale 0.5s ease-out forwards;
125113
}
114+
`
115+
});
116+
}, 2000); // 2 seconds delay after page load
117+
}
118+
});
119+
120+
// Listen for route changes (for single-page applications)
121+
let lastPath = window.location.pathname;
122+
setInterval(function () {
123+
if (window.location.pathname !== lastPath) {
124+
lastPath = window.location.pathname;
125+
126+
// Hide or show widget based on new page
127+
if (window.discordCrate) {
128+
if (shouldShowWidget()) {
129+
// Show the widget if it was hidden
130+
const crateElement = document.querySelector('widgetbot-crate');
131+
if (crateElement) {
132+
crateElement.style.display = 'block';
126133
}
127-
128-
&[open="false"] {
129-
animation: fadeInScale 0.5s ease-out forwards;
134+
} else {
135+
// Hide the widget
136+
const crateElement = document.querySelector('widgetbot-crate');
137+
if (crateElement) {
138+
crateElement.style.display = 'none';
130139
}
131-
`
132-
});
133-
}, 2000); // 2 seconds delay after page load
134-
});
140+
}
141+
}
142+
}
143+
}, 100); // Check every 100ms for route changes
135144
</script>
136145
</body>
137146

package-lock.json

Lines changed: 59 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"input-otp": "^1.2.4",
5151
"lucide-react": "^0.462.0",
5252
"next-themes": "^0.3.0",
53+
"posthog-js": "^1.261.7",
5354
"react": "^18.3.1",
5455
"react-day-picker": "^8.10.1",
5556
"react-dom": "^18.3.1",

public/goose_sit.png

1.92 MB
Loading

src/App-HashRouter.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Toaster as Sonner } from "@/components/ui/sonner";
44
import { TooltipProvider } from "@/components/ui/tooltip";
55
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
66
import { HashRouter, Routes, Route } from "react-router-dom";
7+
import { AdminRouteProtection } from "@/components/AdminRouteProtection";
78
import Index from "./pages/Index";
89
import Dashboard from "./pages/Dashboard";
910
import LoginPage from "./pages/LoginPage";
@@ -33,8 +34,16 @@ const AppRoutes = () => {
3334
<Route path="/profile" element={<Profile />} />
3435
<Route path="/analysis-records" element={<AnalysisRecords />} />
3536
<Route path="/rebalance-records" element={<RebalanceRecords />} />
36-
<Route path="/admin/invitations" element={<AdminInvitations />} />
37-
<Route path="/admin/debug" element={<AdminInvitationsDebug />} />
37+
<Route path="/admin/invitations" element={
38+
<AdminRouteProtection>
39+
<AdminInvitations />
40+
</AdminRouteProtection>
41+
} />
42+
<Route path="/admin/debug" element={
43+
<AdminRouteProtection>
44+
<AdminInvitationsDebug />
45+
</AdminRouteProtection>
46+
} />
3847
<Route path="/forgot-password" element={<ForgotPassword />} />
3948
<Route path="/reset-password" element={<ResetPasswordPage />} />
4049
<Route path="*" element={<NotFound />} />

src/App.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
66
import { BrowserRouter, Routes, Route } from "react-router-dom";
77
import { AuthProvider } from "@/components/AuthProvider";
88
import { RBACProvider } from "@/contexts/RBACContext";
9+
import { PostHogProvider } from "@/components/PostHogProvider";
910
import { AlpacaConnectionErrorModal } from "@/components/AlpacaConnectionErrorModal";
1011
import { useAlpacaConnection } from "@/hooks/useAlpacaConnection";
12+
import { AdminRouteProtection } from "@/components/AdminRouteProtection";
1113
import Index from "./pages/Index";
1214
import Dashboard from "./pages/Dashboard";
1315
import LoginPage from "./pages/LoginPage";
@@ -43,9 +45,21 @@ const AppRoutes = () => {
4345
<Route path="/analysis-records" element={<AnalysisRecords />} />
4446
<Route path="/rebalance-records" element={<RebalanceRecords />} />
4547
<Route path="/trade-history" element={<TradeHistory />} />
46-
<Route path="/admin/invitations" element={<AdminInvitations />} />
47-
<Route path="/admin/roles" element={<AdminRoleManager />} />
48-
<Route path="/admin/users" element={<AdminUserManager />} />
48+
<Route path="/admin/invitations" element={
49+
<AdminRouteProtection>
50+
<AdminInvitations />
51+
</AdminRouteProtection>
52+
} />
53+
<Route path="/admin/roles" element={
54+
<AdminRouteProtection>
55+
<AdminRoleManager />
56+
</AdminRouteProtection>
57+
} />
58+
<Route path="/admin/users" element={
59+
<AdminRouteProtection>
60+
<AdminUserManager />
61+
</AdminRouteProtection>
62+
} />
4963
<Route path="/forgot-password" element={<ForgotPassword />} />
5064
<Route path="/reset-password" element={<ResetPasswordPage />} />
5165
<Route path="/invitation-setup" element={<InvitationSetup />} />
@@ -83,7 +97,9 @@ const App = () => {
8397
<Toaster />
8498
<Sonner />
8599
<BrowserRouter basename={basename}>
86-
<AppContent />
100+
<PostHogProvider>
101+
<AppContent />
102+
</PostHogProvider>
87103
</BrowserRouter>
88104
</TooltipProvider>
89105
</RBACProvider>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { useEffect } from "react";
2+
import { useNavigate } from "react-router-dom";
3+
import { useAuth } from "@/lib/auth";
4+
import NotFound from "@/pages/NotFound";
5+
6+
interface AdminRouteProtectionProps {
7+
children: React.ReactNode;
8+
}
9+
10+
export const AdminRouteProtection = ({ children }: AdminRouteProtectionProps) => {
11+
const { isAuthenticated, isAdmin, isLoading } = useAuth();
12+
const navigate = useNavigate();
13+
14+
// Show loading state while checking auth
15+
if (isLoading) {
16+
return <div className="min-h-screen bg-background flex items-center justify-center">
17+
<div className="text-muted-foreground">Loading...</div>
18+
</div>;
19+
}
20+
21+
// If not authenticated or not admin, show NotFound page
22+
if (!isAuthenticated || !isAdmin) {
23+
return <NotFound />;
24+
}
25+
26+
// User is authenticated and is admin
27+
return <>{children}</>;
28+
};

0 commit comments

Comments
 (0)