diff --git a/nuxt4/app/components/UserProfileForm.vue b/nuxt4/app/components/UserProfileForm.vue index 669b9ad..b6435cc 100644 --- a/nuxt4/app/components/UserProfileForm.vue +++ b/nuxt4/app/components/UserProfileForm.vue @@ -10,7 +10,7 @@ color="neutral" variant="ghost" icon="i-heroicons-x-mark" - @click="$emit('close')" + @click="handleClose" > Cancelar @@ -262,7 +262,7 @@ color="neutral" variant="ghost" size="lg" - @click="$emit('close')" + @click="handleClose" :disabled="isSubmitting" > Cancelar @@ -311,6 +311,63 @@ + + + + + + + + ¿Estás seguro de salir? + + + + + Tienes cambios pendientes en: + + + + + {{ field }} + + + + + + Estos cambios quedarán guardados localmente en tu navegador, + pero NO han sido enviados al servidor. + + + + + + Para guardar definitivamente, haz clic en "Guardar cambios". + + + + + + + + Continuar editando + + + + Salir sin guardar + + + + + @@ -319,12 +376,13 @@ const { user } = useAuthentik() const toast = useToast() // Emits -defineEmits(['close']) +const emit = defineEmits(['close']) // Estado del formulario const isSubmitting = ref(false) const isUploading = ref(false) const showCamera = ref(false) +const showExitConfirm = ref(false) // Cookie para persistir cambios del formulario const formCookie = useCookie>('profile-form-draft', { @@ -536,6 +594,23 @@ const handleAvatarCapture = async (imageBlob: Blob) => { } } +// Manejar intento de cerrar formulario +const handleClose = () => { + if (hasChanges.value) { + // Si hay cambios, mostrar modal de confirmación + showExitConfirm.value = true + } else { + // Si no hay cambios, cerrar directamente + emit('close') + } +} + +// Confirmar salida sin guardar +const confirmExit = () => { + showExitConfirm.value = false + emit('close') +} + // Reiniciar formulario a valores originales const resetForm = () => { if (!confirm('¿Estás seguro de descartar todos los cambios?\n\nSe restaurarán los valores originales y se eliminará el borrador guardado.')) { @@ -746,6 +821,120 @@ const removeAvatar = async () => { overflow-y: auto; } +/* Modal de confirmación de salida */ +.exit-confirm-modal { + padding: 2rem; + max-width: 600px; + margin: 0 auto; +} + +.exit-modal-header { + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; + margin-bottom: 1.5rem; + text-align: center; +} + +.exit-modal-title { + font-size: 1.5rem; + font-weight: 700; + color: var(--color-gray-900); + margin: 0; +} + +.exit-modal-body { + display: flex; + flex-direction: column; + gap: 1rem; + margin-bottom: 2rem; +} + +.exit-modal-message { + font-size: 1rem; + font-weight: 600; + color: var(--color-gray-800); + margin: 0; +} + +.exit-modal-fields { + list-style: none; + padding: 1rem; + margin: 0; + background: rgba(var(--color-warning-500), 0.1); + border-radius: 0.75rem; + border: 1px solid rgba(var(--color-warning-500), 0.3); + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.exit-field-item { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.875rem; + font-weight: 500; + color: var(--color-gray-700); +} + +.exit-modal-notice { + display: flex; + gap: 0.75rem; + padding: 1rem; + background: rgba(var(--color-error-500), 0.1); + border-radius: 0.75rem; + border: 1px solid rgba(var(--color-error-500), 0.3); +} + +.exit-modal-notice p { + margin: 0; + font-size: 0.875rem; + line-height: 1.5; + color: var(--color-gray-700); +} + +.exit-modal-help { + display: flex; + gap: 0.75rem; + padding: 1rem; + background: rgba(var(--color-primary-500), 0.1); + border-radius: 0.75rem; + border: 1px solid rgba(var(--color-primary-500), 0.3); +} + +.exit-modal-help p { + margin: 0; + font-size: 0.875rem; + line-height: 1.5; + color: var(--color-gray-700); +} + +.exit-modal-actions { + display: flex; + gap: 1rem; + justify-content: center; +} + +@media (max-width: 640px) { + .exit-confirm-modal { + padding: 1.5rem; + } + + .exit-modal-title { + font-size: 1.25rem; + } + + .exit-modal-actions { + flex-direction: column-reverse; + } + + .exit-modal-actions button { + width: 100%; + } +} + .form-actions { display: flex; justify-content: flex-end; @@ -827,4 +1016,39 @@ const removeAvatar = async () => { .dark .modal-title { color: var(--color-gray-100) !important; } + +.dark .exit-modal-title { + color: var(--color-gray-100) !important; +} + +.dark .exit-modal-message { + color: var(--color-gray-200) !important; +} + +.dark .exit-field-item { + color: var(--color-gray-300) !important; +} + +.dark .exit-modal-fields { + background: rgba(var(--color-warning-500), 0.15) !important; + border-color: rgba(var(--color-warning-500), 0.4) !important; +} + +.dark .exit-modal-notice { + background: rgba(var(--color-error-500), 0.15) !important; + border-color: rgba(var(--color-error-500), 0.4) !important; +} + +.dark .exit-modal-notice p { + color: var(--color-gray-300) !important; +} + +.dark .exit-modal-help { + background: rgba(var(--color-primary-500), 0.15) !important; + border-color: rgba(var(--color-primary-500), 0.4) !important; +} + +.dark .exit-modal-help p { + color: var(--color-gray-300) !important; +}
+ Tienes cambios pendientes en: +
+ Estos cambios quedarán guardados localmente en tu navegador, + pero NO han sido enviados al servidor. +
+ Para guardar definitivamente, haz clic en "Guardar cambios". +