1
- import React , { useRef , useEffect } from 'react' ;
1
+ import React , { useRef , useEffect , useState } from 'react' ;
2
2
3
3
const Testimonial = ( ) => {
4
4
const scrollRef = useRef ( null ) ;
5
+ const [ isPaused , setIsPaused ] = useState ( false ) ;
6
+ const [ currentIndex , setCurrentIndex ] = useState ( 0 ) ;
5
7
6
8
useEffect ( ( ) => {
7
9
const scrollContainer = scrollRef . current ;
8
10
let isDown = false ;
9
11
let startX ;
10
12
let scrollLeft ;
13
+ let autoScrollInterval ;
14
+ let pauseTimeout ;
11
15
12
16
const handleMouseDown = ( e ) => {
13
17
isDown = true ;
18
+ setIsPaused ( true ) ;
14
19
scrollContainer . classList . add ( 'active' ) ;
15
20
startX = e . pageX - scrollContainer . offsetLeft ;
16
21
scrollLeft = scrollContainer . scrollLeft ;
@@ -19,11 +24,17 @@ const Testimonial = () => {
19
24
const handleMouseLeave = ( ) => {
20
25
isDown = false ;
21
26
scrollContainer . classList . remove ( 'active' ) ;
27
+ // Resume auto-scroll after 2 seconds of no interaction
28
+ clearTimeout ( pauseTimeout ) ;
29
+ pauseTimeout = setTimeout ( ( ) => setIsPaused ( false ) , 2000 ) ;
22
30
} ;
23
31
24
32
const handleMouseUp = ( ) => {
25
33
isDown = false ;
26
34
scrollContainer . classList . remove ( 'active' ) ;
35
+ // Resume auto-scroll after 2 seconds of no interaction
36
+ clearTimeout ( pauseTimeout ) ;
37
+ pauseTimeout = setTimeout ( ( ) => setIsPaused ( false ) , 2000 ) ;
27
38
} ;
28
39
29
40
const handleMouseMove = ( e ) => {
@@ -34,11 +45,43 @@ const Testimonial = () => {
34
45
scrollContainer . scrollLeft = scrollLeft - walk ;
35
46
} ;
36
47
48
+ const handleScroll = ( ) => {
49
+ if ( ! scrollContainer ) return ;
50
+ setIsPaused ( true ) ;
51
+ clearTimeout ( pauseTimeout ) ;
52
+ pauseTimeout = setTimeout ( ( ) => setIsPaused ( false ) , 2000 ) ;
53
+ } ;
54
+
55
+ const autoScroll = ( ) => {
56
+ if ( ! scrollContainer || isPaused ) return ;
57
+
58
+ const cardWidth = 400 ; // Width of each testimonial card
59
+ const gap = 32 ; // Gap between cards (8 * 4 = 32px from gap-8)
60
+ const totalWidth = scrollContainer . scrollWidth ;
61
+
62
+ setCurrentIndex ( ( prevIndex ) => {
63
+ const nextIndex = ( prevIndex + 1 ) % 4 ; // 4 is the number of testimonials
64
+ const scrollPosition = ( cardWidth + gap ) * nextIndex ;
65
+
66
+ scrollContainer . scrollTo ( {
67
+ left : scrollPosition ,
68
+ behavior : 'smooth'
69
+ } ) ;
70
+
71
+ return nextIndex ;
72
+ } ) ;
73
+ } ;
74
+
75
+ // Set up event listeners
37
76
if ( scrollContainer ) {
38
77
scrollContainer . addEventListener ( 'mousedown' , handleMouseDown ) ;
39
78
scrollContainer . addEventListener ( 'mouseleave' , handleMouseLeave ) ;
40
79
scrollContainer . addEventListener ( 'mouseup' , handleMouseUp ) ;
41
80
scrollContainer . addEventListener ( 'mousemove' , handleMouseMove ) ;
81
+ scrollContainer . addEventListener ( 'scroll' , handleScroll ) ;
82
+
83
+ // Start auto-scrolling
84
+ autoScrollInterval = setInterval ( autoScroll , 5000 ) ; // Scroll every 5 seconds
42
85
}
43
86
44
87
return ( ) => {
@@ -47,9 +90,12 @@ const Testimonial = () => {
47
90
scrollContainer . removeEventListener ( 'mouseleave' , handleMouseLeave ) ;
48
91
scrollContainer . removeEventListener ( 'mouseup' , handleMouseUp ) ;
49
92
scrollContainer . removeEventListener ( 'mousemove' , handleMouseMove ) ;
93
+ scrollContainer . removeEventListener ( 'scroll' , handleScroll ) ;
50
94
}
95
+ clearInterval ( autoScrollInterval ) ;
96
+ clearTimeout ( pauseTimeout ) ;
51
97
} ;
52
- } , [ ] ) ;
98
+ } , [ isPaused ] ) ;
53
99
54
100
return (
55
101
< section className = "py-16 bg-gradient-to-r from-gray-50 to-gray-100 overflow-hidden" >
@@ -167,11 +213,31 @@ const Testimonial = () => {
167
213
</ div >
168
214
</ div >
169
215
170
- { /* Scroll Indicator */ }
171
- < div className = "mt-8 flex justify- center" >
216
+ { /* Scroll Indicator and Navigation Dots */ }
217
+ < div className = "mt-8 flex flex-col items- center gap-4 " >
172
218
< div className = "text-sm text-gray-500" >
173
219
← Scroll or drag to see more testimonials →
174
220
</ div >
221
+ < div className = "flex gap-2" >
222
+ { [ 0 , 1 , 2 , 3 ] . map ( ( index ) => (
223
+ < button
224
+ key = { index }
225
+ className = { `w-2 h-2 rounded-full transition-all duration-300 ${
226
+ currentIndex === index ? 'bg-gray-800 w-4' : 'bg-gray-300'
227
+ } `}
228
+ onClick = { ( ) => {
229
+ setIsPaused ( true ) ;
230
+ setCurrentIndex ( index ) ;
231
+ scrollRef . current ?. scrollTo ( {
232
+ left : index * ( 400 + 32 ) ,
233
+ behavior : 'smooth'
234
+ } ) ;
235
+ setTimeout ( ( ) => setIsPaused ( false ) , 2000 ) ;
236
+ } }
237
+ aria-label = { `Go to testimonial ${ index + 1 } ` }
238
+ />
239
+ ) ) }
240
+ </ div >
175
241
</ div >
176
242
</ div >
177
243
0 commit comments