Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 12x 12x 5x 5x 5x 1x 1x 1x 5x 4x 4x 4x 4x 4x 5x 5x 1x 2x 2x 5x | 'use client';
import { useEffect, useCallback, useRef, useState } from 'react';
type Props = {
message: string;
type?: 'error' | 'success' | 'info';
onClose: () => void;
duration?: number;
}
export default function Notification({ message, type = 'error', onClose, duration = 1000 }: Props) {
const timerRef = useRef<NodeJS.Timeout | null>(null);
const [isExiting, setIsExiting] = useState(false);
const handleClose = useCallback(() => {
// Déclencher l'animation de sortie
setIsExiting(true);
// Attendre la fin de l'animation (300ms) puis fermer réellement
setTimeout(() => {
onClose();
}, 300);
}, [onClose]);
useEffect(() => {
Iif (timerRef.current) {
clearTimeout(timerRef.current);
}
timerRef.current = setTimeout(() => {
handleClose();
}, duration);
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
};
}, [handleClose, duration]);
const getTypeStyles = useCallback(() => {
switch (type) {
case 'error':
return 'bg-red-500 border-red-600';
case 'success':
return 'bg-green-500 border-green-600';
case 'info':
return 'bg-blue-500 border-blue-600';
default:
return 'bg-red-500 border-red-600';
}
}, [type]);
return (
<div
className={`fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-[60] ${getTypeStyles()} text-white px-4 py-3 rounded-lg shadow-lg border-l-4 min-w-[300px] max-w-[400px] transition-all duration-300 ease-in-out ${
isExiting
? 'animate-slide-out'
: 'animate-slide-in'
}`}
>
<div className="flex items-center justify-between">
<p className="text-sm font-medium">{message}</p>
<button
onClick={handleClose}
className="ml-3 text-white hover:text-gray-200 font-bold text-lg"
aria-label="Fermer"
>
×
</button>
</div>
<div
className={`absolute bottom-0 left-0 h-1 ${type === 'error' ? 'bg-red-300' : type === 'success' ? 'bg-green-300' : 'bg-blue-300'}`}
style={{
animation: `progress ${duration}ms linear forwards`,
animationPlayState: isExiting ? 'paused' : 'running'
}}
></div>
</div>
);
}
|