## 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>
204 lines
7.0 KiB
TypeScript
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);
|
|
}
|
|
} |