veza/apps/web/src/utils/firstTime.ts
senke e70c1c4ed0 cognitive-load: add first-time user detection utility
- Created firstTime utility for detecting first-time users
- Functions: isFirstTime, markAsNotFirstTime, isOnboardingCompleted, markOnboardingCompleted
- Uses localStorage to persist state across sessions
- Graceful error handling with logger warnings
- SSR-safe (returns false on server)
- Can be integrated with Onboarding component
- Action 10.4.1.4 complete
2026-01-16 02:33:46 +01:00

120 lines
3.5 KiB
TypeScript

import { logger } from '@/utils/logger';
/**
* First Time Detection Utility
* Action 10.4.1.4: Add "first time" detection
*
* Provides utilities to detect first-time users and track onboarding completion
* Uses localStorage to persist state across sessions
*/
const FIRST_TIME_KEY = 'veza_first_time';
const ONBOARDING_COMPLETED_KEY = 'veza_onboarding_completed';
/**
* Check if this is the user's first time using the application
* @returns True if first time, false otherwise
*/
export function isFirstTime(): boolean {
if (typeof window === 'undefined') {
// Server-side rendering - assume not first time
return false;
}
try {
const value = localStorage.getItem(FIRST_TIME_KEY);
// If the key doesn't exist, it's the first time
return value === null;
} catch (error) {
logger.warn('Error checking first time status', {
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
});
// On error, assume not first time to avoid showing onboarding repeatedly
return false;
}
}
/**
* Mark the user as no longer first-time
* This should be called after the user has completed onboarding or interacted with the app
*/
export function markAsNotFirstTime(): void {
if (typeof window === 'undefined') {
return;
}
try {
localStorage.setItem(FIRST_TIME_KEY, 'false');
logger.debug('User marked as not first-time');
} catch (error) {
logger.warn('Error marking user as not first-time', {
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
});
}
}
/**
* Check if onboarding has been completed
* @returns True if onboarding was completed, false otherwise
*/
export function isOnboardingCompleted(): boolean {
if (typeof window === 'undefined') {
return false;
}
try {
const value = localStorage.getItem(ONBOARDING_COMPLETED_KEY);
return value === 'true';
} catch (error) {
logger.warn('Error checking onboarding completion status', {
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
});
return false;
}
}
/**
* Mark onboarding as completed
* This should be called when the user completes the onboarding flow
*/
export function markOnboardingCompleted(): void {
if (typeof window === 'undefined') {
return;
}
try {
localStorage.setItem(ONBOARDING_COMPLETED_KEY, 'true');
// Also mark as not first-time when onboarding is completed
markAsNotFirstTime();
logger.debug('Onboarding marked as completed');
} catch (error) {
logger.warn('Error marking onboarding as completed', {
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
});
}
}
/**
* Reset first-time detection (useful for testing or admin purposes)
* This will make the user appear as first-time again
*/
export function resetFirstTimeDetection(): void {
if (typeof window === 'undefined') {
return;
}
try {
localStorage.removeItem(FIRST_TIME_KEY);
localStorage.removeItem(ONBOARDING_COMPLETED_KEY);
logger.debug('First-time detection reset');
} catch (error) {
logger.warn('Error resetting first-time detection', {
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
});
}
}