'use client'; /** * Client-side logging utility * Logs to console in development, can be extended to send to server in production */ type LogLevel = 'debug' | 'info' | 'warn' | 'error'; interface LogContext { [key: string]: any; } class ClientLogger { private isDevelopment: boolean; constructor() { this.isDevelopment = process.env.NODE_ENV === 'development'; } private formatMessage(level: LogLevel, message: string, context?: LogContext): string { const timestamp = new Date().toISOString(); const contextStr = context ? ` ${JSON.stringify(context)}` : ''; return `[${timestamp}] [${level.toUpperCase()}] ${message}${contextStr}`; } private shouldLog(level: LogLevel): boolean { // In production, only log warnings and errors if (!this.isDevelopment && (level === 'debug' || level === 'info')) { return false; } return true; } debug(message: string, context?: LogContext): void { if (this.shouldLog('debug')) { console.debug(this.formatMessage('debug', message, context)); } } info(message: string, context?: LogContext): void { if (this.shouldLog('info')) { console.info(this.formatMessage('info', message, context)); } } warn(message: string, context?: LogContext): void { if (this.shouldLog('warn')) { console.warn(this.formatMessage('warn', message, context)); } } error(message: string, error?: Error | unknown, context?: LogContext): void { if (this.shouldLog('error')) { const errorContext = { ...context, error: error instanceof Error ? { message: error.message, stack: error.stack, name: error.name, } : error, }; console.error(this.formatMessage('error', message, errorContext)); } } // Performance timing helper time(label: string): void { if (this.isDevelopment) { console.time(label); } } timeEnd(label: string): void { if (this.isDevelopment) { console.timeEnd(label); } } // Group logging for related operations group(label: string): void { if (this.isDevelopment) { console.group(label); } } groupEnd(): void { if (this.isDevelopment) { console.groupEnd(); } } } // Export singleton instance export const clientLogger = new ClientLogger(); // Hook-specific logger factory export function createHookLogger(hookName: string) { return { debug: (message: string, context?: LogContext) => clientLogger.debug(`[${hookName}] ${message}`, context), info: (message: string, context?: LogContext) => clientLogger.info(`[${hookName}] ${message}`, context), warn: (message: string, context?: LogContext) => clientLogger.warn(`[${hookName}] ${message}`, context), error: (message: string, error?: Error | unknown, context?: LogContext) => clientLogger.error(`[${hookName}] ${message}`, error, context), }; } // Query/Mutation logger factory export function createQueryLogger(queryKey: readonly unknown[]) { const key = JSON.stringify(queryKey); return { debug: (message: string, context?: LogContext) => clientLogger.debug(`[Query: ${key}] ${message}`, context), info: (message: string, context?: LogContext) => clientLogger.info(`[Query: ${key}] ${message}`, context), warn: (message: string, context?: LogContext) => clientLogger.warn(`[Query: ${key}] ${message}`, context), error: (message: string, error?: Error | unknown, context?: LogContext) => clientLogger.error(`[Query: ${key}] ${message}`, error, context), }; } export function createMutationLogger(mutationKey: string) { return { debug: (message: string, context?: LogContext) => clientLogger.debug(`[Mutation: ${mutationKey}] ${message}`, context), info: (message: string, context?: LogContext) => clientLogger.info(`[Mutation: ${mutationKey}] ${message}`, context), warn: (message: string, context?: LogContext) => clientLogger.warn(`[Mutation: ${mutationKey}] ${message}`, context), error: (message: string, error?: Error | unknown, context?: LogContext) => clientLogger.error(`[Mutation: ${mutationKey}] ${message}`, error, context), }; }