Replace date-fns with native date formatting and remove unused code
All checks were successful
Build And Push Image / docker (push) Successful in 1m34s

Remove date-fns dependency in favor of native Intl.DateTimeFormat APIs, clean up obsolete admin endpoints, utility files, and archived documentation. Consolidate docs structure and remove unused plugins.
This commit is contained in:
2025-08-14 15:08:40 +02:00
parent 676bbc04f6
commit 503d68cd2d
40 changed files with 19225 additions and 5851 deletions

View File

@@ -179,13 +179,26 @@ definePageMeta({
middleware: 'guest'
});
import { getStaticDeviceInfo, getDeviceCssClasses, applyMobileSafariOptimizations, getMobileSafariViewportMeta } from '~/utils/static-device-detection';
// Device detection
const isMobile = ref(false);
const isMobileSafari = ref(false);
// Static device detection - no reactive dependencies
const deviceInfo = getStaticDeviceInfo();
// Initialize device detection on mount
onMounted(() => {
if (process.client) {
const userAgent = navigator.userAgent;
isMobile.value = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent) || window.innerWidth <= 768;
isMobileSafari.value = /iPhone|iPad|iPod/i.test(userAgent) && /Safari/i.test(userAgent);
}
});
// Static CSS classes - computed once, never reactive
const containerClasses = ref(getDeviceCssClasses('password-setup-page'));
// CSS classes based on device detection
const containerClasses = computed(() => {
const classes = ['password-setup-page'];
if (isMobile.value) classes.push('is-mobile');
if (isMobileSafari.value) classes.push('is-mobile-safari', 'performance-mode');
return classes.join(' ');
});
// Reactive state
const loading = ref(false);
@@ -265,7 +278,7 @@ useHead({
name: 'description',
content: 'Set your password to complete your MonacoUSA Portal registration.'
},
{ name: 'viewport', content: getMobileSafariViewportMeta() }
{ name: 'viewport', content: 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover' }
]
});
@@ -333,24 +346,9 @@ const setupPassword = async () => {
}
};
// Component initialization - Safari iOS reload loop prevention
// Component initialization
onMounted(async () => {
console.log('[setup-password] Password setup page loaded for:', email.value);
// CRITICAL: Check reload loop prevention first
const { initReloadLoopPrevention } = await import('~/utils/reload-loop-prevention');
const canLoad = initReloadLoopPrevention('setup-password-page');
if (!canLoad) {
console.error('[setup-password] Page load blocked by reload loop prevention system');
return; // Stop all initialization if blocked
}
// Apply mobile Safari optimizations early
if (deviceInfo.isMobileSafari) {
applyMobileSafariOptimizations();
console.log('[setup-password] Mobile Safari optimizations applied');
}
// Check if we have required parameters
if (!email.value) {

View File

@@ -91,26 +91,36 @@
</template>
<script setup lang="ts">
import { getStaticDeviceInfo, getDeviceCssClasses, applyMobileSafariOptimizations, getMobileSafariViewportMeta } from '~/utils/static-device-detection';
definePageMeta({
layout: false,
middleware: 'guest'
});
// Get query parameters - static to prevent reload loops
// Get query parameters
const route = useRoute();
const email = ref((route.query.email as string) || '');
const partialWarning = ref(route.query.warning === 'partial');
// Static device detection - no reactive dependencies
const deviceInfo = getStaticDeviceInfo();
// Simple device detection
const isMobile = ref(false);
const isMobileSafari = ref(false);
// Static CSS classes - computed once, never reactive
const containerClasses = ref(getDeviceCssClasses('verification-success'));
// Initialize device detection on mount
onMounted(() => {
if (process.client) {
const userAgent = navigator.userAgent;
isMobile.value = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent) || window.innerWidth <= 768;
isMobileSafari.value = /iPhone|iPad|iPod/i.test(userAgent) && /Safari/i.test(userAgent);
}
});
// Static setup password URL - no reactive dependencies
const setupPasswordUrl = 'https://auth.monacousa.org/realms/monacousa/account/';
// CSS classes based on device detection
const containerClasses = computed(() => {
const classes = ['verification-success'];
if (isMobile.value) classes.push('is-mobile');
if (isMobileSafari.value) classes.push('is-mobile-safari');
return classes.join(' ');
});
// Set page title with mobile viewport optimization
useHead({
@@ -120,7 +130,10 @@ useHead({
name: 'description',
content: 'Your email has been successfully verified. You can now log in to the MonacoUSA Portal.'
},
{ name: 'viewport', content: getMobileSafariViewportMeta() }
{
name: 'viewport',
content: 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover'
}
]
});
@@ -134,19 +147,12 @@ const goToPasswordSetup = () => {
});
};
// Track verification - Safari iOS reload loop prevention
// Track verification
onMounted(() => {
console.log('[verify-success] Email verification completed', {
email: email.value,
partialWarning: partialWarning.value,
setupPasswordUrl: setupPasswordUrl
partialWarning: partialWarning.value
});
// Apply mobile Safari optimizations early
if (deviceInfo.isMobileSafari) {
applyMobileSafariOptimizations();
console.log('[verify-success] Mobile Safari optimizations applied');
}
});
</script>

View File

@@ -54,17 +54,14 @@
Verifying Your Email
</h1>
<p class="text-body-1 text-medium-emphasis" v-if="verificationState">
<p class="text-body-1 text-medium-emphasis">
{{ statusMessage || 'Please wait while we verify your email address...' }}
</p>
<p class="text-body-1 text-medium-emphasis" v-else>
Please wait while we verify your email address...
</p>
<!-- Attempt Counter -->
<div v-if="verificationState && verificationState.attempts > 1" class="mt-2">
<div v-if="attemptCount > 1" class="mt-2">
<v-chip size="small" color="primary" variant="outlined">
Attempt {{ verificationState.attempts }}/{{ verificationState.maxAttempts }}
Attempt {{ attemptCount }}/{{ maxAttempts }}
</v-chip>
</div>
</div>
@@ -88,7 +85,7 @@
</p>
<!-- Circuit Breaker Status -->
<div v-if="verificationState && statusMessage" class="mb-4">
<div v-if="statusMessage" class="mb-4">
<v-alert
type="info"
variant="tonal"
@@ -210,18 +207,6 @@ definePageMeta({
middleware: 'guest'
});
import { getStaticDeviceInfo, getDeviceCssClasses, applyMobileSafariOptimizations, getMobileSafariViewportMeta } from '~/utils/static-device-detection';
import {
getVerificationState,
initVerificationState,
recordAttempt,
shouldBlockVerification,
getStatusMessage,
navigateWithFallback,
getMobileNavigationDelay,
type VerificationAttempt
} from '~/utils/verification-state';
// Get route and token immediately
const route = useRoute();
const token = route.query.token as string || '';
@@ -231,17 +216,33 @@ const verifying = ref(false);
const error = ref('');
const partialSuccess = ref(false);
// Verification state management
const verificationState = ref<VerificationAttempt | null>(null);
// Simple retry logic
const isBlocked = ref(false);
const canRetry = ref(true);
const statusMessage = ref('');
const attemptCount = ref(0);
const maxAttempts = 3;
// Static device detection - no reactive dependencies
const deviceInfo = getStaticDeviceInfo();
// Device detection
const isMobile = ref(false);
const isMobileSafari = ref(false);
// Static container classes - must be reactive for template
const containerClasses = ref(getDeviceCssClasses('verification-page'));
// Initialize device detection on mount
onMounted(() => {
if (process.client) {
const userAgent = navigator.userAgent;
isMobile.value = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent) || window.innerWidth <= 768;
isMobileSafari.value = /iPhone|iPad|iPod/i.test(userAgent) && /Safari/i.test(userAgent);
}
});
// CSS classes based on device detection
const containerClasses = computed(() => {
const classes = ['verification-page'];
if (isMobile.value) classes.push('is-mobile');
if (isMobileSafari.value) classes.push('is-mobile-safari', 'performance-mode');
return classes.join(' ');
});
// Set page title with mobile viewport optimization
useHead({
@@ -251,49 +252,43 @@ useHead({
name: 'description',
content: 'Verifying your email address for the MonacoUSA Portal.'
},
{ name: 'viewport', content: getMobileSafariViewportMeta() }
{
name: 'viewport',
content: 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover'
}
]
});
// Update UI state based on verification state
// Simple verification logic
const updateUIState = () => {
if (!verificationState.value) return;
statusMessage.value = getStatusMessage(verificationState.value);
isBlocked.value = shouldBlockVerification(token);
canRetry.value = verificationState.value.attempts < verificationState.value.maxAttempts && !isBlocked.value;
console.log('[auth/verify] UI State updated:', {
status: verificationState.value.status,
attempts: verificationState.value.attempts,
isBlocked: isBlocked.value,
canRetry: canRetry.value
});
if (attemptCount.value >= maxAttempts) {
isBlocked.value = true;
canRetry.value = false;
statusMessage.value = `Too many failed attempts. Please wait before trying again.`;
} else {
canRetry.value = attemptCount.value < maxAttempts;
}
};
// Verify email function with circuit breaker
// Verify email function
const verifyEmail = async () => {
if (!token) {
error.value = 'No verification token provided. Please check your email for the correct verification link.';
return;
}
// Initialize or get existing verification state
verificationState.value = initVerificationState(token);
updateUIState();
// Check if verification should be blocked
if (shouldBlockVerification(token)) {
console.log('[auth/verify] Verification blocked by circuit breaker');
if (attemptCount.value >= maxAttempts) {
isBlocked.value = true;
return;
}
console.log(`[auth/verify] Starting verification attempt ${verificationState.value.attempts + 1}/${verificationState.value.maxAttempts}`);
try {
verifying.value = true;
error.value = '';
partialSuccess.value = false;
attemptCount.value++;
console.log(`[auth/verify] Starting verification attempt ${attemptCount.value}/${maxAttempts}`);
// Call the API endpoint to verify the email
const response = await $fetch(`/api/auth/verify-email?token=${token}`, {
@@ -302,10 +297,6 @@ const verifyEmail = async () => {
console.log('[auth/verify] Email verification successful:', response);
// Record successful attempt
verificationState.value = recordAttempt(token, true);
updateUIState();
// Extract response data
const email = response?.data?.email || '';
const isPartialSuccess = response?.data?.partialSuccess || false;
@@ -335,26 +326,22 @@ const verifyEmail = async () => {
redirectUrl += '?' + queryParams.join('&');
}
// Use progressive navigation with mobile delay
const navigationDelay = getMobileNavigationDelay();
console.log(`[auth/verify] Navigating to success page with ${navigationDelay}ms delay`);
// Navigate to success page
console.log(`[auth/verify] Navigating to success page`);
setTimeout(async () => {
try {
await navigateWithFallback(redirectUrl, { replace: true });
await navigateTo(redirectUrl, { replace: true });
} catch (navError) {
console.error('[auth/verify] Navigation failed:', navError);
// Final fallback - direct window location
window.location.replace(redirectUrl);
}
}, navigationDelay);
}, 500);
} catch (err: any) {
console.error('[auth/verify] Email verification failed:', err);
// Record failed attempt
const errorMessage = err.data?.message || err.message || 'Email verification failed';
verificationState.value = recordAttempt(token, false, errorMessage);
updateUIState();
// Set error message based on status code
@@ -367,7 +354,7 @@ const verifyEmail = async () => {
} else if (err.statusCode === 404) {
error.value = 'User not found. The verification token may be invalid.';
} else {
error.value = errorMessage;
error.value = err.data?.message || err.message || 'Email verification failed';
}
verifying.value = false;
@@ -385,40 +372,15 @@ const retryVerification = async () => {
await verifyEmail();
};
// Component initialization - Safari iOS reload loop prevention
// Component initialization
onMounted(async () => {
console.log('[auth/verify] Component mounted with token:', token?.substring(0, 20) + '...');
// CRITICAL: Check reload loop prevention first
const { initReloadLoopPrevention } = await import('~/utils/reload-loop-prevention');
const canLoad = initReloadLoopPrevention('verify-page');
if (!canLoad) {
console.error('[auth/verify] Page load blocked by reload loop prevention system');
return; // Stop all initialization if blocked
}
// Apply mobile Safari optimizations early
if (deviceInfo.isMobileSafari) {
applyMobileSafariOptimizations();
console.log('[auth/verify] Mobile Safari optimizations applied');
}
// Check if token exists
if (!token) {
error.value = 'No verification token provided. Please check your email for the correct verification link.';
return;
}
// Initialize verification state
verificationState.value = initVerificationState(token, 3);
updateUIState();
// Check if verification is blocked before starting
if (shouldBlockVerification(token)) {
console.log('[auth/verify] Verification blocked by circuit breaker on mount');
return;
}
// Start verification process with a small delay to ensure stability
setTimeout(() => {