monacousa-portal/pages/auth/verify-expired.vue

279 lines
7.6 KiB
Vue

<template>
<div class="verification-expired">
<v-container class="fill-height" fluid>
<v-row align="center" justify="center">
<v-col cols="12" sm="8" md="6" lg="4">
<v-card class="elevation-12 rounded-lg">
<v-card-text class="text-center pa-8">
<div class="mb-6">
<v-icon
color="warning"
size="80"
class="mb-4"
>
mdi-clock-alert
</v-icon>
<h1 class="text-h4 font-weight-bold text-warning mb-3">
{{ pageTitle }}
</h1>
<p class="text-body-1 text-medium-emphasis mb-6">
{{ pageDescription }}
</p>
<!-- Information alert -->
<v-alert
type="info"
variant="tonal"
class="mb-6 text-start"
icon="mdi-information"
>
<div class="text-body-2">
<strong>What to do next:</strong>
<ul class="mt-2 pl-4">
<li>Request a new verification email below</li>
<li>Check your spam/junk folder for emails from MonacoUSA</li>
<li>Make sure you're checking the correct email address</li>
</ul>
</div>
</v-alert>
</div>
<!-- Resend verification form -->
<v-form @submit.prevent="resendVerification" :disabled="loading">
<div class="mb-4">
<v-text-field
v-model="email"
label="Email Address"
type="email"
variant="outlined"
prepend-inner-icon="mdi-email"
:rules="emailRules"
:error-messages="emailError"
required
class="mb-3"
/>
</div>
<div class="d-flex flex-column gap-3 mb-6">
<v-btn
type="submit"
color="primary"
size="large"
variant="elevated"
block
:loading="loading"
:disabled="!email || !isValidEmail(email)"
class="text-none"
>
<v-icon start>mdi-email-send</v-icon>
{{ loading ? 'Sending...' : 'Send New Verification Email' }}
</v-btn>
<v-btn
color="secondary"
size="large"
variant="outlined"
block
to="/login"
class="text-none"
>
<v-icon start>mdi-login</v-icon>
Back to Login
</v-btn>
</div>
</v-form>
<!-- Success message -->
<v-alert
v-if="successMessage"
type="success"
variant="tonal"
class="mb-4"
icon="mdi-check"
>
{{ successMessage }}
</v-alert>
<!-- Error message -->
<v-alert
v-if="errorMessage"
type="error"
variant="tonal"
class="mb-4"
icon="mdi-alert"
>
{{ errorMessage }}
</v-alert>
<!-- Additional help -->
<div class="mt-6 pt-4 border-t">
<p class="text-caption text-medium-emphasis mb-2">
Still having trouble? Contact support:
</p>
<v-chip
size="small"
variant="outlined"
prepend-icon="mdi-email"
>
support@monacousa.org
</v-chip>
</div>
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-container>
</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: false,
middleware: 'guest'
});
// Get query parameters
const route = useRoute();
const reason = computed(() => route.query.reason as string || 'expired');
// Reactive data
const email = ref('');
const loading = ref(false);
const successMessage = ref('');
const errorMessage = ref('');
const emailError = ref('');
// Computed properties
const pageTitle = computed(() => {
switch (reason.value) {
case 'used':
return 'Verification Link Already Used';
case 'invalid':
return 'Invalid Verification Link';
default:
return 'Verification Link Expired';
}
});
const pageDescription = computed(() => {
switch (reason.value) {
case 'used':
return 'This verification link has already been used. If you need to verify your email again, please request a new verification link below.';
case 'invalid':
return 'The verification link you clicked is invalid or malformed. Please request a new verification link below.';
default:
return 'Your verification link has expired. Verification links are valid for 24 hours. Please request a new verification link below.';
}
});
// Validation rules
const emailRules = [
(v: string) => !!v || 'Email is required',
(v: string) => isValidEmail(v) || 'Please enter a valid email address'
];
// Helper function
function isValidEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
// Resend verification email
async function resendVerification() {
if (!email.value || !isValidEmail(email.value)) {
return;
}
loading.value = true;
successMessage.value = '';
errorMessage.value = '';
emailError.value = '';
try {
const response = await $fetch('/api/auth/send-verification-email', {
method: 'POST',
body: { email: email.value }
});
successMessage.value = 'A new verification email has been sent! Please check your inbox and spam folder.';
email.value = ''; // Clear the form
} catch (error: any) {
console.error('[verify-expired] Failed to resend verification:', error);
if (error.status === 404) {
emailError.value = 'No account found with this email address.';
} else if (error.status === 429) {
errorMessage.value = 'Please wait a few minutes before requesting another verification email.';
} else {
errorMessage.value = error.data?.message || 'Failed to send verification email. Please try again.';
}
} finally {
loading.value = false;
}
}
// Set page title
useHead({
title: `${pageTitle.value} - MonacoUSA Portal`,
meta: [
{
name: 'description',
content: 'Request a new email verification link for your MonacoUSA Portal account.'
}
]
});
// Track page view
onMounted(() => {
console.log('[verify-expired] Page accessed', { reason: reason.value });
});
</script>
<style scoped>
.verification-expired {
min-height: 100vh;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}
.fill-height {
min-height: 100vh;
}
.border-t {
border-top: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
}
.gap-3 {
gap: 12px;
}
/* Animation for the warning icon */
.v-icon {
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
}
}
/* List styling */
ul {
list-style-type: disc;
}
li {
margin-bottom: 4px;
}
</style>