veza/apps/web/src/features/player/components/PlayerError.tsx

115 lines
2.9 KiB
TypeScript

/**
* Composant PlayerError
* Affiche les erreurs du player avec messages utilisateur et bouton retry
*
* Uses ErrorDisplay component internally for consistent error presentation.
*/
import { ErrorDisplay } from '@/components/ui/ErrorDisplay';
import { cn } from '@/lib/utils';
export type PlayerErrorType =
| 'network'
| 'decode'
| 'source'
| 'abort'
| 'unknown';
export interface PlayerErrorProps {
error: Error | null;
errorType?: PlayerErrorType;
onRetry?: () => void;
className?: string;
showRetry?: boolean;
retryLabel?: string;
}
const ERROR_MESSAGES: Record<PlayerErrorType, string> = {
network: 'Erreur de connexion. Vérifiez votre connexion internet.',
decode: 'Erreur de décodage audio. Le fichier est peut-être corrompu.',
source: 'Erreur de source audio. Le fichier est introuvable ou inaccessible.',
abort: 'Chargement annulé.',
unknown: 'Une erreur est survenue lors de la lecture.',
};
function getErrorType(error: Error | null): PlayerErrorType {
if (!error) return 'unknown';
const message = error.message?.toLowerCase() || '';
const name = error.name?.toLowerCase() || '';
if (
message.includes('network') ||
message.includes('fetch') ||
name === 'networkerror'
) {
return 'network';
}
if (message.includes('decode') || name === 'decodeerror') {
return 'decode';
}
if (
message.includes('source') ||
message.includes('not found') ||
name === 'notfounderror'
) {
return 'source';
}
if (message.includes('abort') || name === 'aborterror') {
return 'abort';
}
return 'unknown';
}
function getErrorMessage(
error: Error | null,
errorType?: PlayerErrorType,
): string {
const type = errorType || getErrorType(error);
return ERROR_MESSAGES[type] || ERROR_MESSAGES.unknown;
}
export function PlayerError({
error,
errorType,
onRetry,
className,
showRetry = true,
retryLabel: _retryLabel = 'Réessayer', // Unused - ErrorDisplay uses its own retry button text
}: PlayerErrorProps) {
if (!error) {
return null;
}
const detectedErrorType = errorType || getErrorType(error);
const customMessage = getErrorMessage(error, errorType);
// Create error object with custom message for ErrorDisplay
const errorForDisplay = new Error(customMessage);
// Preserve original error stack if available
if (error.stack) {
errorForDisplay.stack = error.stack;
}
return (
<div className={cn('w-full', className)}>
<ErrorDisplay
error={errorForDisplay}
variant="card"
severity="error"
title="Erreur de lecture"
context={{
action: 'playing audio',
resource: 'player',
errorType: detectedErrorType,
}}
onRetry={showRetry && onRetry ? onRetry : undefined}
showDetails={import.meta.env.DEV}
dismissible={false}
/>
</div>
);
}
export default PlayerError;