useRecords.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. import { useState, useEffect, useCallback } from "react"
  2. import { useSession } from "next-auth/react"
  3. import { notifications } from "@/lib/notifications"
  4. import { downloadReactPDF } from "@/utils/pdf"
  5. import { generateTXTReport } from "@/utils/reports"
  6. import { Record } from "@/components/records/types"
  7. export function useRecords() {
  8. const { data: session, status } = useSession()
  9. const [records, setRecords] = useState<Record[]>([])
  10. const [filteredRecords, setFilteredRecords] = useState<Record[]>([])
  11. const [loading, setLoading] = useState(true)
  12. const [selectedRecord, setSelectedRecord] = useState<Record | null>(null)
  13. const [showModal, setShowModal] = useState(false)
  14. const [currentPage, setCurrentPage] = useState(1)
  15. const [generatingPDF, setGeneratingPDF] = useState(false)
  16. // Filtros y paginación
  17. const [searchTerm, setSearchTerm] = useState("")
  18. const [selectedPatientId, setSelectedPatientId] = useState<string | null>(null)
  19. const [selectedPatient, setSelectedPatient] = useState<{
  20. id: string
  21. name: string
  22. lastname: string
  23. email: string
  24. username: string
  25. profileImage: string | null
  26. createdAt: string
  27. _count: {
  28. records: number
  29. }
  30. } | null>(null)
  31. const [dateFilter, setDateFilter] = useState("")
  32. const [itemsPerPage, setItemsPerPage] = useState(3)
  33. const [showFilters, setShowFilters] = useState(false)
  34. const [showLoadingSkeleton, setShowLoadingSkeleton] = useState(false)
  35. const fetchRecords = useCallback(async () => {
  36. if (status !== "authenticated") return
  37. try {
  38. setLoading(true)
  39. // Construir URL con parámetros según el rol
  40. let url = "/api/chat/report"
  41. if (session?.user?.role === "PATIENT") {
  42. // Los pacientes solo ven sus propios reportes
  43. url += `?userId=${session.user.id}`
  44. } else if ((session?.user?.role === "DOCTOR" || session?.user?.role === "ADMIN") && selectedPatientId) {
  45. // Los doctores y admins pueden filtrar por paciente específico
  46. url += `?userId=${selectedPatientId}`
  47. }
  48. // Los doctores ven todos los reportes (sin parámetros) si no hay paciente seleccionado
  49. const response = await fetch(url, {
  50. credentials: "include",
  51. headers: {
  52. "Content-Type": "application/json",
  53. },
  54. })
  55. if (response.ok) {
  56. const data = await response.json()
  57. setRecords(data.records || [])
  58. setFilteredRecords(data.records || [])
  59. } else {
  60. console.error("Error response:", response.status, response.statusText)
  61. notifications.records.loadError()
  62. }
  63. } catch (error) {
  64. console.error("Error fetching records:", error)
  65. notifications.records.loadError()
  66. } finally {
  67. setLoading(false)
  68. }
  69. }, [status, session?.user?.role, session?.user?.id, selectedPatientId])
  70. // Efecto para recargar datos cuando cambia el paciente seleccionado
  71. useEffect(() => {
  72. if (status === "authenticated" && (session?.user?.role === "DOCTOR" || session?.user?.role === "ADMIN") && selectedPatientId) {
  73. setShowLoadingSkeleton(false)
  74. fetchRecords()
  75. }
  76. }, [status, selectedPatientId, fetchRecords])
  77. // Función para manejar la selección de paciente
  78. const handlePatientSelect = (patient: {
  79. id: string
  80. name: string
  81. lastname: string
  82. email: string
  83. username: string
  84. profileImage: string | null
  85. createdAt: string
  86. _count: {
  87. records: number
  88. }
  89. } | null) => {
  90. if (patient) {
  91. setSelectedPatientId(patient.id)
  92. setSelectedPatient(patient)
  93. } else {
  94. setSelectedPatientId(null)
  95. setSelectedPatient(null)
  96. }
  97. }
  98. // Efecto separado para mostrar skeleton después de 3 segundos
  99. useEffect(() => {
  100. let skeletonTimer: NodeJS.Timeout
  101. if (loading && status === "authenticated" && (session?.user?.role === "DOCTOR" || session?.user?.role === "ADMIN")) {
  102. skeletonTimer = setTimeout(() => {
  103. setShowLoadingSkeleton(true)
  104. }, 3000)
  105. } else {
  106. setShowLoadingSkeleton(false)
  107. }
  108. return () => {
  109. if (skeletonTimer) {
  110. clearTimeout(skeletonTimer)
  111. }
  112. }
  113. }, [loading, status, session?.user?.role])
  114. useEffect(() => {
  115. if (status === "authenticated") {
  116. fetchRecords()
  117. }
  118. }, [status, fetchRecords])
  119. // Filtrar registros
  120. useEffect(() => {
  121. let filtered = [...records]
  122. // Filtro por fecha
  123. if (dateFilter) {
  124. const filterDate = new Date(dateFilter)
  125. filtered = filtered.filter((record) => {
  126. const recordDate = new Date(record.createdAt)
  127. return recordDate.toDateString() === filterDate.toDateString()
  128. })
  129. }
  130. setFilteredRecords(filtered)
  131. setCurrentPage(1) // Resetear a la primera página cuando se filtran
  132. }, [records, dateFilter])
  133. const downloadReport = (record: Record) => {
  134. try {
  135. // Generar el reporte TXT mejorado
  136. const reportContent = generateTXTReport(record)
  137. const blob = new Blob([reportContent], {
  138. type: "text/plain; charset=utf-8",
  139. })
  140. const url = URL.createObjectURL(blob)
  141. const a = document.createElement("a")
  142. a.href = url
  143. a.download = `reporte-medico-${record.id.slice(-8)}-${
  144. new Date().toISOString().split("T")[0]
  145. }.txt`
  146. document.body.appendChild(a)
  147. a.click()
  148. document.body.removeChild(a)
  149. URL.revokeObjectURL(url)
  150. notifications.records.txtDownloaded()
  151. } catch (error) {
  152. console.error("Error generando reporte TXT:", error)
  153. notifications.records.txtError()
  154. }
  155. }
  156. const handleGeneratePDF = async (record: Record) => {
  157. if (!session?.user?.role) return
  158. setGeneratingPDF(true)
  159. try {
  160. console.log("Iniciando generación de PDF con React-PDF...")
  161. await downloadReactPDF(record)
  162. notifications.records.pdfDownloaded()
  163. } catch (error) {
  164. console.error("Error generando PDF:", error)
  165. notifications.records.pdfError()
  166. } finally {
  167. setGeneratingPDF(false)
  168. }
  169. }
  170. const copyToClipboard = (text: string) => {
  171. navigator.clipboard.writeText(text)
  172. notifications.records.copied()
  173. }
  174. const clearFilters = () => {
  175. setSearchTerm("")
  176. setSelectedPatientId(null)
  177. setSelectedPatient(null)
  178. setDateFilter("")
  179. setCurrentPage(1)
  180. setShowLoadingSkeleton(false)
  181. }
  182. const handleViewRecord = (record: Record) => {
  183. setSelectedRecord(record)
  184. setShowModal(true)
  185. }
  186. const handleCloseModal = () => {
  187. setShowModal(false)
  188. setSelectedRecord(null)
  189. }
  190. // Calcular paginación
  191. const totalPages = Math.ceil(filteredRecords.length / itemsPerPage)
  192. const startIndex = (currentPage - 1) * itemsPerPage
  193. const endIndex = startIndex + itemsPerPage
  194. const currentRecords = filteredRecords.slice(startIndex, endIndex)
  195. const handlePageChange = (page: number) => {
  196. setCurrentPage(page)
  197. }
  198. return {
  199. // Estado
  200. records,
  201. filteredRecords,
  202. loading,
  203. selectedRecord,
  204. showModal,
  205. currentPage,
  206. generatingPDF,
  207. searchTerm,
  208. selectedPatientId,
  209. selectedPatient,
  210. dateFilter,
  211. itemsPerPage,
  212. showFilters,
  213. showLoadingSkeleton,
  214. totalPages,
  215. startIndex,
  216. endIndex,
  217. currentRecords,
  218. session,
  219. status,
  220. // Acciones
  221. setSearchTerm,
  222. setSelectedPatientId,
  223. setSelectedPatient,
  224. setDateFilter,
  225. setItemsPerPage,
  226. setShowFilters,
  227. downloadReport,
  228. handleGeneratePDF,
  229. copyToClipboard,
  230. clearFilters,
  231. handleViewRecord,
  232. handleCloseModal,
  233. handlePageChange,
  234. fetchRecords,
  235. handlePatientSelect
  236. }
  237. }