diff --git a/app/pages/accept-invite.vue b/app/pages/accept-invite.vue index e5e0f04..ba6b655 100644 --- a/app/pages/accept-invite.vue +++ b/app/pages/accept-invite.vue @@ -32,7 +32,10 @@ class="form-input" type="text" required + @blur="validateName" + @input="if (fieldErrors.name) fieldErrors.name = ''" > +

{{ fieldErrors.name }}

@@ -201,6 +204,13 @@ const form = reactive({ agreedToGuidelines: false, }); +// Inline blur validation (UI feedback only — does not block submission) +const fieldErrors = reactive({ name: "" }); + +const validateName = () => { + fieldErrors.name = form.name.trim() ? "" : "Please enter your name."; +}; + const isFormValid = computed(() => { return ( form.name && @@ -447,6 +457,12 @@ textarea.form-input { line-height: 1.4; } +.field-error { + font-size: 11px; + color: var(--ember); + margin-top: 4px; +} + /* ---- CIRCLE RADIOS ---- */ .circle-radios { display: grid; diff --git a/app/pages/join.vue b/app/pages/join.vue index eb33733..6a1df14 100644 --- a/app/pages/join.vue +++ b/app/pages/join.vue @@ -128,7 +128,10 @@ class="form-input" type="text" required + @blur="validateName" + @input="if (fieldErrors.name) fieldErrors.name = ''" > +

{{ fieldErrors.name }}

@@ -139,7 +142,10 @@ type="email" placeholder="you@example.com" required + @blur="validateEmail" + @input="if (fieldErrors.email) fieldErrors.email = ''" > +

{{ fieldErrors.email }}

@@ -346,6 +352,23 @@ const errorMessage = ref(""); const successMessage = ref(""); const cadence = ref("monthly"); // 'monthly' | 'annual' +// Inline blur validation (UI feedback only — does not block submission) +const fieldErrors = reactive({ name: "", email: "" }); + +const validateName = () => { + fieldErrors.name = form.name.trim() ? "" : "Please enter your name."; +}; + +const validateEmail = () => { + const value = form.email.trim(); + if (!value) { + fieldErrors.email = ""; + return; + } + const ok = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value); + fieldErrors.email = ok ? "" : "Please enter a valid email address."; +}; + // Flow overlay state — drives the post-submit full-viewport UI. // 'idle' = overlay hidden; user is editing the form. // 'creating-customer' | 'opening-payment' | 'processing-payment' @@ -762,6 +785,11 @@ onUnmounted(() => { .form-input::placeholder { color: var(--text-faint); } +.field-error { + font-size: 11px; + color: var(--ember); + margin-top: 4px; +} /* ---- CIRCLE RADIOS ---- */ .circle-radios { diff --git a/app/pages/member/account.vue b/app/pages/member/account.vue index 370f622..048fed9 100644 --- a/app/pages/member/account.vue +++ b/app/pages/member/account.vue @@ -173,9 +173,12 @@ type="email" placeholder="you@example.com" autofocus + @blur="validateNewEmail" + @input="if (fieldErrors.email) fieldErrors.email = ''" @keydown.enter="handleUpdateEmail" @keydown.escape="cancelEmailEdit" > +

{{ fieldErrors.email }}