| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- import { useState, useEffect, useCallback } from "react"
- import { useSession } from "next-auth/react"
- import { useRouter } from "next/navigation"
- import { notifications } from "@/lib/notifications"
- import { useProfileImageContext } from "@/contexts/ProfileImageContext"
- import { validateMedicalInfo } from "@/components/account/MedicalInfoSection"
- interface FormData {
- name: string
- lastname: string
- email: string
- identificacion?: string
- currentPassword: string
- newPassword: string
- confirmPassword: string
- phone?: string
- dateOfBirth?: string
- gender?: string
- address?: string
- emergencyContact?: string
- medicalHistory?: string
- allergies?: string
- currentMedications?: string
- }
- export function useAccountForm() {
- const { data: session, update } = useSession()
- const router = useRouter()
- const { updateProfileImage } = useProfileImageContext()
- const [formData, setFormData] = useState<FormData>({
- name: "",
- lastname: "",
- email: "",
- currentPassword: "",
- newPassword: "",
- confirmPassword: "",
- phone: "",
- dateOfBirth: "",
- gender: "",
- address: "",
- emergencyContact: "",
- medicalHistory: "",
- allergies: "",
- currentMedications: ""
- })
-
- const [loading, setLoading] = useState(false)
- const [profileImage, setProfileImage] = useState<string | null>(null)
- const [imageFile, setImageFile] = useState<File | null>(null)
- const [loadingImage, setLoadingImage] = useState(false)
- const [imageLoaded, setImageLoaded] = useState(false)
- const [isUpdating, setIsUpdating] = useState(false) // Flag para prevenir race conditions
- const loadProfileImage = useCallback(async () => {
- if (!session?.user?.id || imageLoaded) return
-
- setLoadingImage(true)
- try {
- const response = await fetch("/api/account/profile-image", {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
- })
-
- if (response.ok) {
- const data = await response.json()
- setProfileImage(data.profileImage)
- } else {
- console.log(`Error HTTP: ${response.status}`)
- setProfileImage(null)
- }
- } catch (error) {
- console.error("Error cargando imagen de perfil:", error)
- setProfileImage(null)
- } finally {
- setLoadingImage(false)
- setImageLoaded(true)
- }
- }, [session?.user?.id, imageLoaded])
- // Cargar datos del usuario cuando la sesión esté disponible
- useEffect(() => {
- // No actualizar formData si estamos en medio de una actualización manual
- if (session?.user && !isUpdating) {
- setFormData(prev => ({
- ...prev,
- name: session.user.name || "",
- lastname: session.user.lastname || "",
- email: session.user.email || "",
- identificacion: session.user.identificacion || "",
- phone: session.user.phone || "",
- dateOfBirth: session.user.dateOfBirth ? new Date(session.user.dateOfBirth).toISOString().split('T')[0] : "",
- gender: session.user.gender || "",
- address: session.user.address || "",
- emergencyContact: session.user.emergencyContact || "",
- medicalHistory: session.user.medicalHistory || "",
- allergies: session.user.allergies || "",
- currentMedications: session.user.currentMedications || ""
- }))
- }
- }, [session, isUpdating])
- // Cargar imagen de perfil cuando el usuario esté autenticado
- useEffect(() => {
- if (session?.user?.id && !imageLoaded) {
- loadProfileImage()
- }
- }, [session?.user?.id, imageLoaded, loadProfileImage])
- const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
- const { name, value } = e.target
-
- setFormData(prev => ({
- ...prev,
- [name]: value
- }))
- }
- const handleImageChange = (file: File | null) => {
- setImageFile(file)
-
- if (file) {
- // Crear preview
- const reader = new FileReader()
- reader.onload = (e) => {
- setProfileImage(e.target?.result as string)
- }
- reader.readAsDataURL(file)
- } else {
- setImageLoaded(false)
- }
- }
- const handleImageRemove = async () => {
- if (!profileImage) return
-
- setLoadingImage(true)
- try {
- const response = await fetch("/api/account/profile-image", {
- method: 'DELETE',
- headers: {
- 'Content-Type': 'application/json',
- },
- })
-
- if (response.ok) {
- setProfileImage(null)
- setImageFile(null)
- setImageLoaded(false)
-
- // Actualizar el contexto global
- updateProfileImage(null)
-
- // Actualizar la sesión
- await update({
- profileImage: null
- })
-
- notifications.profile.imageRemoved()
- } else {
- const data = await response.json()
- notifications.profile.imageRemoveError(data.error)
- }
- } catch (error) {
- console.error("Error eliminando imagen:", error)
- notifications.profile.imageRemoveError()
- } finally {
- setLoadingImage(false)
- }
- }
- const handleSubmit = async (e: React.FormEvent) => {
- e.preventDefault()
- setLoading(true)
- setIsUpdating(true) // Activar flag para prevenir race condition
- try {
- // Validar información médica
- const medicalValidation = validateMedicalInfo({
- phone: formData.phone,
- gender: formData.gender,
- address: formData.address,
- emergencyContact: formData.emergencyContact,
- medicalHistory: formData.medicalHistory,
- allergies: formData.allergies,
- currentMedications: formData.currentMedications
- })
- if (!medicalValidation.isValid) {
- const errorMessages = Object.values(medicalValidation.errors).join(', ')
- notifications.profile.updateError(`Errores de validación: ${errorMessages}`)
- setLoading(false)
- return
- }
- // Validaciones de contraseña
- if (formData.newPassword && formData.newPassword !== formData.confirmPassword) {
- notifications.auth.passwordMismatch()
- setLoading(false)
- return
- }
-
- if (formData.newPassword && formData.newPassword.length < 6) {
- notifications.auth.passwordTooShort()
- setLoading(false)
- return
- }
- const formDataToSend = new FormData()
- formDataToSend.append('name', formData.name)
- formDataToSend.append('lastname', formData.lastname)
- formDataToSend.append('email', formData.email)
-
- if (formData.currentPassword) {
- formDataToSend.append('currentPassword', formData.currentPassword)
- }
-
- if (formData.newPassword) {
- formDataToSend.append('newPassword', formData.newPassword)
- }
-
- // Agregar campos médicos y personales
- if (formData.phone) {
- formDataToSend.append('phone', formData.phone)
- }
-
- // dateOfBirth NO se envía - es provisto por la API UTB y no es editable
-
- if (formData.gender) {
- formDataToSend.append('gender', formData.gender)
- }
-
- if (formData.address) {
- formDataToSend.append('address', formData.address)
- }
-
- if (formData.emergencyContact) {
- formDataToSend.append('emergencyContact', formData.emergencyContact)
- }
-
- if (formData.medicalHistory) {
- formDataToSend.append('medicalHistory', formData.medicalHistory)
- }
-
- if (formData.allergies) {
- formDataToSend.append('allergies', formData.allergies)
- }
-
- if (formData.currentMedications) {
- formDataToSend.append('currentMedications', formData.currentMedications)
- }
-
- if (imageFile) {
- formDataToSend.append('profileImage', imageFile)
- }
- const response = await fetch("/api/account/update", {
- method: "POST",
- body: formDataToSend
- })
- const data = await response.json()
- if (response.ok) {
- notifications.profile.updated()
-
- // Actualizar formData local con los datos guardados
- setFormData(prev => ({
- ...prev,
- name: data.user.name || "",
- lastname: data.user.lastname || "",
- email: data.user.email || "",
- phone: data.user.phone || "",
- dateOfBirth: data.user.dateOfBirth ? new Date(data.user.dateOfBirth).toISOString().split('T')[0] : "",
- gender: data.user.gender || "",
- address: data.user.address || "",
- emergencyContact: data.user.emergencyContact || "",
- medicalHistory: data.user.medicalHistory || "",
- allergies: data.user.allergies || "",
- currentMedications: data.user.currentMedications || "",
- // Limpiar contraseñas
- currentPassword: "",
- newPassword: "",
- confirmPassword: ""
- }))
- // Actualizar la sesión de NextAuth con todos los datos nuevos
- await update({
- name: data.user.name,
- lastname: data.user.lastname,
- email: data.user.email,
- profileImage: data.user.profileImage,
- phone: data.user.phone,
- dateOfBirth: data.user.dateOfBirth,
- gender: data.user.gender,
- address: data.user.address,
- emergencyContact: data.user.emergencyContact,
- medicalHistory: data.user.medicalHistory,
- allergies: data.user.allergies,
- currentMedications: data.user.currentMedications
- })
- // Actualizar la imagen de perfil en el contexto global
- if (data.user.profileImage) {
- updateProfileImage(data.user.profileImage)
- }
- // Recargar imagen de perfil si se actualizó
- if (imageFile) {
- setImageLoaded(false)
- setTimeout(() => {
- loadProfileImage()
- }, 500)
- }
- // Desactivar flag después de que la sesión se haya actualizado
- setTimeout(() => {
- setIsUpdating(false)
- }, 500)
- } else {
- notifications.profile.updateError(data.error)
- setIsUpdating(false)
- }
- } catch (error) {
- console.error("Error updating profile:", error)
- notifications.profile.updateError()
- setIsUpdating(false)
- } finally {
- setLoading(false)
- }
- }
- return {
- formData,
- loading,
- profileImage,
- loadingImage,
- imageLoaded,
- handleInputChange,
- handleImageChange,
- handleImageRemove,
- handleSubmit,
- loadProfileImage
- }
- }
|