From fba021e0485d0a5bf9fc95359e5748028f4554e3 Mon Sep 17 00:00:00 2001 From: Squad03_Leticia_Lacerda Date: Sat, 9 May 2026 23:32:04 -0300 Subject: [PATCH 1/3] modified: package-lock.json modified: package.json modified: src/App.jsx modified: src/index.css modified: src/pages/MedicalRecordsPage.jsx modified: src/pages/ReportsPage.jsx modified: src/repositories/medicalRecordRepository.js --- package-lock.json | 654 +++++++++++++- package.json | 5 + src/App.jsx | 17 + src/index.css | 126 +++ src/pages/MedicalRecordsPage.jsx | 937 +++++++++++++++----- src/pages/ReportsPage.jsx | 384 ++++++-- src/repositories/medicalRecordRepository.js | 305 ++++++- 7 files changed, 2125 insertions(+), 303 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0b60fb0..e8c8718 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,11 @@ "name": "projeto-residencia", "version": "0.0.0", "dependencies": { + "@tiptap/extension-text-align": "^3.23.1", + "@tiptap/extension-underline": "^3.23.1", + "@tiptap/pm": "^3.23.1", + "@tiptap/react": "^3.23.1", + "@tiptap/starter-kit": "^3.23.1", "date-fns": "^4.1.0", "react": "^19.2.4", "react-dom": "^19.2.4" @@ -459,6 +464,34 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT", + "optional": true + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1156,6 +1189,447 @@ "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, + "node_modules/@tiptap/core": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.23.1.tgz", + "integrity": "sha512-8YvSGiJTeU5wPuGiYIIYgyiyaaT1CAx+kJL0bju0w871OvbJJj0T/ywhcmxGXW6pOal2T8X2xt9ZqE+vib0VJw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/pm": "3.23.1" + } + }, + "node_modules/@tiptap/extension-blockquote": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.23.1.tgz", + "integrity": "sha512-FdVZLZOkL06j3WLXOC2UeX7++Cj3qI2vfohruMJiz4vk1Q5UUH7G4+AykFzjzBJHrdEpkiRUkRpU1KZIWdbluw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1" + } + }, + "node_modules/@tiptap/extension-bold": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.23.1.tgz", + "integrity": "sha512-EAYdNzyOjlQh2VBY1EhdxtiTjVMaOAD6P0ezms60dKRjd4oj/8grfXfUqwgo4NVdFb11Ks85vXoHuXJSylfR4A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1" + } + }, + "node_modules/@tiptap/extension-bubble-menu": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.23.1.tgz", + "integrity": "sha512-1advMCpPkHD/3ucZhYmNau8B4tF0L6iRAFhUOglp5bBZDuq13+rYujh3cm4vFmjH9KqThzpcUDn+ZU2c+mTMyw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1", + "@tiptap/pm": "3.23.1" + } + }, + "node_modules/@tiptap/extension-bullet-list": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.23.1.tgz", + "integrity": "sha512-owWnBBI4t+jqVDY0naDjhsAmrNGldh4czouef2K+mEf032B7uGsDVCwKp1qaX1JZesyYDfvXOaIwT22hNID2mw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.23.1" + } + }, + "node_modules/@tiptap/extension-code": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.23.1.tgz", + "integrity": "sha512-nGuhb4YghgTfkejwWHrD9GSpwcC5kkVmm2sN/UY4yceDw+PkyysYKJWZehRLTOC8GNgSAhq/EeQeq14Xwk6dyg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1" + } + }, + "node_modules/@tiptap/extension-code-block": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.23.1.tgz", + "integrity": "sha512-BdJGqM57CsKgYrQUZz78vIG8Yn7EpsE2pA7iKn5tYoSXpYtt0IaU4qB1heH7lwWD/vVCAm0YQVD7/0F+0++yhA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1", + "@tiptap/pm": "3.23.1" + } + }, + "node_modules/@tiptap/extension-document": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.23.1.tgz", + "integrity": "sha512-NA5Rx59HRwG6Hb6LwLpC5lE7z6vCj6f90S7RNNsnE+CyiXNR/OhY2BcjuxiGnascHvsnsAbvxGU3ymKMDgvDVg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1" + } + }, + "node_modules/@tiptap/extension-dropcursor": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.23.1.tgz", + "integrity": "sha512-WRN7e/h9m3uI5j9/+L6jcPhHbTL6aKxfFfQWZHNf5M8TqSL1P+/2h034td0XMj3n48i4fWyzjVUV9+sz6t2fDw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "3.23.1" + } + }, + "node_modules/@tiptap/extension-floating-menu": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.23.1.tgz", + "integrity": "sha512-XrYHpLn1DpLFSGTko9F9xgbNamL6fGpWkK4wqgwPVbg/SJwQCDO/9p5D3DtJTwD+xgw4sQ9as4O6rt6jx8JT+Q==", + "license": "MIT", + "optional": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@floating-ui/dom": "^1.0.0", + "@tiptap/core": "3.23.1", + "@tiptap/pm": "3.23.1" + } + }, + "node_modules/@tiptap/extension-gapcursor": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.23.1.tgz", + "integrity": "sha512-E4hB0xquUpEXy7kboLBazrFyRCsN0j0fsTFR8udgQf5xetAVPhOexSTKuzOcU/n0kxsKJin7laYYEag/Fd2KNw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "3.23.1" + } + }, + "node_modules/@tiptap/extension-hard-break": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.23.1.tgz", + "integrity": "sha512-XYkCKC5RVqMmmBk+nd22/6IDDx1OC54sdStH5VEHtfOrarriO0JztK8Mr0TijPPk9N4rKXsmndYZM2xyWZZytQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1" + } + }, + "node_modules/@tiptap/extension-heading": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.23.1.tgz", + "integrity": "sha512-1z9yCSp8fevgX3r/4kWXO3of0WFCQWfYjWfHANvoJ4JQTYBkARjXlj1tbk5rrAJBFDDfKRkUpZOurXKgGo+h+g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1" + } + }, + "node_modules/@tiptap/extension-horizontal-rule": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.23.1.tgz", + "integrity": "sha512-30XUHXdEZxcz1FCWjz9HW2EEq06NQcAye6rXGnvHo6Y60iJ6MRsrX5byvceFNF9DTVtOIcUFBQ/psIiRcoi0KA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1", + "@tiptap/pm": "3.23.1" + } + }, + "node_modules/@tiptap/extension-italic": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.23.1.tgz", + "integrity": "sha512-lZB9YCjoVNDoPMguya66nBvaS/2YpGN5iAcjAGx/JQkCAZeOAtl9+ALMzbWPKH6tQP6m98YtkY1T7RXr++T0bA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1" + } + }, + "node_modules/@tiptap/extension-link": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.23.1.tgz", + "integrity": "sha512-uOeyLqYQI0WG62agpFG24kVHSn3Z48gD8Y0uLLJbtzh/nDFC3d9So2sQGWlSVyMzsgkJ4k/9jNnxxsVO8qgJOg==", + "license": "MIT", + "dependencies": { + "linkifyjs": "^4.3.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1", + "@tiptap/pm": "3.23.1" + } + }, + "node_modules/@tiptap/extension-list": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.23.1.tgz", + "integrity": "sha512-v1AeXPpagslgRZdOp7WdjCoO4TjjNP8RM2R6Gqx0/inGaNXnM8zCMshOxZlAb03Ad7kq/4RGJmkpM/Jjsi6dEQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1", + "@tiptap/pm": "3.23.1" + } + }, + "node_modules/@tiptap/extension-list-item": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.23.1.tgz", + "integrity": "sha512-Fk/884un5OSLCFxe2TbOmfp3sLMB5b76CnMjaSrvgfiaZnsV2WlJZGPXxCAPbxNIATTykNlSBsVuMBO7we64Vg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.23.1" + } + }, + "node_modules/@tiptap/extension-list-keymap": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.23.1.tgz", + "integrity": "sha512-sHbE5sxiJzhgGn94GUAzD4qKM9SyImBrOlAGS/EIe+pausjqQE7xi+YW0gRo2jG+gXhSYl4/oAGXQXzmSInSUQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.23.1" + } + }, + "node_modules/@tiptap/extension-ordered-list": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.23.1.tgz", + "integrity": "sha512-3GG7YFhVJWw/HWmRxvMMUC296x7TPBQRLsH4ryEC1SMAmVJnbTIvetyvIcLqLEXGW7Rj41S7SO8qjOXVceSOTA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.23.1" + } + }, + "node_modules/@tiptap/extension-paragraph": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.23.1.tgz", + "integrity": "sha512-GC7b6yAjASl1q9sNkPmukZmVYMfxx03EEhpMMrLYJY9GBz82Ald927yYQsOqf2aKA/Rjo/aZMYCGtjXkGk6aBA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1" + } + }, + "node_modules/@tiptap/extension-strike": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.23.1.tgz", + "integrity": "sha512-+R5LG0ZW9SDZc4weA79uq6uUduVsCEph9tRcoQCRA82IVIiPYSTxTLew9odalmk/Mc7vdZvOK5jjtO5jUVw/rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1" + } + }, + "node_modules/@tiptap/extension-text": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.23.1.tgz", + "integrity": "sha512-k1Ki9bBV6mLz1mFP+Laqh1YHJ2MY0P8XzaMqpkgMndEBIJQ3XcpWQc5bfAlRnYcOI9ZXDbAgQ8CwgArxHmQWCQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1" + } + }, + "node_modules/@tiptap/extension-text-align": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-3.23.1.tgz", + "integrity": "sha512-ap4ZN31v57mVX2P+0OoW5iO+ehsUNe0C5MgF/Ta2F/HRmTCc1M1mFqYUCk8zJYX1TFRV18vqK2j6STRBk0R8ng==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1" + } + }, + "node_modules/@tiptap/extension-underline": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.23.1.tgz", + "integrity": "sha512-+PvHyVozHyxJ9oWCIQx5JHBZ7LAa/sFJUOFaKyfmel4gL9AbP52MmvrciXARlZHd1WCULJtdbLan0+x5/D/9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1" + } + }, + "node_modules/@tiptap/extensions": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.23.1.tgz", + "integrity": "sha512-7UIn+idaVTVhdlP0KmgzBh8Csmwck357Dq4te5DuAxhSkN1gsXHlq39mpx907UYKJdSOgd+GMFeyOziPwSmbOQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1", + "@tiptap/pm": "3.23.1" + } + }, + "node_modules/@tiptap/pm": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.23.1.tgz", + "integrity": "sha512-8G+TkNsUHHAAJYREpA6fw+Dw/m2Y3Go4/QMQM8RYepid+wTeE1wSv7sBA/CBrphhYmJSWeTyCPtgQIxnTJXMCA==", + "license": "MIT", + "dependencies": { + "prosemirror-changeset": "^2.3.0", + "prosemirror-commands": "^1.6.2", + "prosemirror-dropcursor": "^1.8.1", + "prosemirror-gapcursor": "^1.3.2", + "prosemirror-history": "^1.4.1", + "prosemirror-keymap": "^1.2.2", + "prosemirror-model": "^1.24.1", + "prosemirror-schema-list": "^1.5.0", + "prosemirror-state": "^1.4.3", + "prosemirror-tables": "^1.6.4", + "prosemirror-transform": "^1.10.2", + "prosemirror-view": "^1.38.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tiptap/react": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-3.23.1.tgz", + "integrity": "sha512-43zUwKOcsxRIcgiDbcEUagojhPIez2OIryaNG/uiDcRzkrUteiTu2wSJndkQqwouwh3wJEm+KOw8xybNYvU+qA==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "fast-equals": "^5.3.3", + "use-sync-external-store": "^1.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "optionalDependencies": { + "@tiptap/extension-bubble-menu": "^3.23.1", + "@tiptap/extension-floating-menu": "^3.23.1" + }, + "peerDependencies": { + "@tiptap/core": "3.23.1", + "@tiptap/pm": "3.23.1", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tiptap/starter-kit": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.23.1.tgz", + "integrity": "sha512-CURePHQagBaZIDJrHH3of4Nmi0VYGpZ6yBlkdFxFHBxY9aeG2/h5kn+oHo8GbzkSFsRV+9olzRgDTOULVgs8pQ==", + "license": "MIT", + "dependencies": { + "@tiptap/core": "^3.23.1", + "@tiptap/extension-blockquote": "^3.23.1", + "@tiptap/extension-bold": "^3.23.1", + "@tiptap/extension-bullet-list": "^3.23.1", + "@tiptap/extension-code": "^3.23.1", + "@tiptap/extension-code-block": "^3.23.1", + "@tiptap/extension-document": "^3.23.1", + "@tiptap/extension-dropcursor": "^3.23.1", + "@tiptap/extension-gapcursor": "^3.23.1", + "@tiptap/extension-hard-break": "^3.23.1", + "@tiptap/extension-heading": "^3.23.1", + "@tiptap/extension-horizontal-rule": "^3.23.1", + "@tiptap/extension-italic": "^3.23.1", + "@tiptap/extension-link": "^3.23.1", + "@tiptap/extension-list": "^3.23.1", + "@tiptap/extension-list-item": "^3.23.1", + "@tiptap/extension-list-keymap": "^3.23.1", + "@tiptap/extension-ordered-list": "^3.23.1", + "@tiptap/extension-paragraph": "^3.23.1", + "@tiptap/extension-strike": "^3.23.1", + "@tiptap/extension-text": "^3.23.1", + "@tiptap/extension-underline": "^3.23.1", + "@tiptap/extensions": "^3.23.1", + "@tiptap/pm": "^3.23.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", @@ -1185,7 +1659,6 @@ "version": "19.2.14", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -1195,12 +1668,17 @@ "version": "19.2.3", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" } }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, "node_modules/@vitejs/plugin-react": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", @@ -1493,7 +1971,6 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, "license": "MIT" }, "node_modules/date-fns": { @@ -1776,6 +2253,15 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2399,6 +2885,12 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/linkifyjs": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.2.tgz", + "integrity": "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==", + "license": "MIT" + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2513,6 +3005,12 @@ "node": ">= 0.8.0" } }, + "node_modules/orderedmap": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", + "license": "MIT" + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -2644,6 +3142,135 @@ "node": ">= 0.8.0" } }, + "node_modules/prosemirror-changeset": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz", + "integrity": "sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==", + "license": "MIT", + "dependencies": { + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-commands": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", + "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.10.2" + } + }, + "node_modules/prosemirror-dropcursor": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz", + "integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "node_modules/prosemirror-gapcursor": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz", + "integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "node_modules/prosemirror-history": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz", + "integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, + "node_modules/prosemirror-keymap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", + "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.2.0" + } + }, + "node_modules/prosemirror-model": { + "version": "1.25.4", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz", + "integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==", + "license": "MIT", + "dependencies": { + "orderedmap": "^2.0.0" + } + }, + "node_modules/prosemirror-schema-list": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", + "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.7.3" + } + }, + "node_modules/prosemirror-state": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz", + "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.27.0" + } + }, + "node_modules/prosemirror-tables": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz", + "integrity": "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.2.3", + "prosemirror-model": "^1.25.4", + "prosemirror-state": "^1.4.4", + "prosemirror-transform": "^1.10.5", + "prosemirror-view": "^1.41.4" + } + }, + "node_modules/prosemirror-transform": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz", + "integrity": "sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.21.0" + } + }, + "node_modules/prosemirror-view": { + "version": "1.41.8", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.8.tgz", + "integrity": "sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.20.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -2726,6 +3353,12 @@ "dev": true, "license": "MIT" }, + "node_modules/rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", + "license": "MIT" + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -2901,6 +3534,15 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/vite": { "version": "8.0.10", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", @@ -2979,6 +3621,12 @@ } } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 2d18423..92bf7b1 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,11 @@ "preview": "vite preview" }, "dependencies": { + "@tiptap/extension-text-align": "^3.23.1", + "@tiptap/extension-underline": "^3.23.1", + "@tiptap/pm": "^3.23.1", + "@tiptap/react": "^3.23.1", + "@tiptap/starter-kit": "^3.23.1", "date-fns": "^4.1.0", "react": "^19.2.4", "react-dom": "^19.2.4" diff --git a/src/App.jsx b/src/App.jsx index 12d715c..da6c9f1 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -159,6 +159,23 @@ function resolveRoute(pathname, navigate, role) { } } + if (pathname === '/prontuario/novo') { + return { + element: , + title: 'Novo prontuário', + withShell: true, + } + } + + if (pathname.startsWith('/prontuario/')) { + const [, , recordId, action] = pathname.split('/') + return { + element: , + title: action === 'editar' ? 'Editar prontuário' : 'Prontuário', + withShell: true, + } + } + if (pathname.startsWith('/pacientes/')) { const patientId = pathname.split('/')[2] return { diff --git a/src/index.css b/src/index.css index 34504f9..594c7c7 100644 --- a/src/index.css +++ b/src/index.css @@ -61,6 +61,14 @@ button:disabled { color-scheme: light; } +[data-theme='light'] :where(input, textarea, [contenteditable='true'], .ProseMirror) { + caret-color: #000000; +} + +[data-theme='light'] .auth-dark :where(input, textarea) { + caret-color: #e5e5e5; +} + [data-theme='light'] aside.bg-\[\#262626\] { background-color: #f3f4f6; } @@ -114,11 +122,21 @@ button:disabled { border-color: #d6dee8; } +[data-theme='light'] .divide-y.divide-\[\#404040\] > :not(:last-child), +[data-theme='light'] .divide-\[\#404040\] > :not(:last-child), +[data-theme='light'] table .divide-\[\#404040\] > tr:not(:last-child) { + border-color: #d6dee8; +} + [data-theme='light'] .border-\[\#525252\], [data-theme='light'] .hover\:border-\[\#525252\]:hover { border-color: #d1d5db; } +[data-theme='light'] .border-\[\#5b4b75\] { + border-color: #d6dee8; +} + [data-theme='light'] .hover\:border-\[\#404040\]:hover, [data-theme='light'] .disabled\:border-\[\#404040\]:disabled { border-color: #d6dee8; @@ -302,6 +320,114 @@ button:disabled { color: #9f1239; } +[data-theme='light'] .report-editor-backdrop { + background: rgba(15, 23, 42, 0.35); +} + +[data-theme='light'] .report-editor-shell { + border-color: #c8d4e2; + background: #f8fbff; + box-shadow: 0 24px 60px rgba(15, 23, 42, 0.18); +} + +[data-theme='light'] .report-editor-header, +[data-theme='light'] .report-editor-footer { + border-color: #c8d4e2; + background: #ffffff; +} + +[data-theme='light'] .report-editor-sidebar { + border-color: #c8d4e2; + background: #edf4fb; +} + +[data-theme='light'] .report-editor-body { + background: #f8fbff; +} + +[data-theme='light'] .report-template-trigger, +[data-theme='light'] .report-template-menu, +[data-theme='light'] .report-rich-editor, +[data-theme='light'] .report-rich-toolbar { + border-color: #c8d4e2; + background: #ffffff; + color: #333333; +} + +[data-theme='light'] .report-rich-surface { + background: #ffffff; + caret-color: #000000; + color: #333333; +} + +[data-theme='light'] .report-rich-toolbar select { + border-color: #c8d4e2; + background: #ffffff; + color: #333333; +} + +[data-theme='light'] .report-rich-toolbar button { + color: #4b5563; +} + +[data-theme='light'] .report-rich-toolbar button[aria-pressed='true'], +[data-theme='light'] .report-rich-toolbar button:hover { + color: #2563eb; +} + +.report-rich-surface { + caret-color: #e5e5e5; + cursor: text; + min-height: 560px; +} + +.report-rich-surface * { + cursor: text; +} + +.report-rich-surface.ProseMirror-focused { + caret-color: #e5e5e5; +} + +[data-theme='light'] .report-rich-surface.ProseMirror-focused { + caret-color: #000000; +} + +.report-rich-surface p { + margin: 0 0 0.75rem; +} + +.report-rich-surface h2 { + margin: 0 0 0.85rem; + font-size: 1.1rem; + font-weight: 700; +} + +.report-rich-surface h3 { + margin: 0 0 0.75rem; + font-size: 1rem; + font-weight: 700; +} + +.report-rich-surface ul, +.report-rich-surface ol { + margin: 0.5rem 0 0.75rem; + padding-left: 1.4rem; +} + +.report-rich-surface .is-empty::before { + color: #737373; + content: attr(data-placeholder); + float: left; + height: 0; + pointer-events: none; +} + +[data-theme='light'] .report-rich-toolbar button:hover, +[data-theme='light'] .report-template-menu button:hover { + background: #e8edf4; +} + .agenda-calendar-shell { border-color: #3b3b3b; background: #202020; diff --git a/src/pages/MedicalRecordsPage.jsx b/src/pages/MedicalRecordsPage.jsx index efc1dbb..f2d7225 100644 --- a/src/pages/MedicalRecordsPage.jsx +++ b/src/pages/MedicalRecordsPage.jsx @@ -3,19 +3,64 @@ import { useEffect, useMemo, useState } from 'react' import { FeatureCallout } from '../components/FeatureState.jsx' import { medicalRecordRepository } from '../repositories/medicalRecordRepository.js' import { patientRepository } from '../repositories/patientRepository.js' - +import { reportRepository } from '../repositories/reportRepository.js' const inputClass = 'h-10 w-full rounded-lg border border-[#404040] bg-[#1a1a1a] px-3 text-sm text-[#e5e5e5] outline-none transition placeholder:text-[#a3a3a3] focus:border-[#3b82f6] focus:ring-1 focus:ring-[#3b82f6]' +const textareaClass = + 'min-h-28 w-full rounded-lg border border-[#404040] bg-[#1a1a1a] px-3 py-2 text-sm leading-6 text-[#e5e5e5] outline-none transition placeholder:text-[#a3a3a3] focus:border-[#3b82f6] focus:ring-1 focus:ring-[#3b82f6]' const labelClass = 'mb-1 block text-xs font-medium text-[#e5e5e5]' const cardClass = 'rounded-2xl border border-[#404040] bg-[#262626] shadow-sm' -export function MedicalRecordsPage() { +const emptyRecord = { + patientId: '', + patient: '', + patientDocument: '', + patientEmail: '', + patientPhone: '', + dateTime: '', + doctor: '', + type: 'Primeira Consulta', + cid: '', + status: 'completo', + diagnosticReasoning: '', + diagnosticHypotheses: '', + definitiveDiagnosis: '', + prescriptions: '', + procedures: '', + surgeries: '', + orientations: '', + labResults: '', + imageResults: '', + multiprofessionalNotes: '', + signature: '', + professionalStamp: '', +} + +const requiredFields = [ + ['patient', 'paciente'], + ['dateTime', 'data e hora'], + ['doctor', 'profissional'], + ['cid', 'CID ou referência diagnóstica'], + ['diagnosticReasoning', 'raciocínio médico'], + ['diagnosticHypotheses', 'hipóteses diagnósticas'], + ['definitiveDiagnosis', 'diagnóstico definitivo'], + ['prescriptions', 'prescrição médica'], + ['procedures', 'procedimentos realizados'], + ['surgeries', 'cirurgias'], + ['orientations', 'orientações'], + ['labResults', 'laudos laboratoriais'], + ['imageResults', 'laudos de imagem'], + ['multiprofessionalNotes', 'notas multiprofissionais'], + ['signature', 'assinatura/carimbo'], + ['professionalStamp', 'carimbo profissional'], +] + +export function MedicalRecordsPage({ navigate, mode = 'list', recordId = '' }) { const recordTypes = medicalRecordRepository.getRecordTypes() - const [records, setRecords] = useState(() => medicalRecordRepository.getInitialRecords()) + const [records, setRecords] = useState(() => medicalRecordRepository.getAll()) const [patients, setPatients] = useState([]) const [search, setSearch] = useState('') - const [editorOpen, setEditorOpen] = useState(false) useEffect(() => { let active = true @@ -35,18 +80,67 @@ export function MedicalRecordsPage() { }, []) const filteredRecords = useMemo(() => { + const query = normalizeSearch(search) return records.filter((record) => { - const matchesSearch = [record.patient, record.cid, record.doctor] - .join(' ') - .toLowerCase() - .includes(search.toLowerCase()) - return matchesSearch + if (!query) return true + return normalizeSearch([record.patient, record.cid, record.doctor, record.type, record.summary].join(' ')).includes(query) }) }, [records, search]) - function handleCreateRecord(record) { - setRecords((currentRecords) => [record, ...currentRecords]) - setEditorOpen(false) + const selectedRecord = records.find((record) => String(record.id) === String(recordId)) || null + const selectedPatient = selectedRecord ? findPatient(patients, selectedRecord) : null + + function refreshRecords() { + setRecords(medicalRecordRepository.getAll()) + } + + function handleCreateRecord(data) { + const created = medicalRecordRepository.create(data) + refreshRecords() + navigate(`/prontuario/${created.id}`) + } + + function handleUpdateRecord(data) { + const updated = medicalRecordRepository.update(recordId, data) + refreshRecords() + navigate(`/prontuario/${updated?.id || recordId}`) + } + + if (mode === 'new') { + return ( + + ) + } + + if (mode === 'edit') { + return selectedRecord ? ( + + ) : ( + + ) + } + + if (mode === 'detail') { + return selectedRecord ? ( + + ) : ( + + ) } return ( @@ -60,62 +154,64 @@ export function MedicalRecordsPage() {

Prontuário Médico

-

Registro de consultas, diagnósticos e evolução

+

Registros cronológicos, diagnósticos, condutas e resultados de exames

-
-
- - setSearch(event.target.value)} - placeholder="Buscar por paciente ou CID..." - value={search} - /> -
+
+ + setSearch(event.target.value)} + placeholder="Buscar por paciente, CID, médico ou tipo de registro..." + value={search} + />
{filteredRecords.length ? ( - filteredRecords.map((record) => ) + filteredRecords.map((record) => ( + navigate(`/prontuario/${record.id}/editar`)} + onOpen={() => navigate(`/prontuario/${record.id}`)} + onPrint={() => printRecordAsPdf(record)} + record={record} + /> + )) ) : (
Nenhum registro encontrado nos dados locais.
)}
- - {editorOpen ? ( - setEditorOpen(false)} - onSave={handleCreateRecord} - patients={patients} - recordTypes={recordTypes} - /> - ) : null} ) } -function RecordCard({ record }) { +function RecordCard({ onEdit, onOpen, onPrint, record }) { const statusClass = record.status === 'completo' ? 'bg-emerald-500/20 text-emerald-400' : 'bg-amber-500/20 text-amber-400' return ( -
+
@@ -131,7 +227,7 @@ function RecordCard({ record }) {
- {record.date} + {formatDateTime(record.dateTime)} @@ -147,178 +243,213 @@ function RecordCard({ record }) {
- - - + + +
) } -function IconButton({ label, name }) { +function RecordDetailPage({ navigate, patient, record }) { + const [reports, setReports] = useState(() => medicalRecordRepository.getMockReportHistory(record.patientId, record.patient)) + + useEffect(() => { + let active = true + + loadReportsForPatient(record.patientId, record.patient).then((data) => { + if (active) setReports(data) + }) + + return () => { + active = false + } + }, [record.patientId, record.patient]) + + const chronology = buildChronology(record, reports) + return ( - +
+
+
+ +

Prontuário de {record.patient}

+

+ Registro cronológico inverso com assinatura profissional e histórico contínuo. +

+
+
+ + + + +
+
+ +
+ + + + +
+ +
+
+ + + + +
+ +
+ + +
+
+
) } -function RecordEditorModal({ onClose, onSave, patients, recordTypes }) { - const [patientSearch, setPatientSearch] = useState('') - const [formData, setFormData] = useState({ - patientId: '', - patient: '', - date: '', - type: 'Primeira Consulta', - cid: '', - anamnesis: '', - physicalExam: '', - conduct: '', - prescriptions: '', - returnDate: '', - status: 'completo', - }) +function RecordEditorPage({ navigate, onSave, patients, record, recordTypes }) { + const [patientSearch, setPatientSearch] = useState(record?.patient || '') + const [formData, setFormData] = useState(() => ({ + ...emptyRecord, + dateTime: toDateTimeLocal(new Date()), + doctor: 'Dr. Henrique Cardoso', + signature: 'Dr. Henrique Cardoso - CRM não informado', + professionalStamp: 'Assinado digitalmente por Dr. Henrique Cardoso', + ...record, + })) + + const filteredPatients = useMemo(() => { + const query = normalizeSearch(patientSearch) + if (!query) return patients.slice(0, 8) + + return patients + .filter((patient) => + normalizeSearch([patient.name, patient.full_name, patient.nome, patient.cpf, patient.document, patient.email].filter(Boolean).join(' ')).includes(query), + ) + .slice(0, 8) + }, [patientSearch, patients]) function updateField(event) { const { name, value } = event.target setFormData((currentData) => ({ ...currentData, [name]: value })) } - const filteredPatients = (() => { - const query = normalizeSearch(patientSearch) - if (!query) return patients - - return patients.filter((patient) => - [patient.name, patient.full_name, patient.nome, patient.cpf, patient.document, patient.email] - .filter(Boolean) - .join(' ') - .normalize('NFD') - .replace(/[\u0300-\u036f]/g, '') - .toLowerCase() - .includes(query), - ) - })() - function selectPatient(patient) { - const name = getPatientName(patient) + const patientName = getPatientName(patient) + setPatientSearch(patientName) setFormData((currentData) => ({ ...currentData, - patientId: patient.id, - patient: name, + patientId: String(patient.id || ''), + patient: patientName, + patientDocument: patient.document || patient.cpf || '', + patientEmail: patient.email || '', + patientPhone: patient.phone || patient.phone_mobile || patient.telefone || '', })) - setPatientSearch(name) } function handleSubmit(event) { event.preventDefault() - const submitter = event.nativeEvent.submitter - const status = submitter?.value || formData.status + const missing = requiredFields.filter(([field]) => !String(formData[field] || '').trim()) + if (missing.length) { + alert(`Preencha os campos obrigatórios: ${missing.map(([, label]) => label).join(', ')}.`) + return + } + + const summary = formData.definitiveDiagnosis || formData.diagnosticReasoning onSave({ - id: `record-${Date.now()}`, - patient: formData.patient || 'Paciente sem nome', - date: formData.date ? formatDate(formData.date) : '07/04/2026', - doctor: 'Dr. Henrique Cardoso', - type: formData.type, - cid: formData.cid || 'CID não informado', - status, - summary: formData.conduct || formData.anamnesis || 'Registro criado localmente para simulação.', + ...formData, + summary, + date: formatDateTime(formData.dateTime), }) } return ( -
-
event.stopPropagation()} - onSubmit={handleSubmit} - > -

Novo Registro de Consulta

+
+
+
+ +

{record ? 'Editar prontuário' : 'Novo prontuário'}

+

+ Preencha os dados clínicos, legais e multiprofissionais obrigatórios do registro. +

+
+
-
-
- + +
+
+ { setPatientSearch(event.target.value) - setFormData((currentData) => ({ ...currentData, patientId: '', patient: '' })) + setFormData((currentData) => ({ ...currentData, patientId: '', patient: event.target.value })) }} placeholder="Buscar paciente..." type="search" - value={patientSearch || formData.patient} + value={patientSearch} /> -
- {filteredPatients.length ? ( - filteredPatients.slice(0, 6).map((patient) => { - const selected = String(patient.id) === String(formData.patientId) - return ( - - ) - }) - ) : ( -

Nenhum paciente encontrado.

- )} -
-
- - -
- - -