Vue OTP Password Reset

User
<script>
import { ref, inject, onMounted } from "vue";
import { useForm, useField } from "vee-validate";
import { useAuthStore } from "@/stores/auth";
import { useRouter } from "vue-router";
import publicApi from "@/publicApi";
import SingleColumn from "@/layouts/SingleColumn.vue";

const authStore = useAuthStore();
const router = useRouter();
const apiUrl = inject<string>("apiUrl");

const showPassword = ref(false);
const alertMessage = ref("");
const alertColor = ref("");
const step = ref(1);
const loading = ref(false);
const otp = ref("");

const items = ["Forget Password", "Reset Password"];

onMounted(() => {
  if (authStore.isAuthenticated) {
    router.push("/dashboard"); // Redirect if already logged in
  }
});

// **Email Form Validation**
const { handleSubmit, handleReset } = useForm({
  validationSchema: {
    email(value: string) {
      return /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/i.test(value) || "Must be a valid e-mail.";
    },
  },
});
const email = useField("email");


const password = useField("password");
const confirmPassword = useField("confirmPassword");

// **Submit Forgot Password**
const submit = handleSubmit(async (values) => {
  loading.value = true;
  alertMessage.value = "";
  alertColor.value = "";

  try {
    const response = await publicApi.post(`${apiUrl}/send-otp-password`, {
      email: values.email,
    });

    loading.value = false;
    if (response.data.success) {
      alertMessage.value = "OTP has been sent successfully!";
      alertColor.value = "success";
      step.value = 2;
    } else {
      alertMessage.value = response.data.message;
      alertColor.value = "error";
    }
  } catch (error: any) {
    loading.value = false;
    alertMessage.value = error.response?.data.message || "Error sending OTP.";
    alertColor.value = "error";
  }
});
</script>

Forget Password

Submit
Clear

Verify Your Account

We sent a verification code to {{ email.value.value || "your email" }}.
Please check your email and paste the code below.

Verify

Didn't receive the code? Resend

also add password and conform password in second step with otp and

Assistant
Here's the updated Vue 3 + Vee-Validate + Vuetify code with password and confirm password fields in the second step along with OTP verification. The form validation for passwords is also included.
Assistant
{"name": "forgot_password_vue", "type": "code/javascript", "content": "

<script>
nimport { ref, inject, onMounted } from "vue";nimport { useForm, useField } from "vee-validate";nimport { useAuthStore } from "@/stores/auth";nimport { useRouter } from "vue-router";nimport publicApi from "@/publicApi";nimport SingleColumn from "@/layouts/SingleColumn.vue";nnconst authStore = useAuthStore();nconst router = useRouter();nconst apiUrl = inject<string>("apiUrl");nnconst showPassword = ref(false);nconst alertMessage = ref("");nconst alertColor = ref("");nconst step = ref(1);nconst loading = ref(false);nconst otp = ref("");nnconst items = ["Forget Password", "Reset Password"];nnonMounted(() => {n  if (authStore.isAuthenticated) {n    router.push("/dashboard"); // Redirect if already logged inn  }n});nn// **Email Form Validation**nconst { handleSubmit, handleReset } = useForm({n  validationSchema: {n    email(value: string) {n      return /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/i.test(value) || "Must be a valid e-mail.";n    },n  },n});nconst email = useField("email");nn// **Password Reset Form Validation**nconst { handleSubmit: handleResetSubmit } = useForm({n  validationSchema: {n    password(value: string) {n      return value.length >= 6 || "Password must be at least 6 characters long.";n    },n    confirmPassword(value: string) {n      return value === password.value.value || "Passwords do not match.";n    },n    otp(value: string) {n      return value.length === 6 || "OTP must be 6 digits.";n    },n  },n});nnconst password = useField("password");nconst confirmPassword = useField("confirmPassword");nconst otpField = useField("otp");nn// **Submit Forgot Password**nconst submit = handleSubmit(async (values) => {n  loading.value = true;n  alertMessage.value = "";n  alertColor.value = "";nn  try {n    const response = await publicApi.post(`${apiUrl}/send-otp-password`, {n      email: values.email,n    });nn    loading.value = false;n    if (response.data.success) {n      alertMessage.value = "OTP has been sent successfully!";n      alertColor.value = "success";n      step.value = 2;n    } else {n      alertMessage.value = response.data.message;n      alertColor.value = "error";n    }n  } catch (error: any) {n    loading.value = false;n    alertMessage.value = error.response?.data.message || "Error sending OTP.";n    alertColor.value = "error";n  }n});nn// **Submit OTP and Reset Password**nconst resetPassword = handleResetSubmit(async (values) => {n  loading.value = true;n  alertMessage.value = "";n  alertColor.value = "";nn  try {n    const response = await publicApi.post(`${apiUrl}/reset-password`, {n      email: email.value.value,n      otp: values.otp,n      password: values.password,n      confirmPassword: values.confirmPassword,n    });nn    loading.value = false;n    if (response.data.success) {n      alertMessage.value = "Password reset successfully!";n      alertColor.value = "success";n      router.push("/login");n    } else {n      alertMessage.value = response.data.message;n      alertColor.value = "error";n    }n  } catch (error: any) {n    loading.value = false;n    alertMessage.value = error.response?.data.message || "Error resetting password.";n    alertColor.value = "error";n  }n});n
</script>

nnn n nn n n n n Forget Passwordnn n n nn Submit n Clear n n n n nn n n n Verify Your Accountnn n We sent a verification code to {{ email.value.value || "your email" }}. n Please check your email and paste the code below.n nn n n n {{ otpField.errorMessage.value }}n n nn nn n Verifyn n n n n n nn n n"}

Assistant
This Vue 3 + Vee-Validate + Vuetify setup includes:
– Step 1: Email submission for OTP
– Step 2: OTP verification along with password reset fields
– Validation for email, OTP, and password fields
– Dynamic alert messages and loading states

Let me know if you need any modifications! 🚀

User
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'length')
at password (ForgetPasswordView.vue:43:20)
Assistant
The error **"Cannot read properties of undefined (reading 'length')"** in `ForgetPasswordView.vue:43:20` suggests that `password` is being accessed before it's properly initialized. Since you're using Vee-Validate's `useField`, the issue is likely due to how you're trying to access the value.

### ✅ Fix:
Make sure you're properly handling `password` and `confirmPassword` fields.

#### **1️⃣ Correct way to initialize fields:**
Modify how you're defining `password` and `confirmPassword` using `useField`. Update your script to ensure that they are initialized properly:

const password = useField<string>("password");
const confirmPassword = useField<string>("confirmPassword");

Then, update your bindings:

<v-text-field
  v-model="password.value.value"
  :error-messages="password.errorMessage.value"
  label="Password"
></v-text-field>

<v-text-field
  v-model="confirmPassword.value.value"
  :error-messages="confirmPassword.errorMessage.value"
  label="Confirm Password"
></v-text-field>

#### **2️⃣ Check for `undefined` before using `.length`**
If you’re using `.length` on `password.value.value`, make sure to check if it's defined:

if (password.value.value && password.value.value.length < 8) {
  alertMessage.value = "Password must be at least 8 characters.";
}

#### **3️⃣ Ensure you have the validation schema for password**
If you're using `validationSchema`, add password validation:

const { handleSubmit } = useForm({
  validationSchema: {
    email(value: string) {
      return /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/i.test(value) || "Must be a valid email.";
    },
    password(value: string) {
      return value?.length >= 8 || "Password must be at least 8 characters.";
    },
    confirmPassword(value: string) {
      return value === password.value.value || "Passwords must match.";
    }
  }
});

This should resolve the **TypeError**. Let me know if you need more help! 🚀

Leave a Comment

Your email address will not be published. Required fields are marked *