diff --git a/src/components/app-layout.tsx b/src/components/app-layout.tsx index f51acd5..aaf35fd 100644 --- a/src/components/app-layout.tsx +++ b/src/components/app-layout.tsx @@ -126,7 +126,7 @@ import { t } from '@/lib/i18n'; import { fetchSchoolYears, fetchStudents, fetchClasses, fetchDBNotifications, markAllNotificationsRead, markSingleNotificationRead, type SchoolYear, type Student, type ClassGroup, type DBNotification, type DBNotificationData } from '@/lib/api'; import { apiGet } from '@/lib/api'; import type { School as SchoolType } from '@/lib/api'; -import OnboardingTour, { isOnboardingCompleted } from '@/components/onboarding-tour'; +import OnboardingTour, { isOnboardingCompleted, isDontShowAgain } from '@/components/onboarding-tour'; import KeyboardShortcutsDialog from '@/components/keyboard-shortcuts-dialog'; import { CommandDialog, @@ -755,10 +755,11 @@ export default function AppLayout() { setCurrentView('classes'); }, [setCurrentClass, setCurrentView]); - // Check onboarding status on mount + // Check onboarding status on mount - respect "don't show again" preference useEffect(() => { - if (!isOnboardingCompleted()) { - setOnboardingOpen(true); + if (!isOnboardingCompleted() && !isDontShowAgain()) { + const timer = setTimeout(() => setOnboardingOpen(true), 1000); + return () => clearTimeout(timer); } }, []); diff --git a/src/components/offline-indicator.tsx b/src/components/offline-indicator.tsx index 8ac7548..0538501 100644 --- a/src/components/offline-indicator.tsx +++ b/src/components/offline-indicator.tsx @@ -94,10 +94,27 @@ export function PWAInstallPrompt() { return; } + // Don't show PWA prompt in development + if (process.env.NODE_ENV === 'development') { + return; + } + + // Check if user dismissed recently (within 7 days) + try { + const dismissedAt = localStorage.getItem('pwa_prompt_dismissed'); + if (dismissedAt) { + const daysSince = (Date.now() - parseInt(dismissedAt)) / (1000 * 60 * 60 * 24); + if (daysSince < 7) return; + } + } catch { + // ignore + } + const handleBeforeInstall = (e: Event) => { e.preventDefault(); setDeferredPrompt(e as BeforeInstallPromptEvent); - setShowInstall(true); + // Delay showing by 30 seconds to avoid interrupting the user + setTimeout(() => setShowInstall(true), 30000); }; const handleAppInstalled = () => { @@ -155,7 +172,10 @@ export function PWAInstallPrompt() {