You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
62 lines
2.1 KiB
62 lines
2.1 KiB
import { useCallback, useState } from 'react';
|
|
import {
|
|
getPasswordRuleMessage,
|
|
resetPassword,
|
|
validatePassword,
|
|
validatePasswordConfirm,
|
|
type LoginResult,
|
|
} from '../api';
|
|
import type { PasswordResetPayload } from '../types';
|
|
|
|
export interface UsePasswordResetReturn {
|
|
/** 重置 / 首次设置密码,成功返回登录结果(后端直接下发登录态) */
|
|
reset: (payload: PasswordResetPayload) => Promise<LoginResult>;
|
|
/** 提交进行中 */
|
|
loading: boolean;
|
|
/** 失败原因(用于页面提示) */
|
|
error: Error | null;
|
|
/**
|
|
* 新密码规则校验:返回中文提示,null 表示通过。
|
|
* 规则本身在 API 层计算,页面只渲染结果,不写判断逻辑。
|
|
*/
|
|
checkPassword: (password: string, confirm: string) => string | null;
|
|
}
|
|
|
|
/**
|
|
* 重置 / 首次设置登录密码。
|
|
*
|
|
* 覆盖两个场景:忘记密码(老用户改密)、首次设置密码(登录即注册的用户天生无密码)。
|
|
* 两条路径共用同一流程与接口,页面按来源只改文案。
|
|
* 发送验证码走独立的 useSmsCode。
|
|
*/
|
|
export function usePasswordReset(): UsePasswordResetReturn {
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<Error | null>(null);
|
|
|
|
const reset = useCallback(async (payload: PasswordResetPayload) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
return await resetPassword(payload);
|
|
} catch (e) {
|
|
const err = e instanceof Error ? e : new Error('密码设置失败,请稍后重试');
|
|
setError(err);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
const checkPassword = useCallback((password: string, confirm: string) => {
|
|
const ruleError = validatePassword(password);
|
|
if (ruleError) return getPasswordRuleMessage(ruleError);
|
|
// 确认框还没开始输入时不提示不一致,避免用户刚敲第一个字符就被报错
|
|
if (confirm.length > 0) {
|
|
const confirmError = validatePasswordConfirm(password, confirm);
|
|
if (confirmError) return getPasswordRuleMessage(confirmError);
|
|
}
|
|
return null;
|
|
}, []);
|
|
|
|
return { reset, loading, error, checkPassword };
|
|
}
|
|
|