307 lines
8.0 KiB
Vue
307 lines
8.0 KiB
Vue
<script setup>
|
||
import { ref } from 'vue';
|
||
import { forgetPassword, sendCodeToEmail } from './api';
|
||
|
||
// Password reset related variables
|
||
const email = ref('');
|
||
const newPassword = ref('');
|
||
const confirmPassword = ref('');
|
||
const verificationCode = ref('');
|
||
const codeBtnText = ref('Get Code');
|
||
const codeBtnDisabled = ref(false);
|
||
let countdownTimer = null;
|
||
|
||
// Email format validation
|
||
const validateEmail = (email) => {
|
||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||
return emailRegex.test(email);
|
||
};
|
||
|
||
// Get verification code
|
||
const getVerificationCode = async () => {
|
||
if (!email.value) {
|
||
uni.showToast({
|
||
title: 'Please enter email',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (!validateEmail(email.value)) {
|
||
uni.showToast({
|
||
title: 'Please enter a valid email',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
// Send verification code
|
||
try {
|
||
uni.showLoading({
|
||
title: 'Sending...',
|
||
mask: true,
|
||
});
|
||
|
||
const params = {
|
||
email: email.value,
|
||
register: false // Not for registration, but for password reset
|
||
};
|
||
|
||
const res = await sendCodeToEmail(params);
|
||
|
||
if (res && res.code === 0) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: 'Verification code sent',
|
||
icon: 'success',
|
||
});
|
||
|
||
// Start countdown
|
||
let timeLeft = 60;
|
||
codeBtnDisabled.value = true;
|
||
codeBtnText.value = `${timeLeft}s`;
|
||
|
||
countdownTimer = setInterval(() => {
|
||
timeLeft--;
|
||
codeBtnText.value = `${timeLeft}s`;
|
||
|
||
if (timeLeft <= 0) {
|
||
clearInterval(countdownTimer);
|
||
codeBtnText.value = 'Resend';
|
||
codeBtnDisabled.value = false;
|
||
}
|
||
}, 1000);
|
||
} else {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: res.msg || 'Send failed',
|
||
icon: 'error',
|
||
});
|
||
}
|
||
} catch (error) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: error.message || 'Send failed, please try again',
|
||
icon: 'error',
|
||
});
|
||
}
|
||
};
|
||
|
||
// Submit password reset
|
||
const onResetPassword = async () => {
|
||
if (!email.value) {
|
||
uni.showToast({
|
||
title: 'Please enter email',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (!validateEmail(email.value)) {
|
||
uni.showToast({
|
||
title: 'Please enter a valid email',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (!verificationCode.value) {
|
||
uni.showToast({
|
||
title: 'Please enter verification code',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (!newPassword.value) {
|
||
uni.showToast({
|
||
title: 'Please enter new password',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (newPassword.value !== confirmPassword.value) {
|
||
uni.showToast({
|
||
title: 'Passwords do not match',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (newPassword.value.length < 6) {
|
||
uni.showToast({
|
||
title: 'Password must be at least 6 characters',
|
||
icon: 'none',
|
||
});
|
||
return;
|
||
}
|
||
|
||
try {
|
||
uni.showLoading({
|
||
title: 'Resetting password...',
|
||
mask: true,
|
||
});
|
||
|
||
// Call password reset API
|
||
const resetParams = {
|
||
email: email.value,
|
||
verificationCode: verificationCode.value,
|
||
password: newPassword.value,
|
||
confirmPassword: confirmPassword.value
|
||
};
|
||
|
||
const res = await forgetPassword(resetParams);
|
||
|
||
if (res && res.code === 0) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: 'Password reset successful',
|
||
icon: 'success',
|
||
});
|
||
|
||
// Navigate back to login page after success
|
||
setTimeout(() => {
|
||
uni.navigateBack();
|
||
}, 1500);
|
||
} else {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: res.msg || 'Password reset failed',
|
||
icon: 'error',
|
||
});
|
||
}
|
||
} catch (error) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: error.message || 'Password reset failed, please try again',
|
||
icon: 'error',
|
||
});
|
||
}
|
||
};
|
||
|
||
// Clear input field
|
||
const clearInput = (type) => {
|
||
if (type === 'email') {
|
||
email.value = '';
|
||
} else if (type === 'newPassword') {
|
||
newPassword.value = '';
|
||
} else if (type === 'confirmPassword') {
|
||
confirmPassword.value = '';
|
||
} else if (type === 'verificationCode') {
|
||
verificationCode.value = '';
|
||
}
|
||
};
|
||
|
||
// Go back to login page
|
||
const goLoginPage = function() {
|
||
uni.navigateTo({
|
||
url: '/pages/login/index'
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<view class="p-4 min-h-screen bg-white flex flex-col justify-center">
|
||
<!-- Title -->
|
||
<view class="mb-12 text-center">
|
||
<image src="/static/tabbar/find.png" class="w-20 h-20 mb-8" mode="aspectFit"></image>
|
||
<text class="block text-3xl font-bold text-gray-800 mb-4">RESET PASSWORD</text>
|
||
<text class="text-sm text-gray-500">Enter your email and new password</text>
|
||
</view>
|
||
|
||
<!-- Email input -->
|
||
<view class="mb-6">
|
||
<view class=" flex items-center h-12 bg-gray-100 rounded-lg px-6 gap-1 border border-solid border-round-theme">
|
||
<u-icon name="email" class="h-10" color="black" bold="true"></u-icon>
|
||
<input
|
||
class="w-full text-base text-gray-800 bg-transparent"
|
||
type="email"
|
||
placeholder="Email Address"
|
||
v-model="email"
|
||
/>
|
||
<view
|
||
v-if="email"
|
||
class="absolute right-6 w-8 h-8 flex items-center justify-center bg-gray-400 rounded-full text-black font-bold"
|
||
@tap="clearInput('email')"
|
||
>
|
||
×
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- Verification code input -->
|
||
<view class="mb-6 relative">
|
||
<view class=" flex items-center h-12 bg-gray-100 rounded-lg px-6 gap-1 border border-solid border-round-theme">
|
||
<u-icon name="chat" class="h-10" color="black" bold="true"></u-icon>
|
||
<input
|
||
class="w-full text-base text-gray-800 bg-transparent pr-32"
|
||
type="text"
|
||
placeholder="Verification Code"
|
||
v-model="verificationCode"
|
||
/>
|
||
</view>
|
||
<button
|
||
class="absolute right-2 top-1/2 transform -translate-y-1/2 h-10 px-4 bg-theme text-white text-xs rounded-full disabled:bg-gray-400 disabled:text-gray-300 flex items-center justify-center"
|
||
:disabled="codeBtnDisabled"
|
||
@tap="getVerificationCode"
|
||
>
|
||
{{ codeBtnText }}
|
||
</button>
|
||
</view>
|
||
|
||
<!-- New password input -->
|
||
<view class="mb-6">
|
||
<view class=" flex items-center h-12 bg-gray-100 rounded-lg px-6 gap-1 border border-solid border-round-theme">
|
||
<u-icon name="lock" class="h-10" color="black" bold="true"></u-icon>
|
||
<input
|
||
class="w-full text-base text-gray-800 bg-transparent"
|
||
type="password"
|
||
placeholder="New Password"
|
||
v-model="newPassword"
|
||
/>
|
||
<view
|
||
v-if="newPassword"
|
||
class="absolute right-6 w-8 h-8 flex items-center justify-center bg-gray-400 rounded-full text-white font-bold"
|
||
@tap="clearInput('newPassword')"
|
||
>
|
||
×
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- Confirm password input -->
|
||
<view class="mb-8">
|
||
<view class=" flex items-center h-12 bg-gray-100 rounded-lg px-6 gap-1 border border-solid border-round-theme">
|
||
<u-icon name="lock" class="h-10" color="black" bold="true"></u-icon>
|
||
<input
|
||
class="w-full text-base text-gray-800 bg-transparent"
|
||
type="password"
|
||
placeholder="Confirm Password"
|
||
v-model="confirmPassword"
|
||
/>
|
||
<view
|
||
v-if="confirmPassword"
|
||
class="absolute right-6 w-8 h-8 flex items-center justify-center bg-gray-400 rounded-full text-white font-bold"
|
||
@tap="clearInput('confirmPassword')"
|
||
>
|
||
×
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- Reset password button -->
|
||
<view
|
||
class="w-full h-12 bg-theme rounded-lg text-white text-xl flex items-center justify-center"
|
||
@click="onResetPassword"
|
||
>
|
||
<text>RESET PASSWORD</text>
|
||
</view>
|
||
|
||
<!-- Back to login link -->
|
||
<view class="flex justify-center items-center my-8 text-gray-500 text-sm">
|
||
<text>Remember your password?</text>
|
||
<text class="text-green-500 ml-2" @click="goLoginPage">Back to Sign in</text>
|
||
</view>
|
||
</view>
|
||
</template> |