slideshare/src/utils/logger.ts
Michael Mainguy 8376e77df7 Refactor presentation components following coding guidelines
## Major Refactoring
- Broke down large components into focused, reusable pieces
- Reduced NewPresentationPage.tsx from 238 to 172 lines
- Reduced PresentationEditor.tsx from 457 to 261 lines
- Eliminated functions exceeding 50-line guideline

## New Reusable Components
- PresentationDetailsForm: Form inputs for title/description
- AspectRatioSelector: Aspect ratio selection grid
- ThemeSelectionSection: Theme selection wrapper
- CreationActions: Action buttons and selected theme info
- EmptyPresentationState: Empty presentation state display
- SlidesSidebar: Complete sidebar with slides list
- SlideThumbnail: Individual slide thumbnail with actions
- LoadingState: Reusable loading component with spinner
- ErrorState: Reusable error display with retry/back actions

## New Hooks
- useSlideOperations: Custom hook for slide duplicate/delete logic

## Code Quality Improvements
- Replaced browser alert() calls with AlertDialog component
- Updated imports to use direct .tsx extensions per IMPORT_STANDARDS.md
- Eliminated browser confirm() calls in favor of ConfirmDialog system
- Consolidated duplicate loading/error state patterns
- Improved type safety throughout

## Benefits
- Better maintainability through component separation
- Consistent UX with shared UI components
- Code reuse across presentation components
- Compliance with 200-line file guideline

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-21 06:23:45 -05:00

204 lines
7.0 KiB
TypeScript

import log from 'loglevel';
/**
* Application logger configuration and utilities
*/
// Define log levels for different parts of the application
export enum LogLevel {
TRACE = 0,
DEBUG = 1,
INFO = 2,
WARN = 3,
ERROR = 4,
SILENT = 5,
}
// Log categories for better organization
export enum LogCategory {
PRESENTATION = 'presentation',
THEME = 'theme',
STORAGE = 'storage',
UI = 'ui',
SECURITY = 'security',
PERFORMANCE = 'performance',
GENERAL = 'general',
}
/**
* Configure logging based on environment
*/
function configureLogger(): void {
// Set default log level based on environment
const isDevelopment = import.meta.env.DEV;
const isProduction = import.meta.env.PROD;
if (isDevelopment) {
log.setLevel(LogLevel.DEBUG);
} else if (isProduction) {
log.setLevel(LogLevel.WARN);
} else {
log.setLevel(LogLevel.INFO);
}
// Add timestamp and category formatting
const originalFactory = log.methodFactory;
log.methodFactory = function (methodName, logLevel, loggerName) {
const rawMethod = originalFactory(methodName, logLevel, loggerName);
return function (category: LogCategory | string, message: string, ...args: LogData[]) {
const timestamp = new Date().toISOString();
const formattedMessage = `[${timestamp}] [${methodName.toUpperCase()}] [${category}] ${message}`;
if (args.length > 0) {
rawMethod(formattedMessage, ...args);
} else {
rawMethod(formattedMessage);
}
};
};
// Apply the new factory
log.setLevel(log.getLevel());
}
/**
* Valid log data types
*/
type LogData = string | number | boolean | null | undefined | Error | Record<string, unknown> | unknown[];
/**
* Logger interface for the application
*/
export interface Logger {
trace(category: LogCategory, message: string, ...args: LogData[]): void;
debug(category: LogCategory, message: string, ...args: LogData[]): void;
info(category: LogCategory, message: string, ...args: LogData[]): void;
warn(category: LogCategory, message: string, ...args: LogData[]): void;
error(category: LogCategory, message: string, ...args: LogData[]): void;
}
/**
* Create a logger instance with proper configuration
*/
function createLogger(): Logger {
configureLogger();
return {
trace: (category: LogCategory, message: string, ...args: LogData[]) => {
log.trace(category, message, ...args);
},
debug: (category: LogCategory, message: string, ...args: LogData[]) => {
log.debug(category, message, ...args);
},
info: (category: LogCategory, message: string, ...args: LogData[]) => {
log.info(category, message, ...args);
},
warn: (category: LogCategory, message: string, ...args: LogData[]) => {
log.warn(category, message, ...args);
},
error: (category: LogCategory, message: string, ...args: LogData[]) => {
log.error(category, message, ...args);
},
};
}
// Export the configured logger instance
export const logger = createLogger();
/**
* Convenience functions for common logging scenarios
*/
export const loggers = {
presentation: {
info: (message: string, ...args: LogData[]) => logger.info(LogCategory.PRESENTATION, message, ...args),
warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.PRESENTATION, message, ...args),
error: (message: string, ...args: LogData[]) => logger.error(LogCategory.PRESENTATION, message, ...args),
debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.PRESENTATION, message, ...args),
},
theme: {
info: (message: string, ...args: LogData[]) => logger.info(LogCategory.THEME, message, ...args),
warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.THEME, message, ...args),
error: (message: string, ...args: LogData[]) => logger.error(LogCategory.THEME, message, ...args),
debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.THEME, message, ...args),
},
storage: {
info: (message: string, ...args: LogData[]) => logger.info(LogCategory.STORAGE, message, ...args),
warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.STORAGE, message, ...args),
error: (message: string, ...args: LogData[]) => logger.error(LogCategory.STORAGE, message, ...args),
debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.STORAGE, message, ...args),
},
ui: {
info: (message: string, ...args: LogData[]) => logger.info(LogCategory.UI, message, ...args),
warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.UI, message, ...args),
error: (message: string, ...args: LogData[]) => logger.error(LogCategory.UI, message, ...args),
debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.UI, message, ...args),
},
security: {
info: (message: string, ...args: LogData[]) => logger.info(LogCategory.SECURITY, message, ...args),
warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.SECURITY, message, ...args),
error: (message: string, ...args: LogData[]) => logger.error(LogCategory.SECURITY, message, ...args),
debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.SECURITY, message, ...args),
},
performance: {
info: (message: string, ...args: LogData[]) => logger.info(LogCategory.PERFORMANCE, message, ...args),
warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.PERFORMANCE, message, ...args),
error: (message: string, ...args: LogData[]) => logger.error(LogCategory.PERFORMANCE, message, ...args),
debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.PERFORMANCE, message, ...args),
},
general: {
info: (message: string, ...args: LogData[]) => logger.info(LogCategory.GENERAL, message, ...args),
warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.GENERAL, message, ...args),
error: (message: string, ...args: LogData[]) => logger.error(LogCategory.GENERAL, message, ...args),
debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.GENERAL, message, ...args),
},
};
/**
* Performance timing utility
*/
export function createPerformanceTimer(operation: string) {
const startTime = performance.now();
return {
end: () => {
const endTime = performance.now();
const duration = endTime - startTime;
loggers.performance.info(`Operation '${operation}' completed in ${duration.toFixed(2)}ms`);
return duration;
}
};
}
/**
* Error logging utility with stack trace
*/
export function logError(category: LogCategory, message: string, error?: Error | unknown, context?: Record<string, any>) {
if (error instanceof Error) {
logger.error(category, `${message}: ${error.message}`, {
stack: error.stack,
context,
});
} else {
logger.error(category, message, { error, context });
}
}
/**
* Development-only logging
*/
export function devLog(category: LogCategory, message: string, ...args: any[]) {
if (import.meta.env.DEV) {
logger.debug(category, `[DEV] ${message}`, ...args);
}
}