115 lines
2.9 KiB
TypeScript
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;
|