cooldown-timer.tsx 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import { useLatest } from 'ahooks'
  4. import SimplePieChart from '@/app/components/base/simple-pie-chart'
  5. import Tooltip from '@/app/components/base/tooltip'
  6. export type CooldownTimerProps = {
  7. secondsRemaining?: number
  8. onFinish?: () => void
  9. }
  10. const CooldownTimer = ({ secondsRemaining, onFinish }: CooldownTimerProps) => {
  11. const { t } = useTranslation()
  12. const targetTime = useRef<number>(Date.now())
  13. const [currentTime, setCurrentTime] = useState(targetTime.current)
  14. const displayTime = useMemo(
  15. () => Math.ceil((targetTime.current - currentTime) / 1000),
  16. [currentTime],
  17. )
  18. const countdownTimeout = useRef<NodeJS.Timeout>()
  19. const clearCountdown = useCallback(() => {
  20. if (countdownTimeout.current) {
  21. clearTimeout(countdownTimeout.current)
  22. countdownTimeout.current = undefined
  23. }
  24. }, [])
  25. const onFinishRef = useLatest(onFinish)
  26. const countdown = useCallback(() => {
  27. clearCountdown()
  28. countdownTimeout.current = setTimeout(() => {
  29. const now = Date.now()
  30. if (now <= targetTime.current) {
  31. setCurrentTime(Date.now())
  32. countdown()
  33. }
  34. else {
  35. onFinishRef.current?.()
  36. clearCountdown()
  37. }
  38. }, 1000)
  39. }, [clearCountdown, onFinishRef])
  40. useEffect(() => {
  41. const now = Date.now()
  42. targetTime.current = now + (secondsRemaining ?? 0) * 1000
  43. setCurrentTime(now)
  44. countdown()
  45. return clearCountdown
  46. }, [clearCountdown, countdown, secondsRemaining])
  47. return displayTime
  48. ? (
  49. <Tooltip popupContent={t('common.modelProvider.apiKeyRateLimit', { seconds: displayTime })}>
  50. <SimplePieChart percentage={Math.round(displayTime / 60 * 100)} className='w-3 h-3' />
  51. </Tooltip>
  52. )
  53. : null
  54. }
  55. export default memo(CooldownTimer)