diff --git a/package-lock.json b/package-lock.json
index cc5357f3..cd675dd6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,11 +11,9 @@
"@base-ui-components/react": "1.0.0-beta.6",
"@hookform/resolvers": "5.0.1",
"@radix-ui/react-checkbox": "1.2.2",
- "@radix-ui/react-dialog": "1.1.14",
"@radix-ui/react-dropdown-menu": "2.1.15",
"@radix-ui/react-popover": "1.1.14",
"@radix-ui/react-radio-group": "1.3.6",
- "@radix-ui/react-select": "2.2.2",
"@radix-ui/react-slot": "1.2.0",
"@tanstack/react-query": "5.83.0",
"class-variance-authority": "0.7.1",
@@ -2499,38 +2497,11 @@
"url": "https://opencollective.com/unts"
}
},
- "node_modules/@radix-ui/number": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
- "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="
- },
"node_modules/@radix-ui/primitive": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
"integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="
},
- "node_modules/@radix-ui/react-arrow": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.4.tgz",
- "integrity": "sha512-qz+fxrqgNxG0dYew5l7qR3c7wdgRu1XVUHGnGYX7rg5HM4p9SWaRmJwfgR3J0SgyUKayLmzQIun+N6rWRgiRKw==",
- "dependencies": {
- "@radix-ui/react-primitive": "2.1.0"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
"node_modules/@radix-ui/react-checkbox": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.2.2.tgz",
@@ -2560,31 +2531,6 @@
}
}
},
- "node_modules/@radix-ui/react-collection": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.4.tgz",
- "integrity": "sha512-cv4vSf7HttqXilDnAnvINd53OTl1/bjUYVZrkFnA7nwmY9Ob2POUy0WY0sfqBAe1s5FyKsyceQlqiEGPYNTadg==",
- "dependencies": {
- "@radix-ui/react-compose-refs": "1.1.2",
- "@radix-ui/react-context": "1.1.2",
- "@radix-ui/react-primitive": "2.1.0",
- "@radix-ui/react-slot": "1.2.0"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
"node_modules/@radix-ui/react-compose-refs": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
@@ -2613,177 +2559,6 @@
}
}
},
- "node_modules/@radix-ui/react-dialog": {
- "version": "1.1.14",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz",
- "integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==",
- "license": "MIT",
- "dependencies": {
- "@radix-ui/primitive": "1.1.2",
- "@radix-ui/react-compose-refs": "1.1.2",
- "@radix-ui/react-context": "1.1.2",
- "@radix-ui/react-dismissable-layer": "1.1.10",
- "@radix-ui/react-focus-guards": "1.1.2",
- "@radix-ui/react-focus-scope": "1.1.7",
- "@radix-ui/react-id": "1.1.1",
- "@radix-ui/react-portal": "1.1.9",
- "@radix-ui/react-presence": "1.1.4",
- "@radix-ui/react-primitive": "2.1.3",
- "@radix-ui/react-slot": "1.2.3",
- "@radix-ui/react-use-controllable-state": "1.2.2",
- "aria-hidden": "^1.2.4",
- "react-remove-scroll": "^2.6.3"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": {
- "version": "1.1.10",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz",
- "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==",
- "dependencies": {
- "@radix-ui/primitive": "1.1.2",
- "@radix-ui/react-compose-refs": "1.1.2",
- "@radix-ui/react-primitive": "2.1.3",
- "@radix-ui/react-use-callback-ref": "1.1.1",
- "@radix-ui/react-use-escape-keydown": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
- "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
- "dependencies": {
- "@radix-ui/react-compose-refs": "1.1.2",
- "@radix-ui/react-primitive": "2.1.3",
- "@radix-ui/react-use-callback-ref": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
- "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
- "dependencies": {
- "@radix-ui/react-primitive": "2.1.3",
- "@radix-ui/react-use-layout-effect": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz",
- "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==",
- "dependencies": {
- "@radix-ui/react-compose-refs": "1.1.2",
- "@radix-ui/react-use-layout-effect": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
- "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
- "dependencies": {
- "@radix-ui/react-slot": "1.2.3"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
- "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
- "dependencies": {
- "@radix-ui/react-compose-refs": "1.1.2"
- },
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
"node_modules/@radix-ui/react-direction": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
@@ -2798,32 +2573,6 @@
}
}
},
- "node_modules/@radix-ui/react-dismissable-layer": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.7.tgz",
- "integrity": "sha512-j5+WBUdhccJsmH5/H0K6RncjDtoALSEr6jbkaZu+bjw6hOPOhHycr6vEUujl+HBK8kjUfWcoCJXxP6e4lUlMZw==",
- "dependencies": {
- "@radix-ui/primitive": "1.1.2",
- "@radix-ui/react-compose-refs": "1.1.2",
- "@radix-ui/react-primitive": "2.1.0",
- "@radix-ui/react-use-callback-ref": "1.1.1",
- "@radix-ui/react-use-escape-keydown": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
"node_modules/@radix-ui/react-dropdown-menu": {
"version": "2.1.15",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.15.tgz",
@@ -2908,30 +2657,6 @@
}
}
},
- "node_modules/@radix-ui/react-focus-scope": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.4.tgz",
- "integrity": "sha512-r2annK27lIW5w9Ho5NyQgqs0MmgZSTIKXWpVCJaLC1q2kZrZkcqnmHkCHMEmv8XLvsLlurKMPT+kbKkRkm/xVA==",
- "dependencies": {
- "@radix-ui/react-compose-refs": "1.1.2",
- "@radix-ui/react-primitive": "2.1.0",
- "@radix-ui/react-use-callback-ref": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
"node_modules/@radix-ui/react-id": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
@@ -3466,60 +3191,6 @@
}
}
},
- "node_modules/@radix-ui/react-popper": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.4.tgz",
- "integrity": "sha512-3p2Rgm/a1cK0r/UVkx5F/K9v/EplfjAeIFCGOPYPO4lZ0jtg4iSQXt/YGTSLWaf4x7NG6Z4+uKFcylcTZjeqDA==",
- "dependencies": {
- "@floating-ui/react-dom": "^2.0.0",
- "@radix-ui/react-arrow": "1.1.4",
- "@radix-ui/react-compose-refs": "1.1.2",
- "@radix-ui/react-context": "1.1.2",
- "@radix-ui/react-primitive": "2.1.0",
- "@radix-ui/react-use-callback-ref": "1.1.1",
- "@radix-ui/react-use-layout-effect": "1.1.1",
- "@radix-ui/react-use-rect": "1.1.1",
- "@radix-ui/react-use-size": "1.1.1",
- "@radix-ui/rect": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-portal": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.6.tgz",
- "integrity": "sha512-XmsIl2z1n/TsYFLIdYam2rmFwf9OC/Sh2avkbmVMDuBZIe7hSpM0cYnWPAo7nHOVx8zTuwDZGByfcqLdnzp3Vw==",
- "dependencies": {
- "@radix-ui/react-primitive": "2.1.0",
- "@radix-ui/react-use-layout-effect": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
"node_modules/@radix-ui/react-presence": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.3.tgz",
@@ -3752,48 +3423,6 @@
}
}
},
- "node_modules/@radix-ui/react-select": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.2.tgz",
- "integrity": "sha512-HjkVHtBkuq+r3zUAZ/CvNWUGKPfuicGDbgtZgiQuFmNcV5F+Tgy24ep2nsAW2nFgvhGPJVqeBZa6KyVN0EyrBA==",
- "dependencies": {
- "@radix-ui/number": "1.1.1",
- "@radix-ui/primitive": "1.1.2",
- "@radix-ui/react-collection": "1.1.4",
- "@radix-ui/react-compose-refs": "1.1.2",
- "@radix-ui/react-context": "1.1.2",
- "@radix-ui/react-direction": "1.1.1",
- "@radix-ui/react-dismissable-layer": "1.1.7",
- "@radix-ui/react-focus-guards": "1.1.2",
- "@radix-ui/react-focus-scope": "1.1.4",
- "@radix-ui/react-id": "1.1.1",
- "@radix-ui/react-popper": "1.2.4",
- "@radix-ui/react-portal": "1.1.6",
- "@radix-ui/react-primitive": "2.1.0",
- "@radix-ui/react-slot": "1.2.0",
- "@radix-ui/react-use-callback-ref": "1.1.1",
- "@radix-ui/react-use-controllable-state": "1.2.2",
- "@radix-ui/react-use-layout-effect": "1.1.1",
- "@radix-ui/react-use-previous": "1.1.1",
- "@radix-ui/react-visually-hidden": "1.2.0",
- "aria-hidden": "^1.2.4",
- "react-remove-scroll": "^2.6.3"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
"node_modules/@radix-ui/react-slot": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz",
@@ -3939,28 +3568,6 @@
}
}
},
- "node_modules/@radix-ui/react-visually-hidden": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.0.tgz",
- "integrity": "sha512-rQj0aAWOpCdCMRbI6pLQm8r7S2BM3YhTa0SzOYD55k+hJA8oo9J+H+9wLM9oMlZWOX/wJWPTzfDfmZkf7LvCfg==",
- "dependencies": {
- "@radix-ui/react-primitive": "2.1.0"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
"node_modules/@radix-ui/rect": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
diff --git a/package.json b/package.json
index 7b050219..c0541f50 100644
--- a/package.json
+++ b/package.json
@@ -19,11 +19,9 @@
"@base-ui-components/react": "1.0.0-beta.6",
"@hookform/resolvers": "5.0.1",
"@radix-ui/react-checkbox": "1.2.2",
- "@radix-ui/react-dialog": "1.1.14",
"@radix-ui/react-dropdown-menu": "2.1.15",
"@radix-ui/react-popover": "1.1.14",
"@radix-ui/react-radio-group": "1.3.6",
- "@radix-ui/react-select": "2.2.2",
"@radix-ui/react-slot": "1.2.0",
"@tanstack/react-query": "5.83.0",
"class-variance-authority": "0.7.1",
diff --git a/src/actions/patients/get-patient.ts b/src/actions/patients/get-patient.ts
index 530b9d42..6d4825cb 100644
--- a/src/actions/patients/get-patient.ts
+++ b/src/actions/patients/get-patient.ts
@@ -2,13 +2,13 @@
import { NEXT_CACHE_TAGS } from '@/constants/cache'
import { api } from '@/lib/api'
-import type { PatientType } from '@/types/patients'
+import type { Patient } from '@/types/patients'
export async function getPatient(id: string) {
const REVALIDATE_IN_SECONDS = 3600
try {
- const response = await api(`/patients/${id}`, {
+ const response = await api(`/patients/${id}`, {
includeCookies: true,
cache: 'force-cache',
next: {
diff --git a/src/actions/users.ts b/src/actions/users.ts
index 148b3adb..056f2e6e 100644
--- a/src/actions/users.ts
+++ b/src/actions/users.ts
@@ -5,7 +5,7 @@ import { redirect } from 'next/navigation'
import { NEXT_CACHE_TAGS } from '@/constants/cache'
import { ROUTES } from '@/constants/routes'
import { api } from '@/lib/api'
-import type { UserType } from '@/types/users'
+import type { User } from '@/types/users'
import { getDataFromToken } from './token'
@@ -16,7 +16,7 @@ export async function getProfile() {
if (!data?.userId) return null
- const response = await api('/users/profile', {
+ const response = await api('/users/profile', {
includeCookies: true,
cache: 'force-cache',
next: {
diff --git a/src/app/(dashboard)/_sidebar/account.tsx b/src/app/(dashboard)/_sidebar/account.tsx
index 628ee26d..10a028d8 100644
--- a/src/app/(dashboard)/_sidebar/account.tsx
+++ b/src/app/(dashboard)/_sidebar/account.tsx
@@ -16,10 +16,10 @@ import { NEXT_CACHE_TAGS } from '@/constants/cache'
import { ROUTES } from '@/constants/routes'
import { api } from '@/lib/api'
import { useSidebar } from '@/store/sidebar'
-import type { UserType } from '@/types/users'
+import type { User } from '@/types/users'
interface SidebarAccountProps {
- user: UserType
+ user: User
}
export function SidebarAccount({ user }: Readonly) {
diff --git a/src/app/(dashboard)/_sidebar/container.tsx b/src/app/(dashboard)/_sidebar/container.tsx
index d747efb3..bf7f9e2c 100644
--- a/src/app/(dashboard)/_sidebar/container.tsx
+++ b/src/app/(dashboard)/_sidebar/container.tsx
@@ -20,7 +20,7 @@ export function DashboardSidebarContainer({
className={cn(
'border-border flex h-screen shrink-0 flex-col gap-8 overflow-x-hidden overflow-y-auto border-r py-6 transition-all duration-500',
className,
- expanded ? 'w-56 px-6' : 'w-18 px-4',
+ expanded ? 'w-60 px-6' : 'w-18 px-4',
)}
{...props}
/>
@@ -30,7 +30,7 @@ export function DashboardSidebarContainer({
variant='outline'
data-expanded={expanded}
className={cn(
- 'text-disabled hover:text-foreground-soft absolute top-20 -right-4 z-50 size-8 rounded-full transition-all delay-75 duration-300 [&_svg]:size-5',
+ 'text-disabled hover:text-foreground-soft absolute top-20 -right-4 z-10 size-8 rounded-full transition-all delay-75 duration-300 [&_svg]:size-5',
'data-[expanded=true]:rotate-180',
)}
onClick={toogleSidebar}
diff --git a/src/app/(dashboard)/encaminhados/_cards/mock-data.ts b/src/app/(dashboard)/encaminhados/_cards/mock-data.ts
deleted file mode 100644
index f5fa66a2..00000000
--- a/src/app/(dashboard)/encaminhados/_cards/mock-data.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export function getMockReferralsCount() {
- return {
- total: 125,
- }
-}
-
-export function getMockReferredPatients() {
- return {
- percentage: 71,
- }
-}
diff --git a/src/app/(dashboard)/equipes/(members-list)/page.tsx b/src/app/(dashboard)/equipes/page.tsx
similarity index 53%
rename from src/app/(dashboard)/equipes/(members-list)/page.tsx
rename to src/app/(dashboard)/equipes/page.tsx
index 09d716e6..3491eecc 100644
--- a/src/app/(dashboard)/equipes/(members-list)/page.tsx
+++ b/src/app/(dashboard)/equipes/page.tsx
@@ -1,11 +1,11 @@
import type { Metadata } from 'next'
+import { TeamListTable } from '@/modules/teams/table'
+
export const metadata: Metadata = {
- title: 'Equipes',
+ title: 'Equipe',
}
-import { MembersListTable } from './table'
-
export default function Page() {
- return
+ return
}
diff --git a/src/app/(dashboard)/pacientes/(patients-list)/page.tsx b/src/app/(dashboard)/pacientes/(patients-list)/page.tsx
deleted file mode 100644
index d88dcccb..00000000
--- a/src/app/(dashboard)/pacientes/(patients-list)/page.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import type { Metadata } from 'next'
-import { Suspense } from 'react'
-
-import { DashboardContainer } from '@/components/dashboard/container'
-import { DashboardTabButtons } from '@/components/dashboard/tab-buttons'
-import { ROUTES } from '@/constants/routes'
-
-import { PatientsListTable } from './table'
-
-export const metadata: Metadata = {
- title: 'Pacientes',
-}
-
-export default function Page() {
- const tabButtons = [
- {
- title: 'Listagem de pacientes',
- path: ROUTES.dashboard.patients.main,
- },
- ]
-
- return (
- <>
-
-
- Carregando...}>
-
-
-
- >
- )
-}
diff --git a/src/app/(dashboard)/pacientes/[id]/documentos/page.tsx b/src/app/(dashboard)/pacientes/[id]/documentos/page.tsx
index 0a506f7b..48439f7b 100644
--- a/src/app/(dashboard)/pacientes/[id]/documentos/page.tsx
+++ b/src/app/(dashboard)/pacientes/[id]/documentos/page.tsx
@@ -1,4 +1,4 @@
-import { PatientsDocuments } from './patients-documents'
+import { PatientDocuments } from '../../../../../modules/patients/documents'
const PATIENT_SECTIONS = [
{
@@ -46,5 +46,5 @@ export default function Page() {
return Nenhum documento encontrado.
}
- return
+ return
}
diff --git a/src/app/(dashboard)/pacientes/[id]/historico/page.tsx b/src/app/(dashboard)/pacientes/[id]/historico/page.tsx
index 59959094..b1c163dc 100644
--- a/src/app/(dashboard)/pacientes/[id]/historico/page.tsx
+++ b/src/app/(dashboard)/pacientes/[id]/historico/page.tsx
@@ -3,8 +3,6 @@ import { redirect } from 'next/navigation'
import { ROUTES } from '@/constants/routes'
-import PatientHistoryTable from './patient-history-table'
-
export const metadata: Metadata = {
title: 'Histórico',
}
@@ -22,5 +20,5 @@ export default async function Page({
redirect(ROUTES.dashboard.patients.main)
}
- return
+ return Histórico do paciente {patientId}
}
diff --git a/src/app/(dashboard)/pacientes/[id]/historico/patient-history-table.tsx b/src/app/(dashboard)/pacientes/[id]/historico/patient-history-table.tsx
deleted file mode 100644
index 0836d23c..00000000
--- a/src/app/(dashboard)/pacientes/[id]/historico/patient-history-table.tsx
+++ /dev/null
@@ -1,206 +0,0 @@
-'use client'
-
-import {
- CheckIcon,
- HistoryIcon,
- PencilIcon,
- Trash2Icon,
- XIcon,
-} from 'lucide-react'
-import React, { useState } from 'react'
-
-import { DataTableHeader } from '@/components/data-table/header'
-import { DataTableHeaderInfo } from '@/components/data-table/header/info'
-import { Button } from '@/components/ui/button'
-import { Card } from '@/components/ui/card'
-import { Divider } from '@/components/ui/divider'
-import { ExpandableText } from '@/components/ui/expandable-text'
-import { Select, SelectValue } from '@/components/ui/select'
-import { SelectContent } from '@/components/ui/select/content'
-import { SelectItem } from '@/components/ui/select/item'
-import { SelectTrigger } from '@/components/ui/select/trigger'
-import { PATIENT_STATUS } from '@/types/patients'
-import { PATIENTS_MOCKS } from '@/utils/mock/patients'
-
-export default function PatientHistoryTable() {
- const longText =
- 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatem similique, eveniet ipsa quam quaerat suscipit dolorum, consequatur totam recusandae voluptatum perferendis placeat molestiae! Obcaecati officia consequatur voluptates, enim nemo dolorem! Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatem similique, eveniet ipsa quam quaerat suscipit dolorum, consequatur totam recusandae voluptatum perferendis placeat molestiae! Obcaecati officia consequatur voluptates, enim nemo dolorem!'
-
- const initialPatients = PATIENTS_MOCKS.map((p) => ({
- ...p,
- status: 'stable',
- created_at: new Date(p.created_at),
- notes: longText,
- }))
-
- const [patients, setPatients] = useState(initialPatients)
- const [editingRowId, setEditingRowId] = useState(null)
- const [selectedStatus, setSelectedStatus] = useState(null)
- const [editingNotes, setEditingNotes] = useState('')
-
- const handleEditClick = (
- patientId: string,
- currentStatus: string,
- currentNotes: string,
- ) => {
- setEditingRowId(patientId)
- setSelectedStatus(currentStatus)
- setEditingNotes(currentNotes)
- }
-
- const handleCancelClick = () => {
- setEditingRowId(null)
- setSelectedStatus(null)
- setEditingNotes('')
- }
-
- const handleSaveClick = (patientId: string) => {
- if (!selectedStatus) return
-
- setPatients(
- patients.map((p) =>
- p.id === patientId
- ? {
- ...p,
- status: selectedStatus,
- notes: editingNotes,
- }
- : p,
- ),
- )
- handleCancelClick()
- }
-
- return (
- <>
-
- }
- title='Histórico do paciente'
- />
-
-
-
-
-
-
-
-
-
Data
-
Profissional
-
Quadro geral
-
-
-
- {patients.length === 0 ? (
-
- Nenhum histórico para esse paciente.
-
- ) : (
- patients.map((patient) => {
- const isEditing = editingRowId === patient.id
-
- return (
-
-
- {/* Seção de cabeçalho da tabela*/}
-
-
{patient.created_at.toLocaleDateString('pt-BR')}
-
-
-
- {isEditing ? (
-
- ) : (
-
Status
- )}
-
-
- {/* Seção de observações e botões de ação */}
-
-
- Observações:
- {isEditing ? (
-
-
- {isEditing ? (
- <>
-
-
- >
- ) : (
- <>
-
-
- >
- )}
-
-
-
-
-
- )
- })
- )}
-
-
- >
- )
-}
diff --git a/src/app/(dashboard)/pacientes/[id]/informacoes/page.tsx b/src/app/(dashboard)/pacientes/[id]/informacoes/page.tsx
index 873a7d26..993a5f52 100644
--- a/src/app/(dashboard)/pacientes/[id]/informacoes/page.tsx
+++ b/src/app/(dashboard)/pacientes/[id]/informacoes/page.tsx
@@ -3,11 +3,10 @@ import type { Metadata } from 'next'
import { redirect } from 'next/navigation'
import { getPatient } from '@/actions/patients/get-patient'
-import { PatientsForm } from '@/components/patients/form'
import { Button } from '@/components/ui/button'
import { ROUTES } from '@/constants/routes'
-
-import { PatientInactivateButton } from './inactivate-button'
+import { PatientForm } from '@/modules/patients/form'
+import { InactivatePatientButton } from '@/modules/patients/inactivate-button'
export const metadata: Metadata = {
title: 'Informações do paciente',
@@ -45,7 +44,7 @@ export default async function Page({
- {isPatientActive &&
}
+ {isPatientActive &&
}
-
+
>
)
}
diff --git a/src/app/(dashboard)/pacientes/cadastrar/page.tsx b/src/app/(dashboard)/pacientes/cadastrar/page.tsx
index 296d0299..3b9124c6 100644
--- a/src/app/(dashboard)/pacientes/cadastrar/page.tsx
+++ b/src/app/(dashboard)/pacientes/cadastrar/page.tsx
@@ -2,7 +2,7 @@ import { UserRoundPlusIcon } from 'lucide-react'
import type { Metadata } from 'next'
import { DashboardContainer } from '@/components/dashboard/container'
-import { PatientsForm } from '@/components/patients/form'
+import { PatientForm } from '@/modules/patients/form'
export const metadata: Metadata = {
title: 'Cadastrar novo paciente',
@@ -19,7 +19,7 @@ export default function Page() {
Cadastrar novo paciente
-
+
)
}
diff --git a/src/app/(dashboard)/pacientes/page.tsx b/src/app/(dashboard)/pacientes/page.tsx
new file mode 100644
index 00000000..db02417c
--- /dev/null
+++ b/src/app/(dashboard)/pacientes/page.tsx
@@ -0,0 +1,19 @@
+import type { Metadata } from 'next'
+import { Suspense } from 'react'
+
+import { DashboardContainer } from '@/components/dashboard/container'
+import { PatientsListTable } from '@/modules/patients/list/table'
+
+export const metadata: Metadata = {
+ title: 'Pacientes',
+}
+
+export default function Page() {
+ return (
+
+ Carregando...}>
+
+
+
+ )
+}
diff --git a/src/app/(dashboard)/page.tsx b/src/app/(dashboard)/page.tsx
index 03edd0de..3bb85f53 100644
--- a/src/app/(dashboard)/page.tsx
+++ b/src/app/(dashboard)/page.tsx
@@ -1,12 +1,11 @@
import { Suspense } from 'react'
-import { DashboardOverviewPatientsByGender } from '@/app/(dashboard)/_cards/patients-by-gender'
-import { DashboardOverviewPatientsByStatus } from '@/app/(dashboard)/_cards/patients-by-status'
import { DashboardContainer } from '@/components/dashboard/container'
import { Skeleton } from '@/components/ui/skeleton'
-
-import DashboardOverviewAppointments from './_cards/appointments'
-import { DashboardOverviewPatientsByCity } from './_cards/patients-by-city'
+import AppointmentsCard from '@/modules/dashboard/appointments-card'
+import { PatientsByCityCard } from '@/modules/dashboard/patients-by-city-card'
+import { PatientsByGenderCard } from '@/modules/dashboard/patients-by-gender-card'
+import { PatientsByStatusCards } from '@/modules/dashboard/patients-by-status-cards'
export const dynamic = 'force-dynamic'
@@ -19,13 +18,13 @@ export default function Page() {
}
>
-
+
-
-
+
+
-
+
)
diff --git a/src/app/paciente/_header/user-dropdown.tsx b/src/app/paciente/_header/user-dropdown.tsx
index cac12499..1349da5e 100644
--- a/src/app/paciente/_header/user-dropdown.tsx
+++ b/src/app/paciente/_header/user-dropdown.tsx
@@ -16,10 +16,10 @@ import { DropdownMenuTrigger } from '@/components/ui/dropdown/trigger'
import { NEXT_CACHE_TAGS } from '@/constants/cache'
import { ROUTES } from '@/constants/routes'
import { api } from '@/lib/api'
-import type { UserType } from '@/types/users'
+import type { User } from '@/types/users'
interface PatientHeaderUserDropdownProps {
- user: UserType
+ user: User
}
export function PatientHeaderUserDropdown({
diff --git a/src/app/paciente/triagem/seus-dados/patient-data-form.tsx b/src/app/paciente/triagem/seus-dados/patient-data-form.tsx
index e54f745a..c29f5384 100644
--- a/src/app/paciente/triagem/seus-dados/patient-data-form.tsx
+++ b/src/app/paciente/triagem/seus-dados/patient-data-form.tsx
@@ -10,11 +10,11 @@ import { FormContainer } from '@/components/form/form-container'
import { SelectInput } from '@/components/form/select-input'
import { TextInput } from '@/components/form/text-input'
import { Button } from '@/components/ui/button'
-import { BRAZILIAN_STATES_OPTIONS, type UFType } from '@/constants/enums'
+import { BRAZILIAN_STATES_OPTIONS, type UF } from '@/constants/enums'
import { ROUTES } from '@/constants/routes'
import { PATIENT_STORAGE_KEYS } from '@/constants/storage-keys'
import { useCities } from '@/hooks/cities'
-import { GENDERS_OPTIONS } from '@/types/patients'
+import { GENDER_OPTIONS } from '@/types/patients'
import { useScreening } from '../hooks'
import {
@@ -41,7 +41,7 @@ export function ScreeningPatientDataForm() {
mode: 'onBlur',
})
const { clearErrors, setValue, watch, reset } = formMethods
- const UF = watch('state') as UFType
+ const UF = watch('state') as UF
const cities = useCities(UF)
function handleSelectState(value: string) {
@@ -82,7 +82,7 @@ export function ScreeningPatientDataForm() {
diff --git a/src/components/appointments/modal.tsx b/src/components/appointments/modal.tsx
deleted file mode 100644
index 3a00bc8e..00000000
--- a/src/components/appointments/modal.tsx
+++ /dev/null
@@ -1,149 +0,0 @@
-'use client'
-
-import { zodResolver } from '@hookform/resolvers/zod'
-import { SmilePlusIcon } from 'lucide-react'
-import { FormProvider, useForm } from 'react-hook-form'
-import { toast } from 'sonner'
-import { z } from 'zod'
-
-import { TextInput } from '@/components/form/text-input'
-import { Button } from '@/components/ui/button'
-import { DialogClose } from '@/components/ui/dialog/close'
-import { DialogContainer } from '@/components/ui/dialog/container'
-import { DialogContent } from '@/components/ui/dialog/content'
-import { DialogFooter } from '@/components/ui/dialog/footer'
-import { DialogHeader } from '@/components/ui/dialog/header'
-import { DialogTitle } from '@/components/ui/dialog/title'
-import { api } from '@/lib/api'
-
-import { DateInput } from '../form/date-input'
-import { FormContainer } from '../form/form-container'
-import { TextareaInput } from '../form/textarea-input'
-
-interface AppointmentModalProps {
- onOpenChange: (open: boolean) => void
-}
-
-const appointmentFormSchema = z.object({
- patient_name: z.string().min(1, 'O nome do paciente é obrigatório'),
- appointment_date: z.string().datetime('A data do atendimento é obrigatória'),
- specialist_id: z.string().uuid('O especialista é obrigatório'),
- specialist_specialty: z.string(),
- condition: z
- .string()
- .nullable()
- .transform((value) => (!value ? null : value)),
- annotation: z
- .string()
- .max(500)
- .nullable()
- .transform((value) => (!value ? null : value)),
-})
-type AppointmentFormSchema = z.infer
-
-export function AppointmentModal({ onOpenChange }: AppointmentModalProps) {
- const formMethods = useForm({
- resolver: zodResolver(appointmentFormSchema),
- defaultValues: {
- patient_name: '',
- appointment_date: '',
- specialist_id: '',
- specialist_specialty: '',
- condition: '',
- annotation: '',
- },
- mode: 'onBlur',
- })
-
- async function submitForm(data: AppointmentFormSchema) {
- console.log(data)
-
- const response = await api('/appointments', {
- method: 'POST',
- body: JSON.stringify(data),
- })
-
- if (!response.success) {
- toast.error(response.message)
- return
- }
-
- toast.success(response.message)
- onOpenChange(false)
- }
-
- return (
-
-
- Novo atendimento
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Cancelar
-
-
-
-
-
- )
-}
diff --git a/src/components/appointments/new-button.tsx b/src/components/appointments/new-button.tsx
deleted file mode 100644
index c47d6e07..00000000
--- a/src/components/appointments/new-button.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-'use client'
-
-import { PlusIcon } from 'lucide-react'
-import { useState } from 'react'
-
-import { Dialog } from '@/components/ui/dialog'
-import { DialogTrigger } from '@/components/ui/dialog/trigger'
-
-import type { ButtonProps } from '../ui/button'
-import { AppointmentModal } from './modal'
-
-export function NewAppointmentButton(props: Readonly) {
- const [dialogOpen, setDialogOpen] = useState(false)
-
- return (
-
- )
-}
diff --git a/src/components/data-table/filters/status.tsx b/src/components/data-table/filters/status.tsx
index 87f99316..8e984b8e 100644
--- a/src/components/data-table/filters/status.tsx
+++ b/src/components/data-table/filters/status.tsx
@@ -2,11 +2,7 @@
import { type LucideIcon } from 'lucide-react'
-import { Select, SelectValue } from '@/components/ui/select'
-import { SelectContent } from '@/components/ui/select/content'
-import { SelectItem } from '@/components/ui/select/item'
-import { SelectItemReset } from '@/components/ui/select/item-reset'
-import { SelectTrigger } from '@/components/ui/select/trigger'
+import { Select, type SelectOption } from '@/components/ui/select'
import { QUERY_PARAMS } from '@/constants/params'
import { useParams } from '@/hooks/params'
import { cn } from '@/utils/class-name-merge'
@@ -16,9 +12,7 @@ import {
type DataTableFilterContainerProps,
} from './container'
-type StatusOption = {
- label: string
- value: string
+type StatusOption = SelectOption & {
icon?: LucideIcon
color?: string
}
@@ -57,28 +51,13 @@ export function DataTableFilterStatus({
className={cn('w-48 shrink-0', className)}
{...props}
>
-
+
)
}
diff --git a/src/components/data-table/header/order-by.tsx b/src/components/data-table/header/order-by.tsx
index 85a06b8a..86fb1c4a 100644
--- a/src/components/data-table/header/order-by.tsx
+++ b/src/components/data-table/header/order-by.tsx
@@ -1,57 +1,45 @@
'use client'
-import type { SelectTriggerProps } from '@radix-ui/react-select'
-import { ArrowDownWideNarrowIcon } from 'lucide-react'
-
-import { Select, type SelectOptions, SelectValue } from '@/components/ui/select'
-import { SelectContent } from '@/components/ui/select/content'
-import { SelectItem } from '@/components/ui/select/item'
-import { SelectItemReset } from '@/components/ui/select/item-reset'
-import { SelectTrigger } from '@/components/ui/select/trigger'
+import { Select, type SelectOption } from '@/components/ui/select'
import { QUERY_PARAMS } from '@/constants/params'
import { useParams } from '@/hooks/params'
import { cn } from '@/utils/class-name-merge'
-interface DataTableHeaderOrderByProps extends SelectTriggerProps {
- options: SelectOptions
+interface DataTableHeaderOrderByProps {
+ options: SelectOption[]
+ className?: string
}
export function DataTableHeaderOrderBy({
options,
className,
- ...props
}: Readonly) {
const { getParam, updateParams } = useParams()
const orderByParam = QUERY_PARAMS.orderBy
- const orderBy = getParam(orderByParam) || ''
+ const orderBy = getParam(orderByParam)
- function handleSelect(value: string) {
- if (value === 'reset') {
+ function handleSelect(value: string | null) {
+ if (!value || value === 'reset') {
updateParams({ remove: [orderByParam] })
return
}
- updateParams({ set: [{ key: orderByParam, value: value }] })
+ updateParams({ set: [{ key: orderByParam, value }] })
}
+ const enhancedOptions: SelectOption[] = [
+ ...options.map(({ label, value }) => ({ label: label, value: value })),
+ ...(orderBy ? [{ label: 'Limpar ordem', value: 'reset' }] : []),
+ ]
+
return (
-
+
)
}
diff --git a/src/components/form/form-message.tsx b/src/components/form/form-message.tsx
index 172e71db..f944e711 100644
--- a/src/components/form/form-message.tsx
+++ b/src/components/form/form-message.tsx
@@ -3,7 +3,7 @@ import { AlertCircleIcon } from 'lucide-react'
import { cn } from '@/utils/class-name-merge'
-const formMessageVariants = cva('mt-1 flex items-center gap-1 text-sm', {
+const formMessageVariants = cva('mt-1 flex items-center gap-1.5 text-sm', {
variants: {
variant: {
default: 'text-foreground-soft',
@@ -37,7 +37,7 @@ export function FormMessage({
)}
{...props}
>
- {error && }
+ {error && }
{children}
)
diff --git a/src/components/form/select-input.tsx b/src/components/form/select-input.tsx
index eb1efddf..0cbc3126 100644
--- a/src/components/form/select-input.tsx
+++ b/src/components/form/select-input.tsx
@@ -4,27 +4,26 @@ import { Controller, useFormContext } from 'react-hook-form'
import { cn } from '@/utils/class-name-merge'
import { Label } from '../ui/label'
-import { Select, type SelectOptions, SelectValue } from '../ui/select'
-import { SelectContent } from '../ui/select/content'
-import { SelectItem } from '../ui/select/item'
-import { SelectTrigger, type SelectTriggerProps } from '../ui/select/trigger'
+import { Select, type SelectOption } from '../ui/select'
import { FormMessage } from './form-message'
import { RequiredInput } from './required-input'
interface RequiredSelectInputProps {
name: string
label: string | ReactNode
- options: SelectOptions
+ options: SelectOption[]
}
-type SelectInputProps = RequiredSelectInputProps &
- SelectTriggerProps & {
- isRequired?: boolean
- placeholder?: string
- message?: string
- wrapperClassName?: SelectTriggerProps['className']
- onValueChange?: (value: T) => void
- }
+type SelectInputProps = RequiredSelectInputProps & {
+ isRequired?: boolean
+ placeholder?: string
+ message?: string
+ onValueChange?: (value: T) => void
+ disabled?: boolean
+ readOnly?: boolean
+ modal?: boolean
+ className?: string
+}
export function SelectInput({
name,
@@ -34,9 +33,10 @@ export function SelectInput({
readOnly,
isRequired,
placeholder,
- wrapperClassName,
onValueChange,
- ...props
+ disabled,
+ modal,
+ className,
}: Readonly>) {
const { control } = useFormContext()
@@ -57,32 +57,20 @@ export function SelectInput({
}
return (
-
+
+ disabled={disabled || readOnly}
+ readOnly={readOnly}
+ />
{showMessage}
diff --git a/src/components/patients/cancel-patient-creation-modal.tsx b/src/components/patients/cancel-patient-creation-modal.tsx
deleted file mode 100644
index 5e2616df..00000000
--- a/src/components/patients/cancel-patient-creation-modal.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { CircleAlertIcon } from 'lucide-react'
-
-import { Button } from '../ui/button'
-import { DialogClose } from '../ui/dialog/close'
-import { DialogContainer } from '../ui/dialog/container'
-import { DialogDescription } from '../ui/dialog/description'
-import { DialogFooter } from '../ui/dialog/footer'
-import { DialogHeader } from '../ui/dialog/header'
-import { DialogTitle } from '../ui/dialog/title'
-
-interface CancelPatientCreationModalProps {
- onConfirm: () => void
-}
-
-export default function CancelPatientCreationModal({
- onConfirm,
-}: CancelPatientCreationModalProps) {
- return (
-
-
- Cancelar o cadastro do paciente?
-
- Esta ação é irreversível e todo o progresso será perdido.
-
-
-
-
- Voltar
-
-
- )
-}
diff --git a/src/components/select-period.tsx b/src/components/select-period.tsx
index 88589463..e17c9736 100644
--- a/src/components/select-period.tsx
+++ b/src/components/select-period.tsx
@@ -1,16 +1,13 @@
'use client'
-import { QUERY_PERIODS_OPTIONS, type QueryPeriodType } from '@/types/queries'
+import { QUERY_PERIODS_OPTIONS, type QueryPeriod } from '@/types/queries'
-import { Select, SelectValue } from './ui/select'
-import { SelectContent } from './ui/select/content'
-import { SelectItem } from './ui/select/item'
-import { SelectTrigger } from './ui/select/trigger'
+import { Select, type SelectOption } from './ui/select'
interface SelectPeriodProps {
- period: QueryPeriodType
- onSelect: (value: QueryPeriodType) => void
+ period: QueryPeriod
disabled?: boolean
+ onSelect: (value: QueryPeriod) => void
}
export function SelectPeriod({
@@ -18,25 +15,21 @@ export function SelectPeriod({
disabled,
onSelect,
}: Readonly) {
- const defaultValue = QUERY_PERIODS_OPTIONS.find(
- (option) => option.value === period,
- )
+ const options: SelectOption[] = QUERY_PERIODS_OPTIONS.map((option) => ({
+ label: option.label,
+ value: option.value,
+ }))
+
+ function handleValueChange(value: string) {
+ onSelect(value as QueryPeriod)
+ }
return (
+ options={options}
+ onValueChange={handleValueChange}
+ disabled={disabled}
+ />
)
}
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index 108b56b3..58fe7cf3 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -25,6 +25,7 @@ const buttonVariants = cva(
sm: 'h-9 min-h-9 px-4 [&_svg]:size-4',
lg: 'h-11 min-h-11 rounded-xl px-3 [&_svg]:size-5',
icon: 'min-size-10 size-10 [&_svg]:size-5',
+ icon_sm: 'min-size-9 size-9 [&_svg]:size-5',
},
},
defaultVariants: {
diff --git a/src/components/ui/calendar/dropdown-nav.tsx b/src/components/ui/calendar/dropdown-nav.tsx
index 41e6c3a6..605eca9a 100644
--- a/src/components/ui/calendar/dropdown-nav.tsx
+++ b/src/components/ui/calendar/dropdown-nav.tsx
@@ -3,10 +3,7 @@ import { useEffect, useState } from 'react'
import { NavProps, useDayPicker } from 'react-day-picker'
import { Button } from '../button'
-import { Select, SelectValue } from '../select'
-import { SelectContent } from '../select/content'
-import { SelectItem } from '../select/item'
-import { SelectTrigger } from '../select/trigger'
+import { Select, type SelectOption } from '../select'
const monthsOfYear = [
'Jan',
@@ -59,6 +56,16 @@ export function CalendarDropdownNav({
? monthsOfYear.filter((_, index) => index <= new Date().getMonth())
: monthsOfYear
+ const monthOptions: SelectOption[] = availableMonths.map((month) => ({
+ label: month,
+ value: month,
+ }))
+
+ const yearOptions: SelectOption[] = availableYears.map((year) => ({
+ label: String(year),
+ value: String(year),
+ }))
+
useEffect(() => {
if (!months.length) return
@@ -80,42 +87,24 @@ export function CalendarDropdownNav({
+ options={monthOptions}
+ className='h-8 w-16'
+ />
+ options={yearOptions}
+ className='h-8 w-18'
+ />
diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx
new file mode 100644
index 00000000..ad3ac72f
--- /dev/null
+++ b/src/components/ui/dialog.tsx
@@ -0,0 +1,158 @@
+import { Dialog as BaseDialog } from '@base-ui-components/react/dialog'
+import type { VariantProps } from 'class-variance-authority'
+import { type LucideIcon, XIcon } from 'lucide-react'
+
+import { cn } from '@/utils/class-name-merge'
+
+import { buttonVariants } from './button'
+
+interface DialogProps extends React.ComponentProps
{
+ children: React.ReactNode
+}
+export function Dialog({ children, ...props }: Readonly) {
+ return {children}
+}
+
+type DialogTriggerProps = React.ComponentProps &
+ VariantProps
+export function DialogTrigger({
+ variant,
+ size,
+ className,
+ ...props
+}: Readonly) {
+ return (
+
+ )
+}
+
+export function DialogContainer({
+ className,
+ children,
+ ...props
+}: Readonly>) {
+ return (
+
+
+
+
+
+
+ {children}
+
+
+ )
+}
+
+interface DialogHeaderProps extends React.ComponentProps<'div'> {
+ icon?: React.ReactNode
+}
+export function DialogHeader({
+ icon,
+ className,
+ ...props
+}: Readonly) {
+ return (
+
+ )
+}
+
+interface DialogIconProps extends React.ComponentProps<'div'> {
+ icon: LucideIcon
+}
+export function DialogIcon({
+ icon: Icon,
+ className,
+}: Readonly) {
+ return (
+
+ )
+}
+
+export function DialogTitle({
+ className,
+ ...props
+}: Readonly>) {
+ return (
+
+ )
+}
+
+export function DialogDescription({
+ className,
+ ...props
+}: Readonly>) {
+ return (
+
+ )
+}
+
+export function DialogContent({
+ className,
+ ...props
+}: Readonly>) {
+ return (
+
+ )
+}
+
+export function DialogFooter({
+ className,
+ ...props
+}: Readonly>) {
+ return (
+
+ )
+}
+
+type DialogCloseProps = React.ComponentProps &
+ VariantProps
+export function DialogClose({
+ variant = 'outline',
+ size,
+ className,
+ ...props
+}: Readonly) {
+ return (
+
+ )
+}
diff --git a/src/components/ui/dialog/close.tsx b/src/components/ui/dialog/close.tsx
deleted file mode 100644
index b7dbf8a3..00000000
--- a/src/components/ui/dialog/close.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import * as DialogPrimitive from '@radix-ui/react-dialog'
-import { VariantProps } from 'class-variance-authority'
-
-import { cn } from '@/utils/class-name-merge'
-
-import { buttonVariants } from '../button'
-
-interface DialogCloseProps
- extends Omit<
- React.ComponentPropsWithoutRef,
- 'asChild'
- >,
- VariantProps {}
-
-export function DialogClose({
- variant = 'outline',
- size,
- children,
- className,
- ...props
-}: Readonly) {
- return (
-
- {children}
-
- )
-}
diff --git a/src/components/ui/dialog/container.tsx b/src/components/ui/dialog/container.tsx
deleted file mode 100644
index 91c2ab42..00000000
--- a/src/components/ui/dialog/container.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import * as DialogPrimitive from '@radix-ui/react-dialog'
-import { XIcon } from 'lucide-react'
-
-import { cn } from '@/utils/class-name-merge'
-
-import { buttonVariants } from '../button'
-
-interface DialogContentProps
- extends React.ComponentProps {
- showCloseButton?: boolean
-}
-
-export function DialogContainer({
- className,
- children,
- showCloseButton = true,
- ...props
-}: Readonly) {
- return (
-
-
-
- {children}
- {showCloseButton && (
-
-
-
- )}
-
-
- )
-}
diff --git a/src/components/ui/dialog/content.tsx b/src/components/ui/dialog/content.tsx
deleted file mode 100644
index 7b068f03..00000000
--- a/src/components/ui/dialog/content.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import { cn } from '@/utils/class-name-merge'
-
-export function DialogContent({
- className,
- ...props
-}: Readonly>) {
- return
-}
diff --git a/src/components/ui/dialog/description.tsx b/src/components/ui/dialog/description.tsx
deleted file mode 100644
index 16b0ff23..00000000
--- a/src/components/ui/dialog/description.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import * as DialogPrimitive from '@radix-ui/react-dialog'
-
-import { cn } from '@/utils/class-name-merge'
-
-export function DialogDescription({
- className,
- ...props
-}: Readonly>) {
- return (
-
- )
-}
diff --git a/src/components/ui/dialog/footer.tsx b/src/components/ui/dialog/footer.tsx
deleted file mode 100644
index 12691a3f..00000000
--- a/src/components/ui/dialog/footer.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { cn } from '@/utils/class-name-merge'
-
-export function DialogFooter({
- className,
- ...props
-}: Readonly>) {
- return (
-
- )
-}
diff --git a/src/components/ui/dialog/header.tsx b/src/components/ui/dialog/header.tsx
deleted file mode 100644
index 4f1f7d4b..00000000
--- a/src/components/ui/dialog/header.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import type { LucideIcon } from 'lucide-react'
-
-import { cn } from '@/utils/class-name-merge'
-
-interface DialogHeaderProps extends React.ComponentProps<'header'> {
- icon?: LucideIcon
- iconClassName?: React.ComponentProps<'div'>['className']
-}
-
-export function DialogHeader({
- className,
- icon,
- iconClassName,
- ...props
-}: Readonly) {
- const Icon = icon
-
- return (
-
- {Icon && (
-
-
-
- )}
-
- {props.children}
-
- )
-}
diff --git a/src/components/ui/dialog/index.tsx b/src/components/ui/dialog/index.tsx
deleted file mode 100644
index 70251f8e..00000000
--- a/src/components/ui/dialog/index.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import * as DialogPrimitive from '@radix-ui/react-dialog'
-import React from 'react'
-
-export function Dialog(
- props: Readonly>,
-) {
- return
-}
-
-/* USAGE
-
-
-
-*/
diff --git a/src/components/ui/dialog/title.tsx b/src/components/ui/dialog/title.tsx
deleted file mode 100644
index d852b4b5..00000000
--- a/src/components/ui/dialog/title.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import * as DialogPrimitive from '@radix-ui/react-dialog'
-
-import { cn } from '@/utils/class-name-merge'
-
-export function DialogTitle({
- className,
- ...props
-}: Readonly>) {
- return (
-
- )
-}
diff --git a/src/components/ui/dialog/trigger.tsx b/src/components/ui/dialog/trigger.tsx
deleted file mode 100644
index dddf3f31..00000000
--- a/src/components/ui/dialog/trigger.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as DialogPrimitive from '@radix-ui/react-dialog'
-import { VariantProps } from 'class-variance-authority'
-
-import { cn } from '@/utils/class-name-merge'
-
-import { buttonVariants } from '../button'
-
-interface DialogTriggerProps
- extends Omit, 'asChild'>,
- VariantProps {}
-
-export function DialogTrigger({
- variant,
- size,
- className,
- children,
- ...props
-}: Readonly) {
- return (
-
- {children}
-
- )
-}
diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx
new file mode 100644
index 00000000..2ef10502
--- /dev/null
+++ b/src/components/ui/select.tsx
@@ -0,0 +1,94 @@
+'use client'
+
+import {
+ Select as BaseSelect,
+ type SelectRootProps,
+} from '@base-ui-components/react/select'
+import { CheckIcon, ChevronsUpDownIcon } from 'lucide-react'
+
+import { cn } from '@/utils/class-name-merge'
+
+export type SelectOption = {
+ label: string
+ value: string
+ description?: string
+}
+
+export type SelectProps = Omit, 'items'> & {
+ options: SelectOption[]
+ className?: string
+ placeholder?: string
+}
+
+export function Select({
+ value,
+ options,
+ className,
+ placeholder = 'Selecione uma opção',
+ ...props
+}: Readonly) {
+ const selectedOption = options.find((option) => option.value === value)
+
+ return (
+
+
+
+ {() => (selectedOption ? selectedOption.label : placeholder)}
+
+
+
+
+
+
+
+
+
+ {options.map(({ label, value, description }) => (
+
+
+ {label}
+ {description && (
+ {description}
+ )}
+
+
+
+
+
+
+ ))}
+
+
+
+
+
+ )
+}
diff --git a/src/components/ui/select/content.tsx b/src/components/ui/select/content.tsx
deleted file mode 100644
index 7f78d195..00000000
--- a/src/components/ui/select/content.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-'use client'
-
-import * as SelectPrimitive from '@radix-ui/react-select'
-
-import { cn } from '@/utils/class-name-merge'
-
-import { SelectScrollButton } from './scroll-buttons'
-
-export function SelectContent({
- className,
- children,
- position = 'popper',
- ...props
-}: Readonly>) {
- return (
-
-
-
-
- {children}
-
-
-
-
- )
-}
diff --git a/src/components/ui/select/index.tsx b/src/components/ui/select/index.tsx
deleted file mode 100644
index 4c8247bb..00000000
--- a/src/components/ui/select/index.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-'use client'
-
-import * as SelectPrimitive from '@radix-ui/react-select'
-
-export type SelectOptions = Array<{ label: string; value: string }>
-
-export const Select = SelectPrimitive.Root
-export const SelectGroup = SelectPrimitive.Group
-export const SelectValue = SelectPrimitive.Value
-
-/* USAGE
-
-
-
-*/
diff --git a/src/components/ui/select/item-reset.tsx b/src/components/ui/select/item-reset.tsx
deleted file mode 100644
index 31aaca4a..00000000
--- a/src/components/ui/select/item-reset.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { XIcon } from 'lucide-react'
-
-import { Divider } from '../divider'
-import { SelectItem } from './item'
-
-interface SelectItemResetProps {
- title: string
-}
-
-export function SelectItemReset({ title }: Readonly) {
- return (
- <>
-
-
-
-
- {title}
-
-
- >
- )
-}
diff --git a/src/components/ui/select/item.tsx b/src/components/ui/select/item.tsx
deleted file mode 100644
index 021dec15..00000000
--- a/src/components/ui/select/item.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-'use client'
-
-import * as SelectPrimitive from '@radix-ui/react-select'
-import { CheckIcon } from 'lucide-react'
-
-import { cn } from '@/utils/class-name-merge'
-
-export function SelectItem({
- className,
- disabled,
- children,
- ...props
-}: Readonly>) {
- return (
-
- {children}
-
-
-
-
- )
-}
diff --git a/src/components/ui/select/scroll-buttons.tsx b/src/components/ui/select/scroll-buttons.tsx
deleted file mode 100644
index fae4b59a..00000000
--- a/src/components/ui/select/scroll-buttons.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-'use client'
-
-import * as SelectPrimitive from '@radix-ui/react-select'
-import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react'
-
-import { cn } from '@/utils/class-name-merge'
-
-interface SelectScrollButtonProps
- extends React.ComponentProps {
- direction: 'up' | 'down'
-}
-
-export function SelectScrollButton({
- direction,
- className,
- ...props
-}: Readonly) {
- const Component =
- direction === 'up'
- ? SelectPrimitive.ScrollUpButton
- : SelectPrimitive.ScrollDownButton
- const Icon = direction === 'up' ? ChevronUpIcon : ChevronDownIcon
-
- return (
-
-
-
- )
-}
diff --git a/src/components/ui/select/trigger.tsx b/src/components/ui/select/trigger.tsx
deleted file mode 100644
index 58b8e26e..00000000
--- a/src/components/ui/select/trigger.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-'use client'
-
-import * as SelectPrimitive from '@radix-ui/react-select'
-import { cva, type VariantProps } from 'class-variance-authority'
-import { ChevronsUpDownIcon, Loader2Icon, type LucideIcon } from 'lucide-react'
-
-import { cn } from '@/utils/class-name-merge'
-
-export interface SelectTriggerProps
- extends React.ComponentProps,
- VariantProps {
- readOnly?: boolean
- icon?: LucideIcon
- loading?: boolean
-}
-
-const triggerVariants = cva(
- 'ring-offset-background focus-visible:ring-ring bg-background disabled:bg-background hover:bg-accent data-[placeholder]:text-disabled [&_svg]:text-disabled flex h-10 cursor-pointer items-center gap-2 rounded-lg border whitespace-nowrap shadow-xs transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 data-[readonly=true]:pointer-events-none [&_svg]:size-4.5 [&_svg]:shrink-0',
- {
- variants: {
- variant: {
- default: 'border-border text-foreground',
- error: 'border-error focus-visible:ring-error',
- },
- size: {
- default: 'h-10 pr-2 pl-3 [&_svg]:size-4.5',
- sm: 'h-9 pr-2 pl-3 text-sm [&_svg]:size-4',
- },
- },
- defaultVariants: {
- variant: 'default',
- size: 'default',
- },
- },
-)
-
-export function SelectTrigger({
- readOnly,
- variant,
- icon: Icon,
- className,
- size,
- loading,
- disabled,
- children,
- ...props
-}: Readonly) {
- const iconColors = {
- default: 'text-disabled',
- error: 'text-error',
- }
-
- const disabledTrigger = disabled || loading
- const IndicatorIcon = loading ? Loader2Icon : ChevronsUpDownIcon
-
- return (
-
- {Icon && }
-
- {children}
-
-
-
-
-
- )
-}
diff --git a/src/constants/cache.ts b/src/constants/cache.ts
index a6387851..53136848 100644
--- a/src/constants/cache.ts
+++ b/src/constants/cache.ts
@@ -8,7 +8,13 @@ export const NEXT_CACHE_TAGS = {
export const QUERY_CACHE_KEYS = {
profile: 'profile',
- patients: 'patients',
+ patients: {
+ allActive: 'patients-all-active',
+ list: 'patients-list',
+ },
+ referrals: {
+ list: 'referrals-list',
+ },
approvals: {
pending: 'approvals-pending',
approved: 'approvals-approved',
diff --git a/src/constants/enums.ts b/src/constants/enums.ts
index ce51f0a3..783698a7 100644
--- a/src/constants/enums.ts
+++ b/src/constants/enums.ts
@@ -36,5 +36,5 @@ export const UF_LIST = {
SE: 'Sergipe',
TO: 'Tocantins',
}
-export type UFType = keyof typeof UF_LIST
+export type UF = keyof typeof UF_LIST
export const BRAZILIAN_STATES_OPTIONS = convertObjectToOptions(UF_LIST)
diff --git a/src/hooks/cities.ts b/src/hooks/cities.ts
index ef748b55..5d555330 100644
--- a/src/hooks/cities.ts
+++ b/src/hooks/cities.ts
@@ -2,12 +2,12 @@
import { useMemo } from 'react'
-import type { SelectOptions } from '@/components/ui/select'
+import type { SelectOption } from '@/components/ui/select'
import { CITIES_BY_UF } from '@/constants/cities'
-import type { UFType } from '@/constants/enums'
+import type { UF } from '@/constants/enums'
-export function useCities(uf: UFType) {
- const cities = useMemo(() => {
+export function useCities(uf: UF) {
+ const cities = useMemo(() => {
if (!uf || !(uf in CITIES_BY_UF)) {
return []
}
diff --git a/src/hooks/use-patient-otions.ts b/src/hooks/use-patient-otions.ts
new file mode 100644
index 00000000..6719f55d
--- /dev/null
+++ b/src/hooks/use-patient-otions.ts
@@ -0,0 +1,27 @@
+'use client'
+
+import { useQuery } from '@tanstack/react-query'
+
+import { QUERY_CACHE_KEYS } from '@/constants/cache'
+import { api } from '@/lib/api'
+import type { Patient } from '@/types/patients'
+import { formatCpfNumber } from '@/utils/formatters/format-cpf-number'
+
+export function usePatientOptions() {
+ const { data: response } = useQuery({
+ queryKey: [QUERY_CACHE_KEYS.patients.allActive],
+ queryFn: () =>
+ api<{ patients: Patient[] }>('/patients', {
+ params: { all: true, status: 'active' },
+ }),
+ })
+
+ const patientOptions =
+ response?.data?.patients.map((patient) => ({
+ value: patient.id,
+ label: patient.name,
+ description: `CPF: ${formatCpfNumber(patient.cpf)}`,
+ })) || []
+
+ return { patientOptions }
+}
diff --git a/src/modules/appointments/appointment-modal.tsx b/src/modules/appointments/appointment-modal.tsx
new file mode 100644
index 00000000..dacc71a4
--- /dev/null
+++ b/src/modules/appointments/appointment-modal.tsx
@@ -0,0 +1,158 @@
+'use client'
+
+import { zodResolver } from '@hookform/resolvers/zod'
+import { SmilePlusIcon } from 'lucide-react'
+import { FormProvider, useForm } from 'react-hook-form'
+import { toast } from 'sonner'
+import { z } from 'zod'
+
+import { revalidateCache } from '@/actions/cache'
+import { ComboboxInput } from '@/components/form/combobox-input'
+import { DateInput } from '@/components/form/date-input'
+import { FormContainer } from '@/components/form/form-container'
+import { SelectInput } from '@/components/form/select-input'
+import { TextInput } from '@/components/form/text-input'
+import { TextareaInput } from '@/components/form/textarea-input'
+import { Button } from '@/components/ui/button'
+import {
+ DialogClose,
+ DialogContainer,
+ DialogContent,
+ DialogFooter,
+ DialogHeader,
+ DialogIcon,
+ DialogTitle,
+} from '@/components/ui/dialog'
+import { NEXT_CACHE_TAGS, QUERY_CACHE_KEYS } from '@/constants/cache'
+import { usePatientOptions } from '@/hooks/use-patient-otions'
+import { api } from '@/lib/api'
+import { queryClient } from '@/lib/tanstack-query'
+import {
+ PATIENT_CONDITION_ENUM,
+ PATIENT_CONDITION_OPTIONS,
+} from '@/types/patients'
+
+const appointmentFormSchema = z.object({
+ patient_id: z.string().uuid('Paciente é obrigatório'),
+ date: z.string().datetime('A data é obrigatória'),
+ referred_to: z
+ .string()
+ .nullable()
+ .transform((value) => (!value ? null : value)),
+ condition: z.enum(PATIENT_CONDITION_ENUM, {
+ message: 'O quadro é obrigatório',
+ }),
+ annotation: z
+ .string()
+ .max(500)
+ .nullable()
+ .transform((value) => (!value ? null : value)),
+})
+type AppointmentFormSchema = z.infer
+
+interface AppointmentModalProps {
+ onClose: () => void
+}
+
+export function AppointmentModal({ onClose }: Readonly) {
+ const { patientOptions } = usePatientOptions()
+
+ const formMethods = useForm({
+ resolver: zodResolver(appointmentFormSchema),
+ defaultValues: {
+ patient_id: '',
+ date: '',
+ referred_to: '',
+ condition: '',
+ annotation: '',
+ } as unknown as AppointmentFormSchema,
+ mode: 'onBlur',
+ })
+
+ async function submitForm(data: AppointmentFormSchema) {
+ const response = await api('/appointments', {
+ method: 'POST',
+ body: JSON.stringify(data),
+ })
+
+ if (!response.success) {
+ toast.error(response.message)
+ return
+ }
+
+ queryClient.invalidateQueries({
+ queryKey: [QUERY_CACHE_KEYS.referrals.list],
+ })
+ revalidateCache(NEXT_CACHE_TAGS.patient(data.patient_id))
+ toast.success(response.message)
+ onClose()
+ }
+
+ return (
+
+ }>
+ Novo atendimento
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancelar
+
+
+
+ )
+}
diff --git a/src/modules/appointments/new-appointment-button.tsx b/src/modules/appointments/new-appointment-button.tsx
new file mode 100644
index 00000000..7538c85c
--- /dev/null
+++ b/src/modules/appointments/new-appointment-button.tsx
@@ -0,0 +1,24 @@
+'use client'
+
+import { PlusIcon } from 'lucide-react'
+import { useState } from 'react'
+
+import { Dialog, DialogTrigger } from '@/components/ui/dialog'
+
+import type { ButtonProps } from '../../components/ui/button'
+import { AppointmentModal } from './appointment-modal'
+
+export function NewAppointmentButton(props: Readonly) {
+ const [modalOpen, setModalOpen] = useState(false)
+
+ return (
+
+ )
+}
diff --git a/src/app/(dashboard)/_cards/appointments.tsx b/src/modules/dashboard/appointments-card.tsx
similarity index 97%
rename from src/app/(dashboard)/_cards/appointments.tsx
rename to src/modules/dashboard/appointments-card.tsx
index 410eb00d..353e40d7 100644
--- a/src/app/(dashboard)/_cards/appointments.tsx
+++ b/src/modules/dashboard/appointments-card.tsx
@@ -10,7 +10,6 @@ import {
} from 'lucide-react'
import { useRouter } from 'next/navigation'
-import { NewAppointmentButton } from '@/components/appointments/new-button'
import { DataTableHeader } from '@/components/data-table/header'
import { DataTableHeaderActions } from '@/components/data-table/header/actions'
import { DataTableHeaderInfo } from '@/components/data-table/header/info'
@@ -33,11 +32,12 @@ import {
} from '@/components/ui/table'
import { Tag } from '@/components/ui/tag'
import { ROUTES } from '@/constants/routes'
+import { NewAppointmentButton } from '@/modules/appointments/new-appointment-button'
import { PATIENT_CONDITIONS } from '@/types/patients'
import { formatDate } from '@/utils/formatters/format-date'
import { QUEUE_SERVICE_PATIENTS_MOCK } from '@/utils/mock/queue-service-patients'
-export default function DashboardOverviewAppointments() {
+export default function AppointmentsCard() {
const patients = QUEUE_SERVICE_PATIENTS_MOCK
const router = useRouter()
diff --git a/src/app/(dashboard)/_cards/patients-by-city.tsx b/src/modules/dashboard/patients-by-city-card.tsx
similarity index 94%
rename from src/app/(dashboard)/_cards/patients-by-city.tsx
rename to src/modules/dashboard/patients-by-city-card.tsx
index aec84449..f180de57 100644
--- a/src/app/(dashboard)/_cards/patients-by-city.tsx
+++ b/src/modules/dashboard/patients-by-city-card.tsx
@@ -10,12 +10,12 @@ import { SelectPeriod } from '@/components/select-period'
import { Skeleton } from '@/components/ui/skeleton'
import { QUERY_CACHE_KEYS } from '@/constants/cache'
import { api } from '@/lib/api'
-import { type QueryPeriodType } from '@/types/queries'
+import { type QueryPeriod } from '@/types/queries'
-export function DashboardOverviewPatientsByCity(
+export function PatientsByCityCard(
props: Readonly>,
) {
- const [period, setPeriod] = useState('last-year')
+ const [period, setPeriod] = useState('last-year')
const limit = 6
const withPercentage = true
diff --git a/src/app/(dashboard)/_cards/patients-by-gender.tsx b/src/modules/dashboard/patients-by-gender-card.tsx
similarity index 85%
rename from src/app/(dashboard)/_cards/patients-by-gender.tsx
rename to src/modules/dashboard/patients-by-gender-card.tsx
index 13bb443a..d5e40267 100644
--- a/src/app/(dashboard)/_cards/patients-by-gender.tsx
+++ b/src/modules/dashboard/patients-by-gender-card.tsx
@@ -10,19 +10,19 @@ import { SelectPeriod } from '@/components/select-period'
import { Skeleton } from '@/components/ui/skeleton'
import { QUERY_CACHE_KEYS } from '@/constants/cache'
import { api } from '@/lib/api'
-import { GENDERS, type GenderType } from '@/types/patients'
-import { type QueryPeriodType } from '@/types/queries'
+import { type Gender, GENDERS } from '@/types/patients'
+import { type QueryPeriod } from '@/types/queries'
-export function DashboardOverviewPatientsByGender(
+export function PatientsByGenderCard(
props: Readonly>,
) {
- const [period, setPeriod] = useState('last-year')
+ const [period, setPeriod] = useState('last-year')
const { data: response, isLoading } = useQuery({
queryKey: [QUERY_CACHE_KEYS.dashboard.patientsByGender, period],
queryFn: () =>
api<{
- genders: { gender: GenderType; total: string }[]
+ genders: { gender: Gender; total: string }[]
total: number
}>('/statistics/patients-by-gender', {
params: { period },
diff --git a/src/app/(dashboard)/_cards/patients-by-status.tsx b/src/modules/dashboard/patients-by-status-cards.tsx
similarity index 96%
rename from src/app/(dashboard)/_cards/patients-by-status.tsx
rename to src/modules/dashboard/patients-by-status-cards.tsx
index 43e73591..981292fd 100644
--- a/src/app/(dashboard)/_cards/patients-by-status.tsx
+++ b/src/modules/dashboard/patients-by-status-cards.tsx
@@ -3,7 +3,7 @@ import { CheckCircle2Icon, CircleXIcon, Users2Icon } from 'lucide-react'
import { getTotalPatientsByStatus } from '@/actions/patients/statistics/get-total-patients-by-status'
import { Card } from '@/components/ui/card'
-export async function DashboardOverviewPatientsByStatus() {
+export async function PatientsByStatusCards() {
const statistics = await getTotalPatientsByStatus()
if (!statistics) {
diff --git a/src/modules/patient-requirements/add-patient-requirement-button.tsx b/src/modules/patient-requirements/add-patient-requirement-button.tsx
index 4003e564..8c5323af 100644
--- a/src/modules/patient-requirements/add-patient-requirement-button.tsx
+++ b/src/modules/patient-requirements/add-patient-requirement-button.tsx
@@ -4,8 +4,7 @@ import { PlusIcon } from 'lucide-react'
import React, { useState } from 'react'
import type { ButtonProps } from '@/components/ui/button'
-import { Dialog } from '@/components/ui/dialog/index'
-import { DialogTrigger } from '@/components/ui/dialog/trigger'
+import { Dialog, DialogTrigger } from '@/components/ui/dialog'
import { PatientRequirementModal } from './requirement-modal'
@@ -24,7 +23,9 @@ export function AddPatientRequirementButton(props: Readonly) {
{isPatientRequirementOpen && (
-
+ setIsPatientRequirementOpen(false)}
+ />
)}
)
diff --git a/src/modules/patient-requirements/approved-list-table.tsx b/src/modules/patient-requirements/approved-list-table.tsx
index 9481cbc3..da91bd32 100644
--- a/src/modules/patient-requirements/approved-list-table.tsx
+++ b/src/modules/patient-requirements/approved-list-table.tsx
@@ -25,7 +25,7 @@ import { QUERY_CACHE_KEYS } from '@/constants/cache'
import { QUERY_PARAMS } from '@/constants/params'
import { useParams } from '@/hooks/params'
import { api } from '@/lib/api'
-import type { OrderMappingType } from '@/types/order'
+import type { OrderMapping } from '@/types/order'
import {
PATIENT_REQUIREMENT_TYPES,
PATIENT_REQUIREMENTS_ORDER_OPTIONS,
@@ -45,7 +45,7 @@ export function ApprovedPatientRequirementsListTable() {
const search = getParam(QUERY_PARAMS.search)
const orderBy = getParam(QUERY_PARAMS.orderBy)
- const ORDER_MAPPING: OrderMappingType = {
+ const ORDER_MAPPING: OrderMapping = {
name_asc: { orderBy: 'name', order: 'ASC' },
name_desc: { orderBy: 'name', order: 'DESC' },
date_asc: { orderBy: 'approved_at', order: 'ASC' },
@@ -55,8 +55,8 @@ export function ApprovedPatientRequirementsListTable() {
}
const orderByQuery = ORDER_MAPPING[orderBy as PatientRequirementsOrder] ?? {
- orderBy: 'approved_at',
- order: 'DESC',
+ orderBy: 'name',
+ order: 'ASC',
}
const { data: response, isLoading } = useQuery({
diff --git a/src/modules/patient-requirements/pending-requirements.tsx b/src/modules/patient-requirements/pending-requirements.tsx
index 8a91aa64..f64ab8c5 100644
--- a/src/modules/patient-requirements/pending-requirements.tsx
+++ b/src/modules/patient-requirements/pending-requirements.tsx
@@ -18,7 +18,7 @@ import { QUERY_PARAMS } from '@/constants/params'
import { getTimeDistanceToNow } from '@/helpers/get-time-distance-to-now'
import { useParams } from '@/hooks/params'
import { api } from '@/lib/api'
-import type { OrderMappingType } from '@/types/order'
+import type { OrderMapping } from '@/types/order'
import type { PatientRequirement } from '@/types/patient-requirements'
import {
PATIENT_REQUIREMENT_TYPES,
@@ -40,7 +40,7 @@ export function PendingPatientRequirements() {
const search = getParam(QUERY_PARAMS.search)
const orderBy = getParam(QUERY_PARAMS.orderBy)
- const ORDER_MAPPING: OrderMappingType = {
+ const ORDER_MAPPING: OrderMapping = {
name_asc: { orderBy: 'name', order: 'ASC' },
name_desc: { orderBy: 'name', order: 'DESC' },
date_asc: { orderBy: 'date', order: 'ASC' },
@@ -51,7 +51,7 @@ export function PendingPatientRequirements() {
const orderByQuery = ORDER_MAPPING[orderBy as PatientRequirementsOrder] ?? {
orderBy: 'date',
- order: 'DESC',
+ order: 'ASC',
}
const { data: response, isLoading } = useQuery({
diff --git a/src/modules/patient-requirements/requirement-modal.tsx b/src/modules/patient-requirements/requirement-modal.tsx
index fa2e17ae..7db3cf1e 100644
--- a/src/modules/patient-requirements/requirement-modal.tsx
+++ b/src/modules/patient-requirements/requirement-modal.tsx
@@ -1,25 +1,35 @@
'use client'
import { zodResolver } from '@hookform/resolvers/zod'
import { FormProvider, useForm } from 'react-hook-form'
+import { toast } from 'sonner'
import { z } from 'zod'
+import { ComboboxInput } from '@/components/form/combobox-input'
import { FormContainer } from '@/components/form/form-container'
import { SelectInput } from '@/components/form/select-input'
-import { TextInput } from '@/components/form/text-input'
import { TextareaInput } from '@/components/form/textarea-input'
import { Button } from '@/components/ui/button'
-import { DialogClose } from '@/components/ui/dialog/close'
-import { DialogContainer } from '@/components/ui/dialog/container'
-import { DialogContent } from '@/components/ui/dialog/content'
-import { DialogDescription } from '@/components/ui/dialog/description'
-import { DialogFooter } from '@/components/ui/dialog/footer'
-import { DialogHeader } from '@/components/ui/dialog/header'
-import { DialogTitle } from '@/components/ui/dialog/title'
-import { PATIENT_REQUIREMENT_TYPE_OPTIONS } from '@/types/patient-requirements'
+import {
+ DialogClose,
+ DialogContainer,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from '@/components/ui/dialog'
+import { QUERY_CACHE_KEYS } from '@/constants/cache'
+import { usePatientOptions } from '@/hooks/use-patient-otions'
+import { api } from '@/lib/api'
+import { queryClient } from '@/lib/tanstack-query'
+import {
+ PATIENT_REQUIREMENT_TYPE_ENUM,
+ PATIENT_REQUIREMENT_TYPE_OPTIONS,
+} from '@/types/patient-requirements'
const patientRequirementFormSchema = z.object({
- name: z.string().min(1, 'O nome do paciente é obrigatório'),
- type: z.enum(['medical_report', 'screening']),
+ patient_id: z.string().uuid('Paciente é obrigatório'),
+ type: z.enum(PATIENT_REQUIREMENT_TYPE_ENUM),
description: z
.string()
.max(500)
@@ -29,26 +39,40 @@ const patientRequirementFormSchema = z.object({
type PatientRequirementFormSchema = z.infer
interface PatientRequirementModalProps {
- onOpenChange: (open: boolean) => void
+ onClose: () => void
}
export function PatientRequirementModal({
- onOpenChange,
+ onClose,
}: Readonly) {
+ const { patientOptions } = usePatientOptions()
+
const formMethods = useForm({
resolver: zodResolver(patientRequirementFormSchema),
defaultValues: {
- patient_name: '',
- document_type: '',
+ patient_id: '',
+ type: '',
description: '',
} as unknown as PatientRequirementFormSchema,
mode: 'onBlur',
})
async function submitForm(data: PatientRequirementFormSchema) {
- // TODO: submit form data to API
- console.log(data)
- onOpenChange(false)
+ const response = await api('/patient-requirements', {
+ method: 'POST',
+ body: JSON.stringify(data),
+ })
+
+ if (!response.success) {
+ toast.error(response.message)
+ return
+ }
+
+ queryClient.invalidateQueries({
+ queryKey: [QUERY_CACHE_KEYS.approvals.pending],
+ })
+ toast.success(response.message)
+ onClose()
}
return (
@@ -61,13 +85,16 @@ export function PatientRequirementModal({
-
-
-
-
+
+
+
+
-
+
+
+
-
-
- Cancelar
-
-
-
+
+
+
+ Cancelar
+
+
)
}
diff --git a/src/modules/patient-requirements/under-review-requirements.tsx b/src/modules/patient-requirements/under-review-requirements.tsx
index e265393a..ddfd04a6 100644
--- a/src/modules/patient-requirements/under-review-requirements.tsx
+++ b/src/modules/patient-requirements/under-review-requirements.tsx
@@ -17,7 +17,7 @@ import { QUERY_PARAMS } from '@/constants/params'
import { getTimeDistanceToNow } from '@/helpers/get-time-distance-to-now'
import { useParams } from '@/hooks/params'
import { api } from '@/lib/api'
-import type { OrderMappingType } from '@/types/order'
+import type { OrderMapping } from '@/types/order'
import type { PatientRequirement } from '@/types/patient-requirements'
import {
PATIENT_REQUIREMENT_TYPES,
@@ -37,7 +37,7 @@ export function UnderReviewPatientRequirements() {
const search = getParam(QUERY_PARAMS.search)
const orderBy = getParam(QUERY_PARAMS.orderBy)
- const ORDER_MAPPING: OrderMappingType = {
+ const ORDER_MAPPING: OrderMapping = {
name_asc: { orderBy: 'name', order: 'ASC' },
name_desc: { orderBy: 'name', order: 'DESC' },
date_asc: { orderBy: 'submitted_at', order: 'ASC' },
@@ -48,7 +48,7 @@ export function UnderReviewPatientRequirements() {
const orderByQuery = ORDER_MAPPING[orderBy as PatientRequirementsOrder] ?? {
orderBy: 'submitted_at',
- order: 'DESC',
+ order: 'ASC',
}
const { data: response, isLoading } = useQuery({
@@ -92,7 +92,7 @@ export function UnderReviewPatientRequirements() {
- {isLoading && }
+ {isLoading && }
{isEmpty && !isLoading && (
diff --git a/src/modules/patients/cancel-form-modal.tsx b/src/modules/patients/cancel-form-modal.tsx
new file mode 100644
index 00000000..a0cbaeac
--- /dev/null
+++ b/src/modules/patients/cancel-form-modal.tsx
@@ -0,0 +1,44 @@
+import { CircleAlertIcon } from 'lucide-react'
+
+import { Button } from '../../components/ui/button'
+import {
+ DialogClose,
+ DialogContainer,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogIcon,
+ DialogTitle,
+} from '../../components/ui/dialog'
+
+interface CancelPatientFormModalProps {
+ onConfirm: () => void
+}
+
+export default function CancelPatientFormModal({
+ onConfirm,
+}: Readonly
) {
+ return (
+
+
+ }
+ >
+ Cancelar o cadastro do paciente?
+
+ Esta ação é irreversível e todo o progresso será perdido.
+
+
+
+
+ Voltar
+
+
+ )
+}
diff --git a/src/app/(dashboard)/pacientes/[id]/documentos/patients-documents.tsx b/src/modules/patients/documents.tsx
similarity index 74%
rename from src/app/(dashboard)/pacientes/[id]/documentos/patients-documents.tsx
rename to src/modules/patients/documents.tsx
index 1c1f6c68..bb69d86b 100644
--- a/src/app/(dashboard)/pacientes/[id]/documentos/patients-documents.tsx
+++ b/src/modules/patients/documents.tsx
@@ -1,38 +1,33 @@
'use client'
-import { CircleXIcon, PaperclipIcon, PlusIcon, Trash2Icon } from 'lucide-react'
+import { PaperclipIcon, PlusIcon, Trash2Icon } from 'lucide-react'
import { useState } from 'react'
import { Button } from '@/components/ui/button'
-import { Dialog } from '@/components/ui/dialog'
-import { DialogClose } from '@/components/ui/dialog/close'
-import { DialogContainer } from '@/components/ui/dialog/container'
-import { DialogDescription } from '@/components/ui/dialog/description'
-import { DialogFooter } from '@/components/ui/dialog/footer'
-import { DialogHeader } from '@/components/ui/dialog/header'
-import { DialogTitle } from '@/components/ui/dialog/title'
-import { DialogTrigger } from '@/components/ui/dialog/trigger'
+import {
+ Dialog,
+ DialogClose,
+ DialogContainer,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from '@/components/ui/dialog'
import { NavLink } from '@/components/ui/nav-link'
+import type { PatientDocument } from '@/types/patients'
import { formatDate } from '@/utils/formatters/format-date'
-type Document = {
- id: string
- name: string
- url: string
- created_at: string
- size: string
-}
-
-interface PatientsDocumentsProps {
+interface PatientDocumentsProps {
sections: {
title: string
- documents: Document[]
+ documents: PatientDocument[]
}[]
}
-export function PatientsDocuments({
+export function PatientDocuments({
sections,
-}: Readonly) {
+}: Readonly) {
const [isEditing, setIsEditing] = useState(false)
function handleConfirmDelete(id: string) {
@@ -85,11 +80,7 @@ export function PatientsDocuments({
-
+
Excluir documento?
Confirme a exclusão do documento{' '}
diff --git a/src/components/patients/form-schema.tsx b/src/modules/patients/form-schema.tsx
similarity index 100%
rename from src/components/patients/form-schema.tsx
rename to src/modules/patients/form-schema.tsx
diff --git a/src/components/patients/form.tsx b/src/modules/patients/form.tsx
similarity index 93%
rename from src/components/patients/form.tsx
rename to src/modules/patients/form.tsx
index 17aa74a9..7e5136e2 100644
--- a/src/components/patients/form.tsx
+++ b/src/modules/patients/form.tsx
@@ -24,34 +24,37 @@ import { Divider } from '@/components/ui/divider'
import { QUERY_CACHE_KEYS } from '@/constants/cache'
import {
BRAZILIAN_STATES_OPTIONS,
- type UFType,
+ type UF,
YES_OR_NO_OPTIONS,
} from '@/constants/enums'
import { ROUTES } from '@/constants/routes'
import { useCities } from '@/hooks/cities'
import { api } from '@/lib/api'
import { queryClient } from '@/lib/tanstack-query'
-import { GENDERS_OPTIONS, PatientType } from '@/types/patients'
+import { GENDER_OPTIONS, Patient } from '@/types/patients'
import { formatCpfNumber } from '@/utils/formatters/format-cpf-number'
import { formatPhoneNumber } from '@/utils/formatters/format-phone-number'
import { removeNonNumbers } from '@/utils/sanitizers'
-import { ComboboxInput } from '../form/combobox-input'
-import { Dialog } from '../ui/dialog'
-import CancelPatientCreationModal from './cancel-patient-creation-modal'
+import { ComboboxInput } from '../../components/form/combobox-input'
+import { Dialog } from '../../components/ui/dialog'
+import CancelPatientFormModal from './cancel-form-modal'
import { type PatientsFormSchema, patientsFormSchema } from './form-schema'
-type PatientsFormModeType = 'view' | 'edit' | 'create'
+type PatientFormMode = 'view' | 'edit' | 'create'
-interface PatientsFormProps {
- patient?: PatientType | null
- mode?: PatientsFormModeType
+interface PatientFormProps {
+ patient?: Patient | null
+ mode?: PatientFormMode
}
-export function PatientsForm({ patient, mode = 'view' }: PatientsFormProps) {
+export function PatientForm({
+ patient,
+ mode = 'view',
+}: Readonly) {
const [isCancelConfirmModalOpen, setIsCancelConfirmModalOpen] =
useState(false)
- const [formState, setFormState] = useState(mode)
+ const [formState, setFormState] = useState(mode)
const router = useRouter()
@@ -95,7 +98,7 @@ export function PatientsForm({ patient, mode = 'view' }: PatientsFormProps) {
}))
: []
- const selectedUF = watch('state') as UFType
+ const selectedUF = watch('state') as UF
const cities = useCities(selectedUF)
const isViewMode = formState === 'view'
@@ -207,11 +210,11 @@ export function PatientsForm({ patient, mode = 'view' }: PatientsFormProps) {
{(formState === 'create' || patientSupports.length >= 1) && (
@@ -462,7 +465,7 @@ export function PatientsForm({ patient, mode = 'view' }: PatientsFormProps) {
onOpenChange={setIsCancelConfirmModalOpen}
>
{isCancelConfirmModalOpen && (
- router.back()} />
+ router.back()} />
)}
diff --git a/src/app/(dashboard)/pacientes/[id]/informacoes/inactivate-button.tsx b/src/modules/patients/inactivate-button.tsx
similarity index 52%
rename from src/app/(dashboard)/pacientes/[id]/informacoes/inactivate-button.tsx
rename to src/modules/patients/inactivate-button.tsx
index aff49b55..9edf412e 100644
--- a/src/app/(dashboard)/pacientes/[id]/informacoes/inactivate-button.tsx
+++ b/src/modules/patients/inactivate-button.tsx
@@ -3,18 +3,17 @@
import { UserRoundMinusIcon } from 'lucide-react'
import { useState } from 'react'
-import { PatientsInactivateModal } from '@/components/patients/inactivate-modal'
-import { Dialog } from '@/components/ui/dialog'
-import { DialogTrigger } from '@/components/ui/dialog/trigger'
-import type { PatientType } from '@/types/patients'
+import { Dialog, DialogTrigger } from '@/components/ui/dialog'
+import { InactivatePatientModal } from '@/modules/patients/inactivate-modal'
+import type { Patient } from '@/types/patients'
-interface PatientInactivateButtonProps {
- patient: PatientType
+interface InactivatePatientButtonProps {
+ patient: Patient
}
-export function PatientInactivateButton({
+export function InactivatePatientButton({
patient,
-}: Readonly) {
+}: Readonly) {
const [isInactivateModalOpen, setInactivateModalOpen] = useState(false)
return (
@@ -25,10 +24,10 @@ export function PatientInactivateButton({
{isInactivateModalOpen && (
- setInactivateModalOpen(false)}
/>
)}
diff --git a/src/components/patients/inactivate-modal.tsx b/src/modules/patients/inactivate-modal.tsx
similarity index 50%
rename from src/components/patients/inactivate-modal.tsx
rename to src/modules/patients/inactivate-modal.tsx
index 754693f3..e5cdcd6c 100644
--- a/src/components/patients/inactivate-modal.tsx
+++ b/src/modules/patients/inactivate-modal.tsx
@@ -7,32 +7,34 @@ import { toast } from 'sonner'
import { z } from 'zod'
import { revalidateCache } from '@/actions/cache'
+import { FormContainer } from '@/components/form/form-container'
import { TextInput } from '@/components/form/text-input'
import { Button } from '@/components/ui/button'
-import { DialogClose } from '@/components/ui/dialog/close'
-import { DialogContainer } from '@/components/ui/dialog/container'
-import { DialogContent } from '@/components/ui/dialog/content'
-import { DialogDescription } from '@/components/ui/dialog/description'
-import { DialogFooter } from '@/components/ui/dialog/footer'
-import { DialogHeader } from '@/components/ui/dialog/header'
-import { DialogTitle } from '@/components/ui/dialog/title'
+import {
+ DialogClose,
+ DialogContainer,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogIcon,
+ DialogTitle,
+} from '@/components/ui/dialog'
import { NEXT_CACHE_TAGS, QUERY_CACHE_KEYS } from '@/constants/cache'
import { api } from '@/lib/api'
import { queryClient } from '@/lib/tanstack-query'
-interface PatientsInactivateModalProps {
+interface InactivatePatientModalProps {
id: string
name: string
- dropdownTrigger?: React.RefObject
- onOpenChange: (open: boolean) => void
+ onClose: () => void
}
-export function PatientsInactivateModal({
+export function InactivatePatientModal({
id,
name,
- dropdownTrigger,
- onOpenChange,
-}: PatientsInactivateModalProps) {
+ onClose,
+}: Readonly) {
const inactivatePatientFormSchema = z.object({
name: z.string().refine((val) => val === name, {
message: `Insira o nome do paciente corretamente: ${name}`,
@@ -56,55 +58,60 @@ export function PatientsInactivateModal({
return
}
- queryClient.invalidateQueries({ queryKey: [QUERY_CACHE_KEYS.patients] })
+ queryClient.invalidateQueries({
+ queryKey: [QUERY_CACHE_KEYS.patients.list],
+ })
+ queryClient.invalidateQueries({
+ queryKey: [QUERY_CACHE_KEYS.patients.allActive],
+ })
revalidateCache(NEXT_CACHE_TAGS.patient(id))
toast.success(response.message)
- onOpenChange(false)
- }
-
- function handleFocusOnTrigger(e: Event) {
- if (!dropdownTrigger) return
-
- e.preventDefault()
- dropdownTrigger?.current?.focus()
+ onClose()
}
return (
-
+
+ }
>
Inativar {name}?
Confirme a inativação do paciente
-
-
+
-
-
- Cancelar
-
-
-
+
+
+
+ Cancelar
+
+
)
}
diff --git a/src/app/(dashboard)/pacientes/(patients-list)/actions.tsx b/src/modules/patients/list/actions.tsx
similarity index 78%
rename from src/app/(dashboard)/pacientes/(patients-list)/actions.tsx
rename to src/modules/patients/list/actions.tsx
index 672f4a2e..7bf59f5d 100644
--- a/src/app/(dashboard)/pacientes/(patients-list)/actions.tsx
+++ b/src/modules/patients/list/actions.tsx
@@ -6,19 +6,19 @@ import {
EllipsisIcon,
SendIcon,
} from 'lucide-react'
-import { useRef, useState } from 'react'
+import { useState } from 'react'
-import { PatientsInactivateModal } from '@/components/patients/inactivate-modal'
import { Dialog } from '@/components/ui/dialog'
import { Divider } from '@/components/ui/divider'
import { DropdownMenu } from '@/components/ui/dropdown'
import { DropdownMenuContent } from '@/components/ui/dropdown/content'
import { DropdownMenuItem } from '@/components/ui/dropdown/item'
import { DropdownMenuTrigger } from '@/components/ui/dropdown/trigger'
-import type { PatientType } from '@/types/patients'
+import { InactivatePatientModal } from '@/modules/patients/inactivate-modal'
+import type { Patient } from '@/types/patients'
interface PatientsListTableActionsProps {
- patient: PatientType
+ patient: Patient
}
export function PatientsListTableActions({
@@ -26,19 +26,13 @@ export function PatientsListTableActions({
}: PatientsListTableActionsProps) {
const [isDropdownOpen, setDropdownOpen] = useState(false)
const [isInactivateModalOpen, setInactivateModalOpen] = useState(false)
- const dropdownTriggerRef = useRef(null)
const isPatientActive = patient.status === 'active'
return (
<>
-
+
@@ -78,11 +72,10 @@ export function PatientsListTableActions({
onOpenChange={setInactivateModalOpen}
>
{isInactivateModalOpen && (
- setInactivateModalOpen(false)}
/>
)}
diff --git a/src/app/(dashboard)/pacientes/(patients-list)/skeleton.tsx b/src/modules/patients/list/skeleton.tsx
similarity index 95%
rename from src/app/(dashboard)/pacientes/(patients-list)/skeleton.tsx
rename to src/modules/patients/list/skeleton.tsx
index 0de0319a..4a914000 100644
--- a/src/app/(dashboard)/pacientes/(patients-list)/skeleton.tsx
+++ b/src/modules/patients/list/skeleton.tsx
@@ -1,7 +1,7 @@
import { Skeleton } from '@/components/ui/skeleton'
import { TableBody, TableCell, TableRow } from '@/components/ui/table'
-export default function PatientsListTableBodySkeleton() {
+export default function PatientsListTableSkeleton() {
const skeletons = Array.from({ length: 10 }).map((_, index) => index)
return (
diff --git a/src/app/(dashboard)/pacientes/(patients-list)/table.tsx b/src/modules/patients/list/table.tsx
similarity index 92%
rename from src/app/(dashboard)/pacientes/(patients-list)/table.tsx
rename to src/modules/patients/list/table.tsx
index 411aeada..6f452f3f 100644
--- a/src/app/(dashboard)/pacientes/(patients-list)/table.tsx
+++ b/src/modules/patients/list/table.tsx
@@ -33,19 +33,19 @@ import { QUERY_PARAMS } from '@/constants/params'
import { ROUTES } from '@/constants/routes'
import { useParams } from '@/hooks/params'
import { api } from '@/lib/api'
-import type { OrderMappingType } from '@/types/order'
+import type { OrderMapping } from '@/types/order'
import {
- PATIENT_STATUS,
+ type Patient,
PATIENT_STATUS_OPTIONS,
+ PATIENT_STATUSES,
PATIENTS_ORDER_OPTIONS,
- type PatientsOrderType,
- type PatientType,
+ type PatientsOrder,
} from '@/types/patients'
import { formatDate } from '@/utils/formatters/format-date'
import { formatPhoneNumber } from '@/utils/formatters/format-phone-number'
import { PatientsListTableActions } from './actions'
-import PatientsListTableBodySkeleton from './skeleton'
+import PatientsListTableSkeleton from './skeleton'
export function PatientsListTable() {
const [showFilters, setShowFilters] = useState(false)
@@ -61,7 +61,7 @@ export function PatientsListTable() {
const endDate = getParam(QUERY_PARAMS.endDate)
const filterQueries = [page, search, orderBy, status, startDate, endDate]
- const ORDER_MAPPING: OrderMappingType = {
+ const ORDER_MAPPING: OrderMapping = {
date_asc: { orderBy: 'date', order: 'ASC' },
date_desc: { orderBy: 'date', order: 'DESC' },
email_asc: { orderBy: 'email', order: 'ASC' },
@@ -71,16 +71,16 @@ export function PatientsListTable() {
}
const { data: response, isLoading } = useQuery({
- queryKey: [QUERY_CACHE_KEYS.patients, filterQueries],
+ queryKey: [QUERY_CACHE_KEYS.patients.list, filterQueries],
queryFn: () =>
- api<{ patients: PatientType[]; total: number }>('/patients', {
+ api<{ patients: Patient[]; total: number }>('/patients', {
params: {
page,
search,
status,
startDate,
endDate,
- ...ORDER_MAPPING[orderBy as PatientsOrderType],
+ ...ORDER_MAPPING[orderBy as PatientsOrder],
},
}),
})
@@ -154,7 +154,7 @@ export function PatientsListTable() {
- {isLoading && }
+ {isLoading && }
{!isLoading && isPatientsEmpty && (
@@ -171,7 +171,7 @@ export function PatientsListTable() {
{!isLoading && !isPatientsEmpty && (
{patients.map((patient) => {
- const status = PATIENT_STATUS[patient.status]
+ const status = PATIENT_STATUSES[patient.status]
return (
diff --git a/src/modules/referrals/summary-card.tsx b/src/modules/referrals/summary-card.tsx
index d177a1fc..3cc7eba9 100644
--- a/src/modules/referrals/summary-card.tsx
+++ b/src/modules/referrals/summary-card.tsx
@@ -1,22 +1,15 @@
import { HeartPulse, Waypoints } from 'lucide-react'
-import {
- getMockReferralsCount,
- getMockReferredPatients,
-} from '@/app/(dashboard)/encaminhados/_cards/mock-data'
import { Card } from '@/components/ui/card'
export function ReferralsSummaryCard() {
- const referrals = getMockReferralsCount()
- const referredPatients = getMockReferredPatients()
-
const statistics = [
{
- value: referrals.total,
+ value: 50,
label: 'referrals',
},
{
- value: `${referredPatients.percentage}%`,
+ value: `${70}%`,
label: 'patients',
},
] as const
diff --git a/src/app/(dashboard)/equipes/(members-list)/table.tsx b/src/modules/teams/table.tsx
similarity index 99%
rename from src/app/(dashboard)/equipes/(members-list)/table.tsx
rename to src/modules/teams/table.tsx
index 3b5888ea..055129ce 100644
--- a/src/app/(dashboard)/equipes/(members-list)/table.tsx
+++ b/src/modules/teams/table.tsx
@@ -38,7 +38,7 @@ import { TEAMS_ORDER_OPTIONS } from '@/types/teams'
import { formatDate } from '@/utils/formatters/format-date'
import { TEAMS_MOCK } from '@/utils/mock/teams'
-export function MembersListTable() {
+export function TeamListTable() {
const members = TEAMS_MOCK
const [statusFilter, setStatusFilter] = useState<
diff --git a/src/types/order.ts b/src/types/order.ts
index 77363095..703e48ba 100644
--- a/src/types/order.ts
+++ b/src/types/order.ts
@@ -1,4 +1,4 @@
-export type OrderMappingType = Record<
+export type OrderMapping = Record<
T,
{ orderBy: string; order: string }
>
diff --git a/src/types/patient-requirements.ts b/src/types/patient-requirements.ts
index 26496608..189f998d 100644
--- a/src/types/patient-requirements.ts
+++ b/src/types/patient-requirements.ts
@@ -1,5 +1,20 @@
import { convertObjectToOptions } from '@/helpers/convert-object-to-options'
+export type PatientRequirement = {
+ id: string
+ type: PatientRequirementType
+ status: PatientRequirementStatus
+ description: string | null
+ submitted_at: string | null
+ approved_at: string | null
+ created_at: string
+ patient: {
+ id: string
+ name: string
+ avatar_url: string | null
+ }
+}
+
export const PATIENT_REQUIREMENTS_ORDERS = {
name_asc: 'Nome (Crescente)',
name_desc: 'Nome (Decrescente)',
@@ -9,38 +24,28 @@ export const PATIENT_REQUIREMENTS_ORDERS = {
type_desc: 'Tipo (Decrescente)',
}
export type PatientRequirementsOrder = keyof typeof PATIENT_REQUIREMENTS_ORDERS
+
export const PATIENT_REQUIREMENTS_ORDER_OPTIONS = convertObjectToOptions(
PATIENT_REQUIREMENTS_ORDERS,
)
-export const PATIENT_REQUIREMENT_STATUS = {
+export const PATIENT_REQUIREMENT_STATUSES = {
pending: 'Pendente',
under_review: 'Em análise',
approved: 'Aprovado',
declined: 'Recusado',
}
-export type PatientRequirementStatus = keyof typeof PATIENT_REQUIREMENT_STATUS
+export type PatientRequirementStatus = keyof typeof PATIENT_REQUIREMENT_STATUSES
export const PATIENT_REQUIREMENT_TYPES = {
screening: 'Triagem',
medical_report: 'Laudo',
}
export type PatientRequirementType = keyof typeof PATIENT_REQUIREMENT_TYPES
+
export const PATIENT_REQUIREMENT_TYPE_OPTIONS = convertObjectToOptions(
PATIENT_REQUIREMENT_TYPES,
)
-
-export type PatientRequirement = {
- id: string
- type: PatientRequirementType
- status: PatientRequirementStatus
- description: string | null
- submitted_at: string | null
- approved_at: string | null
- created_at: string
- patient: {
- id: string
- name: string
- avatar_url: string | null
- }
-}
+export const PATIENT_REQUIREMENT_TYPE_ENUM = Object.keys(
+ PATIENT_REQUIREMENT_TYPES,
+) as [PatientRequirementType]
diff --git a/src/types/patient-support.ts b/src/types/patient-support.ts
index 9a67ca87..e3e432e6 100644
--- a/src/types/patient-support.ts
+++ b/src/types/patient-support.ts
@@ -1,4 +1,4 @@
-export type PatientSupportType = {
+export type PatientSupport = {
id: string
name: string
phone: string
diff --git a/src/types/patients.ts b/src/types/patients.ts
index c2437a00..19162ce4 100644
--- a/src/types/patients.ts
+++ b/src/types/patients.ts
@@ -7,15 +7,15 @@ import {
import { convertObjectToOptions } from '@/helpers/convert-object-to-options'
-import { PatientSupportType } from './patient-support'
+import { PatientSupport } from './patient-support'
-export type PatientType = {
+export type Patient = {
id: string
user_id: string
- gender: GenderType
+ gender: Gender
date_of_birth: string
phone: string
- status: PatientStatusType
+ status: PatientStatus
cpf: string
state: string
city: string
@@ -30,7 +30,7 @@ export type PatientType = {
name: string
email: string
avatar_url: string | null
- supports?: PatientSupportType[]
+ supports?: PatientSupport[]
}
export const GENDERS = {
@@ -42,10 +42,11 @@ export const GENDERS = {
prefer_not_to_say: 'Prefiro não informar',
other: 'Outro',
}
-export type GenderType = keyof typeof GENDERS
-export const GENDERS_OPTIONS = convertObjectToOptions(GENDERS)
+export type Gender = keyof typeof GENDERS
-export const PATIENT_STATUS = {
+export const GENDER_OPTIONS = convertObjectToOptions(GENDERS)
+
+export const PATIENT_STATUSES = {
active: {
variant: 'success',
label: 'Ativo',
@@ -59,9 +60,9 @@ export const PATIENT_STATUS = {
color: '[&_svg]:text-error',
},
} as const
-export type PatientStatusType = keyof typeof PATIENT_STATUS
+export type PatientStatus = keyof typeof PATIENT_STATUSES
-export const PATIENT_STATUS_OPTIONS = Object.entries(PATIENT_STATUS).map(
+export const PATIENT_STATUS_OPTIONS = Object.entries(PATIENT_STATUSES).map(
([key, status]) => ({
label: status.label,
value: key,
@@ -84,7 +85,14 @@ export const PATIENT_CONDITIONS = {
} as const
export type PatientCondition = keyof typeof PATIENT_CONDITIONS
-export const PATIENTS_ORDER = {
+export const PATIENT_CONDITION_OPTIONS = Object.entries(PATIENT_CONDITIONS).map(
+ ([key, status]) => ({ label: status.label, value: key }),
+)
+export const PATIENT_CONDITION_ENUM = Object.keys(PATIENT_CONDITIONS) as [
+ PatientCondition,
+]
+
+export const PATIENTS_ORDERS = {
name_asc: 'Nome (Crescente)',
name_desc: 'Nome (Decrescente)',
date_asc: 'Data (Crescente)',
@@ -92,5 +100,14 @@ export const PATIENTS_ORDER = {
email_asc: 'E-mail (Crescente)',
email_desc: 'E-mail (Decrescente)',
}
-export type PatientsOrderType = keyof typeof PATIENTS_ORDER
-export const PATIENTS_ORDER_OPTIONS = convertObjectToOptions(PATIENTS_ORDER)
+export type PatientsOrder = keyof typeof PATIENTS_ORDERS
+
+export const PATIENTS_ORDER_OPTIONS = convertObjectToOptions(PATIENTS_ORDERS)
+
+export type PatientDocument = {
+ id: string
+ name: string
+ url: string
+ created_at: string
+ size: string
+}
diff --git a/src/types/queries.ts b/src/types/queries.ts
index bf1fcd77..dd55879f 100644
--- a/src/types/queries.ts
+++ b/src/types/queries.ts
@@ -1,10 +1,11 @@
import { convertObjectToOptions } from '@/helpers/convert-object-to-options'
export const QUERY_PERIODS = {
+ today: 'Hoje',
'last-year': 'No último ano',
'last-month': 'No último mês',
'last-week': 'Na última semana',
}
-export type QueryPeriodType = keyof typeof QUERY_PERIODS
+export type QueryPeriod = keyof typeof QUERY_PERIODS
export const QUERY_PERIODS_OPTIONS = convertObjectToOptions(QUERY_PERIODS)
diff --git a/src/types/referrals.ts b/src/types/referrals.ts
new file mode 100644
index 00000000..40c55183
--- /dev/null
+++ b/src/types/referrals.ts
@@ -0,0 +1,57 @@
+import { convertObjectToOptions } from '@/helpers/convert-object-to-options'
+
+import type { PatientCondition } from './patients'
+
+export type Referral = {
+ id: string
+ patient_id: string
+ date: string
+ category: ReferralCategory
+ condition: PatientCondition
+ annotation: string | null
+ status: string
+ referred_to: string | null
+ referred_by: string | null
+ created_at: string
+ updated_at: string
+ patient: {
+ id: string
+ name: string
+ avatar_url: string | null
+ }
+}
+
+export const REFERRAL_STATUSES = {
+ scheduled: 'Agendado',
+ canceled: 'Cancelado',
+ completed: 'Concluído',
+ no_show: 'Não compareceu',
+} as const
+export type ReferralStatus = keyof typeof REFERRAL_STATUSES
+
+export const REFERRAL_STATUS_OPTIONS = convertObjectToOptions(REFERRAL_STATUSES)
+
+export const REFERRAL_STATUS_ENUM = Object.keys(REFERRAL_STATUSES) as [
+ ReferralStatus,
+]
+
+export const REFERRAL_CATEGORIES = {
+ medical_care: 'Medicina',
+ legal: 'Jurídico',
+ nursing: 'Enfermagem',
+ psychology: 'Psicologia',
+ nutrition: 'Nutrição',
+ physical_training: 'Preparação Física',
+ social_work: 'Serviço Social',
+ psychiatry: 'Psiquiatria',
+ neurology: 'Neurologia',
+ ophthalmology: 'Oftalmologia',
+} as const
+export type ReferralCategory = keyof typeof REFERRAL_CATEGORIES
+
+export const REFERRAL_CATEGORY_OPTIONS =
+ convertObjectToOptions(REFERRAL_CATEGORIES)
+
+export const REFERRAL_CATEGORY_ENUM = Object.keys(REFERRAL_CATEGORIES) as [
+ ReferralCategory,
+]
diff --git a/src/types/teams.ts b/src/types/teams.ts
index d1f988dc..90127a5c 100644
--- a/src/types/teams.ts
+++ b/src/types/teams.ts
@@ -1,6 +1,6 @@
import { convertObjectToOptions } from '@/helpers/convert-object-to-options'
-export const TEAMS_ORDER = {
+export const TEAMS_ORDERS = {
name_asc: 'Nome (Crescente)',
name_desc: 'Nome (Decrescente)',
date_asc: 'Data (Crescente)',
@@ -10,5 +10,5 @@ export const TEAMS_ORDER = {
specialty_desc: 'Especialidade (Decrescente)',
specialty_asc: 'Especialidade (Crescente)',
}
-export type TeamsOrderType = keyof typeof TEAMS_ORDER
-export const TEAMS_ORDER_OPTIONS = convertObjectToOptions(TEAMS_ORDER)
+export type TeamsOrder = keyof typeof TEAMS_ORDERS
+export const TEAMS_ORDER_OPTIONS = convertObjectToOptions(TEAMS_ORDERS)
diff --git a/src/types/users.ts b/src/types/users.ts
index 205ea99d..dfbaac03 100644
--- a/src/types/users.ts
+++ b/src/types/users.ts
@@ -1,18 +1,14 @@
-import { CheckCircle2Icon, CircleXIcon } from 'lucide-react'
+import type { Patient } from './patients'
-import { convertObjectToOptions } from '@/helpers/convert-object-to-options'
-
-import type { PatientType } from './patients'
-
-export type UserType = {
+export type User = {
id: string
name: string
email: string
- role: 'admin' | 'nurse' | 'specialist' | 'manager' | 'patient'
+ role: UserRole
avatar_url: string | null
created_at: Date
updated_at: Date
- patient: PatientType | null
+ patient: Patient | null
}
export const USER_ROLES = {
@@ -22,20 +18,10 @@ export const USER_ROLES = {
manager: 'Manager',
patient: 'Paciente',
}
+export type UserRole = keyof typeof USER_ROLES
export const USER_STATUS = {
active: 'Ativo',
inactive: 'Inativo',
}
-export type UserStatusType = keyof typeof USER_STATUS
-
-const PATIENT_STATUS_ICONS_AND_COLOR = {
- active: { icon: CheckCircle2Icon, color: '[&_svg]:text-success' },
- inactive: { icon: CircleXIcon, color: '[&_svg]:text-error' },
-}
-export const USER_STATUS_OPTIONS = convertObjectToOptions(USER_STATUS).map(
- (option) => ({
- ...option,
- ...PATIENT_STATUS_ICONS_AND_COLOR[option.value as UserStatusType],
- }),
-)
+export type UserStatus = keyof typeof USER_STATUS
diff --git a/src/utils/mock/patients.ts b/src/utils/mock/patients.ts
index d4585a12..ba395508 100644
--- a/src/utils/mock/patients.ts
+++ b/src/utils/mock/patients.ts
@@ -1,6 +1,6 @@
-import type { PatientType } from '@/types/patients'
+import type { Patient } from '@/types/patients'
-export const PATIENTS_MOCKS: PatientType[] = [
+export const PATIENTS_MOCKS: Patient[] = [
{
id: '1',
user_id: '1',