From bbb18dfe3ed1afca5cb6d732718fa08929422a5f Mon Sep 17 00:00:00 2001 From: Stephen Zhou <38493346+hyoban@users.noreply.github.com> Date: Tue, 5 Nov 2024 23:38:25 +0800 Subject: [PATCH] refactor: useCountdown --- .../components/mark-all-button.tsx | 12 +--- packages/hooks/src/index.ts | 1 + packages/hooks/src/useCountDown.ts | 65 +++++++++++++++++++ 3 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 packages/hooks/src/useCountDown.ts diff --git a/apps/renderer/src/modules/entry-column/components/mark-all-button.tsx b/apps/renderer/src/modules/entry-column/components/mark-all-button.tsx index 360f8fd77d..c1e76e7930 100644 --- a/apps/renderer/src/modules/entry-column/components/mark-all-button.tsx +++ b/apps/renderer/src/modules/entry-column/components/mark-all-button.tsx @@ -1,10 +1,11 @@ import { useViewport } from "@follow/components/hooks/useViewport.js" import { ActionButton, Button, IconButton } from "@follow/components/ui/button/index.js" import { RootPortal } from "@follow/components/ui/portal/index.jsx" +import { useCountdown } from "@follow/hooks" import { cn, getOS } from "@follow/utils/utils" import { AnimatePresence, m } from "framer-motion" import type { FC, ReactNode } from "react" -import { forwardRef, Fragment, useEffect, useState } from "react" +import { forwardRef, Fragment, useState } from "react" import { useHotkeys } from "react-hotkeys-hook" import { Trans, useTranslation } from "react-i18next" import { toast } from "sonner" @@ -186,20 +187,13 @@ const Popup = ({ which, containerRef, setPopoverRef, setShow, handleMarkAllAsRea const ConfirmMarkAllReadInfo = ({ undo }: { undo: () => any }) => { const { t } = useTranslation() - const [countdown, setCountdown] = useState(3) + const [countdown] = useCountdown({ countStart: 3 }) useHotkeys("ctrl+z,meta+z", undo, { scopes: HotKeyScopeMap.Home, preventDefault: true, }) - useEffect(() => { - if (countdown > 0) { - const timer = setTimeout(() => setCountdown(countdown - 1), 1000) - return () => clearTimeout(timer) - } - }, [countdown]) - return (
{t("mark_all_read_button.confirm_mark_all_info")}
diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index a6188977f8..cc321c9baf 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -1,5 +1,6 @@ export type { HTMLMediaState } from "./factory/createHTMLMediaHook" export * from "./useAnyPointDown" +export * from "./useCountDown" export * from "./useDark" export * from "./useInputComposition" export * from "./useInterval" diff --git a/packages/hooks/src/useCountDown.ts b/packages/hooks/src/useCountDown.ts new file mode 100644 index 0000000000..460c73d9bb --- /dev/null +++ b/packages/hooks/src/useCountDown.ts @@ -0,0 +1,65 @@ +// credits: https://usehooks-ts.com/react-hook/use-countdown + +import { useCallback } from "react" +import { useBoolean, useCounter, useInterval } from "usehooks-ts" + +type CountdownOptions = { + countStart: number + + intervalMs?: number + isIncrement?: boolean + autoStart?: boolean + + countStop?: number +} + +type CountdownControllers = { + startCountdown: () => void + stopCountdown: () => void + resetCountdown: () => void +} + +export function useCountdown({ + countStart, + countStop = 0, + intervalMs = 1000, + isIncrement = false, + autoStart = true, +}: CountdownOptions): [number, CountdownControllers] { + const { count, increment, decrement, reset: resetCounter } = useCounter(countStart) + + /* + * Note: used to control the useInterval + * running: If true, the interval is running + * start: Should set running true to trigger interval + * stop: Should set running false to remove interval. + */ + const { + value: isCountdownRunning, + setTrue: startCountdown, + setFalse: stopCountdown, + } = useBoolean(autoStart) + + // Will set running false and reset the seconds to initial value. + const resetCountdown = useCallback(() => { + stopCountdown() + resetCounter() + }, [stopCountdown, resetCounter]) + + const countdownCallback = useCallback(() => { + if (count === countStop) { + stopCountdown() + return + } + + if (isIncrement) { + increment() + } else { + decrement() + } + }, [count, countStop, decrement, increment, isIncrement, stopCountdown]) + + useInterval(countdownCallback, isCountdownRunning ? intervalMs : null) + + return [count, { startCountdown, stopCountdown, resetCountdown }] +}