返回 AiToEarn
useCountdown.ts
根目录 / project / aitoearn-web / src / app / [lng] / auth / login / components / LoginContent / useCountdown.ts
1 /**
2 * useCountdown - 验证码倒计时 hook
3 */
4
5 import { useCallback, useEffect, useState } from 'react'
6
7 const COUNTDOWN_SECONDS = 60
8
9 function getRemainingSeconds(deadlineAt: number) {
10 return Math.max(Math.ceil((deadlineAt - Date.now()) / 1000), 0)
11 }
12
13 export function useCountdown() {
14 const [deadlineAt, setDeadlineAt] = useState<number | null>(null)
15 const [countdown, setCountdown] = useState(0)
16
17 const start = useCallback(() => {
18 const nextDeadlineAt = Date.now() + COUNTDOWN_SECONDS * 1000
19 setDeadlineAt(nextDeadlineAt)
20 setCountdown(COUNTDOWN_SECONDS)
21 }, [])
22
23 useEffect(() => {
24 if (!deadlineAt) {
25 setCountdown(0)
26 return
27 }
28
29 const syncCountdown = () => {
30 const remaining = getRemainingSeconds(deadlineAt)
31 setCountdown(remaining)
32 return remaining
33 }
34
35 if (syncCountdown() <= 0)
36 return
37
38 const timer = setInterval(() => {
39 if (syncCountdown() <= 0) {
40 clearInterval(timer)
41 }
42 }, 1000)
43
44 const handleVisibilityChange = () => {
45 if (document.visibilityState === 'visible') {
46 syncCountdown()
47 }
48 }
49
50 document.addEventListener('visibilitychange', handleVisibilityChange)
51
52 return () => {
53 clearInterval(timer)
54 document.removeEventListener('visibilitychange', handleVisibilityChange)
55 }
56 }, [deadlineAt])
57
58 return { countdown, isCounting: countdown > 0, start }
59 }
60
60 lines TYPESCRIPT