feat(fasting): 新增轻断食功能模块

新增完整的轻断食功能,包括:
- 断食计划列表和详情页面,支持12-12、14-10、16-8、18-6四种计划
- 断食状态实时追踪和倒计时显示
- 自定义开始时间选择器
- 断食通知提醒功能
- Redux状态管理和数据持久化
- 新增tab导航入口和路由配置
This commit is contained in:
richarjiang
2025-10-13 19:21:29 +08:00
parent 971aebd560
commit e03b2b3032
17 changed files with 2390 additions and 7 deletions

54
hooks/useCountdown.ts Normal file
View File

@@ -0,0 +1,54 @@
import { useEffect, useMemo, useRef, useState } from 'react';
import { formatCountdown } from '@/utils/fasting';
interface CountdownOptions {
target: Date | null | undefined;
intervalMs?: number;
autoStart?: boolean;
}
export const useCountdown = ({ target, intervalMs = 1000, autoStart = true }: CountdownOptions) => {
const [now, setNow] = useState(() => new Date());
const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
const targetTimestamp = target instanceof Date ? target.getTime() : null;
useEffect(() => {
if (!autoStart) return undefined;
if (targetTimestamp == null) return undefined;
timerRef.current && clearInterval(timerRef.current);
timerRef.current = setInterval(() => {
setNow(new Date());
}, intervalMs);
return () => {
if (timerRef.current) {
clearInterval(timerRef.current);
timerRef.current = null;
}
};
}, [targetTimestamp, intervalMs, autoStart]);
useEffect(() => {
if (targetTimestamp == null) return;
setNow(new Date());
}, [targetTimestamp]);
const diffMs = useMemo(() => {
if (targetTimestamp == null) return 0;
return targetTimestamp - now.getTime();
}, [targetTimestamp, now]);
const formatted = useMemo(() => {
if (targetTimestamp == null) return '--:--:--';
return formatCountdown(new Date(targetTimestamp), now);
}, [targetTimestamp, now]);
return {
now,
diffMs,
formatted,
isExpired: diffMs <= 0,
hasTarget: targetTimestamp != null,
};
};