Fix Safari iOS reload loop with static device detection and caching
All checks were successful
Build And Push Image / docker (push) Successful in 3m7s

- Replace reactive device detection with static utilities to prevent
  infinite reload loops on mobile Safari
- Add static-device-detection.ts for one-time device info computation
- Add config-cache.ts for improved configuration loading performance
- Apply mobile Safari viewport and CSS optimizations across auth pages
- Remove reactive dependencies that caused rendering issues on iOS
This commit is contained in:
2025-08-10 15:18:34 +02:00
parent 4e53e7ea10
commit 30136117ce
6 changed files with 797 additions and 204 deletions

View File

@@ -163,8 +163,13 @@ definePageMeta({
middleware: 'guest'
});
// Static CSS classes based on device (no reactive dependencies)
const containerClasses = ref('password-setup-page');
import { getStaticDeviceInfo, getDeviceCssClasses, applyMobileSafariOptimizations, getMobileSafariViewportMeta } from '~/utils/static-device-detection';
// Static device detection - no reactive dependencies
const deviceInfo = getStaticDeviceInfo();
// Static CSS classes - computed once, never reactive
const containerClasses = ref(getDeviceCssClasses('password-setup-page'));
// Reactive state
const loading = ref(false);
@@ -238,7 +243,7 @@ useHead({
name: 'description',
content: 'Set your password to complete your MonacoUSA Portal registration.'
},
{ name: 'viewport', content: 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no' }
{ name: 'viewport', content: getMobileSafariViewportMeta() }
]
});
@@ -306,35 +311,20 @@ const setupPassword = async () => {
}
};
// Component initialization
// Component initialization - Safari iOS reload loop prevention
onMounted(() => {
console.log('[setup-password] Password setup page loaded for:', email.value);
// Static device detection from Nuxt Device Module - no reactive dependencies
const { isMobile, isIos, isSafari } = useDevice();
// Detect mobile Safari specifically
const isMobileSafari = isMobile && isIos && isSafari;
// Apply classes once (static, no reactivity)
const containerClassList = ['password-setup-page'];
if (isMobile) containerClassList.push('is-mobile');
if (isMobileSafari) containerClassList.push('is-mobile-safari');
if (isIos) containerClassList.push('is-ios');
containerClasses.value = containerClassList.join(' ');
// 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) {
errorMessage.value = 'No email address provided. Please use the link from your verification email.';
}
// Prevent auto-zoom on iOS when focusing input fields
if (isIos) {
const metaViewport = document.querySelector('meta[name="viewport"]');
if (metaViewport) {
metaViewport.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no');
}
}
});
</script>

View File

@@ -138,8 +138,13 @@ const error = ref('');
let verificationStarted = false;
let verificationComplete = false;
import { getStaticDeviceInfo, getDeviceCssClasses, applyMobileSafariOptimizations, getMobileSafariViewportMeta } from '~/utils/static-device-detection';
// Static device detection - no reactive dependencies
const deviceInfo = getStaticDeviceInfo();
// Static container classes - compute once to prevent re-renders
let containerClasses = 'verification-page';
let containerClasses = getDeviceCssClasses('verification-page');
// Set page title with mobile viewport optimization
useHead({
@@ -149,7 +154,7 @@ useHead({
name: 'description',
content: 'Verifying your email address for the MonacoUSA Portal.'
},
{ name: 'viewport', content: 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no' }
{ name: 'viewport', content: getMobileSafariViewportMeta() }
]
});
@@ -236,24 +241,15 @@ const retryVerification = () => {
verifyEmail();
};
// Initialize mobile detection and classes AFTER component is stable
// Component initialization - Safari iOS reload loop prevention
onMounted(() => {
// Only set mobile classes once to prevent re-renders
if (typeof window !== 'undefined') {
const userAgent = navigator.userAgent;
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
const isIOS = /iPad|iPhone|iPod/.test(userAgent) && !(window as any).MSStream;
const isSafari = /^((?!chrome|android).)*safari/i.test(userAgent);
const isMobileSafari = isIOS && isSafari;
const classes = ['verification-page'];
if (isMobile) classes.push('is-mobile');
if (isMobileSafari) classes.push('is-mobile-safari');
if (isIOS) classes.push('is-ios');
containerClasses = classes.join(' ');
}
console.log('[auth/verify] Component mounted with token:', token?.substring(0, 20) + '...');
// Apply mobile Safari optimizations early
if (deviceInfo.isMobileSafari) {
applyMobileSafariOptimizations();
console.log('[auth/verify] Mobile Safari optimizations applied');
}
// Start verification process with a small delay to ensure stability
setTimeout(() => {