@@ -5,22 +5,85 @@ import { dismissMessage } from "../../actions/MessageActions";
55import { useI18n } from "../../hooks/useI18n" ;
66import { MESSAGE_DURATION } from "../../constants/DefaultConstants" ;
77import PropTypes from "prop-types" ;
8+ import { useCallback , useEffect } from "react" ;
89
910export const Message = ( { message } ) => {
1011 const { formatMessage } = useI18n ( ) ;
1112 const dispatch = useDispatch ( ) ;
12- const dismiss = React . useCallback ( ( ) => dispatch ( dismissMessage ( message ) ) , [ message , dispatch ] ) ;
13- React . useEffect ( ( ) => {
13+ const [ progress , setProgress ] = React . useState ( 0 ) ;
14+ const [ isVisible , setIsVisible ] = React . useState ( false ) ;
15+
16+ const dismiss = useCallback ( ( ) => dispatch ( dismissMessage ( message ) ) , [ message , dispatch ] ) ;
17+
18+ useEffect ( ( ) => {
19+ requestAnimationFrame ( ( ) => {
20+ setIsVisible ( true ) ;
21+ } ) ;
22+
23+ const startTime = Date . now ( ) ;
1424 const timer = setTimeout ( ( ) => {
15- dismiss ( ) ;
25+ setIsVisible ( false ) ;
26+
27+ setTimeout ( ( ) => {
28+ dismiss ( ) ;
29+ } , 400 ) ;
1630 } , MESSAGE_DURATION ) ;
17- return ( ) => clearTimeout ( timer ) ;
31+
32+ const progressInterval = setInterval ( ( ) => {
33+ const elapsed = Date . now ( ) - startTime ;
34+ const newProgress = Math . min ( ( elapsed / MESSAGE_DURATION ) * 100 , 100 ) ;
35+ setProgress ( newProgress ) ;
36+ } , 50 ) ;
37+
38+ return ( ) => {
39+ clearTimeout ( timer ) ;
40+ clearInterval ( progressInterval ) ;
41+ } ;
1842 } , [ dismiss , message ] ) ;
1943
44+ const size = 24 ;
45+ const strokeWidth = 2 ;
46+ const radius = ( size - strokeWidth ) / 2 ;
47+ const circumference = 2 * Math . PI * radius ;
48+ const offset = circumference - ( progress / 100 ) * circumference ;
49+
2050 return (
21- < Alert variant = { message . type } onClose = { dismiss } dismissible = { true } >
22- { message . messageId ? formatMessage ( message . messageId , message . values ) : message . message }
23- </ Alert >
51+ < div
52+ style = { {
53+ transform : isVisible ? "translateX(0)" : "translateX(100%)" ,
54+ opacity : isVisible ? 1 : 0 ,
55+ transition : "transform 0.4s ease-out, opacity 0.4s ease-out" ,
56+ } }
57+ >
58+ < Alert variant = { message . type } onClose = { dismiss } dismissible = { true } >
59+ < div style = { { display : "flex" , alignItems : "center" , gap : "8px" } } >
60+ < svg width = { size } height = { size } style = { { transform : "rotate(-90deg)" } } >
61+ < circle
62+ cx = { size / 2 }
63+ cy = { size / 2 }
64+ r = { radius }
65+ fill = "none"
66+ stroke = "currentColor"
67+ strokeWidth = { strokeWidth }
68+ opacity = { 0.2 }
69+ />
70+ < circle
71+ cx = { size / 2 }
72+ cy = { size / 2 }
73+ r = { radius }
74+ fill = "none"
75+ stroke = "currentColor"
76+ strokeWidth = { strokeWidth }
77+ strokeDasharray = { circumference }
78+ strokeDashoffset = { offset }
79+ strokeLinecap = "round"
80+ style = { { transition : "stroke-dashoffset 0.05s linear" } }
81+ />
82+ </ svg >
83+ < span > { message . messageId ? formatMessage ( message . messageId , message . values ) : message . message } </ span >
84+ </ div >
85+ </ Alert >
86+ </ div >
2487 ) ;
2588} ;
2689
0 commit comments