合并 verify 和 otp 界面,增加 password 界面
This commit is contained in:
@@ -13,11 +13,14 @@ export interface OTPBindState {
|
||||
mobile: string;
|
||||
otp: string;
|
||||
password: string;
|
||||
needPassword: boolean;
|
||||
passwordRequired: boolean;
|
||||
formStarted: boolean;
|
||||
otpSent: boolean;
|
||||
step: 'mobile' | 'otp' | 'processing';
|
||||
loading: boolean;
|
||||
otpData: any;
|
||||
errorMessage: string;
|
||||
resendCountdown: number;
|
||||
}
|
||||
|
||||
export interface OTPBindActions {
|
||||
@@ -38,24 +41,48 @@ export function useOTPBind(
|
||||
mobileLength?: number;
|
||||
additionalParams?: any;
|
||||
initialMobile?: string;
|
||||
passwordBeforeOtp?: boolean;
|
||||
passwordRequiredMsg?: string;
|
||||
resendCooldown?: number;
|
||||
}
|
||||
): [OTPBindState, OTPBindActions] {
|
||||
const [mobile, setMobile] = useState('');
|
||||
const [otp, setOtp] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [needPassword, setNeedPassword] = useState(false);
|
||||
const [passwordRequired, setPasswordRequired] = useState(false);
|
||||
const [formStarted, setFormStarted] = useState(false);
|
||||
const [otpSent, setOtpSent] = useState(false);
|
||||
const [step, setStep] = useState<'mobile' | 'otp' | 'processing'>('mobile');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [otpData, setOtpData] = useState<any>(null);
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
const [resendCountdown, setResendCountdown] = useState(0);
|
||||
|
||||
const { onRequestOTP, onVerifyOTP, onSuccess, onError, isDebug = false } = callbacks;
|
||||
const { otpLength = 6, mobileLength = 10, additionalParams = {}, initialMobile = '' } = config || {};
|
||||
const {
|
||||
otpLength = 6,
|
||||
mobileLength = 10,
|
||||
additionalParams = {},
|
||||
initialMobile = '',
|
||||
passwordBeforeOtp = false,
|
||||
passwordRequiredMsg = 'Please enter your password',
|
||||
resendCooldown = 20,
|
||||
} = config || {};
|
||||
|
||||
useEffect(() => {
|
||||
if (initialMobile) setMobile(initialMobile);
|
||||
}, [initialMobile]);
|
||||
|
||||
useEffect(() => {
|
||||
if (resendCountdown <= 0) return;
|
||||
const timer = setInterval(() => {
|
||||
setResendCountdown(prev => (prev <= 1 ? 0 : prev - 1));
|
||||
}, 1000);
|
||||
return () => clearInterval(timer);
|
||||
}, [resendCountdown]);
|
||||
|
||||
const startResendCooldown = () => setResendCountdown(resendCooldown);
|
||||
|
||||
const clearError = () => setErrorMessage('');
|
||||
|
||||
const log = (...args: any[]) => {
|
||||
@@ -67,6 +94,19 @@ export function useOTPBind(
|
||||
};
|
||||
|
||||
const requestOTP = async () => {
|
||||
const withPassword = passwordBeforeOtp && formStarted && passwordRequired;
|
||||
const isResend = otpSent && formStarted;
|
||||
|
||||
if (isResend && resendCountdown > 0) {
|
||||
return;
|
||||
}
|
||||
if (withPassword && !password.trim()) {
|
||||
const msg = passwordRequiredMsg;
|
||||
setErrorMessage(msg);
|
||||
onError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mobile || mobile.length !== mobileLength) {
|
||||
const msg = 'Invalid mobile number';
|
||||
setErrorMessage(msg);
|
||||
@@ -76,19 +116,31 @@ export function useOTPBind(
|
||||
|
||||
setLoading(true);
|
||||
setErrorMessage('');
|
||||
log('Requesting OTP for:', mobile);
|
||||
log(isResend ? 'Resending OTP for:' : withPassword ? 'Requesting OTP with password for:' : 'Requesting OTP for:', mobile);
|
||||
|
||||
try {
|
||||
const response = await onRequestOTP(walletType, {
|
||||
mobile,
|
||||
...(withPassword ? { password, sessionId: otpData?.sessionId } : {}),
|
||||
...(isResend && !withPassword && otpData ? { ...otpData } : {}),
|
||||
...additionalParams,
|
||||
});
|
||||
log('OTP response:', response);
|
||||
|
||||
if (response.success) {
|
||||
setOtpData(response.data);
|
||||
setNeedPassword(!!response.data?.needPassword);
|
||||
setStep('otp');
|
||||
setFormStarted(true);
|
||||
if (passwordBeforeOtp && response.data?.needPassword && !withPassword && !isResend) {
|
||||
setPasswordRequired(true);
|
||||
setOtpSent(false);
|
||||
} else {
|
||||
setPasswordRequired(!!response.data?.needPassword || withPassword);
|
||||
setOtpSent(true);
|
||||
startResendCooldown();
|
||||
if (!passwordBeforeOtp) {
|
||||
setStep('otp');
|
||||
}
|
||||
}
|
||||
setErrorMessage('');
|
||||
} else {
|
||||
error('OTP request failed:', response.message);
|
||||
@@ -108,13 +160,13 @@ export function useOTPBind(
|
||||
|
||||
const verifyOTP = async () => {
|
||||
if (!otp || otp.length !== otpLength) {
|
||||
const msg = `请输入 ${otpLength} 位验证码`;
|
||||
const msg = `Please enter the ${otpLength}-digit verification code`;
|
||||
setErrorMessage(msg);
|
||||
onError(msg);
|
||||
return;
|
||||
}
|
||||
if (needPassword && !password.trim()) {
|
||||
const msg = '请输入 Amazon 账号密码';
|
||||
if (passwordRequired && !password.trim()) {
|
||||
const msg = passwordRequiredMsg;
|
||||
setErrorMessage(msg);
|
||||
onError(msg);
|
||||
return;
|
||||
@@ -129,7 +181,7 @@ export function useOTPBind(
|
||||
const response = await onVerifyOTP(walletType, {
|
||||
mobile,
|
||||
otp,
|
||||
password: needPassword ? password : undefined,
|
||||
password: passwordRequired ? password : undefined,
|
||||
...additionalParams,
|
||||
...(otpData || {}),
|
||||
});
|
||||
@@ -141,13 +193,13 @@ export function useOTPBind(
|
||||
} else {
|
||||
log('Verify failed:', response.message);
|
||||
const msg = response.message || 'Failed to verify OTP';
|
||||
setStep('otp');
|
||||
setStep(passwordBeforeOtp ? 'mobile' : 'otp');
|
||||
setErrorMessage(msg);
|
||||
}
|
||||
} catch (e) {
|
||||
error('Verify OTP error:', e);
|
||||
const msg = e instanceof Error ? e.message : 'Failed to verify OTP';
|
||||
setStep('otp');
|
||||
setStep(passwordBeforeOtp ? 'mobile' : 'otp');
|
||||
setErrorMessage(msg);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
@@ -158,12 +210,28 @@ export function useOTPBind(
|
||||
setStep('mobile');
|
||||
setOtp('');
|
||||
setPassword('');
|
||||
setNeedPassword(false);
|
||||
setPasswordRequired(false);
|
||||
setFormStarted(false);
|
||||
setOtpSent(false);
|
||||
setOtpData(null);
|
||||
setErrorMessage('');
|
||||
setResendCountdown(0);
|
||||
};
|
||||
|
||||
return [
|
||||
{ mobile, otp, password, needPassword, step, loading, otpData, errorMessage },
|
||||
{
|
||||
mobile,
|
||||
otp,
|
||||
password,
|
||||
passwordRequired,
|
||||
formStarted,
|
||||
otpSent,
|
||||
step,
|
||||
loading,
|
||||
otpData,
|
||||
errorMessage,
|
||||
resendCountdown,
|
||||
},
|
||||
{ setMobile, setOtp, setPassword, requestOTP, verifyOTP, resetToMobile, clearError },
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user