components/ 拆为三层:
- providers/ — 状态管理(App/Theme/SettingsProvider)
- shell/ — 应用外壳(Layout/NavBar/PageDispatcher)
- ui/ — 通用 UI 原子(FloatingPanel/LegalTextModal)
pages/ 重命名 + 重组:
- headers/ → panels/ NavBar 触发的面板页
- login/ → auth/ 认证模块(含注册/忘记密码)
- settings/blocks/ → sections/
- home/components/ → panels/ features/ controls/ hooks/
按职责分:panels(布局壳) + features(功能面板) + controls(表单控件) + hooks
其他清理:
- 删除空占位 Test3.tsx
- HomeContext 从 HomeContent 拆出独立文件
- uploadValidation 内联到 ImageInput
- 修复过时注释(useUI → controls)
58 lines
1.8 KiB
TypeScript
58 lines
1.8 KiB
TypeScript
// ============================================================
|
||
// useSmsCooldown — 短信验证码发送冷却 Hook
|
||
//
|
||
// 从 RegisterForm 提取,供所有需要短信验证码的场景复用:
|
||
// - 注册(RegisterForm)
|
||
// - 忘记密码(ForgotPasswordModal)
|
||
// ============================================================
|
||
|
||
import { useState, useCallback, useRef, useEffect } from 'react';
|
||
|
||
export interface SmsCooldownState {
|
||
/** 是否在冷却中 */
|
||
cooldown: boolean;
|
||
/** 冷却剩余秒数 */
|
||
secondsLeft: number;
|
||
/** 开始冷却 */
|
||
startCooldown: () => void;
|
||
}
|
||
|
||
export function useSmsCooldown(cooldownSeconds: number = 60): SmsCooldownState {
|
||
const [cooldown, setCooldown] = useState(false);
|
||
const [secondsLeft, setSecondsLeft] = useState(0);
|
||
const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||
|
||
const startCooldown = useCallback(() => {
|
||
// 清理之前的计时器(防止重复点击导致多个计时器叠加)
|
||
if (timerRef.current) {
|
||
clearInterval(timerRef.current);
|
||
}
|
||
setCooldown(true);
|
||
setSecondsLeft(cooldownSeconds);
|
||
timerRef.current = setInterval(() => {
|
||
setSecondsLeft((prev) => {
|
||
if (prev <= 1) {
|
||
if (timerRef.current) {
|
||
clearInterval(timerRef.current);
|
||
timerRef.current = null;
|
||
}
|
||
setCooldown(false);
|
||
return 0;
|
||
}
|
||
return prev - 1;
|
||
});
|
||
}, 1000);
|
||
}, [cooldownSeconds]);
|
||
|
||
// 组件卸载时清理计时器
|
||
useEffect(() => {
|
||
return () => {
|
||
if (timerRef.current) {
|
||
clearInterval(timerRef.current);
|
||
}
|
||
};
|
||
}, []);
|
||
|
||
return { cooldown, secondsLeft, startCooldown };
|
||
}
|