From 38e3209c12d0c46f0fd97cf306d53dfbc35ab488 Mon Sep 17 00:00:00 2001 From: Ketan Kauntia Date: Tue, 9 Dec 2025 23:56:19 +0530 Subject: [PATCH 01/22] fix: enabled option to login for loggedout users --- apps/web/src/components/dashboard/Sidebar.tsx | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/apps/web/src/components/dashboard/Sidebar.tsx b/apps/web/src/components/dashboard/Sidebar.tsx index 3e6c49df..afea0818 100644 --- a/apps/web/src/components/dashboard/Sidebar.tsx +++ b/apps/web/src/components/dashboard/Sidebar.tsx @@ -11,6 +11,7 @@ import { HomeIcon, FolderIcon, ArrowRightOnRectangleIcon, + ArrowLeftOnRectangleIcon, SparklesIcon, StarIcon, DocumentTextIcon, @@ -462,9 +463,11 @@ function ProfileMenu({ isCollapsed }: { isCollapsed: boolean }) {
- {firstName} + {isLoggedIn ? firstName : "Guest"} + + + {isLoggedIn ? userEmail : "Not signed in"} - {userEmail}
- {fullName} + {isLoggedIn ? fullName : "Guest"} + + + {isLoggedIn ? userEmail : "Not signed in"} - {userEmail}
@@ -510,20 +515,29 @@ function ProfileMenu({ isCollapsed }: { isCollapsed: boolean }) { Account Settings )} - + ) : ( + + setOpen(false); + }} + className="w-full flex items-center gap-3 px-3 py-2 text-sm text-text-secondary hover:bg-dash-hover transition-colors" + > + + Login + + )} )} From 45b1123d5a8a98696d71876a716720257b0cdb6f Mon Sep 17 00:00:00 2001 From: apsinghdev Date: Wed, 17 Dec 2025 13:52:56 +0530 Subject: [PATCH 02/22] chore: add seed data --- apps/api/package.json | 3 + apps/api/prisma/seed.ts | 149 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 apps/api/prisma/seed.ts diff --git a/apps/api/package.json b/apps/api/package.json index 628886a5..0c6722ac 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -38,5 +38,8 @@ "superjson": "^2.2.5", "zeptomail": "^6.2.1", "zod": "^4.1.9" + }, + "prisma": { + "seed": "tsx prisma/seed.ts" } } diff --git a/apps/api/prisma/seed.ts b/apps/api/prisma/seed.ts new file mode 100644 index 00000000..381a8ae9 --- /dev/null +++ b/apps/api/prisma/seed.ts @@ -0,0 +1,149 @@ +import { PrismaClient } from '@prisma/client'; + +const prisma = new PrismaClient(); + +async function main() { + console.log('🌱 Starting database seed...'); + + // Clear existing data (optional - only if you want fresh data each time) + // Uncomment if you want to reset data on each seed + // await prisma.testimonial.deleteMany(); + // await prisma.payment.deleteMany(); + // await prisma.subscription.deleteMany(); + // await prisma.account.deleteMany(); + // await prisma.user.deleteMany(); + // await prisma.plan.deleteMany(); + + // Create test plan (1 rupee test plan) + const testPlan = await prisma.plan.upsert({ + where: { id: '385b8215-d70f-473e-81c9-68a673c0d2fc-test' }, + update: {}, + create: { + id: '385b8215-d70f-473e-81c9-68a673c0d2fc-test', + name: 'Test Plan', + interval: 'yearly', + price: 100, // 1 rupee in paise + currency: 'INR', + }, + }); + console.log('✅ Created test plan:', testPlan.id); + + // Create test user + const testUser = await prisma.user.upsert({ + where: { email: 'test@example.com' }, + update: {}, + create: { + email: 'test@example.com', + firstName: 'Test User', + authMethod: 'google', + }, + }); + console.log('✅ Created test user:', testUser.email); + + // Create test user with premium subscription + const premiumUser = await prisma.user.upsert({ + where: { email: 'premium@example.com' }, + update: {}, + create: { + email: 'premium@example.com', + firstName: 'Premium User', + authMethod: 'github', + }, + }); + console.log('✅ Created premium user:', premiumUser.email); + + // Create premium subscription for premium user + const existingSubscription = await prisma.subscription.findFirst({ + where: { + userId: premiumUser.id, + }, + }); + + const premiumSubscription = existingSubscription + ? await prisma.subscription.update({ + where: { id: existingSubscription.id }, + data: { + planId: testPlan.id, + status: 'active', + startDate: new Date(), + endDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // 1 year from now + autoRenew: true, + }, + }) + : await prisma.subscription.create({ + data: { + userId: premiumUser.id, + planId: testPlan.id, + status: 'active', + startDate: new Date(), + endDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // 1 year from now + autoRenew: true, + }, + }); + console.log('✅ Created/updated premium subscription'); + + // Create test payment + const testPayment = await prisma.payment.upsert({ + where: { + razorpayPaymentId: 'pay_test_123456789', + }, + update: {}, + create: { + userId: premiumUser.id, + subscriptionId: premiumSubscription.id, + razorpayPaymentId: 'pay_test_123456789', + razorpayOrderId: 'order_test_123456789', + amount: 100, // 1 rupee in paise + currency: 'INR', + status: 'captured', + }, + }); + console.log('✅ Created test payment'); + + // Create test testimonial (if Testimonial model exists) + try { + const testTestimonial = await (prisma as any).testimonial.upsert({ + where: { + userId: premiumUser.id, + }, + update: {}, + create: { + userId: premiumUser.id, + name: 'Premium User', + content: 'Opensox has been amazing! The platform makes managing open source projects so much easier.', + avatar: 'https://i.pravatar.cc/150?u=premium', + }, + }); + console.log('✅ Created test testimonial'); + } catch (error) { + // Testimonial model might not exist in current schema + console.log('⚠️ Skipping testimonial (model may not exist)'); + } + + // Create QueryCount if it doesn't exist + try { + await prisma.queryCount.upsert({ + where: { id: 1 }, + update: {}, + create: { + id: 1, + total_queries: BigInt(2212), + }, + }); + console.log('✅ Created QueryCount'); + } catch (error) { + console.log('⚠️ QueryCount already exists or error:', error); + } + + console.log('✅ Database seed completed successfully!'); +} + +main() + .catch((e) => { + console.error('❌ Error seeding database:', e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); + From 392abc3b211f815ea207a8147ae43850c303e3eb Mon Sep 17 00:00:00 2001 From: apsinghdev Date: Wed, 17 Dec 2025 14:04:50 +0530 Subject: [PATCH 03/22] fix: remove the testimonials aon --- apps/api/prisma/seed.ts | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/apps/api/prisma/seed.ts b/apps/api/prisma/seed.ts index 381a8ae9..1f6b186c 100644 --- a/apps/api/prisma/seed.ts +++ b/apps/api/prisma/seed.ts @@ -1,5 +1,7 @@ import { PrismaClient } from '@prisma/client'; +const MILLIS_PER_YEAR = 365 * 24 * 60 * 60 * 1000; + const prisma = new PrismaClient(); async function main() { @@ -7,7 +9,6 @@ async function main() { // Clear existing data (optional - only if you want fresh data each time) // Uncomment if you want to reset data on each seed - // await prisma.testimonial.deleteMany(); // await prisma.payment.deleteMany(); // await prisma.subscription.deleteMany(); // await prisma.account.deleteMany(); @@ -66,7 +67,7 @@ async function main() { planId: testPlan.id, status: 'active', startDate: new Date(), - endDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // 1 year from now + endDate: new Date(Date.now() + MILLIS_PER_YEAR), // 1 year from now autoRenew: true, }, }) @@ -76,7 +77,7 @@ async function main() { planId: testPlan.id, status: 'active', startDate: new Date(), - endDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // 1 year from now + endDate: new Date(Date.now() + MILLIS_PER_YEAR), // 1 year from now autoRenew: true, }, }); @@ -100,26 +101,6 @@ async function main() { }); console.log('✅ Created test payment'); - // Create test testimonial (if Testimonial model exists) - try { - const testTestimonial = await (prisma as any).testimonial.upsert({ - where: { - userId: premiumUser.id, - }, - update: {}, - create: { - userId: premiumUser.id, - name: 'Premium User', - content: 'Opensox has been amazing! The platform makes managing open source projects so much easier.', - avatar: 'https://i.pravatar.cc/150?u=premium', - }, - }); - console.log('✅ Created test testimonial'); - } catch (error) { - // Testimonial model might not exist in current schema - console.log('⚠️ Skipping testimonial (model may not exist)'); - } - // Create QueryCount if it doesn't exist try { await prisma.queryCount.upsert({ From 37efb4adafefbf071a43c385fb3b1aeeb1a202fd Mon Sep 17 00:00:00 2001 From: apsinghdev Date: Wed, 17 Dec 2025 14:17:10 +0530 Subject: [PATCH 04/22] fix: fix the react vulnerabilities --- apps/docs/package.json | 4 +- apps/web/package.json | 4 +- pnpm-lock.yaml | 347 ++++++++++++++++------------------------- 3 files changed, 140 insertions(+), 215 deletions(-) diff --git a/apps/docs/package.json b/apps/docs/package.json index 6c96c0e9..85b96abd 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@repo/ui": "workspace:*", - "next": "14.2.15", + "next": "14.2.35", "react": "18.3.1", "react-dom": "18.3.1" }, @@ -21,7 +21,7 @@ "@types/react": "^18", "@types/react-dom": "^18", "eslint": "^8", - "eslint-config-next": "14.2.6", + "eslint-config-next": "14.2.35", "typescript": "^5" } } diff --git a/apps/web/package.json b/apps/web/package.json index aaa18cbc..c302d2b6 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -30,7 +30,7 @@ "gray-matter": "^4.0.3", "lucide-react": "^0.456.0", "marked": "^17.0.0", - "next": "16.0.7", + "next": "16.0.10", "next-auth": "^4.24.11", "next-themes": "^0.4.3", "posthog-js": "^1.203.1", @@ -53,7 +53,7 @@ "@types/sanitize-html": "^2.16.0", "depcheck": "^1.4.7", "eslint": "^8", - "eslint-config-next": "16.0.7", + "eslint-config-next": "16.0.10", "postcss": "^8", "prettier": "^3.4.1", "tailwindcss": "^3.4.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b8a1bf1f..3aa88864 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -91,8 +91,8 @@ importers: specifier: workspace:* version: link:../../packages/ui next: - specifier: 14.2.15 - version: 14.2.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 14.2.35 + version: 14.2.35(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: 18.3.1 version: 18.3.1 @@ -119,8 +119,8 @@ importers: specifier: ^8 version: 8.57.1 eslint-config-next: - specifier: 14.2.6 - version: 14.2.6(eslint@8.57.1)(typescript@5.9.3) + specifier: 14.2.35 + version: 14.2.35(eslint@8.57.1)(typescript@5.9.3) typescript: specifier: ^5 version: 5.9.3 @@ -162,10 +162,10 @@ importers: version: 11.7.2(typescript@5.9.3) '@vercel/analytics': specifier: ^1.4.1 - version: 1.6.1(next@16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 1.6.1(next@16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@vercel/speed-insights': specifier: ^1.1.0 - version: 1.3.1(next@16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 1.3.1(next@16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) class-variance-authority: specifier: ^0.7.0 version: 0.7.1 @@ -180,7 +180,7 @@ importers: version: 11.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) geist: specifier: ^1.5.1 - version: 1.5.1(next@16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + version: 1.5.1(next@16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) gray-matter: specifier: ^4.0.3 version: 4.0.3 @@ -191,11 +191,11 @@ importers: specifier: ^17.0.0 version: 17.0.1 next: - specifier: 16.0.7 - version: 16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 16.0.10 + version: 16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-auth: specifier: ^4.24.11 - version: 4.24.13(next@16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 4.24.13(next@16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-themes: specifier: ^0.4.3 version: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -255,8 +255,8 @@ importers: specifier: ^8 version: 8.57.1 eslint-config-next: - specifier: 16.0.7 - version: 16.0.7(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) + specifier: 16.0.10 + version: 16.0.10(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) postcss: specifier: ^8 version: 8.5.6 @@ -280,7 +280,7 @@ importers: version: 7.18.0(eslint@8.57.1)(typescript@5.9.3) '@vercel/style-guide': specifier: ^5.2.0 - version: 5.2.0(@next/eslint-plugin-next@14.2.6)(eslint@8.57.1)(prettier@3.7.4)(typescript@5.9.3) + version: 5.2.0(@next/eslint-plugin-next@14.2.35)(eslint@8.57.1)(prettier@3.7.4)(typescript@5.9.3) eslint-config-prettier: specifier: ^9.1.0 version: 9.1.2(eslint@8.57.1) @@ -884,116 +884,116 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@next/env@14.2.15': - resolution: {integrity: sha512-S1qaj25Wru2dUpcIZMjxeMVSwkt8BK4dmWHHiBuRstcIyOsMapqT4A4jSB6onvqeygkSSmOkyny9VVx8JIGamQ==} + '@next/env@14.2.35': + resolution: {integrity: sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==} - '@next/env@16.0.7': - resolution: {integrity: sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw==} + '@next/env@16.0.10': + resolution: {integrity: sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==} - '@next/eslint-plugin-next@14.2.6': - resolution: {integrity: sha512-d3+p4AjIYmhqzYHhhmkRYYN6ZU35TwZAKX08xKRfnHkz72KhWL2kxMFsDptpZs5e8bBGdepn7vn1+9DaF8iX+A==} + '@next/eslint-plugin-next@14.2.35': + resolution: {integrity: sha512-Jw9A3ICz2183qSsqwi7fgq4SBPiNfmOLmTPXKvlnzstUwyvBrtySiY+8RXJweNAs9KThb1+bYhZh9XWcNOr2zQ==} - '@next/eslint-plugin-next@16.0.7': - resolution: {integrity: sha512-hFrTNZcMEG+k7qxVxZJq3F32Kms130FAhG8lvw2zkKBgAcNOJIxlljNiCjGygvBshvaGBdf88q2CqWtnqezDHA==} + '@next/eslint-plugin-next@16.0.10': + resolution: {integrity: sha512-b2NlWN70bbPLmfyoLvvidPKWENBYYIe017ZGUpElvQjDytCWgxPJx7L9juxHt0xHvNVA08ZHJdOyhGzon/KJuw==} - '@next/swc-darwin-arm64@14.2.15': - resolution: {integrity: sha512-Rvh7KU9hOUBnZ9TJ28n2Oa7dD9cvDBKua9IKx7cfQQ0GoYUwg9ig31O2oMwH3wm+pE3IkAQ67ZobPfEgurPZIA==} + '@next/swc-darwin-arm64@14.2.33': + resolution: {integrity: sha512-HqYnb6pxlsshoSTubdXKu15g3iivcbsMXg4bYpjL2iS/V6aQot+iyF4BUc2qA/J/n55YtvE4PHMKWBKGCF/+wA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-arm64@16.0.7': - resolution: {integrity: sha512-LlDtCYOEj/rfSnEn/Idi+j1QKHxY9BJFmxx7108A6D8K0SB+bNgfYQATPk/4LqOl4C0Wo3LACg2ie6s7xqMpJg==} + '@next/swc-darwin-arm64@16.0.10': + resolution: {integrity: sha512-4XgdKtdVsaflErz+B5XeG0T5PeXKDdruDf3CRpnhN+8UebNa5N2H58+3GDgpn/9GBurrQ1uWW768FfscwYkJRg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@14.2.15': - resolution: {integrity: sha512-5TGyjFcf8ampZP3e+FyCax5zFVHi+Oe7sZyaKOngsqyaNEpOgkKB3sqmymkZfowy3ufGA/tUgDPPxpQx931lHg==} + '@next/swc-darwin-x64@14.2.33': + resolution: {integrity: sha512-8HGBeAE5rX3jzKvF593XTTFg3gxeU4f+UWnswa6JPhzaR6+zblO5+fjltJWIZc4aUalqTclvN2QtTC37LxvZAA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-darwin-x64@16.0.7': - resolution: {integrity: sha512-rtZ7BhnVvO1ICf3QzfW9H3aPz7GhBrnSIMZyr4Qy6boXF0b5E3QLs+cvJmg3PsTCG2M1PBoC+DANUi4wCOKXpA==} + '@next/swc-darwin-x64@16.0.10': + resolution: {integrity: sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@14.2.15': - resolution: {integrity: sha512-3Bwv4oc08ONiQ3FiOLKT72Q+ndEMyLNsc/D3qnLMbtUYTQAmkx9E/JRu0DBpHxNddBmNT5hxz1mYBphJ3mfrrw==} + '@next/swc-linux-arm64-gnu@14.2.33': + resolution: {integrity: sha512-JXMBka6lNNmqbkvcTtaX8Gu5by9547bukHQvPoLe9VRBx1gHwzf5tdt4AaezW85HAB3pikcvyqBToRTDA4DeLw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-gnu@16.0.7': - resolution: {integrity: sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww==} + '@next/swc-linux-arm64-gnu@16.0.10': + resolution: {integrity: sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@14.2.15': - resolution: {integrity: sha512-k5xf/tg1FBv/M4CMd8S+JL3uV9BnnRmoe7F+GWC3DxkTCD9aewFRH1s5rJ1zkzDa+Do4zyN8qD0N8c84Hu96FQ==} + '@next/swc-linux-arm64-musl@14.2.33': + resolution: {integrity: sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@16.0.7': - resolution: {integrity: sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g==} + '@next/swc-linux-arm64-musl@16.0.10': + resolution: {integrity: sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@14.2.15': - resolution: {integrity: sha512-kE6q38hbrRbKEkkVn62reLXhThLRh6/TvgSP56GkFNhU22TbIrQDEMrO7j0IcQHcew2wfykq8lZyHFabz0oBrA==} + '@next/swc-linux-x64-gnu@14.2.33': + resolution: {integrity: sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-gnu@16.0.7': - resolution: {integrity: sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA==} + '@next/swc-linux-x64-gnu@16.0.10': + resolution: {integrity: sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@14.2.15': - resolution: {integrity: sha512-PZ5YE9ouy/IdO7QVJeIcyLn/Rc4ml9M2G4y3kCM9MNf1YKvFY4heg3pVa/jQbMro+tP6yc4G2o9LjAz1zxD7tQ==} + '@next/swc-linux-x64-musl@14.2.33': + resolution: {integrity: sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@16.0.7': - resolution: {integrity: sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w==} + '@next/swc-linux-x64-musl@16.0.10': + resolution: {integrity: sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@14.2.15': - resolution: {integrity: sha512-2raR16703kBvYEQD9HNLyb0/394yfqzmIeyp2nDzcPV4yPjqNUG3ohX6jX00WryXz6s1FXpVhsCo3i+g4RUX+g==} + '@next/swc-win32-arm64-msvc@14.2.33': + resolution: {integrity: sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-arm64-msvc@16.0.7': - resolution: {integrity: sha512-EviG+43iOoBRZg9deGauXExjRphhuYmIOJ12b9sAPy0eQ6iwcPxfED2asb/s2/yiLYOdm37kPaiZu8uXSYPs0Q==} + '@next/swc-win32-arm64-msvc@16.0.10': + resolution: {integrity: sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-ia32-msvc@14.2.15': - resolution: {integrity: sha512-fyTE8cklgkyR1p03kJa5zXEaZ9El+kDNM5A+66+8evQS5e/6v0Gk28LqA0Jet8gKSOyP+OTm/tJHzMlGdQerdQ==} + '@next/swc-win32-ia32-msvc@14.2.33': + resolution: {integrity: sha512-pc9LpGNKhJ0dXQhZ5QMmYxtARwwmWLpeocFmVG5Z0DzWq5Uf0izcI8tLc+qOpqxO1PWqZ5A7J1blrUIKrIFc7Q==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@next/swc-win32-x64-msvc@14.2.15': - resolution: {integrity: sha512-SzqGbsLsP9OwKNUG9nekShTwhj6JSB9ZLMWQ8g1gG6hdE5gQLncbnbymrwy2yVmH9nikSLYRYxYMFu78Ggp7/g==} + '@next/swc-win32-x64-msvc@14.2.33': + resolution: {integrity: sha512-nOjfZMy8B94MdisuzZo9/57xuFVLHJaDj5e/xrduJp9CV2/HrfxTRH2fbyLe+K9QT41WBLUd4iXX3R7jBp0EUg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@next/swc-win32-x64-msvc@16.0.7': - resolution: {integrity: sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug==} + '@next/swc-win32-x64-msvc@16.0.10': + resolution: {integrity: sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1550,16 +1550,6 @@ packages: typescript: optional: true - '@typescript-eslint/parser@7.2.0': - resolution: {integrity: sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - '@typescript-eslint/parser@8.48.1': resolution: {integrity: sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1585,10 +1575,6 @@ packages: resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/scope-manager@7.2.0': - resolution: {integrity: sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==} - engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/scope-manager@8.48.1': resolution: {integrity: sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1638,10 +1624,6 @@ packages: resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/types@7.2.0': - resolution: {integrity: sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==} - engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/types@8.48.1': resolution: {integrity: sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1673,15 +1655,6 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@7.2.0': - resolution: {integrity: sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - '@typescript-eslint/typescript-estree@8.48.1': resolution: {integrity: sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1725,10 +1698,6 @@ packages: resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/visitor-keys@7.2.0': - resolution: {integrity: sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==} - engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/visitor-keys@8.48.1': resolution: {integrity: sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2149,9 +2118,6 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001723: - resolution: {integrity: sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==} - caniuse-lite@1.0.30001759: resolution: {integrity: sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==} @@ -2574,8 +2540,8 @@ packages: engines: {node: '>=6.0'} hasBin: true - eslint-config-next@14.2.6: - resolution: {integrity: sha512-z0URA5LO6y8lS/YLN0EDW/C4LEkDODjJzA37dvLVdzCPzuewjzTe1os5g3XclZAZrQ8X8hPaSMQ2JuVWwMmrTA==} + eslint-config-next@14.2.35: + resolution: {integrity: sha512-BpLsv01UisH193WyT/1lpHqq5iJ/Orfz9h/NOOlAmTUq4GY349PextQ62K4XpnaM9supeiEn3TaOTeQO07gURg==} peerDependencies: eslint: ^7.23.0 || ^8.0.0 typescript: '>=3.3.1' @@ -2583,8 +2549,8 @@ packages: typescript: optional: true - eslint-config-next@16.0.7: - resolution: {integrity: sha512-WubFGLFHfk2KivkdRGfx6cGSFhaQqhERRfyO8BRx+qiGPGp7WLKcPvYC4mdx1z3VhVRcrfFzczjjTrbJZOpnEQ==} + eslint-config-next@16.0.10: + resolution: {integrity: sha512-BxouZUm0I45K4yjOOIzj24nTi0H2cGo0y7xUmk+Po/PYtJXFBYVDS1BguE7t28efXjKdcN0tmiLivxQy//SsZg==} peerDependencies: eslint: '>=9.0.0' typescript: '>=3.3.1' @@ -3754,8 +3720,8 @@ packages: react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - next@14.2.15: - resolution: {integrity: sha512-h9ctmOokpoDphRvMGnwOJAedT6zKhwqyZML9mDtspgf4Rh3Pn7UTYKqePNoDvhsWBAO5GoPNYshnAUGIazVGmw==} + next@14.2.35: + resolution: {integrity: sha512-KhYd2Hjt/O1/1aZVX3dCwGXM1QmOV4eNM2UTacK5gipDdPN/oHHK/4oVGy7X8GMfPMsUTUEmGlsy0EY1YGAkig==} engines: {node: '>=18.17.0'} hasBin: true peerDependencies: @@ -3772,8 +3738,8 @@ packages: sass: optional: true - next@16.0.7: - resolution: {integrity: sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A==} + next@16.0.10: + resolution: {integrity: sha512-RtWh5PUgI+vxlV3HdR+IfWA1UUHu0+Ram/JBO4vWB54cVPentCD0e+lxyAYEsDTqGGMg7qpjhKh6dc6aW7W/sA==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -5523,67 +5489,67 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@next/env@14.2.15': {} + '@next/env@14.2.35': {} - '@next/env@16.0.7': {} + '@next/env@16.0.10': {} - '@next/eslint-plugin-next@14.2.6': + '@next/eslint-plugin-next@14.2.35': dependencies: glob: 10.3.10 - '@next/eslint-plugin-next@16.0.7': + '@next/eslint-plugin-next@16.0.10': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@14.2.15': + '@next/swc-darwin-arm64@14.2.33': optional: true - '@next/swc-darwin-arm64@16.0.7': + '@next/swc-darwin-arm64@16.0.10': optional: true - '@next/swc-darwin-x64@14.2.15': + '@next/swc-darwin-x64@14.2.33': optional: true - '@next/swc-darwin-x64@16.0.7': + '@next/swc-darwin-x64@16.0.10': optional: true - '@next/swc-linux-arm64-gnu@14.2.15': + '@next/swc-linux-arm64-gnu@14.2.33': optional: true - '@next/swc-linux-arm64-gnu@16.0.7': + '@next/swc-linux-arm64-gnu@16.0.10': optional: true - '@next/swc-linux-arm64-musl@14.2.15': + '@next/swc-linux-arm64-musl@14.2.33': optional: true - '@next/swc-linux-arm64-musl@16.0.7': + '@next/swc-linux-arm64-musl@16.0.10': optional: true - '@next/swc-linux-x64-gnu@14.2.15': + '@next/swc-linux-x64-gnu@14.2.33': optional: true - '@next/swc-linux-x64-gnu@16.0.7': + '@next/swc-linux-x64-gnu@16.0.10': optional: true - '@next/swc-linux-x64-musl@14.2.15': + '@next/swc-linux-x64-musl@14.2.33': optional: true - '@next/swc-linux-x64-musl@16.0.7': + '@next/swc-linux-x64-musl@16.0.10': optional: true - '@next/swc-win32-arm64-msvc@14.2.15': + '@next/swc-win32-arm64-msvc@14.2.33': optional: true - '@next/swc-win32-arm64-msvc@16.0.7': + '@next/swc-win32-arm64-msvc@16.0.10': optional: true - '@next/swc-win32-ia32-msvc@14.2.15': + '@next/swc-win32-ia32-msvc@14.2.33': optional: true - '@next/swc-win32-x64-msvc@14.2.15': + '@next/swc-win32-x64-msvc@14.2.33': optional: true - '@next/swc-win32-x64-msvc@16.0.7': + '@next/swc-win32-x64-msvc@16.0.10': optional: true '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': @@ -6184,19 +6150,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 7.2.0 - '@typescript-eslint/types': 7.2.0 - '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 7.2.0 - debug: 4.4.1 - eslint: 8.57.1 - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.48.1 @@ -6233,11 +6186,6 @@ snapshots: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 - '@typescript-eslint/scope-manager@7.2.0': - dependencies: - '@typescript-eslint/types': 7.2.0 - '@typescript-eslint/visitor-keys': 7.2.0 - '@typescript-eslint/scope-manager@8.48.1': dependencies: '@typescript-eslint/types': 8.48.1 @@ -6289,8 +6237,6 @@ snapshots: '@typescript-eslint/types@7.18.0': {} - '@typescript-eslint/types@7.2.0': {} - '@typescript-eslint/types@8.48.1': {} '@typescript-eslint/typescript-estree@5.62.0(typescript@5.9.3)': @@ -6337,21 +6283,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.2.0(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 7.2.0 - '@typescript-eslint/visitor-keys': 7.2.0 - debug: 4.4.1 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.3 - semver: 7.7.2 - ts-api-utils: 1.4.3(typescript@5.9.3) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/typescript-estree@8.48.1(typescript@5.9.3)': dependencies: '@typescript-eslint/project-service': 8.48.1(typescript@5.9.3) @@ -6433,11 +6364,6 @@ snapshots: '@typescript-eslint/types': 7.18.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@7.2.0': - dependencies: - '@typescript-eslint/types': 7.2.0 - eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@8.48.1': dependencies: '@typescript-eslint/types': 8.48.1 @@ -6504,17 +6430,17 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vercel/analytics@1.6.1(next@16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@vercel/analytics@1.6.1(next@16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': optionalDependencies: - next: 16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 - '@vercel/speed-insights@1.3.1(next@16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@vercel/speed-insights@1.3.1(next@16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': optionalDependencies: - next: 16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 - '@vercel/style-guide@5.2.0(@next/eslint-plugin-next@14.2.6)(eslint@8.57.1)(prettier@3.7.4)(typescript@5.9.3)': + '@vercel/style-guide@5.2.0(@next/eslint-plugin-next@14.2.35)(eslint@8.57.1)(prettier@3.7.4)(typescript@5.9.3)': dependencies: '@babel/core': 7.28.0 '@babel/eslint-parser': 7.28.0(@babel/core@7.28.0)(eslint@8.57.1) @@ -6536,7 +6462,7 @@ snapshots: eslint-plugin-unicorn: 48.0.1(eslint@8.57.1) prettier-plugin-packagejson: 2.5.19(prettier@3.7.4) optionalDependencies: - '@next/eslint-plugin-next': 14.2.6 + '@next/eslint-plugin-next': 14.2.35 eslint: 8.57.1 prettier: 3.7.4 typescript: 5.9.3 @@ -6841,8 +6767,6 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001723: {} - caniuse-lite@1.0.30001759: {} chalk@2.4.2: @@ -7352,15 +7276,16 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-next@14.2.6(eslint@8.57.1)(typescript@5.9.3): + eslint-config-next@14.2.35(eslint@8.57.1)(typescript@5.9.3): dependencies: - '@next/eslint-plugin-next': 14.2.6 + '@next/eslint-plugin-next': 14.2.35 '@rushstack/eslint-patch': 1.11.0 - '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.5(eslint@8.57.1) eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.57.1) @@ -7371,9 +7296,9 @@ snapshots: - eslint-plugin-import-x - supports-color - eslint-config-next@16.0.7(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3): + eslint-config-next@16.0.10(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3): dependencies: - '@next/eslint-plugin-next': 16.0.7 + '@next/eslint-plugin-next': 16.0.10 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1) @@ -7413,7 +7338,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 @@ -7424,11 +7349,11 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 @@ -7439,11 +7364,11 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 @@ -7454,7 +7379,7 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -7468,14 +7393,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.1(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -7525,7 +7450,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -7536,7 +7461,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -7548,7 +7473,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -7993,9 +7918,9 @@ snapshots: functions-have-names@1.2.3: {} - geist@1.5.1(next@16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): + geist@1.5.1(next@16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): dependencies: - next: 16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) gensync@1.0.0-beta.2: {} @@ -8737,13 +8662,13 @@ snapshots: netmask@2.0.2: {} - next-auth@4.24.13(next@16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next-auth@4.24.13(next@16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.27.6 '@panva/hkdf': 1.2.1 cookie: 0.7.2 jose: 4.15.9 - next: 16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) oauth: 0.9.15 openid-client: 5.7.1 preact: 10.26.9 @@ -8757,34 +8682,34 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - next@14.2.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@14.2.35(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@next/env': 14.2.15 + '@next/env': 14.2.35 '@swc/helpers': 0.5.5 busboy: 1.6.0 - caniuse-lite: 1.0.30001723 + caniuse-lite: 1.0.30001759 graceful-fs: 4.2.11 postcss: 8.4.31 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) styled-jsx: 5.1.1(react@18.3.1) optionalDependencies: - '@next/swc-darwin-arm64': 14.2.15 - '@next/swc-darwin-x64': 14.2.15 - '@next/swc-linux-arm64-gnu': 14.2.15 - '@next/swc-linux-arm64-musl': 14.2.15 - '@next/swc-linux-x64-gnu': 14.2.15 - '@next/swc-linux-x64-musl': 14.2.15 - '@next/swc-win32-arm64-msvc': 14.2.15 - '@next/swc-win32-ia32-msvc': 14.2.15 - '@next/swc-win32-x64-msvc': 14.2.15 + '@next/swc-darwin-arm64': 14.2.33 + '@next/swc-darwin-x64': 14.2.33 + '@next/swc-linux-arm64-gnu': 14.2.33 + '@next/swc-linux-arm64-musl': 14.2.33 + '@next/swc-linux-x64-gnu': 14.2.33 + '@next/swc-linux-x64-musl': 14.2.33 + '@next/swc-win32-arm64-msvc': 14.2.33 + '@next/swc-win32-ia32-msvc': 14.2.33 + '@next/swc-win32-x64-msvc': 14.2.33 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - next@16.0.7(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@16.0.10(@babel/core@7.28.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@next/env': 16.0.7 + '@next/env': 16.0.10 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001759 postcss: 8.4.31 @@ -8792,14 +8717,14 @@ snapshots: react-dom: 18.3.1(react@18.3.1) styled-jsx: 5.1.6(@babel/core@7.28.5)(react@18.3.1) optionalDependencies: - '@next/swc-darwin-arm64': 16.0.7 - '@next/swc-darwin-x64': 16.0.7 - '@next/swc-linux-arm64-gnu': 16.0.7 - '@next/swc-linux-arm64-musl': 16.0.7 - '@next/swc-linux-x64-gnu': 16.0.7 - '@next/swc-linux-x64-musl': 16.0.7 - '@next/swc-win32-arm64-msvc': 16.0.7 - '@next/swc-win32-x64-msvc': 16.0.7 + '@next/swc-darwin-arm64': 16.0.10 + '@next/swc-darwin-x64': 16.0.10 + '@next/swc-linux-arm64-gnu': 16.0.10 + '@next/swc-linux-arm64-musl': 16.0.10 + '@next/swc-linux-x64-gnu': 16.0.10 + '@next/swc-linux-x64-musl': 16.0.10 + '@next/swc-win32-arm64-msvc': 16.0.10 + '@next/swc-win32-x64-msvc': 16.0.10 sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' From c64b2e8221eb51a77441d7730f0aac41154e4742 Mon Sep 17 00:00:00 2001 From: apsinghdev Date: Wed, 17 Dec 2025 14:22:32 +0530 Subject: [PATCH 05/22] fix: excluge the seed file --- apps/api/tsconfig.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json index 977def00..20c012cb 100644 --- a/apps/api/tsconfig.json +++ b/apps/api/tsconfig.json @@ -39,5 +39,10 @@ "noUncheckedSideEffectImports": true, "moduleDetection": "force", "skipLibCheck": true, - } + }, + "exclude": [ + "prisma/seed.ts", + "node_modules", + "dist" + ] } From 130f6eff06d55e37eeb0af1fb15401c7eb6ba1ad Mon Sep 17 00:00:00 2001 From: apsinghdev Date: Wed, 17 Dec 2025 14:30:37 +0530 Subject: [PATCH 06/22] fix: excluge the seed file --- apps/api/tsconfig.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json index 20c012cb..aa78dc6f 100644 --- a/apps/api/tsconfig.json +++ b/apps/api/tsconfig.json @@ -40,8 +40,11 @@ "moduleDetection": "force", "skipLibCheck": true, }, + "include": [ + "src/**/*" + ], "exclude": [ - "prisma/seed.ts", + "prisma", "node_modules", "dist" ] From 2abff4401554dbe760a0dbab2cb047453c5094f2 Mon Sep 17 00:00:00 2001 From: Aman Raj <113578582+huamanraj@users.noreply.github.com> Date: Tue, 16 Dec 2025 16:49:27 +0530 Subject: [PATCH 07/22] feat: posthog event tracting for analytics --- .../src/app/(main)/(landing)/pitch/page.tsx | 104 ++++-- .../src/app/(main)/(landing)/pricing/page.tsx | 1 + apps/web/src/app/layout.tsx | 3 +- apps/web/src/app/providers.tsx | 120 +++++- apps/web/src/components/dashboard/Sidebar.tsx | 55 ++- .../src/components/landing-sections/CTA.tsx | 73 ++-- .../src/components/landing-sections/Hero.tsx | 13 +- .../components/landing-sections/footer.tsx | 29 ++ .../components/landing-sections/navbar.tsx | 27 +- apps/web/src/components/login/SignInPage.tsx | 18 +- .../src/components/payment/PaymentFlow.tsx | 41 +++ apps/web/src/hooks/useAnalytics.ts | 259 +++++++++++++ apps/web/src/lib/analytics.ts | 348 ++++++++++++++++++ 13 files changed, 1027 insertions(+), 64 deletions(-) create mode 100644 apps/web/src/hooks/useAnalytics.ts create mode 100644 apps/web/src/lib/analytics.ts diff --git a/apps/web/src/app/(main)/(landing)/pitch/page.tsx b/apps/web/src/app/(main)/(landing)/pitch/page.tsx index 21b82b72..032949c5 100644 --- a/apps/web/src/app/(main)/(landing)/pitch/page.tsx +++ b/apps/web/src/app/(main)/(landing)/pitch/page.tsx @@ -106,7 +106,10 @@ const Pitch = () => { }} className="max-w-4xl mx-auto space-y-4" > -

+

mission statement

@@ -134,7 +137,10 @@ const Pitch = () => { }} className="max-w-4xl mx-auto space-y-6" > -

+

my goal

@@ -190,7 +196,10 @@ const Pitch = () => { }} className="max-w-4xl mx-auto space-y-6" > -

+

the plan

@@ -258,13 +267,19 @@ const Pitch = () => { }} className="max-w-4xl mx-auto space-y-8" > -

+

philosophies i follow

{/* Philosophy #1 */}
-

+

#1 stay small. stay effective.

@@ -303,9 +318,9 @@ const Pitch = () => {

- if i go with this approach, i'll have to sacrifice those - fancy dreams of raising millions, being on the front - page of magazines, having millions of users, etc. + if i go with this approach, i'll have to sacrifice + those fancy dreams of raising millions, being on the + front page of magazines, having millions of users, etc.



but the good part is i'll be able to stay genuine @@ -341,7 +356,10 @@ const Pitch = () => { {/* Philosophy #2 */}

-

+

#2 go beyond what you promise.

@@ -374,7 +392,10 @@ const Pitch = () => { }} className="max-w-4xl mx-auto space-y-6" > -

+

so how small?

@@ -425,7 +446,10 @@ const Pitch = () => { }} className="max-w-4xl mx-auto space-y-6" > -

+

what existing investors said about me?

@@ -458,13 +482,19 @@ const Pitch = () => { }} className="max-w-4xl mx-auto space-y-8" > -

+

questions you may have

-

+

i'm not an absolute beginner, so how does subscribing to opensox.ai make sense to me?

@@ -485,7 +515,10 @@ const Pitch = () => {
-

+

will the quality of your service reduce as you grow?

@@ -496,7 +529,10 @@ const Pitch = () => {

-

+

how does opensox.ai pro help me?

    @@ -555,7 +591,10 @@ const Pitch = () => {
-

+

how much time does it take to get the results?

@@ -572,7 +611,10 @@ const Pitch = () => {

-

+

why should i trust you?

@@ -599,7 +641,10 @@ const Pitch = () => {

-

+

are there any alternatives to what you provide?

@@ -611,7 +656,10 @@ const Pitch = () => {

-

+

what's the difference between opensox pro and a course?

@@ -624,7 +672,10 @@ const Pitch = () => {
-

+

is it for an absolute beginner?

@@ -633,7 +684,10 @@ const Pitch = () => {

-

+

in what cases shouldn't i invest in opensox pro?

@@ -649,7 +703,7 @@ const Pitch = () => {

  • - you don't wanna do it fast + you don't wanna do it fast
  • @@ -663,7 +717,10 @@ const Pitch = () => {
  • -

    +

    are you the best in the market?

    @@ -715,6 +772,7 @@ const Pitch = () => { buttonText="Invest" buttonClassName="w-full max-w-md" callbackUrl={callbackUrl} + buttonLocation="pitch_page" /> ) : ( diff --git a/apps/web/src/app/(main)/(landing)/pricing/page.tsx b/apps/web/src/app/(main)/(landing)/pricing/page.tsx index ac4feb70..2a246bbd 100644 --- a/apps/web/src/app/(main)/(landing)/pricing/page.tsx +++ b/apps/web/src/app/(main)/(landing)/pricing/page.tsx @@ -428,6 +428,7 @@ const SecondaryPricingCard = ({ callbackUrl }: { callbackUrl: string }) => { planIdOk ? "" : "opacity-60 cursor-not-allowed" }`} callbackUrl={callbackUrl} + buttonLocation="pricing_page" />

    + {children} diff --git a/apps/web/src/app/providers.tsx b/apps/web/src/app/providers.tsx index 2a7f0629..4b6bcc54 100644 --- a/apps/web/src/app/providers.tsx +++ b/apps/web/src/app/providers.tsx @@ -2,10 +2,98 @@ import posthog from "posthog-js"; import { PostHogProvider as PHProvider } from "posthog-js/react"; -import { useEffect } from "react"; +import { useEffect, useRef } from "react"; +import { useSession } from "next-auth/react"; import PostHogPageView from "./PostHogPageView"; +// Session storage key to track if sign-in was initiated +const SIGN_IN_INITIATED_KEY = "posthog_sign_in_initiated"; +const SIGN_IN_PROVIDER_KEY = "posthog_sign_in_provider"; + +/** + * PostHog Auth Tracker + * + * This component must be rendered INSIDE SessionProvider. + * It tracks sign_in_completed events when user authenticates. + */ +export function PostHogAuthTracker() { + const { data: session, status } = useSession(); + const hasTrackedSignIn = useRef(false); + const previousStatus = useRef(null); + + useEffect(() => { + if (status === "loading") return; + + try { + // Check if PostHog is initialized + if (!posthog.__loaded) return; + + // Detect transition from unauthenticated to authenticated + const wasSignInInitiated = + sessionStorage.getItem(SIGN_IN_INITIATED_KEY) === "true"; + const storedProvider = sessionStorage.getItem(SIGN_IN_PROVIDER_KEY) as + | "google" + | "github" + | null; + + if (status === "authenticated" && session?.user) { + // Check if this is a fresh sign-in (not just a page refresh) + const isNewSignIn = + wasSignInInitiated || + (previousStatus.current === "unauthenticated" && + !hasTrackedSignIn.current); + + if (isNewSignIn && !hasTrackedSignIn.current) { + hasTrackedSignIn.current = true; + + // Determine provider from stored value + const provider = storedProvider || "google"; // Default to google if unknown + + // Track sign-in completed EVENT only (no person properties) + posthog.capture("sign_in_completed", { + provider: provider, + is_new_user: false, + }); + + if (process.env.NODE_ENV === "development") { + console.log("[Analytics] Event tracked: sign_in_completed", { + provider, + is_new_user: false, + }); + } + + // Clear the sign-in tracking flags + sessionStorage.removeItem(SIGN_IN_INITIATED_KEY); + sessionStorage.removeItem(SIGN_IN_PROVIDER_KEY); + } + } else if (status === "unauthenticated") { + // Reset tracking flag for next sign-in + hasTrackedSignIn.current = false; + + if (process.env.NODE_ENV === "development") { + console.log("[PostHog] User unauthenticated"); + } + } + + // Track previous status + previousStatus.current = status; + } catch (error) { + if (process.env.NODE_ENV === "development") { + console.error("[PostHog] Error handling auth state:", error); + } + } + }, [session, status]); + + return null; +} + +/** + * PostHog Provider + * NOTE: This provider does NOT handle auth tracking. + * Use PostHogAuthTracker inside SessionProvider for that. + */ export function PostHogProvider({ children }: { children: React.ReactNode }) { + // Initialize PostHog useEffect(() => { const posthogKey = process.env.NEXT_PUBLIC_POSTHOG_KEY; const posthogHost = process.env.NEXT_PUBLIC_POSTHOG_HOST; @@ -13,11 +101,37 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) { if (posthogKey && posthogHost) { posthog.init(posthogKey, { api_host: posthogHost, + + // Pageview tracking capture_pageview: false, // Disable automatic pageview capture, as we capture manually - capture_pageleave: true, + capture_pageleave: true, // Track when users leave pages + + // Privacy settings + disable_session_recording: true, // Privacy: No session recordings + respect_dnt: true, // Respect Do Not Track header + ip: false, // Do not store IP addresses (anonymize) + + // Persistence settings + persistence: "localStorage+cookie", // Persist anonymous ID across sessions + + // Performance settings + autocapture: false, // We use custom events for better control + + // Development settings + loaded: (posthog) => { + if (process.env.NODE_ENV === "development") { + console.log("[PostHog] Initialized successfully"); + // Enable debug mode in development + posthog.debug(false); // Set to true to see all PostHog logs + } + }, }); } else { - console.error("PostHog key or host is not defined"); + if (process.env.NODE_ENV === "development") { + console.warn( + "[PostHog] Key or host is not defined - analytics disabled" + ); + } } }, []); diff --git a/apps/web/src/components/dashboard/Sidebar.tsx b/apps/web/src/components/dashboard/Sidebar.tsx index afea0818..22265205 100644 --- a/apps/web/src/components/dashboard/Sidebar.tsx +++ b/apps/web/src/components/dashboard/Sidebar.tsx @@ -20,7 +20,7 @@ import { Squares2X2Icon, ChevronDownIcon, LockClosedIcon, - AcademicCapIcon + AcademicCapIcon, } from "@heroicons/react/24/outline"; import { useShowSidebar } from "@/store/useShowSidebar"; import { signOut, useSession } from "next-auth/react"; @@ -28,6 +28,7 @@ import { ProfilePic } from "./ProfilePic"; import { useSubscription } from "@/hooks/useSubscription"; import { OpensoxProBadge } from "../sheet/OpensoxProBadge"; import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"; +import { useAnalytics } from "@/hooks/useAnalytics"; type RouteConfig = { path: string; @@ -82,6 +83,7 @@ export default function Sidebar({ overlay = false }: { overlay?: boolean }) { const pathname = usePathname(); const { isPaidUser } = useSubscription(); const [proSectionExpanded, setProSectionExpanded] = useState(true); + const { trackLinkClick, trackButtonClick } = useAnalytics(); // auto-expand pro section if user is on a premium route useEffect(() => { @@ -96,6 +98,13 @@ export default function Sidebar({ overlay = false }: { overlay?: boolean }) { }, [pathname, isPaidUser]); const reqFeatureHandler = () => { + // Track feature request click + trackLinkClick( + "https://github.com/apsinghdev/opensox/issues", + "Request a feature", + "sidebar", + true + ); window.open("https://github.com/apsinghdev/opensox/issues", "_blank"); }; @@ -103,6 +112,8 @@ export default function Sidebar({ overlay = false }: { overlay?: boolean }) { if (isPaidUser) { setProSectionExpanded(!proSectionExpanded); } else { + // Track upgrade button click for free users + trackButtonClick("Opensox Pro", "sidebar"); router.push("/pricing"); } }; @@ -166,7 +177,14 @@ export default function Sidebar({ overlay = false }: { overlay?: boolean }) { const isActive = pathname === route.path || pathname.startsWith(`${route.path}/`); return ( - + { + // Track navigation link click + trackLinkClick(route.path, route.label, "sidebar", false); + }} + >
    + { + // Track premium navigation link click + trackLinkClick( + route.path, + route.label, + "sidebar", + false + ); + }} + >
    (
    router.push("/pricing")} + onClick={() => { + // Track locked premium feature click + trackButtonClick(`${route.label} (Locked)`, "sidebar"); + router.push("/pricing"); + }} className="w-full h-[44px] flex items-center rounded-md cursor-pointer transition-colors px-2 gap-3 opacity-50 hover:opacity-75 group" role="button" tabIndex={0} @@ -357,6 +391,7 @@ export default function Sidebar({ overlay = false }: { overlay?: boolean }) { onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); + trackButtonClick(`${route.label} (Locked)`, "sidebar"); router.push("/pricing"); } }} @@ -427,6 +462,7 @@ function ProfileMenu({ isCollapsed }: { isCollapsed: boolean }) { const [open, setOpen] = useState(false); const { data: session } = useSession(); const router = useRouter(); + const { trackButtonClick, trackLinkClick } = useAnalytics(); const isLoggedIn = !!session; const fullName = session?.user?.name || "User"; @@ -506,6 +542,13 @@ function ProfileMenu({ isCollapsed }: { isCollapsed: boolean }) { {isLoggedIn && (