Improve the frontend 3

This commit is contained in:
Urtzi Alfaro
2025-10-30 21:08:07 +01:00
parent 36217a2729
commit 63f5c6d512
184 changed files with 21512 additions and 7442 deletions

192
frontend/src/utils/toast.ts Normal file
View File

@@ -0,0 +1,192 @@
import toast from 'react-hot-toast';
/**
* Centralized toast notification utility
* Wraps react-hot-toast with consistent API and standardized behavior
*/
export interface ToastOptions {
/** Optional title for the toast (displayed above message) */
title?: string;
/** Custom duration in milliseconds (overrides default) */
duration?: number;
/** Toast ID for managing specific toasts */
id?: string;
}
const DEFAULT_DURATIONS = {
success: 4000,
error: 6000,
warning: 5000,
info: 4000,
loading: 0, // infinite until dismissed
} as const;
/**
* Show a success toast notification
* @param message - The message to display (can be translation key or direct string)
* @param options - Optional configuration
*/
const success = (message: string, options?: ToastOptions): string => {
const duration = options?.duration ?? DEFAULT_DURATIONS.success;
const fullMessage = options?.title
? `${options.title}\n${message}`
: message;
return toast.success(fullMessage, {
duration,
id: options?.id,
});
};
/**
* Show an error toast notification
* @param message - The error message to display
* @param options - Optional configuration
*/
const error = (message: string, options?: ToastOptions): string => {
const duration = options?.duration ?? DEFAULT_DURATIONS.error;
const fullMessage = options?.title
? `${options.title}\n${message}`
: message;
return toast.error(fullMessage, {
duration,
id: options?.id,
});
};
/**
* Show a warning toast notification
* @param message - The warning message to display
* @param options - Optional configuration
*/
const warning = (message: string, options?: ToastOptions): string => {
const duration = options?.duration ?? DEFAULT_DURATIONS.warning;
const fullMessage = options?.title
? `${options.title}\n${message}`
: message;
return toast(fullMessage, {
duration,
id: options?.id,
icon: '⚠️',
});
};
/**
* Show an info toast notification
* @param message - The info message to display
* @param options - Optional configuration
*/
const info = (message: string, options?: ToastOptions): string => {
const duration = options?.duration ?? DEFAULT_DURATIONS.info;
const fullMessage = options?.title
? `${options.title}\n${message}`
: message;
return toast(fullMessage, {
duration,
id: options?.id,
icon: '',
});
};
/**
* Show a loading toast notification
* @param message - The loading message to display
* @param options - Optional configuration
*/
const loading = (message: string, options?: ToastOptions): string => {
const duration = options?.duration ?? DEFAULT_DURATIONS.loading;
const fullMessage = options?.title
? `${options.title}\n${message}`
: message;
return toast.loading(fullMessage, {
duration,
id: options?.id,
});
};
/**
* Dismiss a specific toast by ID
* @param toastId - The ID of the toast to dismiss
*/
const dismiss = (toastId?: string): void => {
toast.dismiss(toastId);
};
/**
* Show a promise toast that updates based on promise state
* Useful for async operations
*/
const promise = <T,>(
promise: Promise<T>,
messages: {
loading: string;
success: string | ((data: T) => string);
error: string | ((error: Error) => string);
},
options?: ToastOptions
): Promise<T> => {
return toast.promise(
promise,
{
loading: messages.loading,
success: messages.success,
error: messages.error,
},
{
success: {
duration: options?.duration ?? DEFAULT_DURATIONS.success,
},
error: {
duration: options?.duration ?? DEFAULT_DURATIONS.error,
},
}
);
};
/**
* Unified toast notification utility
* Use this instead of importing react-hot-toast directly
*
* @example
* ```typescript
* import { showToast } from '@/utils/toast';
*
* // Simple success
* showToast.success('Operation completed');
*
* // Error with title
* showToast.error('Failed to save', { title: 'Error' });
*
* // Promise-based
* showToast.promise(
* apiCall(),
* {
* loading: 'Saving...',
* success: 'Saved successfully',
* error: 'Failed to save'
* }
* );
* ```
*/
export const showToast = {
success,
error,
warning,
info,
loading,
dismiss,
promise,
};
// Re-export toast for advanced use cases (custom toasts, etc.)
export { toast };