Both the organizer app and portal forgot-password pages now validate the email field before submission: required + email format check. Backend already validated this, but empty or malformed emails were being sent to the API unnecessarily. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
142 lines
3.8 KiB
Vue
142 lines
3.8 KiB
Vue
<script setup lang="ts">
|
|
import authV1BottomShape from '@images/svg/auth-v1-bottom-shape.svg?raw'
|
|
import authV1TopShape from '@images/svg/auth-v1-top-shape.svg?raw'
|
|
import { VNodeRenderer } from '@layouts/components/VNodeRenderer'
|
|
import { themeConfig } from '@themeConfig'
|
|
import { requiredValidator, emailValidator } from '@core/utils/validators'
|
|
import { VForm } from 'vuetify/components/VForm'
|
|
import { apiClient } from '@/lib/axios'
|
|
|
|
definePage({
|
|
name: 'forgot-password',
|
|
meta: {
|
|
layout: 'blank',
|
|
requiresAuth: false,
|
|
},
|
|
})
|
|
|
|
const refVForm = ref<VForm>()
|
|
const email = ref('')
|
|
const isSubmitting = ref(false)
|
|
const done = ref(false)
|
|
|
|
async function onSubmit(): Promise<void> {
|
|
const { valid } = await refVForm.value!.validate()
|
|
if (!valid) return
|
|
|
|
isSubmitting.value = true
|
|
try {
|
|
await apiClient.post('/auth/forgot-password', { email: email.value.trim(), app: 'portal' })
|
|
}
|
|
catch {
|
|
// Always show generic success (no email enumeration)
|
|
}
|
|
finally {
|
|
isSubmitting.value = false
|
|
done.value = true
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="auth-wrapper d-flex align-center justify-center pa-4">
|
|
<div class="position-relative my-sm-16">
|
|
<VNodeRenderer
|
|
:nodes="h('div', { innerHTML: authV1TopShape })"
|
|
class="text-primary auth-v1-top-shape d-none d-sm-block"
|
|
/>
|
|
|
|
<VNodeRenderer
|
|
:nodes="h('div', { innerHTML: authV1BottomShape })"
|
|
class="text-primary auth-v1-bottom-shape d-none d-sm-block"
|
|
/>
|
|
|
|
<VCard
|
|
class="auth-card"
|
|
max-width="460"
|
|
:class="$vuetify.display.smAndUp ? 'pa-6' : 'pa-0'"
|
|
>
|
|
<VCardItem class="justify-center">
|
|
<VCardTitle>
|
|
<RouterLink to="/">
|
|
<div class="app-logo">
|
|
<VNodeRenderer :nodes="themeConfig.app.logo" />
|
|
<h1 class="app-logo-title">
|
|
{{ themeConfig.app.title }}
|
|
</h1>
|
|
</div>
|
|
</RouterLink>
|
|
</VCardTitle>
|
|
</VCardItem>
|
|
|
|
<VCardText>
|
|
<h4 class="text-h4 mb-1">
|
|
Wachtwoord vergeten?
|
|
</h4>
|
|
<p class="mb-0">
|
|
Vul je e-mailadres in en we sturen je een link om je wachtwoord te herstellen.
|
|
</p>
|
|
</VCardText>
|
|
|
|
<VCardText>
|
|
<VAlert
|
|
v-if="done"
|
|
type="success"
|
|
variant="tonal"
|
|
class="mb-4"
|
|
>
|
|
Als dit e-mailadres bij ons bekend is, ontvang je een link om je wachtwoord te resetten.
|
|
</VAlert>
|
|
|
|
<VForm
|
|
v-if="!done"
|
|
ref="refVForm"
|
|
@submit.prevent="onSubmit"
|
|
>
|
|
<VRow>
|
|
<VCol cols="12">
|
|
<AppTextField
|
|
v-model="email"
|
|
autofocus
|
|
label="E-mailadres"
|
|
type="email"
|
|
placeholder="je@email.nl"
|
|
:rules="[requiredValidator, emailValidator]"
|
|
/>
|
|
</VCol>
|
|
|
|
<VCol cols="12">
|
|
<VBtn
|
|
block
|
|
type="submit"
|
|
:loading="isSubmitting"
|
|
>
|
|
Verstuur herstelmail
|
|
</VBtn>
|
|
</VCol>
|
|
|
|
<VCol cols="12">
|
|
<RouterLink
|
|
class="d-flex align-center justify-center"
|
|
to="/login"
|
|
>
|
|
<VIcon
|
|
icon="tabler-chevron-left"
|
|
size="20"
|
|
class="me-1 flip-in-rtl"
|
|
/>
|
|
<span>Terug naar inloggen</span>
|
|
</RouterLink>
|
|
</VCol>
|
|
</VRow>
|
|
</VForm>
|
|
</VCardText>
|
|
</VCard>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss">
|
|
@use "@core/scss/template/pages/page-auth";
|
|
</style>
|