Added onboarding progress tracking & landing page
This commit is contained in:
144
frontend/src/hooks/useErrorHandler.ts
Normal file
144
frontend/src/hooks/useErrorHandler.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
|
||||
export interface ErrorState {
|
||||
message: string;
|
||||
details?: string;
|
||||
timestamp: Date;
|
||||
retryable: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom hook for consistent error handling across the application
|
||||
*
|
||||
* Usage:
|
||||
* const { error, setError, clearError, handleError } = useErrorHandler();
|
||||
*
|
||||
* try {
|
||||
* await someAsyncOperation();
|
||||
* } catch (err) {
|
||||
* handleError(err, { retryable: true });
|
||||
* }
|
||||
*/
|
||||
export const useErrorHandler = () => {
|
||||
const [error, setErrorState] = useState<ErrorState | null>(null);
|
||||
|
||||
const setError = useCallback((errorState: ErrorState) => {
|
||||
setErrorState(errorState);
|
||||
|
||||
// Log to console
|
||||
console.error('Error occurred:', errorState);
|
||||
|
||||
// Send to error tracking service
|
||||
logErrorToService(errorState);
|
||||
}, []);
|
||||
|
||||
const clearError = useCallback(() => {
|
||||
setErrorState(null);
|
||||
}, []);
|
||||
|
||||
const handleError = useCallback((
|
||||
err: unknown,
|
||||
options: { retryable?: boolean; context?: string } = {}
|
||||
) => {
|
||||
const { retryable = false, context = '' } = options;
|
||||
|
||||
let message = 'An unexpected error occurred';
|
||||
let details = '';
|
||||
|
||||
if (err instanceof Error) {
|
||||
message = err.message;
|
||||
details = err.stack || '';
|
||||
} else if (typeof err === 'string') {
|
||||
message = err;
|
||||
} else if (err && typeof err === 'object' && 'message' in err) {
|
||||
message = String((err as any).message);
|
||||
}
|
||||
|
||||
const errorState: ErrorState = {
|
||||
message: context ? `${context}: ${message}` : message,
|
||||
details,
|
||||
timestamp: new Date(),
|
||||
retryable,
|
||||
};
|
||||
|
||||
setError(errorState);
|
||||
}, [setError]);
|
||||
|
||||
return {
|
||||
error,
|
||||
setError,
|
||||
clearError,
|
||||
handleError,
|
||||
hasError: error !== null,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Log error to external service (Sentry, LogRocket, etc.)
|
||||
*/
|
||||
function logErrorToService(errorState: ErrorState) {
|
||||
try {
|
||||
// TODO: Integrate with error tracking service
|
||||
// Example: Sentry.captureException(new Error(errorState.message));
|
||||
|
||||
// For now, just console log
|
||||
console.group('📊 Error Logged');
|
||||
console.log('Message:', errorState.message);
|
||||
console.log('Timestamp:', errorState.timestamp.toISOString());
|
||||
console.log('Retryable:', errorState.retryable);
|
||||
if (errorState.details) {
|
||||
console.log('Details:', errorState.details);
|
||||
}
|
||||
console.groupEnd();
|
||||
} catch (e) {
|
||||
console.error('Failed to log error to service:', e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for handling async operations with automatic error handling
|
||||
*
|
||||
* Usage:
|
||||
* const { execute, loading, error } = useAsyncErrorHandler();
|
||||
*
|
||||
* <Button onClick={() => execute(async () => {
|
||||
* await someAsyncOperation();
|
||||
* })}>
|
||||
* Do Something
|
||||
* </Button>
|
||||
*/
|
||||
export const useAsyncErrorHandler = <T = void>() => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { error, handleError, clearError } = useErrorHandler();
|
||||
|
||||
const execute = useCallback(
|
||||
async (
|
||||
asyncFn: () => Promise<T>,
|
||||
options: { context?: string; retryable?: boolean } = {}
|
||||
): Promise<T | null> => {
|
||||
setLoading(true);
|
||||
clearError();
|
||||
|
||||
try {
|
||||
const result = await asyncFn();
|
||||
setLoading(false);
|
||||
return result;
|
||||
} catch (err) {
|
||||
handleError(err, options);
|
||||
setLoading(false);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
[handleError, clearError]
|
||||
);
|
||||
|
||||
return {
|
||||
execute,
|
||||
loading,
|
||||
error,
|
||||
clearError,
|
||||
};
|
||||
};
|
||||
|
||||
export default useErrorHandler;
|
||||
|
||||
53
frontend/src/hooks/usePerformanceMonitor.ts
Normal file
53
frontend/src/hooks/usePerformanceMonitor.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
interface PerformanceMetrics {
|
||||
loadTime: number;
|
||||
renderTime: number;
|
||||
memoryUsage?: number;
|
||||
}
|
||||
|
||||
export const usePerformanceMonitor = (componentName: string) => {
|
||||
const [metrics, setMetrics] = useState<PerformanceMetrics | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const startTime = performance.now();
|
||||
|
||||
// Monitor memory usage if available
|
||||
const getMemoryUsage = () => {
|
||||
if ('memory' in performance) {
|
||||
return (performance as any).memory.usedJSHeapSize / 1024 / 1024; // MB
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const measurePerformance = () => {
|
||||
const endTime = performance.now();
|
||||
const loadTime = endTime - startTime;
|
||||
|
||||
setMetrics({
|
||||
loadTime,
|
||||
renderTime: loadTime,
|
||||
memoryUsage: getMemoryUsage()
|
||||
});
|
||||
|
||||
// Log performance metrics in development
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.log(`Performance metrics for ${componentName}:`, {
|
||||
loadTime: `${loadTime.toFixed(2)}ms`,
|
||||
memoryUsage: getMemoryUsage() ? `${getMemoryUsage()?.toFixed(2)}MB` : 'N/A'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Use requestAnimationFrame to measure after render
|
||||
const rafId = requestAnimationFrame(measurePerformance);
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(rafId);
|
||||
};
|
||||
}, [componentName]);
|
||||
|
||||
return metrics;
|
||||
};
|
||||
|
||||
export default usePerformanceMonitor;
|
||||
Reference in New Issue
Block a user