Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions app/composables/useRegisterValidation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { reactive } from "vue";

export function useRegisterValidation() {
const errors = reactive({
firstname: "",
lastname: "",
email: "",
password: "",
});

function resetErrors() {
errors.firstname = "";
errors.lastname = "";
errors.email = "";
errors.password = "";
}

function validate(form) {
resetErrors();

let valid = true;

// First Name
if (!form.firstname?.trim()) {
errors.firstname = "First name is required.";
valid = false;
}

// Last Name
if (!form.lastname?.trim()) {
errors.lastname = "Last name is required.";
valid = false;
}

// Email
if (!form.email?.trim()) {
errors.email = "Email is required.";
valid = false;
} else if (!/^\S+@\S+\.\S+$/.test(form.email)) {
errors.email = "Enter a valid email.";
valid = false;
}

// Password (single combined rule)
const passwordRegex =
/^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,}$/;

if (!form.password?.trim()) {
errors.password = "Password is required.";
valid = false;
} else if (!passwordRegex.test(form.password)) {
errors.password =
"Password must contain 8 characters, 1 uppercase, 1 lowercase, 1 number, and 1 special character.";
valid = false;
}

return valid;
}

return {
errors,
validate,
resetErrors,
};
}
33 changes: 22 additions & 11 deletions app/pages/account/register.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,29 @@ const password = ref();
const csrfToken = ref();
const component = ref("waiting");
const { kratosUrl } = useRuntimeConfig().public;
const errors = ref({
email: "",
password: "",
firstname: "",
lastname: "",
});
const { errors, validate } = useRegisterValidation();

const registerURLWithFlowQuery = ref("");
console.log(); // this console.log is required because without this, nuxt will give 5xx error as async function is called afterwards

function onSubmit(event) {
const isValid = validate({
firstname: firstname.value,
lastname: lastname.value,
email: email.value,
password: password.value,
});

console.log(isValid);
if (!isValid) {
// Stop form submission
return;
}

// If valid → submit the form manually
event.target.submit();
}

(async () => {
if (process.client) {
const user = getUserData();
Expand Down Expand Up @@ -142,6 +156,7 @@ async function setFlowIDAndCSRFToken() {
method="POST"
:action="registerURLWithFlowQuery"
enctype="application/json"
@submit.prevent="onSubmit"
>
<div class="mb-3">
<label for="firstname" class="form-label">First Name</label>
Expand All @@ -151,7 +166,6 @@ async function setFlowIDAndCSRFToken() {
type="text"
name="traits.name.first"
class="form-control"
required
/>
<div v-if="errors.firstname" class="text-danger">
{{ errors.firstname }}
Expand All @@ -165,7 +179,6 @@ async function setFlowIDAndCSRFToken() {
type="text"
name="traits.name.last"
class="form-control"
required
/>
<div v-if="errors.lastname" class="text-danger">
{{ errors.lastname }}
Expand All @@ -176,10 +189,9 @@ async function setFlowIDAndCSRFToken() {
<input
id="email"
v-model="email"
type="email"
type="text"
name="traits.email"
class="form-control"
required
/>
<div v-if="errors.email" class="text-danger">{{ errors.email }}</div>
</div>
Expand All @@ -191,7 +203,6 @@ async function setFlowIDAndCSRFToken() {
type="password"
name="password"
class="form-control"
required
/>
<div v-if="errors.password" class="text-danger">
{{ errors.password }}
Expand Down