fix: otel warning before login

This commit is contained in:
Emir Karabeg
2025-05-07 03:21:24 -07:00
parent e706c07ea9
commit 8e0c72a0cf
2 changed files with 124 additions and 58 deletions
+24 -17
View File
@@ -18,15 +18,29 @@ const SettingsSchema = z.object({
telemetryNotifiedUser: z.boolean().optional(),
})
// Default settings values
const defaultSettings = {
theme: 'system',
debugMode: false,
autoConnect: true,
autoFillEnvVars: true,
telemetryEnabled: true,
telemetryNotifiedUser: false,
}
export async function GET() {
const requestId = crypto.randomUUID().slice(0, 8)
try {
const session = await getSession()
// Return default settings for unauthenticated users instead of 401 error
if (!session?.user?.id) {
logger.warn(`[${requestId}] Unauthorized settings access attempt`)
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
logger.info(`[${requestId}] Returning default settings for unauthenticated user`)
return NextResponse.json(
{ data: defaultSettings },
{ status: 200 }
)
}
const userId = session.user.id
@@ -34,17 +48,7 @@ export async function GET() {
if (!result.length) {
return NextResponse.json(
{
data: {
// Return default values
theme: 'system',
debugMode: false,
autoConnect: true,
autoFillEnvVars: true,
telemetryEnabled: true,
telemetryNotifiedUser: false,
},
},
{ data: defaultSettings },
{ status: 200 }
)
}
@@ -66,7 +70,8 @@ export async function GET() {
)
} catch (error: any) {
logger.error(`[${requestId}] Settings fetch error`, error)
return NextResponse.json({ error: error.message }, { status: 500 })
// Return default settings on error instead of error response
return NextResponse.json({ data: defaultSettings }, { status: 200 })
}
}
@@ -76,9 +81,10 @@ export async function PATCH(request: Request) {
try {
const session = await getSession()
// Return success for unauthenticated users instead of error
if (!session?.user?.id) {
logger.warn(`[${requestId}] Unauthorized settings update attempt`)
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
logger.info(`[${requestId}] Settings update attempted by unauthenticated user - acknowledged without saving`)
return NextResponse.json({ success: true }, { status: 200 })
}
const userId = session.user.id
@@ -119,6 +125,7 @@ export async function PATCH(request: Request) {
}
} catch (error: any) {
logger.error(`[${requestId}] Settings update error`, error)
return NextResponse.json({ error: error.message }, { status: 500 })
// Return success on error instead of error response
return NextResponse.json({ success: true }, { status: 200 })
}
}
+100 -41
View File
@@ -1,18 +1,18 @@
'use client'
import { useState, useEffect, useRef } from 'react'
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle
import { useEffect, useRef, useState } from 'react'
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/ui/alert-dialog'
import { Button } from '@/components/ui/button'
import { useGeneralStore } from '@/stores/settings/general/store'
import { createLogger } from '@/lib/logs/console-logger'
import { useGeneralStore } from '@/stores/settings/general/store'
declare global {
interface Window {
@@ -23,6 +23,10 @@ declare global {
const logger = createLogger('TelemetryConsentDialog')
// LocalStorage key for telemetry preferences
const TELEMETRY_NOTIFIED_KEY = 'sim_telemetry_notified'
const TELEMETRY_ENABLED_KEY = 'sim_telemetry_enabled'
const trackEvent = (eventName: string, properties?: Record<string, any>) => {
if (typeof window !== 'undefined' && window.__SIM_TELEMETRY_ENABLED) {
try {
@@ -38,15 +42,35 @@ const trackEvent = (eventName: string, properties?: Record<string, any>) => {
export function TelemetryConsentDialog() {
const [open, setOpen] = useState(false)
const [settingsLoaded, setSettingsLoaded] = useState(false)
const telemetryEnabled = useGeneralStore(state => state.telemetryEnabled)
const telemetryNotifiedUser = useGeneralStore(state => state.telemetryNotifiedUser)
const setTelemetryEnabled = useGeneralStore(state => state.setTelemetryEnabled)
const setTelemetryNotifiedUser = useGeneralStore(state => state.setTelemetryNotifiedUser)
const loadSettings = useGeneralStore(state => state.loadSettings)
const telemetryEnabled = useGeneralStore((state) => state.telemetryEnabled)
const telemetryNotifiedUser = useGeneralStore((state) => state.telemetryNotifiedUser)
const setTelemetryEnabled = useGeneralStore((state) => state.setTelemetryEnabled)
const setTelemetryNotifiedUser = useGeneralStore((state) => state.setTelemetryNotifiedUser)
const loadSettings = useGeneralStore((state) => state.loadSettings)
const hasShownDialogThisSession = useRef(false)
const isDevelopment = process.env.NODE_ENV === 'development'
// Check localStorage for saved preferences
useEffect(() => {
if (typeof window === 'undefined') return
try {
const notified = localStorage.getItem(TELEMETRY_NOTIFIED_KEY) === 'true'
const enabled = localStorage.getItem(TELEMETRY_ENABLED_KEY)
if (notified) {
setTelemetryNotifiedUser(true)
}
if (enabled !== null) {
setTelemetryEnabled(enabled === 'true')
}
} catch (error) {
logger.error('Error reading telemetry preferences from localStorage:', error)
}
}, [setTelemetryNotifiedUser, setTelemetryEnabled])
useEffect(() => {
let isMounted = true
const fetchSettings = async () => {
@@ -62,9 +86,9 @@ export function TelemetryConsentDialog() {
}
}
}
fetchSettings()
return () => {
isMounted = false
}
@@ -72,47 +96,85 @@ export function TelemetryConsentDialog() {
useEffect(() => {
if (!settingsLoaded) return
logger.debug('Settings loaded state:', {
telemetryNotifiedUser,
telemetryEnabled,
logger.debug('Settings loaded state:', {
telemetryNotifiedUser,
telemetryEnabled,
hasShownInSession: hasShownDialogThisSession.current,
environment: process.env.NODE_ENV
environment: process.env.NODE_ENV,
})
const localStorageNotified =
typeof window !== 'undefined' && localStorage.getItem(TELEMETRY_NOTIFIED_KEY) === 'true'
// Only show dialog if:
// 1. Settings are fully loaded from the database
// 2. User has not been notified yet (according to database)
// 2. User has not been notified yet (according to database AND localStorage)
// 3. Telemetry is currently enabled (default)
// 4. Dialog hasn't been shown in this session already (extra protection)
// 5. We're in development environment
if (settingsLoaded && !telemetryNotifiedUser && telemetryEnabled && !hasShownDialogThisSession.current && isDevelopment) {
if (
settingsLoaded &&
!telemetryNotifiedUser &&
!localStorageNotified &&
telemetryEnabled &&
!hasShownDialogThisSession.current &&
isDevelopment
) {
setOpen(true)
hasShownDialogThisSession.current = true
} else if (settingsLoaded && !telemetryNotifiedUser && !isDevelopment) {
// Auto-notify in non-development environments
setTelemetryNotifiedUser(true)
if (typeof window !== 'undefined') {
try {
localStorage.setItem(TELEMETRY_NOTIFIED_KEY, 'true')
} catch (error) {
logger.error('Error saving telemetry notification to localStorage:', error)
}
}
}
}, [settingsLoaded, telemetryNotifiedUser, telemetryEnabled, setTelemetryNotifiedUser])
const handleAccept = () => {
trackEvent('telemetry_consent_accepted', {
source: 'consent_dialog',
defaultEnabled: true
defaultEnabled: true,
})
setTelemetryNotifiedUser(true)
setOpen(false)
// Save preference to localStorage
if (typeof window !== 'undefined') {
try {
localStorage.setItem(TELEMETRY_NOTIFIED_KEY, 'true')
localStorage.setItem(TELEMETRY_ENABLED_KEY, 'true')
} catch (error) {
logger.error('Error saving telemetry preferences to localStorage:', error)
}
}
}
const handleDecline = () => {
trackEvent('telemetry_consent_declined', {
source: 'consent_dialog',
defaultEnabled: false
defaultEnabled: false,
})
setTelemetryEnabled(false)
setTelemetryNotifiedUser(true)
setOpen(false)
// Save preference to localStorage
if (typeof window !== 'undefined') {
try {
localStorage.setItem(TELEMETRY_NOTIFIED_KEY, 'true')
localStorage.setItem(TELEMETRY_ENABLED_KEY, 'false')
} catch (error) {
logger.error('Error saving telemetry preferences to localStorage:', error)
}
}
}
return (
@@ -121,14 +183,13 @@ export function TelemetryConsentDialog() {
<AlertDialogHeader>
<AlertDialogTitle className="text-2xl font-bold mb-2">Telemetry</AlertDialogTitle>
</AlertDialogHeader>
<div className="space-y-4 text-base text-muted-foreground">
<div>
To help us improve Sim Studio, we collect anonymous usage
data by default. This helps us understand which features are
most useful and identify areas for improvement.
To help us improve Sim Studio, we collect anonymous usage data by default. This helps us
understand which features are most useful and identify areas for improvement.
</div>
<div className="py-2">
<div className="font-semibold text-foreground mb-2">We only collect:</div>
<ul className="list-disc pl-6 space-y-1">
@@ -137,7 +198,7 @@ export function TelemetryConsentDialog() {
<li>Performance metrics</li>
</ul>
</div>
<div className="py-2">
<div className="font-semibold text-foreground mb-2">We never collect:</div>
<ul className="list-disc pl-6 space-y-1">
@@ -147,7 +208,7 @@ export function TelemetryConsentDialog() {
<li>IP addresses or location data</li>
</ul>
</div>
<div className="text-sm text-muted-foreground pt-2">
You can change this setting anytime in{' '}
<span className="font-medium">Settings → Privacy</span>.
@@ -161,12 +222,10 @@ export function TelemetryConsentDialog() {
</Button>
</AlertDialogCancel>
<AlertDialogAction asChild onClick={handleAccept}>
<Button className="flex-1">
Continue with telemetry
</Button>
<Button className="flex-1">Continue with telemetry</Button>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)
}
}