Merge branch 'release(MVP/Sprint11)'
This commit is contained in:
commit
e98a293286
157 changed files with 5768 additions and 1102 deletions
249
package-lock.json
generated
249
package-lock.json
generated
|
|
@ -19,10 +19,11 @@
|
|||
"@radix-ui/react-label": "^2.1.7",
|
||||
"@radix-ui/react-popover": "^1.1.15",
|
||||
"@radix-ui/react-progress": "^1.1.7",
|
||||
"@radix-ui/react-radio-group": "^1.3.8",
|
||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||
"@radix-ui/react-select": "^2.2.6",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-separator": "^1.1.8",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"@radix-ui/react-switch": "^1.2.6",
|
||||
"@radix-ui/react-tabs": "^1.1.13",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
|
|
@ -123,6 +124,7 @@
|
|||
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.3",
|
||||
|
|
@ -1434,6 +1436,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-alert-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==",
|
||||
"license": "MIT",
|
||||
"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-arrow": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
|
||||
|
|
@ -1570,6 +1590,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-collection/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==",
|
||||
"license": "MIT",
|
||||
"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-compose-refs": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
||||
|
|
@ -1636,6 +1674,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"license": "MIT",
|
||||
"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",
|
||||
|
|
@ -1828,6 +1884,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-menu/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==",
|
||||
"license": "MIT",
|
||||
"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-popover": {
|
||||
"version": "1.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz",
|
||||
|
|
@ -1865,6 +1939,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover/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==",
|
||||
"license": "MIT",
|
||||
"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-popper": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
|
||||
|
|
@ -1968,6 +2060,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-primitive/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==",
|
||||
"license": "MIT",
|
||||
"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-progress": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz",
|
||||
|
|
@ -1992,6 +2102,38 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-radio-group": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz",
|
||||
"integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.3",
|
||||
"@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-presence": "1.1.5",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-roving-focus": "1.1.11",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.2",
|
||||
"@radix-ui/react-use-previous": "1.1.1",
|
||||
"@radix-ui/react-use-size": "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-roving-focus": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz",
|
||||
|
|
@ -2097,13 +2239,54 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-separator": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz",
|
||||
"integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==",
|
||||
"node_modules/@radix-ui/react-select/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==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.3"
|
||||
"@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-separator": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz",
|
||||
"integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.4"
|
||||
},
|
||||
"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-separator/node_modules/@radix-ui/react-primitive": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz",
|
||||
"integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
|
|
@ -2121,9 +2304,9 @@
|
|||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz",
|
||||
"integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2"
|
||||
|
|
@ -2231,6 +2414,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip/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==",
|
||||
"license": "MIT",
|
||||
"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-use-callback-ref": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
|
||||
|
|
@ -2939,6 +3140,7 @@
|
|||
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
|
|
@ -2949,6 +3151,7 @@
|
|||
"integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.2.0"
|
||||
}
|
||||
|
|
@ -2965,6 +3168,7 @@
|
|||
"integrity": "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.46.1",
|
||||
|
|
@ -2995,6 +3199,7 @@
|
|||
"integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.46.1",
|
||||
"@typescript-eslint/types": "8.46.1",
|
||||
|
|
@ -3469,6 +3674,7 @@
|
|||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
|
|
@ -3821,6 +4027,7 @@
|
|||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.8.9",
|
||||
"caniuse-lite": "^1.0.30001746",
|
||||
|
|
@ -4625,6 +4832,7 @@
|
|||
"integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
|
|
@ -4685,6 +4893,7 @@
|
|||
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
},
|
||||
|
|
@ -4811,6 +5020,7 @@
|
|||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.9",
|
||||
|
|
@ -6965,6 +7175,7 @@
|
|||
"resolved": "https://registry.npmjs.org/next/-/next-15.5.5.tgz",
|
||||
"integrity": "sha512-OQVdBPtpBfq7HxFN0kOVb7rXXOSIkt5lTzDJDGRBcOyVvNRIWFauMqi1gIHd1pszq1542vMOGY0HP4CaiALfkA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@next/env": "15.5.5",
|
||||
"@swc/helpers": "0.5.15",
|
||||
|
|
@ -7361,6 +7572,7 @@
|
|||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
|
|
@ -7518,6 +7730,7 @@
|
|||
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
||||
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -7527,6 +7740,7 @@
|
|||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
||||
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.26.0"
|
||||
},
|
||||
|
|
@ -7539,6 +7753,7 @@
|
|||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.65.0.tgz",
|
||||
"integrity": "sha512-xtOzDz063WcXvGWaHgLNrNzlsdFgtUWcb32E6WFaGTd7kPZG3EeDusjdZfUsPwKCKVXy1ZlntifaHZ4l8pAsmw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
|
|
@ -7554,7 +7769,8 @@
|
|||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/react-masked-text": {
|
||||
"version": "1.0.5",
|
||||
|
|
@ -7567,6 +7783,7 @@
|
|||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
||||
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/use-sync-external-store": "^0.0.6",
|
||||
"use-sync-external-store": "^1.4.0"
|
||||
|
|
@ -7685,7 +7902,8 @@
|
|||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/redux-thunk": {
|
||||
"version": "3.1.0",
|
||||
|
|
@ -8445,6 +8663,7 @@
|
|||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -8456,7 +8675,8 @@
|
|||
"version": "8.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tinymce/-/tinymce-8.1.2.tgz",
|
||||
"integrity": "sha512-KITxHEEHRlxC5xOnxA123eAJ67NgsWxNphtItWt9TRu07DiTZrWIqJeIKRX9euE51/l3kJO4WQiqoBXKTJJGsA==",
|
||||
"license": "GPL-2.0-or-later"
|
||||
"license": "GPL-2.0-or-later",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
|
|
@ -8610,6 +8830,7 @@
|
|||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
|
@ -8675,6 +8896,7 @@
|
|||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"napi-postinstall": "^0.3.0"
|
||||
},
|
||||
|
|
@ -8961,6 +9183,7 @@
|
|||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz",
|
||||
"integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,11 @@
|
|||
"@radix-ui/react-label": "^2.1.7",
|
||||
"@radix-ui/react-popover": "^1.1.15",
|
||||
"@radix-ui/react-progress": "^1.1.7",
|
||||
"@radix-ui/react-radio-group": "^1.3.8",
|
||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||
"@radix-ui/react-select": "^2.2.6",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-separator": "^1.1.8",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"@radix-ui/react-switch": "^1.2.6",
|
||||
"@radix-ui/react-tabs": "^1.1.13",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
|
|
|
|||
BIN
public/sounds/success.mp3
Normal file
BIN
public/sounds/success.mp3
Normal file
Binary file not shown.
|
|
@ -3,13 +3,10 @@
|
|||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { GUsuarioSchema } from '../../../../../../packages/administrativo/schemas/GUsuario/GUsuarioSchema';
|
||||
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
|
|
@ -18,8 +15,10 @@ import {
|
|||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
|
||||
import { useGUsuarioSaveHook } from '../../../../../../packages/administrativo/hooks/GUsuario/useGUsuarioSaveHook';
|
||||
import { GUsuarioSchema } from '../../../../../../packages/administrativo/schemas/GUsuario/GUsuarioSchema';
|
||||
|
||||
type FormValues = z.infer<typeof GUsuarioSchema>;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
'use client';
|
||||
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import Link from 'next/link';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
|
|
@ -10,14 +13,14 @@ import {
|
|||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
|
||||
import Usuario from '../../../../../packages/administrativo/interfaces/GUsuario/GUsuarioInterface';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Link from 'next/link';
|
||||
import { useGUsuarioIndexHook } from '../../../../../packages/administrativo/hooks/GUsuario/useGUsuarioIndexHook';
|
||||
import { useEffect } from 'react';
|
||||
import Loading from '@/shared/components/loading/loading';
|
||||
|
||||
import { useGUsuarioIndexHook } from '../../../../../packages/administrativo/hooks/GUsuario/useGUsuarioIndexHook';
|
||||
import Usuario from '../../../../../packages/administrativo/interfaces/GUsuario/GUsuarioInterface';
|
||||
|
||||
|
||||
|
||||
|
||||
export default function UsuarioPage() {
|
||||
const { usuarios, fetchUsuarios } = useGUsuarioIndexHook();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import Loading from '@/shared/components/loading/loading';
|
||||
|
||||
// Componentes específicos para TServicoTipo
|
||||
import TServicoTipoTable from '../../_components/t_servico_tipo/TServicoTipoTable';
|
||||
import TServicoTipoForm from '../../_components/t_servico_tipo/TServicoTipoForm';
|
||||
import TServicoTipoTable from '../../_components/t_servico_tipo/TServicoTipoTable';
|
||||
|
||||
// Hooks específicos para TServicoTipo
|
||||
import { useTServicoTipoReadHook } from '../../_hooks/t_servico_tipo/useTServicoTipoReadHook';
|
||||
import { useTServicoTipoSaveHook } from '../../_hooks/t_servico_tipo/useTServicoTipoSaveHook';
|
||||
import { useTServicoTipoRemoveHook } from '../../_hooks/t_servico_tipo/useTServicoTipoRemoveHook';
|
||||
import { useTServicoTipoEditHook } from '../../_hooks/t_servico_tipo/useTServicoTipoEditHook';
|
||||
import { useTServicoTipoEditHook } from '../../../../../../packages/administrativo/hooks/TServicoTipo/useTServicoTipoEditHook';
|
||||
import { useTServicoTipoReadHook } from '../../../../../../packages/administrativo/hooks/TServicoTipo/useTServicoTipoReadHook';
|
||||
import { useTServicoTipoRemoveHook } from '../../../../../../packages/administrativo/hooks/TServicoTipo/useTServicoTipoRemoveHook';
|
||||
import { useTServicoTipoSaveHook } from '../../../../../../packages/administrativo/hooks/TServicoTipo/useTServicoTipoSaveHook';
|
||||
|
||||
import ConfirmDialog from '@/shared/components/confirmDialog/ConfirmDialog';
|
||||
import { useConfirmDialog } from '@/shared/components/confirmDialog/useConfirmDialog';
|
||||
|
||||
// Interface específica para TServicoTipo
|
||||
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface';
|
||||
import Header from '@/shared/components/structure/Header';
|
||||
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface';
|
||||
|
||||
export default function TServicoTipoPage() {
|
||||
// Hooks para leitura, salvamento e remoção
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import z from 'zod';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useState } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
|
|
@ -15,8 +11,6 @@ import {
|
|||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { CirclePlus, DollarSign, Settings, SquarePen, Trash } from 'lucide-react';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
|
|
@ -26,13 +20,10 @@ import {
|
|||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
SelectItem
|
||||
} from '@/components/ui/select';
|
||||
import {
|
||||
Table,
|
||||
|
|
@ -42,23 +33,28 @@ import {
|
|||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { CirclePlus, DollarSign, Settings, SquarePen, Trash } from 'lucide-react';
|
||||
import React, { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
import { TServicoTipoSchema, TServicoTipoFormValues } from '../../_schemas/TServicoTipoSchema';
|
||||
import { useEffect } from 'react';
|
||||
import GMarcacaoTipoSelect from '@/packages/administrativo/components/GMarcacaoTipo/GMarcacaoTipoSelect';
|
||||
import GEmolumentoSelect from '@/packages/administrativo/components/GEmolumento/GEmolumentoSelect';
|
||||
import { useGEmolumentoItemReadHook } from '@/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento_item/useGEmolumentoItemReadHook';
|
||||
import { useTServicoEtiquetaReadHook } from '@/app/(protected)/(cadastros)/cadastros/_hooks/t_servico_etiqueta/useTServicoEtiquetaReadHook';
|
||||
import { useTServicoEtiquetaRemoveHook } from '@/app/(protected)/(cadastros)/cadastros/_hooks/t_servico_etiqueta/useTServicoEtiquetaRemoveHook';
|
||||
import { useTServicoEtiquetaSaveHook } from '@/app/(protected)/(cadastros)/cadastros/_hooks/t_servico_etiqueta/useTServicoEtiquetaSaveHook';
|
||||
import { GEmolumentoItemReadInterface } from '@/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoItemReadInterface';
|
||||
import CategoriaServicoSelect from '@/shared/components/categoriaServicoSelect/CategoriaServicoSelect';
|
||||
import CCaixaServicoSelect from '@/packages/administrativo/components/CCaixaServico/CCaixaServicoSelect';
|
||||
import { TServicoTipoSaveData } from '../../_data/TServicoTipo/TServicoTipoSaveData';
|
||||
import GEmolumentoSelect from '@/packages/administrativo/components/GEmolumento/GEmolumentoSelect';
|
||||
import GMarcacaoTipoSelect from '@/packages/administrativo/components/GMarcacaoTipo/GMarcacaoTipoSelect';
|
||||
import TTBReconhecimentoTipoSelect from '@/packages/administrativo/components/TTBReconhecimentoTipo/TTBReconhecimentoTipoSelect';
|
||||
import CategoriaServicoSelect from '@/shared/components/categoriaServicoSelect/CategoriaServicoSelect';
|
||||
import { ConfirmacaoCheckBox } from '@/shared/components/confirmacao/ConfirmacaoCheckBox';
|
||||
import ConfirmacaoSelect from '@/shared/components/confirmacao/ConfirmacaoSelect';
|
||||
import { TipoPessoaSelect } from '@/shared/components/tipoPessoa/tipoPessoaSelect';
|
||||
import { useTServicoEtiquetaReadHook } from '@/app/(protected)/(cadastros)/cadastros/_hooks/t_servico_etiqueta/useTServicoEtiquetaReadHook';
|
||||
import { useTServicoEtiquetaSaveHook } from '@/app/(protected)/(cadastros)/cadastros/_hooks/t_servico_etiqueta/useTServicoEtiquetaSaveHook';
|
||||
import { useTServicoEtiquetaRemoveHook } from '@/app/(protected)/(cadastros)/cadastros/_hooks/t_servico_etiqueta/useTServicoEtiquetaRemoveHook';
|
||||
import { useEffect } from 'react';
|
||||
import { TServicoTipoSaveData } from '../../../../../../packages/administrativo/data/TServicoTipo/TServicoTipoSaveData';
|
||||
import { TServicoTipoFormValues, TServicoTipoSchema } from '../../_schemas/TServicoTipoSchema';
|
||||
|
||||
// Propriedades esperadas pelo componente
|
||||
interface Props {
|
||||
|
|
|
|||
|
|
@ -6,20 +6,19 @@ import API from '@/shared/services/api/Api';
|
|||
|
||||
// Importa o enum que define os métodos HTTP disponíveis (GET, POST, PUT, DELETE, etc.)
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
|
||||
import { GEmolumentoReadInterface } from '../../_interfaces/GEmolumentoReadInterface';
|
||||
|
||||
// Função assíncrona responsável por executar a requisição para listar os tipos de marcação
|
||||
async function executeGEmolumentoIndexData(data: GEmolumentoReadInterface) {
|
||||
|
||||
// Cria uma nova instância da classe API para enviar a requisição
|
||||
const api = new API();
|
||||
|
||||
// Concatena o endpoint com a query string (caso existam parâmetros)
|
||||
const endpoint = `administrativo/g_emolumento/${data.sistema_id}`;
|
||||
|
||||
// Envia uma requisição GET para o endpoint 'administrativo/g_marcacao_tipo/'
|
||||
return await api.send({
|
||||
method: Methods.GET,
|
||||
endpoint: endpoint,
|
||||
endpoint: `administrativo/g_emolumento/sistema/${data.sistema_id}?${new URLSearchParams(data.urlParams).toString()}`,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
// Importa o hook responsável por gerenciar e exibir respostas globais (sucesso, erro, etc.)
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
// Importa hooks do React para gerenciamento de estado e memorização de valores
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
// Importa a interface que define a estrutura dos dados de "GEmolumento"
|
||||
import { GEmolumentoInterface } from '../../_interfaces/GEmolumentoInterface';
|
||||
import { GEmolumentoReadInterface } from '../../_interfaces/GEmolumentoReadInterface';
|
||||
|
||||
// Importa o serviço responsável por buscar os dados de "GEmolumento" na API
|
||||
import { GEmolumentoIndexService } from '../../_services/g_emolumento/GEmolumentoIndexService';
|
||||
import { GEmolumentoInterface } from '../../_interfaces/GEmolumentoInterface';
|
||||
|
||||
// Hook personalizado para leitura (consulta) dos emolumentos
|
||||
export const useGEmolumentoReadHook = () => {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
// Importa o hook responsável por gerenciar e exibir respostas globais (sucesso, erro, etc.)
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
// Importa hooks do React para gerenciamento de estado e memorização de valores
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
// Importa a interface que define a estrutura dos dados de "gEmolumentoItem"
|
||||
import { GEmolumentoItemInterface } from '../../_interfaces/GEmolumentoItemInterface';
|
||||
import { GEmolumentoItemReadInterface } from '../../_interfaces/GEmolumentoItemReadInterface';
|
||||
|
||||
// Importa o serviço responsável por buscar os dados de "GEmolumentoItem" na API
|
||||
import { GEmolumentoItemValorService } from '../../_services/g_emolumento_item/GEmolumentoItemValorService';
|
||||
import { GEmolumentoItemInterface } from '../../_interfaces/GEmolumentoItemInterface';
|
||||
|
||||
// Hook personalizado para leitura (consulta) dos emolumentos
|
||||
export const useGEmolumentoItemReadHook = () => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
export interface GEmolumentoReadInterface {
|
||||
sistema_id?: number;
|
||||
urlParams?: object
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ export default interface TServicoTipoInterface {
|
|||
servico_tipo_id?: number; // SERVICO_TIPO_ID NUMERIC(10,2) NOT NULL (PK)
|
||||
descricao: string; // DESCRICAO VARCHAR(60)
|
||||
valor?: number; // VALOR NUMERIC(14,3)
|
||||
tipo_item?: string;
|
||||
requer_autorizacao?: string; // REQUER_AUTORIZACAO VARCHAR(1)
|
||||
requer_biometria?: string; // REQUER_BIOMETRIA VARCHAR(1)
|
||||
tipo_pessoa?: string; // TIPO_PESSOA VARCHAR(1)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { GEmolumentoReadInterface } from '../../_interfaces/GEmolumentoReadInter
|
|||
|
||||
// Função assíncrona responsável por executar o serviço de listagem de tipos de marcação
|
||||
async function executeGEmolumentoIndexService(data: GEmolumentoReadInterface) {
|
||||
|
||||
// Chama a função que realiza a requisição à API e aguarda a resposta
|
||||
const response = await GEmolumentoIndexData(data);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import type { Metadata } from 'next';
|
|||
import { Geist, Geist_Mono } from 'next/font/google';
|
||||
import '../globals.css';
|
||||
|
||||
import { ResponseProvider } from '../../shared/components/response/ResponseContext';
|
||||
import { AppSidebar } from '@/components/app-sidebar';
|
||||
import { ThemeProvider } from '@/components/theme-provider';
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
|
|
@ -15,7 +15,10 @@ import {
|
|||
import { Separator } from '@/components/ui/separator';
|
||||
import { SidebarInset, SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar';
|
||||
import { Toaster } from '@/components/ui/sonner';
|
||||
|
||||
import Response from '../../shared/components/response/response';
|
||||
import { ResponseProvider } from '../../shared/components/response/ResponseContext';
|
||||
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: '--font-geist-sans',
|
||||
|
|
@ -35,46 +38,48 @@ export const metadata: Metadata = {
|
|||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
|
||||
<SidebarProvider>
|
||||
<AppSidebar />
|
||||
<SidebarInset>
|
||||
<header className="mb-4 flex h-16 shrink-0 items-center gap-2 border-b-1 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12">
|
||||
<div className="flex items-center gap-2 px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
<Separator
|
||||
orientation="vertical"
|
||||
className="mr-2 data-[orientation=vertical]:h-4"
|
||||
/>
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem className="hidden md:block">
|
||||
<BreadcrumbLink href="#">Building Your Application</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator className="hidden md:block" />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Data Fetching</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
</header>
|
||||
<ResponseProvider>
|
||||
<div className="flex flex-1 flex-col gap-4 p-4 pt-0">
|
||||
{children}
|
||||
<Toaster richColors position="top-center" />
|
||||
<Response />
|
||||
</div>
|
||||
</ResponseProvider>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
<ThemeProvider>
|
||||
<SidebarProvider>
|
||||
<AppSidebar />
|
||||
|
||||
<SidebarInset>
|
||||
<header className="mb-4 flex h-16 shrink-0 items-center gap-2 border-b-1 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12">
|
||||
<div className="flex items-center gap-2 px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
<Separator
|
||||
orientation="vertical"
|
||||
className="mr-2 data-[orientation=vertical]:h-4"
|
||||
/>
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem className="hidden md:block">
|
||||
<BreadcrumbLink href="#">
|
||||
Building Your Application
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator className="hidden md:block" />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Data Fetching</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<ResponseProvider>
|
||||
<div className="flex flex-1 flex-col gap-4 p-4 pt-0">
|
||||
{children}
|
||||
<Toaster richColors position="top-center" />
|
||||
<Response />
|
||||
</div>
|
||||
</ResponseProvider>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
'use client'
|
||||
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
import TServicoPedidoDetails from "@/packages/servicos/components/TServicoPedido/TServicoPedidoDetails";
|
||||
|
||||
export default function TServicoPedidoDetailsPage() {
|
||||
|
||||
const params = useParams();
|
||||
|
||||
return (
|
||||
<TServicoPedidoDetails
|
||||
servico_pedido_id={Number(params.servicoPedidoId)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
'use client'
|
||||
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
import TServicoPedidoForm from "@/packages/servicos/components/TServicoPedido/TServicoPedidoForm";
|
||||
|
||||
export default function TServicoPedidoPage() {
|
||||
|
||||
const params = useParams();
|
||||
|
||||
return (
|
||||
<TServicoPedidoForm
|
||||
servico_pedido_id={Number(params.servicoPedidoId)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,90 +1,7 @@
|
|||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import TServicoItemPedidoResumo from "@/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoResumo";
|
||||
import TServicoPedidoForm from "@/packages/servicos/components/TServicoPedido/TServicoPedidoForm"
|
||||
|
||||
const itens = [
|
||||
{
|
||||
id: 1,
|
||||
descricao: "Reconhecimento de Firma",
|
||||
valor: 12.50,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
descricao: "Autenticação de Cópia",
|
||||
valor: 6.00,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
descricao: "Procuração Pública",
|
||||
valor: 98.75,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
descricao: "Certidão de Escritura",
|
||||
valor: 42.30,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
descricao: "Registro de Documento",
|
||||
valor: 73.10,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
export default function PedidoPage() {
|
||||
export default function TServicoPedidoPage() {
|
||||
return (
|
||||
<div>
|
||||
<div className="grid w-full grid-cols-12 gap-4">
|
||||
<div className="col-span-12 sm:col-span-9 md:col-span-9">
|
||||
<Card>
|
||||
<CardContent>
|
||||
<div className="grid w-full grid-cols-12 gap-4">
|
||||
<div className="col-span-12 sm:col-span-3 md:col-span-3">
|
||||
<Card>
|
||||
<CardContent>
|
||||
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 sm:col-span-3 md:col-span-3">
|
||||
<Card>
|
||||
<CardContent>
|
||||
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 sm:col-span-3 md:col-span-3">
|
||||
<Card>
|
||||
<CardContent>
|
||||
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 sm:col-span-3 md:col-span-3">
|
||||
<Card>
|
||||
<CardContent>
|
||||
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 sm:col-span-3 md:col-span-3">
|
||||
<Card>
|
||||
<CardContent>
|
||||
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="col-span-12 sm:col-span-3 md:col-span-3">
|
||||
<TServicoItemPedidoResumo
|
||||
dataPedido="01/01/2026"
|
||||
numeroPedido={123}
|
||||
itens={itens}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<TServicoPedidoForm />
|
||||
)
|
||||
}
|
||||
|
|
@ -3,60 +3,179 @@
|
|||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
:root {
|
||||
--background: oklch(0.9911 0 0);
|
||||
--foreground: oklch(0.2988 0.0123 222.4429);
|
||||
--card: oklch(1.0000 0 0);
|
||||
--card-foreground: oklch(0.2988 0.0123 222.4429);
|
||||
--popover: oklch(0.9881 0 0);
|
||||
--popover-foreground: oklch(0.2988 0.0123 222.4429);
|
||||
--primary: oklch(0.7210 0.1873 47.5640);
|
||||
--primary-foreground: oklch(1.0000 0 0);
|
||||
--secondary: oklch(0.2988 0.0123 222.4429);
|
||||
--secondary-foreground: oklch(1.0000 0 0);
|
||||
--muted: oklch(0.9700 0 0);
|
||||
--muted-foreground: oklch(0.5560 0 0);
|
||||
--accent: oklch(0.9551 0 0);
|
||||
--accent-foreground: oklch(0.2988 0.0123 222.4429);
|
||||
--destructive: oklch(0.5770 0.2450 27.3250);
|
||||
--destructive-foreground: oklch(1 0 0);
|
||||
--border: oklch(0.9220 0 0);
|
||||
--input: oklch(0.9220 0 0);
|
||||
--ring: oklch(0.7080 0 0);
|
||||
--chart-1: oklch(0.8100 0.1000 252);
|
||||
--chart-2: oklch(0.6200 0.1900 260);
|
||||
--chart-3: oklch(0.5500 0.2200 263);
|
||||
--chart-4: oklch(0.4900 0.2200 264);
|
||||
--chart-5: oklch(0.4200 0.1800 266);
|
||||
--sidebar: oklch(1.0000 0 0);
|
||||
--sidebar-foreground: oklch(0.2988 0.0123 222.4429);
|
||||
--sidebar-primary: oklch(0.2364 0.0083 240.2365);
|
||||
--sidebar-primary-foreground: oklch(0.9850 0 0);
|
||||
--sidebar-accent: oklch(0.9700 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.2050 0 0);
|
||||
--sidebar-border: oklch(0.9220 0 0);
|
||||
--sidebar-ring: oklch(0.7080 0 0);
|
||||
--font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
|
||||
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--radius: 0.625rem;
|
||||
--shadow-x: 0;
|
||||
--shadow-y: 1px;
|
||||
--shadow-blur: 3px;
|
||||
--shadow-spread: 0px;
|
||||
--shadow-opacity: 0.1;
|
||||
--shadow-color: oklch(0 0 0);
|
||||
--shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
|
||||
--shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
|
||||
--shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
|
||||
--tracking-normal: 0em;
|
||||
--spacing: 0.25rem;
|
||||
--shadow-offset-x: 0;
|
||||
--shadow-offset-y: 1px;
|
||||
--letter-spacing: 0em;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.1934 0.0062 236.9149);
|
||||
--foreground: oklch(0.9881 0 0);
|
||||
--card: oklch(0.2364 0.0083 240.2365);
|
||||
--card-foreground: oklch(0.9881 0 0);
|
||||
--popover: oklch(0.2988 0.0123 222.4429);
|
||||
--popover-foreground: oklch(0.9881 0 0);
|
||||
--primary: oklch(0.7210 0.1873 47.5640);
|
||||
--primary-foreground: oklch(0.2988 0.0123 222.4429);
|
||||
--secondary: oklch(0.2988 0.0123 222.4429);
|
||||
--secondary-foreground: oklch(1.0000 0 0);
|
||||
--muted: oklch(0.2690 0 0);
|
||||
--muted-foreground: oklch(0.7080 0 0);
|
||||
--accent: oklch(0.2988 0.0123 222.4429);
|
||||
--accent-foreground: oklch(1.0000 0 0);
|
||||
--destructive: oklch(0.7040 0.1910 22.2160);
|
||||
--destructive-foreground: oklch(0.9850 0 0);
|
||||
--border: oklch(0.2750 0 0);
|
||||
--input: oklch(0.3250 0 0);
|
||||
--ring: oklch(0.5560 0 0);
|
||||
--chart-1: oklch(0.8100 0.1000 252);
|
||||
--chart-2: oklch(0.6200 0.1900 260);
|
||||
--chart-3: oklch(0.5500 0.2200 263);
|
||||
--chart-4: oklch(0.4900 0.2200 264);
|
||||
--chart-5: oklch(0.4200 0.1800 266);
|
||||
--sidebar: oklch(0.2364 0.0083 240.2365);
|
||||
--sidebar-foreground: oklch(0.9881 0 0);
|
||||
--sidebar-primary: oklch(0.4880 0.2430 264.3760);
|
||||
--sidebar-primary-foreground: oklch(0.9850 0 0);
|
||||
--sidebar-accent: oklch(0.2690 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.9850 0 0);
|
||||
--sidebar-border: oklch(0.2750 0 0);
|
||||
--sidebar-ring: oklch(0.4390 0 0);
|
||||
--font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
|
||||
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--radius: 0.625rem;
|
||||
--shadow-x: 0;
|
||||
--shadow-y: 1px;
|
||||
--shadow-blur: 3px;
|
||||
--shadow-spread: 0px;
|
||||
--shadow-opacity: 0.1;
|
||||
--shadow-color: oklch(0 0 0);
|
||||
--shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
|
||||
--shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
|
||||
--shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
|
||||
--shadow-offset-x: 0;
|
||||
--shadow-offset-y: 1px;
|
||||
--letter-spacing: 0em;
|
||||
--spacing: 0.25rem;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: Inter, sans-serif;
|
||||
--font-mono: JetBrains Mono, monospace;
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-ring: var(--ring);
|
||||
--color-input: var(--input);
|
||||
--color-border: var(--border);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
|
||||
--font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
|
||||
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--font-serif: Source Serif 4, serif;
|
||||
--radius: 0.375rem;
|
||||
|
||||
--shadow-2xs: var(--shadow-2xs);
|
||||
--shadow-xs: var(--shadow-xs);
|
||||
--shadow-sm: var(--shadow-sm);
|
||||
--shadow: var(--shadow);
|
||||
--shadow-md: var(--shadow-md);
|
||||
--shadow-lg: var(--shadow-lg);
|
||||
--shadow-xl: var(--shadow-xl);
|
||||
--shadow-2xl: var(--shadow-2xl);
|
||||
--radius: 0.625rem;
|
||||
--tracking-tighter: calc(var(--tracking-normal) - 0.05em);
|
||||
--tracking-tight: calc(var(--tracking-normal) - 0.025em);
|
||||
--tracking-wide: calc(var(--tracking-normal) + 0.025em);
|
||||
--tracking-wider: calc(var(--tracking-normal) + 0.05em);
|
||||
--tracking-widest: calc(var(--tracking-normal) + 0.1em);
|
||||
--tracking-normal: var(--tracking-normal);
|
||||
--shadow-2xl: var(--shadow-2xl);
|
||||
--shadow-xl: var(--shadow-xl);
|
||||
--shadow-lg: var(--shadow-lg);
|
||||
--shadow-md: var(--shadow-md);
|
||||
--shadow: var(--shadow);
|
||||
--shadow-sm: var(--shadow-sm);
|
||||
--shadow-xs: var(--shadow-xs);
|
||||
--shadow-2xs: var(--shadow-2xs);
|
||||
--spacing: var(--spacing);
|
||||
--letter-spacing: var(--letter-spacing);
|
||||
--shadow-offset-y: var(--shadow-offset-y);
|
||||
|
|
@ -65,118 +184,6 @@
|
|||
--shadow-blur: var(--shadow-blur);
|
||||
--shadow-opacity: var(--shadow-opacity);
|
||||
--color-shadow-color: var(--shadow-color);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
}
|
||||
|
||||
:root {
|
||||
--radius: 0.375rem;
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.2686 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.2686 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.2686 0 0);
|
||||
--primary: oklch(0.7686 0.1647 70.0804);
|
||||
--primary-foreground: oklch(0 0 0);
|
||||
--secondary: oklch(0.967 0.0029 264.5419);
|
||||
--secondary-foreground: oklch(0.4461 0.0263 256.8018);
|
||||
--muted: oklch(0.9846 0.0017 247.8389);
|
||||
--muted-foreground: oklch(0.551 0.0234 264.3637);
|
||||
--accent: oklch(0.9869 0.0214 95.2774);
|
||||
--accent-foreground: oklch(0.4732 0.1247 46.2007);
|
||||
--destructive: oklch(0.6368 0.2078 25.3313);
|
||||
--border: oklch(0.9276 0.0058 264.5313);
|
||||
--input: oklch(0.9276 0.0058 264.5313);
|
||||
--ring: oklch(0.7686 0.1647 70.0804);
|
||||
--chart-1: oklch(0.7686 0.1647 70.0804);
|
||||
--chart-2: oklch(0.6658 0.1574 58.3183);
|
||||
--chart-3: oklch(0.5553 0.1455 48.9975);
|
||||
--chart-4: oklch(0.4732 0.1247 46.2007);
|
||||
--chart-5: oklch(0.4137 0.1054 45.9038);
|
||||
--sidebar: oklch(0.9846 0.0017 247.8389);
|
||||
--sidebar-foreground: oklch(0.2686 0 0);
|
||||
--sidebar-primary: oklch(0.7686 0.1647 70.0804);
|
||||
--sidebar-primary-foreground: oklch(1 0 0);
|
||||
--sidebar-accent: oklch(0.9869 0.0214 95.2774);
|
||||
--sidebar-accent-foreground: oklch(0.4732 0.1247 46.2007);
|
||||
--sidebar-border: oklch(0.9276 0.0058 264.5313);
|
||||
--sidebar-ring: oklch(0.7686 0.1647 70.0804);
|
||||
--destructive-foreground: oklch(1 0 0);
|
||||
--font-sans: Inter, sans-serif;
|
||||
--font-serif: Source Serif 4, serif;
|
||||
--font-mono: JetBrains Mono, monospace;
|
||||
--shadow-color: hsl(0 0% 0%);
|
||||
--shadow-opacity: 0.1;
|
||||
--shadow-blur: 8px;
|
||||
--shadow-spread: -1px;
|
||||
--shadow-offset-x: 0px;
|
||||
--shadow-offset-y: 4px;
|
||||
--letter-spacing: 0em;
|
||||
--spacing: 0.25rem;
|
||||
--shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
|
||||
--shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
|
||||
--shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 1px 2px -2px hsl(0 0% 0% / 0.1);
|
||||
--shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 1px 2px -2px hsl(0 0% 0% / 0.1);
|
||||
--shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 2px 4px -2px hsl(0 0% 0% / 0.1);
|
||||
--shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 4px 6px -2px hsl(0 0% 0% / 0.1);
|
||||
--shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 8px 10px -2px hsl(0 0% 0% / 0.1);
|
||||
--shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25);
|
||||
--tracking-normal: 0em;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.2046 0 0);
|
||||
--foreground: oklch(0.9219 0 0);
|
||||
--card: oklch(0.2686 0 0);
|
||||
--card-foreground: oklch(0.9219 0 0);
|
||||
--popover: oklch(0.2686 0 0);
|
||||
--popover-foreground: oklch(0.9219 0 0);
|
||||
--primary: oklch(0.7686 0.1647 70.0804);
|
||||
--primary-foreground: oklch(0 0 0);
|
||||
--secondary: oklch(0.2686 0 0);
|
||||
--secondary-foreground: oklch(0.9219 0 0);
|
||||
--muted: oklch(0.2686 0 0);
|
||||
--muted-foreground: oklch(0.7155 0 0);
|
||||
--accent: oklch(0.4732 0.1247 46.2007);
|
||||
--accent-foreground: oklch(0.9243 0.1151 95.7459);
|
||||
--destructive: oklch(0.6368 0.2078 25.3313);
|
||||
--border: oklch(0.3715 0 0);
|
||||
--input: oklch(0.3715 0 0);
|
||||
--ring: oklch(0.7686 0.1647 70.0804);
|
||||
--chart-1: oklch(0.8369 0.1644 84.4286);
|
||||
--chart-2: oklch(0.6658 0.1574 58.3183);
|
||||
--chart-3: oklch(0.4732 0.1247 46.2007);
|
||||
--chart-4: oklch(0.5553 0.1455 48.9975);
|
||||
--chart-5: oklch(0.4732 0.1247 46.2007);
|
||||
--sidebar: oklch(0.1684 0 0);
|
||||
--sidebar-foreground: oklch(0.9219 0 0);
|
||||
--sidebar-primary: oklch(0.7686 0.1647 70.0804);
|
||||
--sidebar-primary-foreground: oklch(1 0 0);
|
||||
--sidebar-accent: oklch(0.4732 0.1247 46.2007);
|
||||
--sidebar-accent-foreground: oklch(0.9243 0.1151 95.7459);
|
||||
--sidebar-border: oklch(0.3715 0 0);
|
||||
--sidebar-ring: oklch(0.7686 0.1647 70.0804);
|
||||
--destructive-foreground: oklch(1 0 0);
|
||||
--radius: 0.375rem;
|
||||
--font-sans: Inter, sans-serif;
|
||||
--font-serif: Source Serif 4, serif;
|
||||
--font-mono: JetBrains Mono, monospace;
|
||||
--shadow-color: hsl(0 0% 0%);
|
||||
--shadow-opacity: 0.1;
|
||||
--shadow-blur: 8px;
|
||||
--shadow-spread: -1px;
|
||||
--shadow-offset-x: 0px;
|
||||
--shadow-offset-y: 4px;
|
||||
--letter-spacing: 0em;
|
||||
--spacing: 0.25rem;
|
||||
--shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
|
||||
--shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
|
||||
--shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 1px 2px -2px hsl(0 0% 0% / 0.1);
|
||||
--shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 1px 2px -2px hsl(0 0% 0% / 0.1);
|
||||
--shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 2px 4px -2px hsl(0 0% 0% / 0.1);
|
||||
--shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 4px 6px -2px hsl(0 0% 0% / 0.1);
|
||||
--shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 8px 10px -2px hsl(0 0% 0% / 0.1);
|
||||
--shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
|
|
@ -190,4 +197,4 @@
|
|||
.bg-brand {
|
||||
background-color: #1a292f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import {
|
|||
Frame,
|
||||
GalleryVerticalEnd,
|
||||
HouseIcon,
|
||||
SquareMousePointer,
|
||||
SquareTerminal,
|
||||
UsersIcon
|
||||
} from 'lucide-react';
|
||||
|
|
@ -47,7 +48,7 @@ const data = {
|
|||
{
|
||||
title: 'Servicos',
|
||||
url: '#',
|
||||
icon: UsersIcon,
|
||||
icon: SquareMousePointer,
|
||||
isActive: false,
|
||||
items: [
|
||||
{
|
||||
|
|
@ -177,6 +178,34 @@ const data = {
|
|||
title: 'Atos/Partes Tipos',
|
||||
url: '/administrativo/atos/partes-tipos',
|
||||
},
|
||||
{
|
||||
title: "Valores de Serviços",
|
||||
url: "/administrativo/valores-de-servicos",
|
||||
},
|
||||
{
|
||||
title: "Gramatica",
|
||||
url: "/administrativo/gramatica",
|
||||
},
|
||||
{
|
||||
title: "Cartório",
|
||||
url: "/administrativo/cartorio",
|
||||
},
|
||||
{
|
||||
title: "Financeiro/Periodo",
|
||||
url: "/administrativo/financeiro/periodos",
|
||||
},
|
||||
{
|
||||
title: "Financeiro/Emolumentos",
|
||||
url: "/administrativo/financeiro/emolumentos",
|
||||
},
|
||||
{
|
||||
title: "Selos/Grupos",
|
||||
url: "/administrativo/selos/grupos",
|
||||
},
|
||||
{
|
||||
title: "Financeiro/Cálculo Rápido",
|
||||
url: "/administrativo/financeiro/calculo-rapido",
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
'use client';
|
||||
|
||||
import { ChevronsUpDown, LogOut, Sparkles } from 'lucide-react';
|
||||
import {
|
||||
ChevronsUpDown,
|
||||
LogOut,
|
||||
Moon,
|
||||
Sparkles,
|
||||
Sun,
|
||||
} from 'lucide-react';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import {
|
||||
DropdownMenu,
|
||||
|
|
@ -17,11 +26,9 @@ import {
|
|||
SidebarMenuItem,
|
||||
useSidebar,
|
||||
} from '@/components/ui/sidebar';
|
||||
|
||||
import GUsuarioAuthenticatedInterface from '@/shared/interfaces/GUsuarioAuthenticatedInterface';
|
||||
import ConfirmDialog from '@/shared/components/confirmDialog/ConfirmDialog';
|
||||
import { useGUsuarioLogoutHook } from '@/packages/administrativo/hooks/GUsuario/useGUsuarioLogoutHook';
|
||||
import { use, useCallback, useState } from 'react';
|
||||
import ConfirmDialog from '@/shared/components/confirmDialog/ConfirmDialog';
|
||||
import GUsuarioAuthenticatedInterface from '@/shared/interfaces/GUsuarioAuthenticatedInterface';
|
||||
|
||||
export function NavUser({ user }: { user: GUsuarioAuthenticatedInterface }) {
|
||||
// Hook para encerrar sessão
|
||||
|
|
@ -32,19 +39,26 @@ export function NavUser({ user }: { user: GUsuarioAuthenticatedInterface }) {
|
|||
|
||||
const { isMobile } = useSidebar();
|
||||
|
||||
// Manipulação de formulário de confirmação
|
||||
const handleConfirmOpen = useCallback(async () => {
|
||||
// Tema (claro/escuro) - next-themes
|
||||
const { theme, setTheme } = useTheme();
|
||||
const isDark = theme === 'dark';
|
||||
|
||||
const handleConfirmOpen = useCallback(() => {
|
||||
setIsConfirmOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleLogoutConfirm = useCallback(async () => {
|
||||
const handleLogoutConfirm = useCallback(() => {
|
||||
logoutUsuario();
|
||||
}, []);
|
||||
}, [logoutUsuario]);
|
||||
|
||||
const handleLogoutCancel = useCallback(async () => {
|
||||
const handleLogoutCancel = useCallback(() => {
|
||||
setIsConfirmOpen(false);
|
||||
}, []);
|
||||
|
||||
const handleToggleTheme = useCallback(() => {
|
||||
setTheme(isDark ? 'light' : 'dark');
|
||||
}, [isDark, setTheme]);
|
||||
|
||||
if (!user) {
|
||||
return 'Carregando...';
|
||||
}
|
||||
|
|
@ -61,13 +75,13 @@ export function NavUser({ user }: { user: GUsuarioAuthenticatedInterface }) {
|
|||
>
|
||||
<Avatar className="h-8 w-8 rounded-lg">
|
||||
<AvatarImage src={user.sigla} alt={user.nome} />
|
||||
|
||||
<AvatarFallback className="rounded-lg">{user.sigla}</AvatarFallback>
|
||||
<AvatarFallback className="rounded-lg">
|
||||
{user.sigla}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
<span className="truncate font-medium">{user.nome}</span>
|
||||
|
||||
<span className="truncate text-xs">{user.email}</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -85,13 +99,13 @@ export function NavUser({ user }: { user: GUsuarioAuthenticatedInterface }) {
|
|||
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
|
||||
<Avatar className="h-8 w-8 rounded-lg">
|
||||
<AvatarImage src={user.sigla} alt={user.nome} />
|
||||
|
||||
<AvatarFallback className="rounded-lg">{user.sigla}</AvatarFallback>
|
||||
<AvatarFallback className="rounded-lg">
|
||||
{user.sigla}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
<span className="truncate font-medium">{user.nome}</span>
|
||||
|
||||
<span className="truncate text-xs">{user.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -100,16 +114,32 @@ export function NavUser({ user }: { user: GUsuarioAuthenticatedInterface }) {
|
|||
<DropdownMenuSeparator />
|
||||
|
||||
<DropdownMenuGroup>
|
||||
{/* Alternância de tema */}
|
||||
<DropdownMenuItem
|
||||
className="cursor-pointer"
|
||||
onClick={handleToggleTheme}
|
||||
>
|
||||
{isDark ? (
|
||||
<Sun className="mr-2 h-4 w-4" />
|
||||
) : (
|
||||
<Moon className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
{isDark ? 'Modo claro' : 'Modo escuro'}
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem className="cursor-pointer">
|
||||
<Sparkles />
|
||||
<Sparkles className="mr-2 h-4 w-4" />
|
||||
Configurações
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<DropdownMenuItem className="cursor-pointer" onClick={() => handleConfirmOpen()}>
|
||||
<LogOut />
|
||||
<DropdownMenuItem
|
||||
className="cursor-pointer"
|
||||
onClick={handleConfirmOpen}
|
||||
>
|
||||
<LogOut className="mr-2 h-4 w-4" />
|
||||
Log out
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
|
|
@ -122,11 +152,11 @@ export function NavUser({ user }: { user: GUsuarioAuthenticatedInterface }) {
|
|||
isOpen={isConfirmOpen}
|
||||
title="Log-out"
|
||||
description="Atenção"
|
||||
message={`Deseja realmente encerrar a sessão ? Dados não salvos serão perdidos`}
|
||||
message="Deseja realmente encerrar a sessão? Dados não salvos serão perdidos."
|
||||
confirmText="Sim, sair"
|
||||
cancelText="Cancelar"
|
||||
onConfirm={() => handleLogoutConfirm()}
|
||||
onCancel={() => handleLogoutCancel()}
|
||||
onConfirm={handleLogoutConfirm}
|
||||
onCancel={handleLogoutCancel}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
17
src/components/theme-provider.tsx
Normal file
17
src/components/theme-provider.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
"use client";
|
||||
|
||||
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
||||
import * as React from "react";
|
||||
|
||||
export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<NextThemesProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
{children}
|
||||
</NextThemesProvider>
|
||||
);
|
||||
}
|
||||
83
src/components/ui/button-group.tsx
Normal file
83
src/components/ui/button-group.tsx
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
|
||||
const buttonGroupVariants = cva(
|
||||
"flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2",
|
||||
{
|
||||
variants: {
|
||||
orientation: {
|
||||
horizontal:
|
||||
"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
|
||||
vertical:
|
||||
"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
orientation: "horizontal",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
function ButtonGroup({
|
||||
className,
|
||||
orientation,
|
||||
...props
|
||||
}: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {
|
||||
return (
|
||||
<div
|
||||
role="group"
|
||||
data-slot="button-group"
|
||||
data-orientation={orientation}
|
||||
className={cn(buttonGroupVariants({ orientation }), className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupText({
|
||||
className,
|
||||
asChild = false,
|
||||
...props
|
||||
}: React.ComponentProps<"div"> & {
|
||||
asChild?: boolean
|
||||
}) {
|
||||
const Comp = asChild ? Slot : "div"
|
||||
|
||||
return (
|
||||
<Comp
|
||||
className={cn(
|
||||
"bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupSeparator({
|
||||
className,
|
||||
orientation = "vertical",
|
||||
...props
|
||||
}: React.ComponentProps<typeof Separator>) {
|
||||
return (
|
||||
<Separator
|
||||
data-slot="button-group-separator"
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
ButtonGroup,
|
||||
ButtonGroupSeparator,
|
||||
ButtonGroupText,
|
||||
buttonGroupVariants,
|
||||
}
|
||||
193
src/components/ui/item.tsx
Normal file
193
src/components/ui/item.tsx
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
|
||||
function ItemGroup({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
role="list"
|
||||
data-slot="item-group"
|
||||
className={cn("group/item-group flex flex-col", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ItemSeparator({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof Separator>) {
|
||||
return (
|
||||
<Separator
|
||||
data-slot="item-separator"
|
||||
orientation="horizontal"
|
||||
className={cn("my-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const itemVariants = cva(
|
||||
"group/item flex items-center border border-transparent text-sm rounded-md transition-colors [a]:hover:bg-accent/50 [a]:transition-colors duration-100 flex-wrap outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-transparent",
|
||||
outline: "border-border",
|
||||
muted: "bg-muted/50",
|
||||
},
|
||||
size: {
|
||||
default: "p-4 gap-4 ",
|
||||
sm: "py-3 px-4 gap-2.5",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
function Item({
|
||||
className,
|
||||
variant = "default",
|
||||
size = "default",
|
||||
asChild = false,
|
||||
...props
|
||||
}: React.ComponentProps<"div"> &
|
||||
VariantProps<typeof itemVariants> & { asChild?: boolean }) {
|
||||
const Comp = asChild ? Slot : "div"
|
||||
return (
|
||||
<Comp
|
||||
data-slot="item"
|
||||
data-variant={variant}
|
||||
data-size={size}
|
||||
className={cn(itemVariants({ variant, size, className }))}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const itemMediaVariants = cva(
|
||||
"flex shrink-0 items-center justify-center gap-2 group-has-[[data-slot=item-description]]/item:self-start [&_svg]:pointer-events-none group-has-[[data-slot=item-description]]/item:translate-y-0.5",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-transparent",
|
||||
icon: "size-8 border rounded-sm bg-muted [&_svg:not([class*='size-'])]:size-4",
|
||||
image:
|
||||
"size-10 rounded-sm overflow-hidden [&_img]:size-full [&_img]:object-cover",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
function ItemMedia({
|
||||
className,
|
||||
variant = "default",
|
||||
...props
|
||||
}: React.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>) {
|
||||
return (
|
||||
<div
|
||||
data-slot="item-media"
|
||||
data-variant={variant}
|
||||
className={cn(itemMediaVariants({ variant, className }))}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ItemContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="item-content"
|
||||
className={cn(
|
||||
"flex flex-1 flex-col gap-1 [&+[data-slot=item-content]]:flex-none",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ItemTitle({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="item-title"
|
||||
className={cn(
|
||||
"flex w-fit items-center gap-2 text-sm leading-snug font-medium",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ItemDescription({ className, ...props }: React.ComponentProps<"p">) {
|
||||
return (
|
||||
<p
|
||||
data-slot="item-description"
|
||||
className={cn(
|
||||
"text-muted-foreground line-clamp-2 text-sm leading-normal font-normal text-balance",
|
||||
"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ItemActions({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="item-actions"
|
||||
className={cn("flex items-center gap-2", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ItemHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="item-header"
|
||||
className={cn(
|
||||
"flex basis-full items-center justify-between gap-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ItemFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="item-footer"
|
||||
className={cn(
|
||||
"flex basis-full items-center justify-between gap-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Item,
|
||||
ItemMedia,
|
||||
ItemContent,
|
||||
ItemActions,
|
||||
ItemGroup,
|
||||
ItemSeparator,
|
||||
ItemTitle,
|
||||
ItemDescription,
|
||||
ItemHeader,
|
||||
ItemFooter,
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
'use client';
|
||||
"use client"
|
||||
|
||||
import * as React from 'react';
|
||||
import * as SeparatorPrimitive from '@radix-ui/react-separator';
|
||||
import * as React from "react"
|
||||
import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Separator({
|
||||
className,
|
||||
orientation = 'horizontal',
|
||||
orientation = "horizontal",
|
||||
decorative = true,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
|
||||
|
|
@ -17,12 +17,12 @@ function Separator({
|
|||
decorative={decorative}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px',
|
||||
className,
|
||||
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
export { Separator };
|
||||
export { Separator }
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { Slot } from '@radix-ui/react-slot';
|
||||
import { cva, VariantProps } from 'class-variance-authority';
|
||||
import { PanelLeftIcon } from 'lucide-react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { useIsMobile } from '@/hooks/use-mobile';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
|
|
@ -19,6 +17,8 @@ import {
|
|||
} from '@/components/ui/sheet';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useIsMobile } from '@/hooks/use-mobile';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const SIDEBAR_COOKIE_NAME = 'sidebar_state';
|
||||
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
||||
|
|
@ -548,7 +548,7 @@ function SidebarMenuAction({
|
|||
'peer-data-[size=lg]/menu-button:top-2.5',
|
||||
'group-data-[collapsible=icon]:hidden',
|
||||
showOnHover &&
|
||||
'peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0',
|
||||
'peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -690,5 +690,6 @@ export {
|
|||
SidebarRail,
|
||||
SidebarSeparator,
|
||||
SidebarTrigger,
|
||||
useSidebar,
|
||||
useSidebar
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,20 @@
|
|||
import { CheckIcon, ChevronsUpDownIcon } from 'lucide-react';
|
||||
import React from 'react';
|
||||
|
||||
import { useGEmolumentoReadHook } from '@/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento/useGEmolumentoReadHook';
|
||||
import { GEmolumentoReadInterface } from '@/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoReadInterface';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
|
||||
import { CheckIcon, ChevronsUpDownIcon } from 'lucide-react';
|
||||
import React from 'react';
|
||||
|
||||
import { useGEmolumentoReadHook } from '@/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento/useGEmolumentoReadHook';
|
||||
import { GEmolumentoReadInterface } from '@/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoReadInterface';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
|
@ -154,4 +168,28 @@ export default function GEmolumentoSelect({
|
|||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
// Fecha o popover
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
{/* Ícone de seleção (check) */ }
|
||||
< CheckIcon
|
||||
className = {
|
||||
cn(
|
||||
'mr-2 h-4 w-4',
|
||||
String(field.value?.key ?? field.value) === String(item.emolumento_id)
|
||||
? 'opacity-100'
|
||||
: 'opacity-0',
|
||||
)}
|
||||
/>
|
||||
{/* Nome formatado do emolumento */ }
|
||||
{ GetCapitalize(item.descricao) }
|
||||
</CommandItem >
|
||||
))}
|
||||
</CommandGroup >
|
||||
</CommandList >
|
||||
</Command >
|
||||
</PopoverContent >
|
||||
</Popover >
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,151 @@
|
|||
'use client';
|
||||
|
||||
import { CheckIcon, ChevronsUpDownIcon } from 'lucide-react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { useGEmolumentoReadHook } from '@/app/(protected)/(cadastros)/cadastros/_hooks/g_emolumento/useGEmolumentoReadHook';
|
||||
import { GEmolumentoReadInterface } from '@/app/(protected)/(cadastros)/cadastros/_interfaces/GEmolumentoReadInterface';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '@/components/ui/command';
|
||||
import { FormControl } from '@/components/ui/form';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||
import { cn } from '@/lib/utils';
|
||||
import GetCapitalize from '@/shared/actions/text/GetCapitalize';
|
||||
|
||||
// Tipagem das props do componente
|
||||
interface GEmolumentoSelectProps {
|
||||
sistema_id: number;
|
||||
field: any;
|
||||
onSelectChange?: (emolumento: { emolumento_id: number; descricao: string }) => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
// Componente principal do select de emolumentos
|
||||
export default function GEmolumentoServicoSelect({
|
||||
sistema_id,
|
||||
field,
|
||||
onSelectChange,
|
||||
className,
|
||||
}: GEmolumentoSelectProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
// Define parâmetros de leitura para o hook que busca os emolumentos
|
||||
const gEmolumentoReadParams: GEmolumentoReadInterface = { sistema_id, urlParams: { situacao: 'A' } };
|
||||
const { gEmolumento = [], fetchGEmolumento } = useGEmolumentoReadHook();
|
||||
|
||||
/**
|
||||
* Efeito para buscar os dados apenas uma vez.
|
||||
*/
|
||||
const loadData = useCallback(async () => {
|
||||
if (gEmolumento.length) return;
|
||||
setIsLoading(true);
|
||||
await fetchGEmolumento(gEmolumentoReadParams);
|
||||
setIsLoading(false);
|
||||
}, [gEmolumento.length, fetchGEmolumento, gEmolumentoReadParams]);
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
}, [loadData]);
|
||||
|
||||
/**
|
||||
* Memoriza o item selecionado para evitar reprocessamentos.
|
||||
*/
|
||||
const selected = useMemo(
|
||||
() =>
|
||||
gEmolumento.find(
|
||||
(item) => String(item.emolumento_id) === String(field?.value?.id ?? ''),
|
||||
),
|
||||
[gEmolumento, field?.value],
|
||||
);
|
||||
|
||||
/**
|
||||
* Manipulador de seleção com verificação segura.
|
||||
*/
|
||||
const handleSelect = useCallback(
|
||||
(item: any) => {
|
||||
if (!field?.onChange) return;
|
||||
|
||||
const selectedValue = {
|
||||
emolumento_id: Number(item.emolumento_id),
|
||||
descricao: item.descricao,
|
||||
sistema_id: item.sistema_id,
|
||||
};
|
||||
|
||||
field.onChange(selectedValue);
|
||||
|
||||
if (onSelectChange) onSelectChange(selectedValue);
|
||||
|
||||
setOpen(false);
|
||||
},
|
||||
[field, onSelectChange],
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl className="w-full">
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
disabled={isLoading}
|
||||
className={cn(
|
||||
'justify-between min-h-[2.5rem] w-full text-left break-words whitespace-normal',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{isLoading
|
||||
? 'Carregando...'
|
||||
: field.value?.descricao
|
||||
? GetCapitalize(field.value.descricao)
|
||||
: 'Selecione emolumento'}
|
||||
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
|
||||
<PopoverContent
|
||||
align="start"
|
||||
side="bottom"
|
||||
className="w-[var(--radix-popover-trigger-width)] max-w-full p-0"
|
||||
>
|
||||
<Command>
|
||||
<CommandInput placeholder="Buscar emolumentos..." disabled={isLoading} />
|
||||
<CommandList>
|
||||
<CommandEmpty>
|
||||
{isLoading ? 'Carregando...' : 'Nenhum resultado encontrado.'}
|
||||
</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{gEmolumento.map((item) => (
|
||||
<CommandItem
|
||||
key={item.emolumento_id}
|
||||
value={item.descricao?.toLowerCase() ?? ''}
|
||||
onSelect={() => handleSelect(item)}
|
||||
>
|
||||
<CheckIcon
|
||||
className={cn(
|
||||
'mr-2 h-4 w-4',
|
||||
String(field?.value?.emolumento_id ?? '') ===
|
||||
String(item.emolumento_id)
|
||||
? 'opacity-100'
|
||||
: 'opacity-0',
|
||||
)}
|
||||
/>
|
||||
{GetCapitalize(item.descricao ?? '')}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
'use client';
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
|
||||
import { useGGramaticaDeleteHook } from '@/packages/administrativo/hooks/GGramatica/useGGramaticaDeleteHook';
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
import { DataTable } from '@/shared/components/dataTable/DataTable';
|
||||
|
||||
import GGramaticaColumns from './GGramaticaColumns';
|
||||
import GGramaticaTableInterface from '../../interfaces/GGramatica/GGramaticaTableInterface';
|
||||
import GGramaticaColumns from './GGramaticaColumns';
|
||||
|
||||
/**
|
||||
* Componente principal da tabela de Naturezas
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
'use client';
|
||||
|
||||
import { CheckIcon, ChevronsUpDownIcon } from 'lucide-react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '@/components/ui/command';
|
||||
import { FormControl } from '@/components/ui/form';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useGUsuarioIndexHook } from '@/packages/administrativo/hooks/GUsuario/useGUsuarioIndexHook';
|
||||
import GUsuarioSelectInterface from '@/packages/administrativo/interfaces/GUsuario/GUsuarioSelectInterface';
|
||||
import GetCapitalize from '@/shared/actions/text/GetCapitalize';
|
||||
|
||||
import GUsuarioIndexInterface from '../../interfaces/GUsuario/GusuarioIndexInterface';
|
||||
|
||||
export default function GUsuarioSelect({ field }: GUsuarioSelectInterface) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { usuarios, fetchUsuarios } = useGUsuarioIndexHook();
|
||||
|
||||
/**
|
||||
* Efeito para buscar os dados apenas uma vez.
|
||||
* useCallback evita recriação desnecessária da função.
|
||||
*/
|
||||
const loadData = useCallback(async () => {
|
||||
|
||||
const urlParams = {
|
||||
assina: 'S',
|
||||
situacao: 'A'
|
||||
}
|
||||
|
||||
const GUsuarioIndex: GUsuarioIndexInterface = {
|
||||
urlParams: urlParams
|
||||
}
|
||||
|
||||
if (usuarios?.length) return;
|
||||
setIsLoading(true);
|
||||
await fetchUsuarios(GUsuarioIndex);
|
||||
setIsLoading(false);
|
||||
}, [usuarios?.length, fetchUsuarios]);
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
}, [loadData]);
|
||||
|
||||
/**
|
||||
* Memoriza o bairro selecionado para evitar reprocessamentos.
|
||||
*/
|
||||
const selected = useMemo(
|
||||
() => usuarios?.find((b) => String(b.usuario_id) === String(field?.value ?? '')),
|
||||
[usuarios, field?.value],
|
||||
);
|
||||
|
||||
/**
|
||||
* Manipulador de seleção com verificação segura.
|
||||
*/
|
||||
const handleSelect = useCallback(
|
||||
(bairroId: string | number) => {
|
||||
if (!field?.onChange) return;
|
||||
field.onChange(bairroId);
|
||||
setOpen(false);
|
||||
},
|
||||
[field],
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl className="w-full">
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
disabled={isLoading}
|
||||
className="justify-between"
|
||||
>
|
||||
{isLoading
|
||||
? 'Carregando...'
|
||||
: selected
|
||||
? GetCapitalize(selected.nome_completo)
|
||||
: 'Selecione...'}
|
||||
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-full p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Buscar bairro..." disabled={isLoading} />
|
||||
<CommandList>
|
||||
<CommandEmpty>
|
||||
{isLoading ? 'Carregando...' : 'Nenhum resultado encontrado.'}
|
||||
</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{usuarios?.map((item) => (
|
||||
<CommandItem
|
||||
key={item.usuario_id}
|
||||
value={item?.nome_completo?.toLowerCase() ?? ''}
|
||||
onSelect={() => handleSelect(item.usuario_id)}
|
||||
>
|
||||
<CheckIcon
|
||||
className={cn(
|
||||
'mr-2 h-4 w-4',
|
||||
String(field?.value ?? '') === String(item.usuario_id)
|
||||
? 'opacity-100'
|
||||
: 'opacity-0',
|
||||
)}
|
||||
/>
|
||||
{GetCapitalize(item.nome_completo ?? '')}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
'use client';
|
||||
|
||||
import { HouseIcon, IdCardIcon, UserIcon } from 'lucide-react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,161 @@
|
|||
import { ColumnDef } from '@tanstack/react-table';
|
||||
import { ArrowUpDownIcon } from 'lucide-react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { FormatCPF } from '@/shared/actions/CPF/FormatCPF';
|
||||
import { FormatDateTime } from '@/shared/actions/dateTime/FormatDateTime';
|
||||
import { FormatPhone } from '@/shared/actions/phone/FormatPhone';
|
||||
import GetNameInitials from '@/shared/actions/text/GetNameInitials';
|
||||
import empty from '@/shared/actions/validations/empty';
|
||||
|
||||
import TPessoaInterface from '../../interfaces/TPessoa/TPessoaInterface';
|
||||
|
||||
/**
|
||||
* Função para criar a definição das colunas da tabela
|
||||
*/
|
||||
export function TPessoaTableFormColumnsDialog(setSelectedTPessoa: React.Dispatch<React.SetStateAction<any | null>>): ColumnDef<TPessoaInterface>[] {
|
||||
return [
|
||||
{
|
||||
id: 'select',
|
||||
header: '',
|
||||
cell: ({ row, table }) => (
|
||||
<Checkbox
|
||||
checked={row.getIsSelected()}
|
||||
onCheckedChange={(value) => {
|
||||
// Limpa todas as seleções antes de selecionar uma nova
|
||||
table.resetRowSelection();
|
||||
row.toggleSelected(!!value);
|
||||
setSelectedTPessoa(value ? row.original : null);
|
||||
}}
|
||||
aria-label="Select row"
|
||||
/>
|
||||
),
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
},
|
||||
// ID
|
||||
{
|
||||
accessorKey: 'pessoa_id',
|
||||
header: ({ column }) => (
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
|
||||
>
|
||||
# <ArrowUpDownIcon className="ml-1 h-4 w-4" />
|
||||
</Button>
|
||||
),
|
||||
cell: ({ row }) => Number(row.getValue('pessoa_id')),
|
||||
enableSorting: false,
|
||||
},
|
||||
|
||||
// Nome / Email / Foto
|
||||
{
|
||||
id: 'nome_completo',
|
||||
accessorFn: (row) => row,
|
||||
header: ({ column }) => (
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
|
||||
>
|
||||
Nome / Email <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
|
||||
</Button>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const pessoa = row.original;
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-3">
|
||||
{/* Foto ou Iniciais */}
|
||||
<div className="flex h-10 w-10 items-center justify-center overflow-hidden rounded-full bg-gray-200">
|
||||
{pessoa.foto ? (
|
||||
<img
|
||||
src={pessoa.foto}
|
||||
alt={pessoa.nome || 'Avatar'}
|
||||
className="h-full w-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<span className="text-sm font-medium text-gray-700">
|
||||
{GetNameInitials(pessoa.nome)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Nome e Email */}
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900 capitalize">{pessoa.nome || '-'}</div>
|
||||
<div className="text-sm text-gray-500">
|
||||
{empty(pessoa.email) ? 'Email não informado' : pessoa.email}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
sortingFn: (a, b) =>
|
||||
(a.original.nome?.toLowerCase() || '').localeCompare(b.original.nome?.toLowerCase() || ''),
|
||||
},
|
||||
|
||||
// CPF
|
||||
{
|
||||
accessorKey: 'cpf_cnpj',
|
||||
header: ({ column }) => (
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
|
||||
>
|
||||
CPF <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
|
||||
</Button>
|
||||
),
|
||||
cell: ({ row }) => FormatCPF(row.getValue('cpf_cnpj')),
|
||||
},
|
||||
|
||||
// Telefone
|
||||
{
|
||||
accessorKey: 'telefone',
|
||||
header: ({ column }) => (
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
|
||||
>
|
||||
Telefone <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
|
||||
</Button>
|
||||
),
|
||||
cell: ({ row }) => FormatPhone(row.getValue('telefone')),
|
||||
},
|
||||
|
||||
// Cidade / UF
|
||||
{
|
||||
id: 'cidade_uf',
|
||||
accessorFn: (row) => `${row.cidade}/${row.uf}`,
|
||||
header: ({ column }) => (
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
|
||||
>
|
||||
Cidade/UF <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
|
||||
</Button>
|
||||
),
|
||||
cell: ({ row }) => <span>{row.getValue('cidade_uf') || '-'}</span>,
|
||||
sortingFn: (a, b) =>
|
||||
`${a.original.cidade}/${a.original.uf}`
|
||||
.toLowerCase()
|
||||
.localeCompare(`${b.original.cidade}/${b.original.uf}`.toLowerCase()),
|
||||
},
|
||||
|
||||
// Data de cadastro
|
||||
{
|
||||
accessorKey: 'data_cadastro',
|
||||
header: ({ column }) => (
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
|
||||
>
|
||||
Cadastro <ArrowUpDownIcon className="ml-1 h-4 w-4 cursor-pointer" />
|
||||
</Button>
|
||||
),
|
||||
cell: ({ row }) => FormatDateTime(row.getValue('data_cadastro')),
|
||||
sortingFn: 'datetime',
|
||||
},
|
||||
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle
|
||||
} from '@/components/ui/dialog';
|
||||
import { useTPessoaFisicaIndexHook } from '@/packages/administrativo/hooks/TPessoa/TPessoaFisica/useTPessoaFisicaIndexHook';
|
||||
import { useTPessoaJuridicaIndexHook } from '@/packages/administrativo/hooks/TPessoa/TPessoaJuridica/useTPessoaJuridicaIndexHook';
|
||||
import TPessoaInterface from '@/packages/administrativo/interfaces/TPessoa/TPessoaInterface';
|
||||
import TPessoaTableFormInterface from '@/packages/administrativo/interfaces/TPessoa/TPessoaTableFormInterface';
|
||||
import { DataTable } from '@/shared/components/dataTable/DataTable';
|
||||
import LoadingButton from '@/shared/components/loadingButton/LoadingButton';
|
||||
|
||||
import { TPessoaTableFormColumnsDialog } from './TPessoaTableFormColumnsDialog';
|
||||
|
||||
export default function TPessoaTableFormDialog({
|
||||
isOpen,
|
||||
tipoPessoa,
|
||||
onClose,
|
||||
onSave,
|
||||
buttonIsLoading,
|
||||
}: TPessoaTableFormInterface) {
|
||||
|
||||
const { tPessoaFisica, fetchTPessoaFisica } = useTPessoaFisicaIndexHook();
|
||||
const { tPessoaJuridica, fetchTPessoaJuridica } = useTPessoaJuridicaIndexHook();
|
||||
const [pessoas, setPessoas] = useState<any>()
|
||||
const [selectedTPessoa, setSelectedTPessoa] = useState<TPessoaInterface | null>(null);
|
||||
|
||||
// Executa o Hook de Acordo com o tipo de pessoa informado
|
||||
const loadData = async (tipoPessoa: string) => {
|
||||
|
||||
switch (tipoPessoa) {
|
||||
|
||||
case "F":
|
||||
|
||||
await fetchTPessoaFisica();
|
||||
break;
|
||||
|
||||
case "J":
|
||||
|
||||
await fetchTPessoaJuridica();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Atualiza a variavel de pessoa quando tiver alteração na variavel de pessoas fisicas
|
||||
useEffect(() => {
|
||||
|
||||
setPessoas(tPessoaFisica)
|
||||
|
||||
}, [tPessoaFisica])
|
||||
|
||||
// Atualiza a variavel de pessoa quando tiver alteração na variavel de pessoas juridicas
|
||||
useEffect(() => {
|
||||
|
||||
setPessoas(tPessoaJuridica)
|
||||
|
||||
}, [tPessoaJuridica])
|
||||
|
||||
// Executa o hook correspondente ao tipo de pessoa, sempre que o tipo pessoa mudar
|
||||
useEffect(() => {
|
||||
|
||||
// Verifica se o tipo pessoa esta preenchido
|
||||
if (tipoPessoa) {
|
||||
|
||||
// Dispara o carregamento de informações
|
||||
loadData(tipoPessoa);
|
||||
|
||||
}
|
||||
|
||||
}, [tipoPessoa]);
|
||||
|
||||
const columns = TPessoaTableFormColumnsDialog(setSelectedTPessoa);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) onClose(null, false);
|
||||
}}
|
||||
>
|
||||
<DialogContent className="max-h-[70vh] w-full max-w-full overflow-auto p-6 sm:max-w-4xl md:max-w-6xl lg:max-w-6xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Pessoa</DialogTitle>
|
||||
<DialogDescription>Busque a pessoa desejada</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="max-h-[50vh] overflow-y-auto">
|
||||
<DataTable
|
||||
data={pessoas}
|
||||
columns={columns}
|
||||
filterColumn="nome_completo"
|
||||
filterPlaceholder="Buscar por nome ou email..."
|
||||
/>
|
||||
</div>
|
||||
{/* Rodapé do Dialog */}
|
||||
<DialogFooter className="mt-4">
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
type="button"
|
||||
onClick={() => onClose(null, false)}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
Cancelar
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<LoadingButton
|
||||
text="Selecionar"
|
||||
textLoading="Aguarde..."
|
||||
loading={buttonIsLoading}
|
||||
type="button"
|
||||
onClick={() => { onSave(selectedTPessoa); onClose(null, false); }}
|
||||
/>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
import { FingerprintIcon, WebcamIcon } from 'lucide-react';
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState
|
||||
} from 'react';
|
||||
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Item,
|
||||
ItemActions,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle
|
||||
} from '@/components/ui/item';
|
||||
import TPessoaCartaoForm from '@/packages/servicos/components/TPessoaCartao/TPessoaCartaoForm';
|
||||
import GetNameInitials from '@/shared/actions/text/GetNameInitials';
|
||||
import WebCamDialog from '@/shared/components/webcam/WebCamDialog';
|
||||
import { useFingerTechCaptureHook } from '@/shared/hooks/FingerTech/useFingerTechCaptureHook';
|
||||
|
||||
import TPessoaTableFormSubviewInterface from '../../interfaces/TPessoa/TPessoaTableFormSubviewInterface';
|
||||
|
||||
function TPessoaTableFormSubview({
|
||||
item_index,
|
||||
data,
|
||||
params,
|
||||
form,
|
||||
}: TPessoaTableFormSubviewInterface) {
|
||||
|
||||
const [isWebCamOpenDialog, setIsWebCamOpenDialog] = useState(false)
|
||||
const { base64, captureFingerTech } = useFingerTechCaptureHook();
|
||||
|
||||
// Chama o leitor biométrico
|
||||
const handleBiometria = useCallback(() => {
|
||||
|
||||
console.log(captureFingerTech())
|
||||
|
||||
}, [])
|
||||
|
||||
// Define a classe do botão de biometria com base no status, sem estado extra
|
||||
const biometriaButtonClass = useMemo(() => {
|
||||
switch (1) {
|
||||
case 0:
|
||||
// Amarelo (aviso)
|
||||
return 'bg-amber-100 text-amber-700 border border-amber-300 hover:bg-amber-200 hover:text-amber-800';
|
||||
case 1:
|
||||
// Verde discreto
|
||||
return 'bg-green-100 text-green-700 border border-green-300 hover:bg-green-200 hover:text-green-800';
|
||||
case 2:
|
||||
// Vermelho (erro)
|
||||
return 'bg-red-100 text-red-700 border border-red-300 hover:bg-red-200 hover:text-red-800';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Item variant="outline">
|
||||
<ItemMedia>
|
||||
<Avatar className="size-10">
|
||||
<AvatarImage src={``} />
|
||||
<AvatarFallback>
|
||||
{GetNameInitials(data.pessoa?.nome)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>
|
||||
{data.pessoa?.cpf_cnpj} - {data.pessoa?.nome}
|
||||
</ItemTitle>
|
||||
<ItemDescription>
|
||||
{data.pessoa?.email || 'Email não informado'}
|
||||
</ItemDescription>
|
||||
{params
|
||||
.filter((param) => Number(param.valor) === data.servico.servico_tipo_id)
|
||||
.map((param) => (
|
||||
<TPessoaCartaoForm
|
||||
form={form}
|
||||
index={item_index}
|
||||
key={param.config_id}
|
||||
/>
|
||||
))}
|
||||
|
||||
</ItemContent>
|
||||
<ItemActions>
|
||||
{data.servico.requer_biometria === 'S' && (
|
||||
<Button
|
||||
type="button"
|
||||
size="icon-lg"
|
||||
variant="outline"
|
||||
className={`rounded-full cursor-pointer ${biometriaButtonClass}`}
|
||||
aria-label="Capturar biometria"
|
||||
onClick={() => { handleBiometria() }}
|
||||
>
|
||||
<FingerprintIcon />
|
||||
</Button>
|
||||
)}
|
||||
{data.servico.requer_biometria && (
|
||||
<Button
|
||||
type="button"
|
||||
size="icon-lg"
|
||||
variant="outline"
|
||||
className="rounded-full cursor-pointer"
|
||||
aria-label="Capturar imagem"
|
||||
onClick={() => { setIsWebCamOpenDialog(true) }}
|
||||
>
|
||||
<WebcamIcon />
|
||||
</Button>
|
||||
)}
|
||||
</ItemActions>
|
||||
</Item>
|
||||
{isWebCamOpenDialog && (
|
||||
<WebCamDialog
|
||||
isOpen={isWebCamOpenDialog}
|
||||
onClose={() => { setIsWebCamOpenDialog(false) }}
|
||||
onSave={() => { }}
|
||||
key={item_index}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Memo para evitar re-renderizações desnecessárias da subview
|
||||
export default memo(TPessoaTableFormSubview);
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
'use client';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
|
|
@ -17,11 +17,11 @@ import { ResetFormIfData } from '@/shared/actions/form/ResetFormIfData';
|
|||
import { DataTable } from '@/shared/components/dataTable/DataTable';
|
||||
import LoadingButton from '@/shared/components/loadingButton/LoadingButton';
|
||||
|
||||
import TPessoasRepresentanteFormColumns from './TPessoasRepresentanteFormColumns';
|
||||
import { useTPessoaFisicaIndexHook } from '../../hooks/TPessoa/TPessoaFisica/useTPessoaFisicaIndexHook';
|
||||
import { useTPessoaRepresentanteFormHook } from '../../hooks/TPessoaRepresentante/useTPessoaRepresentanteFormHook';
|
||||
import TPessoaRepresentanteInterface from '../../interfaces/TPessoaRepresentante/TPessoaRepresentanteInterface';
|
||||
import TPessoaRepresentanteFormInterface from '../../interfaces/TPessoaRepresentante/TPessoaRepresentnateFormInterface';
|
||||
import TPessoasRepresentanteFormColumns from './TPessoasRepresentanteFormColumns';
|
||||
|
||||
export default function TPessoaRepresentanteForm({
|
||||
isOpen,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
'use client';
|
||||
|
||||
import { CheckIcon, ChevronsUpDownIcon } from 'lucide-react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '@/components/ui/command';
|
||||
import { FormControl } from '@/components/ui/form';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useTServicoTipoReadHook } from '@/packages/administrativo/hooks/TServicoTipo/useTServicoTipoReadHook';
|
||||
import TServicoTipoSelectInterface from '@/packages/administrativo/interfaces/TServicoTipo/TServicoTipoSelectInterface';
|
||||
import GetCapitalize from '@/shared/actions/text/GetCapitalize';
|
||||
|
||||
import TServicoTipoIndexInteface from '../../interfaces/TServicoTipo/TServicoTipoIndexInteface';
|
||||
|
||||
export default function TServicoTipoSelect({ field }: TServicoTipoSelectInterface) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { tServicoTipo = [], fetchTServicoTipo } = useTServicoTipoReadHook();
|
||||
|
||||
/**
|
||||
* Efeito para buscar os dados apenas uma vez.
|
||||
*/
|
||||
const loadData = useCallback(async () => {
|
||||
|
||||
const TServicoTipoIndex: TServicoTipoIndexInteface = {
|
||||
urlParams: {
|
||||
situacao: 'A'
|
||||
}
|
||||
}
|
||||
|
||||
if (tServicoTipo.length) return;
|
||||
setIsLoading(true);
|
||||
await fetchTServicoTipo(TServicoTipoIndex);
|
||||
setIsLoading(false);
|
||||
}, [tServicoTipo.length, fetchTServicoTipo]);
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
}, [loadData]);
|
||||
|
||||
/**
|
||||
* Item selecionado (comparando por ID)
|
||||
*/
|
||||
const selected = useMemo(
|
||||
() =>
|
||||
tServicoTipo.find(
|
||||
(item) => String(item.servico_tipo_id) === String(field?.value?.servico_tipo_id ?? ''),
|
||||
),
|
||||
[tServicoTipo, field?.value],
|
||||
);
|
||||
|
||||
/**
|
||||
* Manipulador de seleção
|
||||
*/
|
||||
const handleSelect = useCallback(
|
||||
(item: any) => {
|
||||
if (!field?.onChange) return;
|
||||
|
||||
const selectedValue = {
|
||||
servico_tipo_id: Number(item.servico_tipo_id),
|
||||
descricao: item.descricao,
|
||||
tipo_item: item.tipo_item,
|
||||
tipo_pessoa: item.tipo_pessoa,
|
||||
requer_biometria: item.requer_biometria,
|
||||
requer_cpf: item.requer_cpf,
|
||||
servico_caixa_id: item.servico_caixa_id,
|
||||
selar: item.selar,
|
||||
};
|
||||
|
||||
field.onChange(selectedValue);
|
||||
setOpen(false);
|
||||
},
|
||||
[field],
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl className="w-full">
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
disabled={isLoading}
|
||||
className="justify-between"
|
||||
>
|
||||
{isLoading
|
||||
? 'Carregando...'
|
||||
: field.value?.descricao
|
||||
? GetCapitalize(field.value.descricao)
|
||||
: 'Selecione...'}
|
||||
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
|
||||
<PopoverContent className="w-full p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Buscar tipo de serviço..." disabled={isLoading} />
|
||||
<CommandList>
|
||||
<CommandEmpty>
|
||||
{isLoading ? 'Carregando...' : 'Nenhum resultado encontrado.'}
|
||||
</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{tServicoTipo.map((item) => (
|
||||
<CommandItem
|
||||
key={item.servico_tipo_id}
|
||||
value={item.descricao?.toLowerCase() ?? ''}
|
||||
onSelect={() => handleSelect(item)}
|
||||
>
|
||||
<CheckIcon
|
||||
className={cn(
|
||||
'mr-2 h-4 w-4',
|
||||
String(field?.value?.servico_tipo_id ?? '') ===
|
||||
String(item.servico_tipo_id)
|
||||
? 'opacity-100'
|
||||
: 'opacity-0',
|
||||
)}
|
||||
/>
|
||||
{GetCapitalize(item.descricao ?? '')}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import GCalculoInterface from '@/packages/administrativo/interfaces/GCalculo/GCalculoInterface';
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import API from '@/shared/services/api/Api';
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
|
||||
|
||||
|
||||
async function executeGCalculoCalcularData(data: GCalculoInterface): Promise<ApiResponseInterface> {
|
||||
const api = new API();
|
||||
return api.send({
|
||||
method: Methods.POST,
|
||||
endpoint: `administrativo/g_calculo/servico/`,
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
export const GCalculoServico = withClientErrorHandler(executeGCalculoCalcularData);
|
||||
|
|
@ -3,13 +3,17 @@
|
|||
import API from '@/shared/services/api/Api';
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
|
||||
export default async function GUsuarioIndexData() {
|
||||
import GUsuarioIndexInterface from '../../interfaces/GUsuario/GusuarioIndexInterface';
|
||||
|
||||
export default async function GUsuarioIndexData(data: GUsuarioIndexInterface) {
|
||||
const api = new API();
|
||||
|
||||
const response = await api.send({
|
||||
method: Methods.GET,
|
||||
endpoint: `administrativo/g_usuario/`,
|
||||
endpoint: `administrativo/g_usuario?${new URLSearchParams(data.urlParams).toString()}`,
|
||||
});
|
||||
|
||||
console.log(response)
|
||||
|
||||
return response;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import API from '@/shared/services/api/Api'; //
|
|||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum'; //
|
||||
|
||||
// Importa a interface tipada que define a estrutura dos dados do tipo de serviço
|
||||
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface'; // Alterado de GCidadeInterface
|
||||
import TServicoTipoInterface from '../../../../app/(protected)/(cadastros)/cadastros/_interfaces/TServicoTipoInterface'; // Alterado de GCidadeInterface
|
||||
|
||||
// Importa função que encapsula chamadas assíncronas e trata erros automaticamente
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler'; //
|
||||
|
|
@ -1,21 +1,23 @@
|
|||
// Importa o serviço de API que será utilizado para realizar requisições HTTP
|
||||
import API from '@/shared/services/api/Api'; //
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import API from '@/shared/services/api/Api';
|
||||
|
||||
// Importa o enum que contém os métodos HTTP disponíveis (GET, POST, PUT, DELETE)
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum'; //
|
||||
|
||||
import TServicoTipoIndexInteface from '../../interfaces/TServicoTipo/TServicoTipoIndexInteface';
|
||||
|
||||
// Importa função que encapsula chamadas assíncronas e trata erros automaticamente
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler'; //
|
||||
|
||||
// Função assíncrona que implementa a lógica de buscar todos os tipos de serviço (GET)
|
||||
async function executeTServicoTipoIndexData() {
|
||||
async function executeTServicoTipoIndexData(data: TServicoTipoIndexInteface) {
|
||||
// Instancia o cliente da API para enviar a requisição
|
||||
const api = new API(); //
|
||||
|
||||
// Executa a requisição para a API com o método apropriado e o endpoint da tabela t_servico_tipo
|
||||
return await api.send({
|
||||
method: Methods.GET, // GET listar todos os itens
|
||||
endpoint: `administrativo/t_servico_tipo/`, // Endpoint atualizado
|
||||
endpoint: `administrativo/t_servico_tipo/?${new URLSearchParams(data.urlParams).toString()}`,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -5,7 +5,7 @@ import API from '@/shared/services/api/Api'; //
|
|||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum'; //
|
||||
|
||||
// Importa a interface tipada que define a estrutura dos dados do tipo de serviço
|
||||
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface'; // Alterado de GCidadeInterface
|
||||
import TServicoTipoInterface from '../../../../app/(protected)/(cadastros)/cadastros/_interfaces/TServicoTipoInterface'; // Alterado de GCidadeInterface
|
||||
|
||||
// Importa função que encapsula chamadas assíncronas e trata erros automaticamente
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler'; //
|
||||
|
|
@ -2,13 +2,12 @@
|
|||
import API from '@/shared/services/api/Api'; //
|
||||
|
||||
// Importa o esquema de validação de dados para tipos de serviço
|
||||
import { TServicoTipoFormValues } from '../../_schemas/TServicoTipoSchema';
|
||||
import { TServicoTipoFormValues } from '../../../../app/(protected)/(cadastros)/cadastros/_schemas/TServicoTipoSchema';
|
||||
|
||||
// Importa o enum que contém os métodos HTTP disponíveis (GET, POST, PUT, DELETE)
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum'; //
|
||||
|
||||
// Importa a interface tipada que define a estrutura dos dados do tipo de serviço
|
||||
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface'; // Interface alterada
|
||||
|
||||
// Importa função que encapsula chamadas assíncronas e trata erros automaticamente
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler'; //
|
||||
|
|
@ -2,18 +2,21 @@
|
|||
|
||||
import { useState } from 'react';
|
||||
|
||||
import Usuario from '@/packages/administrativo/interfaces/GUsuario/GUsuarioInterface';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
import Usuario from '../../interfaces/GUsuario/GUsuarioInterface';
|
||||
import GUsuarioIndexInterface from '../../interfaces/GUsuario/GusuarioIndexInterface';
|
||||
import GUsuarioIndex from '../../services/GUsuario/GUsuarioIndex';
|
||||
|
||||
|
||||
export const useGUsuarioIndexHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [usuarios, setUsuarios] = useState<Usuario[] | null>(null);
|
||||
|
||||
const fetchUsuarios = async () => {
|
||||
const response = await GUsuarioIndex();
|
||||
const fetchUsuarios = async (data: GUsuarioIndexInterface) => {
|
||||
|
||||
const response = await GUsuarioIndex(data);
|
||||
|
||||
setUsuarios(response.data);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ export const useTPessoaFisicaIndexHook = () => {
|
|||
setTPessoa(response.data);
|
||||
|
||||
setResponse(response);
|
||||
|
||||
return response.data
|
||||
};
|
||||
|
||||
return { tPessoaFisica, fetchTPessoaFisica };
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { useResponse } from '@/shared/components/response/ResponseContext'; // Contexto global para gerenciar respostas da API
|
||||
|
||||
// Interface tipada do tipo de serviço
|
||||
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface';
|
||||
import TServicoTipoInterface from '../../../../app/(protected)/(cadastros)/cadastros/_interfaces/TServicoTipoInterface';
|
||||
|
||||
// Função que Edit o tipo de serviço via API
|
||||
import { TServicoTipoEditData } from '../../_data/TServicoTipo/TServicoTipoEditData';
|
||||
import { TServicoTipoEditData } from '../../data/TServicoTipo/TServicoTipoEditData';
|
||||
|
||||
// Hook customizado para remoção de tipos de serviço
|
||||
export const useTServicoTipoEditHook = () => {
|
||||
|
|
@ -1,14 +1,17 @@
|
|||
import { useResponse } from '@/shared/components/response/ResponseContext'; // Contexto global para gerenciar respostas da API
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext'; // Contexto global para gerenciar respostas da API
|
||||
|
||||
// Serviço que busca a lista de tipos de serviço (TServicoTipoIndexService)
|
||||
import { TServicoTipoIndexService } from '../../_services/t_servico_tipo/TServicoTipoIndexService';
|
||||
import TServicoTipoInterface from '../../../../app/(protected)/(cadastros)/cadastros/_interfaces/TServicoTipoInterface';
|
||||
import TServicoTipoIndexInteface from '../../interfaces/TServicoTipo/TServicoTipoIndexInteface';
|
||||
import { TServicoTipoIndexService } from '../../services/TServicoTipo/TServicoTipoIndexService';
|
||||
|
||||
// Interface tipada do tipo de serviço
|
||||
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface';
|
||||
|
||||
// Hook customizado para leitura de dados de tipos de serviço
|
||||
export const useTServicoTipoReadHook = () => {
|
||||
|
||||
// Hook do contexto de resposta para feedback global (alertas, mensagens etc.)
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
|
|
@ -16,9 +19,9 @@ export const useTServicoTipoReadHook = () => {
|
|||
const [tServicoTipo, setTServicoTipo] = useState<TServicoTipoInterface[]>([]);
|
||||
|
||||
// Função assíncrona que busca os dados dos tipos de serviço
|
||||
const fetchTServicoTipo = async () => {
|
||||
const fetchTServicoTipo = async (data: TServicoTipoIndexInteface) => {
|
||||
// Chama o serviço responsável por consultar a API
|
||||
const response = await TServicoTipoIndexService();
|
||||
const response = await TServicoTipoIndexService(data);
|
||||
|
||||
// Atualiza o estado local com os dados retornados
|
||||
setTServicoTipo(response.data);
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
import { useResponse } from '@/shared/components/response/ResponseContext'; // Contexto global para gerenciar respostas da API
|
||||
|
||||
// Interface tipada do tipo de serviço
|
||||
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface';
|
||||
import TServicoTipoInterface from '../../../../app/(protected)/(cadastros)/cadastros/_interfaces/TServicoTipoInterface';
|
||||
|
||||
// Função que remove o tipo de serviço via API
|
||||
import { TServicoTipoRemoveData } from '../../_data/TServicoTipo/TServicoTipoRemoveData';
|
||||
import { TServicoTipoRemoveData } from '../../data/TServicoTipo/TServicoTipoRemoveData';
|
||||
|
||||
// Hook customizado para remoção de tipos de serviço
|
||||
export const useTServicoTipoRemoveHook = () => {
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
import { useState } from 'react';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
import { useState } from 'react';
|
||||
|
||||
// Interface tipada do tipo de serviço
|
||||
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface';
|
||||
import TServicoTipoInterface from '../../../../app/(protected)/(cadastros)/cadastros/_interfaces/TServicoTipoInterface';
|
||||
|
||||
// Serviço que salva os dados do tipo de serviço
|
||||
import { TServicoTipoSaveService } from '../../_services/t_servico_tipo/TServicoTipoSaveService';
|
||||
import { TServicoTipoSaveService } from '../../services/TServicoTipo/TServicoTipoSaveService';
|
||||
|
||||
export const useTServicoTipoSaveHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export default interface GCalculoServicoInterface {
|
||||
valor_documento?: number;
|
||||
emolumento_id?: number;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export default interface GUsuarioIndexInterface {
|
||||
urlParams: object
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
export default interface GTBairroSelectInterface {
|
||||
field?: {
|
||||
value?: number | string;
|
||||
onChange?: (value: string | number) => void;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
export default interface TPessoaTableFormSubviewInterface {
|
||||
params: any;
|
||||
servico: any;
|
||||
selectedTPessoa: any;
|
||||
form: any;
|
||||
index: number
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
export default interface TPessoaTableFormInterface {
|
||||
isOpen: boolean;
|
||||
tipoPessoa: string;
|
||||
onClose: (item: null, isFormStatus: boolean) => void;
|
||||
onSave: (data: any) => void;
|
||||
buttonIsLoading: boolean;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { UseFormReturn } from "react-hook-form";
|
||||
|
||||
import { TServicoPedidoFormValues } from "@/packages/servicos/schemas/TServicoPedido/TServicoPedidoFormSchema";
|
||||
import GConfigInterface from "@/shared/interfaces/GConfigInterface";
|
||||
|
||||
export default interface TPessoaTableFormSubviewInterface {
|
||||
item_index: number,
|
||||
data: any,
|
||||
params: GConfigInterface[],
|
||||
form: UseFormReturn<TServicoPedidoFormValues>;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export default interface TServicoTipoIndexInteface {
|
||||
urlParams: object
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
export default interface TServicoTipoSelectInterface {
|
||||
field?: {
|
||||
value?: number | string;
|
||||
onChange?: (value: string | number) => void;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
import { GCalculoServico } from "@/packages/administrativo/data/GCalculo/GCalculoServicoData";
|
||||
import GCalculoServicoInterface from "@/packages/administrativo/interfaces/GCalculo/GCalculoServicoInterface";
|
||||
import TServicoItemPedidoAddInterface from "@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoAddInterface";
|
||||
import { withClientErrorHandler } from "@/shared/actions/withClientErrorHandler/withClientErrorHandler";
|
||||
|
||||
|
||||
async function executeGCalculoServicoService(payload: GCalculoServicoInterface, data: TServicoItemPedidoAddInterface) {
|
||||
|
||||
const response = await GCalculoServico(payload);
|
||||
|
||||
if (response.status == 404 || response.status == 400) {
|
||||
|
||||
return {
|
||||
|
||||
'status': response.status,
|
||||
'message': 'Erro ao processar dados'
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
const item = {
|
||||
emolumento_id: response.data.emolumento_id,
|
||||
emolumento_item_id: response.data.emolumento_item_id ?? null,
|
||||
servico_tipo_id: data.servico_tipo.servico_tipo_id ?? 0,
|
||||
tipo_item: data.servico_tipo.tipo_item ?? "",
|
||||
descricao: data.servico_tipo.descricao ?? "",
|
||||
tabela: data.servico_tipo?.descricao ?? "",
|
||||
situacao: "F",
|
||||
qtd: 1,
|
||||
valor: response.data.valor_total ?? 0,
|
||||
emolumento: response.data.valor_emolumento ?? 0,
|
||||
fundesp: response.data.valor_fundos ?? 0,
|
||||
taxa_judiciaria: response.data.taxa_judiciaria ?? 0,
|
||||
valor_iss: response.data.valor_iss ?? 0,
|
||||
pessoa_id: data?.pessoa?.pessoa_id ?? null,
|
||||
subview: {
|
||||
servico: data.servico_tipo,
|
||||
pessoa: data.pessoa,
|
||||
}
|
||||
};
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
export const GCalculoServicoService = withClientErrorHandler(executeGCalculoServicoService);
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
'use server';
|
||||
|
||||
import GUsuarioIndexData from '../../data/GUsuario/GUsuarioIndexData';
|
||||
import GUsuarioIndexInterface from '../../interfaces/GUsuario/GusuarioIndexInterface';
|
||||
|
||||
export default async function GUsuarioIndex() {
|
||||
const response = await GUsuarioIndexData();
|
||||
export default async function GUsuarioIndex(data: GUsuarioIndexInterface) {
|
||||
const response = await GUsuarioIndexData(data);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
// Função que envolve qualquer ação assíncrona para capturar e tratar erros do cliente
|
||||
|
||||
import { TServicoTipoEditData } from '../../_data/TServicoTipo/TServicoTipoEditData';
|
||||
import { TServicoTipoEditData } from '../../data/TServicoTipo/TServicoTipoEditData';
|
||||
// Função que remove os dados do tipo de serviço via API
|
||||
|
||||
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface';
|
||||
import TServicoTipoInterface from '../../../../app/(protected)/(cadastros)/cadastros/_interfaces/TServicoTipoInterface';
|
||||
// Interface tipada do tipo de serviço
|
||||
|
||||
// Função assíncrona que executa a remoção de um tipo de serviço
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
// Função que envolve qualquer ação assíncrona para capturar e tratar erros do cliente
|
||||
|
||||
import { TServicoTipoIndexData } from '../../_data/TServicoTipo/TServicoTipoIndexData';
|
||||
import { TServicoTipoIndexData } from '../../data/TServicoTipo/TServicoTipoIndexData';
|
||||
import TServicoTipoIndexInteface from '../../interfaces/TServicoTipo/TServicoTipoIndexInteface';
|
||||
// Função que retorna os dados da lista de tipos de serviço (chamada à API ou mock)
|
||||
|
||||
// Função assíncrona que executa a chamada para buscar os dados dos tipos de serviço
|
||||
async function executeTServicoTipoIndexService() {
|
||||
async function executeTServicoTipoIndexService(data: TServicoTipoIndexInteface) {
|
||||
// Chama a função que retorna os dados dos tipos de serviço
|
||||
const response = await TServicoTipoIndexData();
|
||||
const response = await TServicoTipoIndexData(data);
|
||||
|
||||
// Retorna a resposta para o chamador
|
||||
return response;
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
// Função que envolve qualquer ação assíncrona para capturar e tratar erros do cliente
|
||||
|
||||
import { TServicoTipoRemoveData } from '../../_data/TServicoTipo/TServicoTipoRemoveData';
|
||||
import { TServicoTipoRemoveData } from '../../data/TServicoTipo/TServicoTipoRemoveData';
|
||||
// Função que remove os dados do tipo de serviço via API
|
||||
|
||||
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface';
|
||||
import TServicoTipoInterface from '../../../../app/(protected)/(cadastros)/cadastros/_interfaces/TServicoTipoInterface';
|
||||
// Interface tipada do tipo de serviço
|
||||
|
||||
// Função assíncrona que executa a remoção de um tipo de serviço
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
|
||||
// Função que salva os dados do tipo de serviço via API (ou mock)
|
||||
import { TServicoTipoSaveData } from '../../_data/TServicoTipo/TServicoTipoSaveData';
|
||||
import { TServicoTipoSaveData } from '../../data/TServicoTipo/TServicoTipoSaveData';
|
||||
|
||||
// Interface tipada do tipo de serviço
|
||||
import TServicoTipoInterface from '../../_interfaces/TServicoTipoInterface';
|
||||
import TServicoTipoInterface from '../../../../app/(protected)/(cadastros)/cadastros/_interfaces/TServicoTipoInterface';
|
||||
|
||||
// Função assíncrona que executa o salvamento de um tipo de serviço
|
||||
async function executeTServicoTipoSaveService(data: TServicoTipoInterface) {
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
interface HandleAddItemInterface {
|
||||
servicoSelecionado: any;
|
||||
emolumentoSelecionado: any;
|
||||
}
|
||||
|
||||
export default async function HandleAddItemAction({ servicoSelecionado, emolumentoSelecionado }: HandleAddItemInterface) {
|
||||
|
||||
if (!servicoSelecionado || !emolumentoSelecionado) return false;
|
||||
|
||||
return {
|
||||
servico_tipo: servicoSelecionado,
|
||||
emolumento: emolumentoSelecionado,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
|
||||
export default function HandleSelectTServicoTipoAction({ servico, emolumento, onOpenPessoaForm, onAddItem }: HandleSelectTServicoTipoInterface) {
|
||||
|
||||
if (!servico || !emolumento) {
|
||||
|
||||
return {
|
||||
'status': 422,
|
||||
'detail': 'Serviço e emolumento devem ser selecionados'
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
if (servico?.tipo_pessoa) {
|
||||
|
||||
onOpenPessoaForm(servico.tipo_pessoa);
|
||||
|
||||
} else {
|
||||
|
||||
onAddItem();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
export default interface HandleSelectTServicoTipoInterface {
|
||||
|
||||
servico: any;
|
||||
emolumento: any;
|
||||
onOpenPessoaForm: (tipoPessoa: string) => void,
|
||||
onAddItem: () => void
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import TServicoItemPedidoAddInterface from "@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoAddInterface";
|
||||
|
||||
export default function TServicoPedidoItemPreparePayload(data: TServicoItemPedidoAddInterface) {
|
||||
|
||||
data.qtd = 1
|
||||
data.valor_documento = 0
|
||||
|
||||
// Verifica dados obrigatórios de serviço e emolumento
|
||||
if (!data?.emolumento?.emolumento_id || !data?.servico_tipo?.servico_tipo_id) {
|
||||
return {
|
||||
status: 400,
|
||||
message: 'Dados informados inválidos: serviço ou emolumento não informado.'
|
||||
};
|
||||
}
|
||||
|
||||
// Valida sistema_id (padrão 2, mas ainda assim precisa ser válido)
|
||||
if (!data?.emolumento.sistema_id || data.servico_tipo.servico_tipo_id <= 0) {
|
||||
return {
|
||||
status: 400,
|
||||
message: 'Sistema inválido ou não informado.'
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
sistema_id: data.emolumento.sistema_id,
|
||||
valor_documento: data.valor_documento,
|
||||
quantidade: data.qtd,
|
||||
emolumento_id: data.emolumento.emolumento_id,
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import { useState } from "react";
|
||||
|
||||
import { FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import TPessoaCartaoFormInterface from "@/packages/servicos/interfaces/TPessoaCartao/TPessoaCartaoFormInterface";
|
||||
import { parseNumberInput } from "@/shared/actions/form/parseNumberInput";
|
||||
import ConfirmacaoSelect from "@/shared/components/confirmacao/ConfirmacaoSelect";
|
||||
|
||||
|
||||
export default function TPessoaCartaoForm({ index, form }: TPessoaCartaoFormInterface) {
|
||||
|
||||
const [cartaoAutomatico, setCartaoAutomatico] = useState(true);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center space-x-2 mt-4">
|
||||
<Switch
|
||||
id={`cartao-automatico-${index}`}
|
||||
checked={cartaoAutomatico}
|
||||
onCheckedChange={(checked) => {
|
||||
setCartaoAutomatico(checked);
|
||||
form.setValue(`itens.${index}.cartao_automatico`, checked);
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor={`cartao-automatico-${index}`}>Cartão Automático</Label>
|
||||
</div>
|
||||
{!cartaoAutomatico && (
|
||||
<div className="grid w-full grid-cols-12 gap-4 mt-4">
|
||||
{/* Gerar selo */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`itens.${index}.cartao_selar`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Gerar Selo</FormLabel>
|
||||
<ConfirmacaoSelect field={field} />
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{/* Nº Cartão */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`itens.${index}.cartao_numero`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Nº cartão</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field}
|
||||
type="number"
|
||||
onChange={(e) => field.onChange(parseNumberInput(e))}
|
||||
defaultValue={field.value ?? ""}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{/* Data de Abertura */}
|
||||
<div className="col-span-12 sm:col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`itens.${index}.cartao_data`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Data de Abertura</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field}
|
||||
type="date"
|
||||
defaultValue={field.value ?? ""}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
import { ColumnDef } from '@tanstack/react-table';
|
||||
import { EllipsisIcon, PencilIcon, Trash2Icon } from 'lucide-react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import GetCapitalize from '@/shared/actions/text/GetCapitalize';
|
||||
import { SortableHeader } from '@/shared/components/dataTable/SortableHeader';
|
||||
|
||||
import TServicoItemPedidoInterface from '../../interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
|
||||
export default function TServicoItemPedidoColumns(
|
||||
onEdit: (item: TServicoItemPedidoInterface, isEditingFormStatus: boolean) => void,
|
||||
onDelete: (item: TServicoItemPedidoInterface, isEditingFormStatus: boolean) => void,
|
||||
): ColumnDef<TServicoItemPedidoInterface>[] {
|
||||
return [
|
||||
// ID
|
||||
{
|
||||
accessorKey: 'gramatica_id',
|
||||
header: ({ column }) => SortableHeader('ID', column),
|
||||
cell: ({ row }) => Number(row.getValue('gramatica_id')),
|
||||
enableSorting: true,
|
||||
},
|
||||
|
||||
// Descrição
|
||||
{
|
||||
accessorKey: 'palavra',
|
||||
header: ({ column }) => SortableHeader('Palavra', column),
|
||||
cell: ({ row }) => GetCapitalize(String(row.getValue('palavra') || '')),
|
||||
},
|
||||
|
||||
// Ações
|
||||
{
|
||||
id: 'actions',
|
||||
header: 'Ações',
|
||||
cell: ({ row }) => {
|
||||
const natureza = row.original;
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon">
|
||||
<EllipsisIcon />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent side="left" align="start">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem onSelect={() => onEdit(natureza, true)}>
|
||||
<PencilIcon className="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<DropdownMenuItem
|
||||
className="text-red-600"
|
||||
onSelect={() => onDelete(natureza, true)}
|
||||
>
|
||||
<Trash2Icon className="mr-2 h-4 w-4" />
|
||||
Remover
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { ResetFormIfData } from '@/shared/actions/form/ResetFormIfData';
|
||||
import LoadingButton from '@/shared/components/loadingButton/LoadingButton';
|
||||
|
||||
import { useTServicoItemPedidoFormHook } from '../../hooks/TServicoItemPedido/useTServicoItemPedidoFormHook';
|
||||
import { TServicoItemPedidoFormInterface } from '../../interfaces/TServicoItemPedido/TServicoItemPedidoFormInterface';
|
||||
|
||||
/**
|
||||
* Formulário de cadastro/edição de Natureza
|
||||
* Baseado nos campos da tabela G_NATUREZA
|
||||
*/
|
||||
export default function TServicoItemPedidoForm({
|
||||
isOpen,
|
||||
data,
|
||||
onClose,
|
||||
onSave,
|
||||
buttonIsLoading,
|
||||
}: TServicoItemPedidoFormInterface) {
|
||||
const form = useTServicoItemPedidoFormHook({});
|
||||
|
||||
// Atualiza o formulário quando recebe dados para edição
|
||||
useEffect(() => {
|
||||
ResetFormIfData(form, data);
|
||||
}, [data, form]);
|
||||
|
||||
function onError(error: any) {
|
||||
console.log('Erro no formulário:', error);
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) onClose(null, false);
|
||||
}}
|
||||
>
|
||||
<DialogContent className="w-full max-w-full p-6 sm:max-w-3xl md:max-w-2xl lg:max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-lg sm:text-xl">Formulário de Gramática</DialogTitle>
|
||||
<DialogDescription className="text-muted-foreground text-sm">
|
||||
Formulário de Gramática
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
{/* Formulário principal */}
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSave, onError)} className="space-y-6">
|
||||
{/* GRID MOBILE FIRST */}
|
||||
<div className="grid w-full grid-cols-12 gap-4">
|
||||
{/* Palavra */}
|
||||
<div className="col-span-12 sm:col-span-6 md:col-span-12">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="desc_complementar"
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Palavra</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
type="text"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* Rodapé */}
|
||||
<DialogFooter className="mt-6 flex flex-col justify-end gap-2 sm:flex-row">
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline" type="button">
|
||||
Cancelar
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<LoadingButton
|
||||
text="Salvar"
|
||||
textLoading="Salvando..."
|
||||
type="submit"
|
||||
loading={buttonIsLoading}
|
||||
/>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
'use client';
|
||||
|
||||
import { Minus, Plus } from 'lucide-react';
|
||||
import React, { memo } from 'react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow
|
||||
} from '@/components/ui/table';
|
||||
import TPessoaTableFormSubview from '@/packages/administrativo/components/TPessoa/TPessoaTableFormSubview';
|
||||
import TServicoItemPedidoFormTableInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoFormTableInterface';
|
||||
import GetCapitalize from '@/shared/actions/text/GetCapitalize';
|
||||
|
||||
function TServicoItemPedidoFormTableComponent({
|
||||
data,
|
||||
form,
|
||||
params
|
||||
}: TServicoItemPedidoFormTableInterface) {
|
||||
return (
|
||||
<div className="rounded-md border">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>
|
||||
Serviço / Tabela
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
Emolumento
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
Tx. Judiciária
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
Fundesp 21%
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
ISS 5%
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
Total
|
||||
</TableHead>
|
||||
<TableHead className="text-center">Qtd.</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data?.length ? (
|
||||
data.map((item, index) => {
|
||||
return (
|
||||
<React.Fragment key={`fragment-${index}`}>
|
||||
{/* Linha principal */}
|
||||
<TableRow key={`row-${index}`} className="cursor-pointer hover:bg-gray-50">
|
||||
<TableCell>
|
||||
<div className="flex items-center gap-3">
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900 capitalize">
|
||||
{GetCapitalize(item.descricao)}
|
||||
</div>
|
||||
<div className="text-sm text-gray-500">
|
||||
{GetCapitalize(item.tabela)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>R$ {item.emolumento ?? '---'}</TableCell>
|
||||
<TableCell>R$ {item.taxa_judiciaria ?? '---'}</TableCell>
|
||||
<TableCell>R$ {item.fundesp ?? '---'}</TableCell>
|
||||
<TableCell>R$ {item.valor_iss ?? '---'}</TableCell>
|
||||
<TableCell>R$ {item.valor ?? '---'}</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex items-center gap-1 justify-center">
|
||||
<Button type="button" size="icon" variant="outline" className="bg-white border h-8 w-8 rounded-lg" >
|
||||
<Minus className="h-4 w-4" />
|
||||
</Button>
|
||||
<Input type="number" className="h-8 text-center px-1 w-12" />
|
||||
<Button type="button" size="icon" variant="outline" className="bg-white border h-8 w-8 rounded-lg" >
|
||||
<Plus className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{/* SubView */}
|
||||
{item.subview && (
|
||||
<TableRow className="bg-gray-50">
|
||||
<TableCell colSpan={7} className="p-4">
|
||||
<TPessoaTableFormSubview
|
||||
item_index={Number(item.index)}
|
||||
data={item.subview}
|
||||
params={params}
|
||||
form={form}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={7} className="text-center py-4">
|
||||
Nenhum item encontrado.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const TServicoItemPedidoFormTable = memo(TServicoItemPedidoFormTableComponent);
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
|
||||
import { useTServicoItemPedidoDeleteHook } from '@/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoDeleteHook';
|
||||
import { useTServicoItemPedidoIndexHook } from '@/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoIndexHook';
|
||||
import { useTServicoItemPedidoSaveHook } from '@/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoSaveHook';
|
||||
import TServicoItemPedidoInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import ConfirmDialog from '@/shared/components/confirmDialog/ConfirmDialog';
|
||||
import { useConfirmDialog } from '@/shared/components/confirmDialog/useConfirmDialog';
|
||||
import Loading from '@/shared/components/loading/loading';
|
||||
import Header from '@/shared/components/structure/Header';
|
||||
|
||||
import TServicoItemPedidoForm from './TServicoItemPedidoForm';
|
||||
import TServicoItemPedidoTable from './TServicoItemPedidoTable';
|
||||
|
||||
export default function TServicoItemPedidoIndex() {
|
||||
|
||||
// Controle de estado do botão
|
||||
const [buttonIsLoading, setButtonIsLoading] = useState(false);
|
||||
|
||||
// Hooks para leitura e salvamento
|
||||
const { TServicoItemPedido, indexTServicoItemPedido } = useTServicoItemPedidoIndexHook();
|
||||
const { saveTServicoItemPedido } = useTServicoItemPedidoSaveHook();
|
||||
const { deleteTServicoItemPedido } = useTServicoItemPedidoDeleteHook();
|
||||
|
||||
// Estados
|
||||
const [selectedData, setSelectedData] = useState<TServicoItemPedidoInterface | null>(null);
|
||||
const [isFormOpen, setIsFormOpen] = useState(false);
|
||||
|
||||
// Estado para saber qual item será deletado
|
||||
const [itemToDelete, setItemToDelete] = useState<TServicoItemPedidoInterface | null>(null);
|
||||
|
||||
/**
|
||||
* Hook do modal de confirmação
|
||||
*/
|
||||
const { isOpen: isConfirmOpen, openDialog: openConfirmDialog, handleCancel } = useConfirmDialog();
|
||||
|
||||
/**
|
||||
* Abre o formulário no modo de edição ou criação
|
||||
*/
|
||||
const handleOpenForm = useCallback((data: TServicoItemPedidoInterface | null) => {
|
||||
setSelectedData(data);
|
||||
setIsFormOpen(true);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Fecha o formulário e limpa o andamento selecionado
|
||||
*/
|
||||
const handleCloseForm = useCallback(() => {
|
||||
setSelectedData(null);
|
||||
setIsFormOpen(false);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Salva os dados do formulário
|
||||
*/
|
||||
const handleSave = useCallback(
|
||||
async (formData: TServicoItemPedidoInterface) => {
|
||||
// Coloca o botão em estado de loading
|
||||
setButtonIsLoading(true);
|
||||
|
||||
// Aguarda salvar o registro
|
||||
await saveTServicoItemPedido(formData);
|
||||
|
||||
// Remove o botão em estado de loading
|
||||
setButtonIsLoading(false);
|
||||
|
||||
// Atualiza a lista de dados
|
||||
indexTServicoItemPedido();
|
||||
},
|
||||
[saveTServicoItemPedido, indexTServicoItemPedido, handleCloseForm],
|
||||
);
|
||||
|
||||
/**
|
||||
* Quando o usuário clica em "remover" na tabela
|
||||
*/
|
||||
const handleConfirmDelete = useCallback(
|
||||
(item: TServicoItemPedidoInterface) => {
|
||||
// Define o item atual para remoção
|
||||
setItemToDelete(item);
|
||||
// Abre o modal de confirmação
|
||||
openConfirmDialog();
|
||||
},
|
||||
[openConfirmDialog],
|
||||
);
|
||||
|
||||
/**
|
||||
* Executa a exclusão de fato quando o usuário confirma
|
||||
*/
|
||||
const handleDelete = useCallback(async () => {
|
||||
// Protege contra null
|
||||
if (!itemToDelete) return;
|
||||
|
||||
// Executa o Hook de remoção
|
||||
await deleteTServicoItemPedido(itemToDelete);
|
||||
|
||||
// Atualiza a lista
|
||||
await indexTServicoItemPedido();
|
||||
|
||||
// Limpa o item selecionado
|
||||
setItemToDelete(null);
|
||||
|
||||
// Fecha o modal
|
||||
handleCancel();
|
||||
}, [itemToDelete, indexTServicoItemPedido, handleCancel]);
|
||||
|
||||
/**
|
||||
* Busca inicial dos dados
|
||||
*/
|
||||
useEffect(() => {
|
||||
indexTServicoItemPedido();
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Tela de loading enquanto carrega os dados
|
||||
*/
|
||||
if (TServicoItemPedido?.length == 0) {
|
||||
return <Loading type={2} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Cabeçalho */}
|
||||
<Header
|
||||
title={'Gramatica'}
|
||||
description={'Gramatica'}
|
||||
buttonText={'Nova palavra'}
|
||||
buttonAction={() => {
|
||||
handleOpenForm(null);
|
||||
}}
|
||||
/>
|
||||
{/* Tabela de andamentos */}
|
||||
<TServicoItemPedidoTable data={TServicoItemPedido} onEdit={handleOpenForm} onDelete={handleConfirmDelete} />
|
||||
{/* Modal de confirmação */}
|
||||
{isConfirmOpen && (
|
||||
<ConfirmDialog
|
||||
isOpen={isConfirmOpen}
|
||||
title="Confirmar exclusão"
|
||||
description="Atenção"
|
||||
message={`Deseja realmente excluir o valor "${itemToDelete?.valor}"?`}
|
||||
confirmText="Sim, excluir"
|
||||
cancelText="Cancelar"
|
||||
onConfirm={handleDelete}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
)}
|
||||
{/* Formulário de criação/edição */}
|
||||
{isFormOpen && (
|
||||
<TServicoItemPedidoForm
|
||||
isOpen={isFormOpen}
|
||||
data={selectedData}
|
||||
onClose={handleCloseForm}
|
||||
onSave={handleSave}
|
||||
buttonIsLoading={buttonIsLoading}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
'use client';
|
||||
|
||||
|
||||
import { BookmarkX, IdCardIcon, MoreHorizontalIcon, RotateCcwIcon, TicketIcon } from 'lucide-react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ButtonGroup } from '@/components/ui/button-group';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
|
||||
import { useTServicoItemPedidoCancelarHook } from '@/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoCancelarHook';
|
||||
import TServicoItemPedidoInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import TServicoItemPedidoListInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoListInterface';
|
||||
import FormatMoney from '@/shared/actions/money/FormatMoney';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
import { ServicosPedidosSituacoesBadge } from '@/shared/components/servicosPedidosSituacoes/ServicosPedidosSituacoesBadge';
|
||||
|
||||
import { useTServicoItemPedidoAtivarHook } from '../../hooks/TServicoItemPedido/useTServicoItemPedidoAtivarHook';
|
||||
|
||||
export default function TServicoItemPedidoList({ items, openConfirmDialog }: TServicoItemPedidoListInterface) {
|
||||
|
||||
const { setResponse } = useResponse();
|
||||
const { cancelarTServicoItemPedido } = useTServicoItemPedidoCancelarHook()
|
||||
const { ativarTServicoItemPedido } = useTServicoItemPedidoAtivarHook()
|
||||
|
||||
const [localItems, setLocalItems] = useState(items || [])
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
setLocalItems(items || [])
|
||||
|
||||
}, [items])
|
||||
|
||||
const handleSituacaoTServicoItemPedido = useCallback(async (item: any) => {
|
||||
|
||||
const servicoItemPedido: TServicoItemPedidoInterface = {
|
||||
|
||||
servico_itempedido_id: item.servico_itempedido_id
|
||||
|
||||
}
|
||||
|
||||
let response: any = null
|
||||
|
||||
switch (item.situacao) {
|
||||
|
||||
case 'C':
|
||||
|
||||
response = await ativarTServicoItemPedido(servicoItemPedido)
|
||||
break
|
||||
|
||||
case 'F':
|
||||
|
||||
response = await cancelarTServicoItemPedido(servicoItemPedido)
|
||||
break
|
||||
|
||||
default:
|
||||
|
||||
setResponse({
|
||||
status: 422,
|
||||
error: 'Situação',
|
||||
detail: 'Situação não tratada'
|
||||
})
|
||||
break
|
||||
|
||||
}
|
||||
|
||||
if (response) {
|
||||
|
||||
setLocalItems((prev) =>
|
||||
|
||||
prev.map((i) =>
|
||||
|
||||
i.servico_itempedido_id === item.servico_itempedido_id ? { ...i, situacao: response.situacao } : i
|
||||
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}, [cancelarTServicoItemPedido, setLocalItems])
|
||||
|
||||
return (
|
||||
<Card className="card-border">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-2xl font-semibold">
|
||||
Itens: {localItems?.length}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
|
||||
{/* Altura máxima + scroll vertical */}
|
||||
<div className="space-y-4 max-h-[60vh] overflow-y-auto pr-1">
|
||||
|
||||
{localItems?.map((item) => {
|
||||
|
||||
const isCancelado = item.situacao === 'C'
|
||||
const actionLabel = isCancelado ? 'Ativar Item' : 'Estornar Item'
|
||||
const confirmTitle = isCancelado ? 'Ativação de Item' : 'Estorno de Item'
|
||||
const confirmMessage = isCancelado ? `Deseja realmente ativar o item #${item.servico_itempedido_id}?` : `Deseja realmente estornar o item #${item.servico_itempedido_id}?`
|
||||
const confirmButton = isCancelado ? 'Sim, ativar item' : 'Sim, estornar item'
|
||||
const actionIcon = isCancelado ? <RotateCcwIcon /> : <BookmarkX />
|
||||
|
||||
return (
|
||||
<div key={item.servico_itempedido_id} className="bg-cart-item border-cart-border rounded-lg border p-4">
|
||||
|
||||
{/* Descrição */}
|
||||
<div className="flex-1">
|
||||
|
||||
<h3 className="text-foreground line-clamp-2 text-sm lg:text-base font-bold">
|
||||
|
||||
{item.descricao} de {item.nome} - <ServicosPedidosSituacoesBadge situacao={item.situacao} />
|
||||
|
||||
</h3>
|
||||
|
||||
<h6 className="text-foreground line-clamp-2 text-sm lg:text-base">
|
||||
|
||||
# {item.servico_itempedido_id}
|
||||
|
||||
</h6>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Valores (grid compacto) */}
|
||||
<div className="grid grid-cols-6 gap-3 mt-4">
|
||||
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">Emolumento</div>
|
||||
<div className="font-semibold">{FormatMoney(item.emolumento)}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">Tx. Judiciária</div>
|
||||
<div className="font-semibold">{FormatMoney(item.taxa_judiciaria)}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">ISS</div>
|
||||
<div className="font-semibold">{FormatMoney(item.valor_iss)}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">Fundesp</div>
|
||||
<div className="font-semibold">{FormatMoney(item.fundesp)}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">Total</div>
|
||||
<div className="font-semibold">{FormatMoney(item.valor)}</div>
|
||||
</div>
|
||||
|
||||
<div className="text-end">
|
||||
<ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">
|
||||
Ações
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="icon" aria-label="More Options">
|
||||
<MoreHorizontalIcon />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-52">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem className='cursor-pointer'>
|
||||
<TicketIcon />
|
||||
Imprimir Etiqueta
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem className='cursor-pointer'>
|
||||
<IdCardIcon />
|
||||
Imprimir Cartão
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
className={`cursor-pointer ${isCancelado ? 'text-green-600' : 'text-destructive'}`}
|
||||
onClick={() =>
|
||||
openConfirmDialog({
|
||||
title: confirmTitle,
|
||||
description: 'Confirmação necessária',
|
||||
message: confirmMessage,
|
||||
confirmText: confirmButton,
|
||||
cancelText: 'Cancelar',
|
||||
onConfirm: () => {
|
||||
handleSituacaoTServicoItemPedido(item)
|
||||
},
|
||||
})
|
||||
}
|
||||
>
|
||||
{actionIcon} {actionLabel}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</ButtonGroup>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import { DataTable } from '@/shared/components/dataTable/DataTable';
|
||||
|
||||
import TServicoItemPedidoColumns from './TServicoItemPedidoColumns';
|
||||
import TServicoItemPedidoTableInterface from '../../interfaces/TServicoItemPedido/TServicoItemPedidoTableInterface';
|
||||
|
||||
/**
|
||||
* Componente principal da tabela de Naturezas
|
||||
*/
|
||||
export default function TServicoItemPedidoTable({ data, onEdit, onDelete }: TServicoItemPedidoTableInterface) {
|
||||
const columns = TServicoItemPedidoColumns(onEdit, onDelete);
|
||||
return (
|
||||
<div>
|
||||
<DataTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
filterColumn="palavra"
|
||||
filterPlaceholder="Buscar por descrição da natureza..."
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { ColumnDef } from '@tanstack/react-table';
|
||||
import { EllipsisIcon, PencilIcon, Trash2Icon } from 'lucide-react';
|
||||
import { EllipsisIcon, EyeIcon, PencilIcon, Trash2Icon } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
|
|
@ -10,8 +11,13 @@ import {
|
|||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { FormatCPF } from '@/shared/actions/CPF/FormatCPF';
|
||||
import { FormatDateTime } from '@/shared/actions/dateTime/FormatDateTime';
|
||||
import GetCapitalize from '@/shared/actions/text/GetCapitalize';
|
||||
import GetNameInitials from '@/shared/actions/text/GetNameInitials';
|
||||
import empty from '@/shared/actions/validations/empty';
|
||||
import { SortableHeader } from '@/shared/components/dataTable/SortableHeader';
|
||||
import { ServicosPedidosSituacoesBadge } from '@/shared/components/servicosPedidosSituacoes/ServicosPedidosSituacoesBadge';
|
||||
|
||||
import TServicoPedidoInterface from '../../interfaces/TServicoPedido/TServicoPedidoInterface';
|
||||
|
||||
|
|
@ -22,17 +28,75 @@ export default function TServicoPedidoColumns(
|
|||
return [
|
||||
// ID
|
||||
{
|
||||
accessorKey: 'gramatica_id',
|
||||
accessorKey: 'servico_pedido_id',
|
||||
header: ({ column }) => SortableHeader('ID', column),
|
||||
cell: ({ row }) => Number(row.getValue('gramatica_id')),
|
||||
cell: ({ row }) => Number(row.getValue('servico_pedido_id')),
|
||||
enableSorting: true,
|
||||
},
|
||||
|
||||
// Descrição
|
||||
// Data Pedido
|
||||
{
|
||||
accessorKey: 'palavra',
|
||||
header: ({ column }) => SortableHeader('Palavra', column),
|
||||
cell: ({ row }) => GetCapitalize(String(row.getValue('palavra') || '')),
|
||||
accessorKey: 'data_pedido',
|
||||
header: ({ column }) => SortableHeader('Data', column),
|
||||
cell: ({ row }) => FormatDateTime(row.getValue('data_pedido')),
|
||||
},
|
||||
|
||||
// Apresentante
|
||||
{
|
||||
accessorKey: 'apresentante',
|
||||
header: ({ column }) => SortableHeader('Apresentante', column),
|
||||
cell: ({ row }) => {
|
||||
const data = row.original;
|
||||
return (
|
||||
<div className="flex items-center gap-3">
|
||||
{/* Foto ou Iniciais */}
|
||||
<div className="flex h-10 w-10 items-center justify-center overflow-hidden rounded-full bg-gray-200">
|
||||
<span className="text-sm font-medium text-gray-700">
|
||||
{GetNameInitials(data.apresentante)}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-semibold text-gray-900 capitalize">{data.apresentante || '-'}</div>
|
||||
<div className="text-sm text-gray-500">
|
||||
{empty(data.cpfcnpj_apresentante) ? '---' : FormatCPF(data.cpfcnpj_apresentante)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
sortingFn: (a, b) =>
|
||||
(a.original.apresentante?.toLowerCase() || '').localeCompare(b.original.apresentante?.toLowerCase() || ''),
|
||||
},
|
||||
|
||||
// Situação
|
||||
{
|
||||
accessorKey: 'situacao',
|
||||
header: ({ column }) => SortableHeader('Situação', column),
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<ServicosPedidosSituacoesBadge situacao={row.getValue('situacao') || ''} />
|
||||
)
|
||||
},
|
||||
},
|
||||
|
||||
// Valor Pedido
|
||||
{
|
||||
accessorKey: 'valor_pedido',
|
||||
header: ({ column }) => SortableHeader('Total', column),
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div className='font-semibold'>
|
||||
R$ {row.getValue('valor_pedido') || '---'}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
// Usuário
|
||||
{
|
||||
accessorKey: 'login',
|
||||
header: ({ column }) => SortableHeader('Operador', column),
|
||||
cell: ({ row }) => GetCapitalize(String(row.getValue('login') || '')),
|
||||
},
|
||||
|
||||
// Ações
|
||||
|
|
@ -40,8 +104,7 @@ export default function TServicoPedidoColumns(
|
|||
id: 'actions',
|
||||
header: 'Ações',
|
||||
cell: ({ row }) => {
|
||||
const natureza = row.original;
|
||||
|
||||
const servicoPedido = row.original;
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
|
|
@ -49,20 +112,23 @@ export default function TServicoPedidoColumns(
|
|||
<EllipsisIcon />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent side="left" align="start">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem onSelect={() => onEdit(natureza, true)}>
|
||||
<PencilIcon className="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
<DropdownMenuItem asChild>
|
||||
<Link href={`/servicos/balcao/detalhes/${row.getValue('servico_pedido_id')}`}>
|
||||
<EyeIcon className="mr-2 h-4 w-4" />
|
||||
Detalhes
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<DropdownMenuItem
|
||||
className="text-red-600"
|
||||
onSelect={() => onDelete(natureza, true)}
|
||||
>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link href={`/servicos/balcao/pedido/${row.getValue('servico_pedido_id')}`}>
|
||||
<PencilIcon className="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onSelect={() => onDelete(servicoPedido, true)}>
|
||||
<Trash2Icon className="mr-2 h-4 w-4" />
|
||||
Remover
|
||||
</DropdownMenuItem>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,268 @@
|
|||
'use client';
|
||||
|
||||
|
||||
import { BookmarkX, CalendarIcon, ReceiptText, RotateCcwIcon } from 'lucide-react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import TServicoItemPedidoList from '@/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoList';
|
||||
import TServicoPedidoDetailsPagamento from '@/packages/servicos/components/TServicoPedido/TServicoPedidoDetailsPagamento';
|
||||
import { useTServicoItemPedidoIndexHook } from '@/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoIndexHook';
|
||||
import { useTServicoPedidoShowHook } from '@/packages/servicos/hooks/TServicoPedido/useTServicoPedidoShowHook';
|
||||
import TServicoPedidoInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface';
|
||||
import { FormatCPF } from '@/shared/actions/CPF/FormatCPF';
|
||||
import { FormatDateTime } from '@/shared/actions/dateTime/FormatDateTime';
|
||||
import GetCapitalize from '@/shared/actions/text/GetCapitalize';
|
||||
import GetNameInitials from '@/shared/actions/text/GetNameInitials';
|
||||
import ConfirmDialog from '@/shared/components/confirmDialog/ConfirmDialog';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
import { useTServicoPedidoAtivarHook } from '../../hooks/TServicoPedido/useTServicoPedidoAtivarHook';
|
||||
import { useTServicoPedidoCancelarHook } from '../../hooks/TServicoPedido/useTServicoPedidoCancelarHook';
|
||||
|
||||
export default function TServicoPedidoDetails({ servico_pedido_id }: TServicoPedidoInterface) {
|
||||
|
||||
const { setResponse } = useResponse();
|
||||
const { ativarTServicoPedido } = useTServicoPedidoAtivarHook()
|
||||
const { cancelarTServicoPedido } = useTServicoPedidoCancelarHook()
|
||||
|
||||
const { TServicoItemPedido, indexTServicoItemPedido } = useTServicoItemPedidoIndexHook()
|
||||
const { TServicoPedido, setTServicoPedido, showTServicoPedido } = useTServicoPedidoShowHook()
|
||||
|
||||
const handleSituacaoTServicoPedido = useCallback(async (pedido: any) => {
|
||||
|
||||
const servicoPedido: TServicoPedidoInterface = {
|
||||
|
||||
servico_pedido_id: pedido.servico_pedido_id
|
||||
|
||||
}
|
||||
|
||||
let response: any = null
|
||||
|
||||
switch (pedido.situacao) {
|
||||
|
||||
case 'C':
|
||||
|
||||
response = await ativarTServicoPedido(servicoPedido)
|
||||
break
|
||||
|
||||
case 'F':
|
||||
|
||||
response = await cancelarTServicoPedido(servicoPedido)
|
||||
break
|
||||
|
||||
default:
|
||||
|
||||
setResponse({
|
||||
status: 422,
|
||||
error: 'Situação',
|
||||
detail: 'Situação não tratada'
|
||||
})
|
||||
break
|
||||
|
||||
}
|
||||
|
||||
if (response) {
|
||||
|
||||
pedido.situacao = response.situacao
|
||||
|
||||
setTServicoPedido(pedido)
|
||||
|
||||
}
|
||||
|
||||
}, [cancelarTServicoPedido])
|
||||
|
||||
const [confirmDialog, setConfirmDialog] = useState({
|
||||
isOpen: false,
|
||||
title: '',
|
||||
description: '',
|
||||
message: '',
|
||||
confirmText: 'Confirmar',
|
||||
cancelText: 'Cancelar',
|
||||
onConfirm: () => { },
|
||||
onCancel: () => { },
|
||||
})
|
||||
|
||||
// 🔹 Função utilitária para abrir o dialog dinamicamente
|
||||
const openConfirmDialog = ({
|
||||
title,
|
||||
description,
|
||||
message,
|
||||
confirmText = 'Confirmar',
|
||||
cancelText = 'Cancelar',
|
||||
onConfirm,
|
||||
onCancel,
|
||||
}) => {
|
||||
setConfirmDialog({
|
||||
isOpen: true,
|
||||
title,
|
||||
description,
|
||||
message,
|
||||
confirmText,
|
||||
cancelText,
|
||||
onConfirm: () => {
|
||||
onConfirm?.()
|
||||
setConfirmDialog((prev) => ({ ...prev, isOpen: false }))
|
||||
},
|
||||
onCancel: () => {
|
||||
onCancel?.()
|
||||
setConfirmDialog((prev) => ({ ...prev, isOpen: false }))
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const TServicoPedidoShowData = useCallback(async () => {
|
||||
const servicoPedido: TServicoPedidoInterface = {
|
||||
servico_pedido_id: servico_pedido_id
|
||||
}
|
||||
const response = await showTServicoPedido(servicoPedido)
|
||||
if (response.servico_pedido_id) {
|
||||
TServicoPedidoItemIndexData(response.servico_pedido_id)
|
||||
}
|
||||
})
|
||||
|
||||
const TServicoPedidoItemIndexData = useCallback(async (servico_pedido_id: number) => {
|
||||
const servicoPedido: TServicoPedidoInterface = {
|
||||
servico_pedido_id: servico_pedido_id
|
||||
}
|
||||
await indexTServicoItemPedido(servicoPedido)
|
||||
})
|
||||
|
||||
const handleCancelServicoPedidoOpenDialog = useCallback((state: boolean) => {
|
||||
setIsCancelServicoPedidoDialogOpen(state)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
TServicoPedidoShowData()
|
||||
}, [])
|
||||
|
||||
const isCancelado = TServicoPedido?.situacao === 'C'
|
||||
const actionLabel = isCancelado ? 'Ativar Pedido' : 'Estornar Pedido'
|
||||
const actionIcon = isCancelado ? <RotateCcwIcon /> : <BookmarkX />
|
||||
|
||||
return (
|
||||
<div className="relative h-full flex flex-col px-2 sm:px-4 py-2 sm:py-4 md:px-6 container mx-auto">
|
||||
<h3 className='text-4xl font-bold mb-4'>
|
||||
Pedido: #{TServicoPedido?.servico_pedido_id}
|
||||
</h3>
|
||||
{/* Main */}
|
||||
<div className="container mx-auto h-full">
|
||||
<div className="flex flex-col lg:flex-row gap-4">
|
||||
{/* Left column */}
|
||||
<div className="flex flex-col flex-auto gap-4">
|
||||
<TServicoItemPedidoList
|
||||
items={TServicoItemPedido}
|
||||
/>
|
||||
<TServicoPedidoDetailsPagamento
|
||||
situacao={TServicoPedido?.situacao}
|
||||
items={TServicoItemPedido}
|
||||
/>
|
||||
</div>
|
||||
{/* Right column (sidebar) */}
|
||||
<div className="lg:w-[320px] xl:w-[420px] flex flex-col gap-4">
|
||||
<Card role="presentation" className="card-border">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-2xl font-semibold">
|
||||
Apresentante
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{/* Header com avatar e link */}
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Foto ou Iniciais */}
|
||||
<div className="flex h-10 w-10 items-center justify-center overflow-hidden rounded-full bg-gray-200">
|
||||
<span className="text-sm font-medium text-gray-700">
|
||||
{GetNameInitials(TServicoPedido?.apresentante)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="font-bold truncate">
|
||||
{GetCapitalize(TServicoPedido?.apresentante)}
|
||||
</div>
|
||||
<div className="font-light truncate">
|
||||
{FormatCPF(String(TServicoPedido?.cpfcnpj_apresentante))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Separator className="my-5" />
|
||||
<div className="flex items-center gap-2">
|
||||
<CalendarIcon className="opacity-70 size-5" />
|
||||
<span className="truncate">
|
||||
{FormatDateTime(TServicoPedido?.data_pedido)}
|
||||
</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card role="presentation" className="card-border">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-2xl font-semibold">
|
||||
Operador
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Foto ou Iniciais */}
|
||||
<div className="flex h-10 w-10 items-center justify-center overflow-hidden rounded-full bg-gray-200">
|
||||
<span className="text-sm font-medium text-gray-700">
|
||||
{GetNameInitials(TServicoPedido?.login)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="font-bold truncate">
|
||||
{GetCapitalize(TServicoPedido?.login)}
|
||||
</div>
|
||||
<div className="font-light truncate">
|
||||
{GetCapitalize(TServicoPedido?.funcao)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="card-border">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-2xl font-semibold">
|
||||
Controles
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-2">
|
||||
<Button
|
||||
className="w-full cursor-pointer"
|
||||
variant={`outline`}
|
||||
onClick={() =>
|
||||
openConfirmDialog({
|
||||
title: 'Estorno do pedido',
|
||||
description: 'Confirmação necessária',
|
||||
message: 'Deseja continuar com o estorno ?',
|
||||
confirmText: 'Sim, continuar',
|
||||
cancelText: 'Cancelar',
|
||||
onConfirm: () => {
|
||||
handleSituacaoTServicoPedido(TServicoPedido)
|
||||
},
|
||||
})
|
||||
}>
|
||||
{actionIcon} {actionLabel}
|
||||
</Button>
|
||||
<Button className="w-full cursor-pointer">
|
||||
<ReceiptText /> Imprimir Recibo
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Confirma o cancelamento do pedido */}
|
||||
<ConfirmDialog
|
||||
isOpen={confirmDialog.isOpen}
|
||||
title={confirmDialog.title}
|
||||
description={confirmDialog.description}
|
||||
message={confirmDialog.message}
|
||||
confirmText={confirmDialog.confirmText}
|
||||
cancelText={confirmDialog.cancelText}
|
||||
onConfirm={confirmDialog.onConfirm}
|
||||
onCancel={confirmDialog.onCancel}
|
||||
/>
|
||||
</div >
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import FormatMoney from '@/shared/actions/money/FormatMoney';
|
||||
import { ServicosPedidosSituacoesBadge } from '@/shared/components/servicosPedidosSituacoes/ServicosPedidosSituacoesBadge';
|
||||
|
||||
import TServicoPedidoDetailsPagamentoInterface from '../../interfaces/TServicoPedido/TServicoPedidoDetailsPagamentoInterface';
|
||||
|
||||
export default function TServicoPedidoDetailsPagamento({
|
||||
situacao,
|
||||
items,
|
||||
}: TServicoPedidoDetailsPagamentoInterface) {
|
||||
|
||||
// Somas por tipo de valor
|
||||
const { emolumento, taxa_judiciaria, valor_iss, fundesp } = React.useMemo(() => {
|
||||
|
||||
return (items ?? []).reduce(
|
||||
|
||||
(acc, item) => {
|
||||
|
||||
if (item.situacao === 'F') {
|
||||
|
||||
acc.emolumento += item.emolumento;
|
||||
acc.taxa_judiciaria += item.taxa_judiciaria;
|
||||
acc.valor_iss += item.valor_iss;
|
||||
acc.fundesp += item.fundesp;
|
||||
|
||||
}
|
||||
|
||||
return acc;
|
||||
|
||||
},
|
||||
{ emolumento: 0, taxa_judiciaria: 0, valor_iss: 0, fundesp: 0 }
|
||||
|
||||
);
|
||||
|
||||
}, [items]);
|
||||
|
||||
// Total exibido = soma dos quatro componentes
|
||||
const total = emolumento + taxa_judiciaria + valor_iss + fundesp;
|
||||
|
||||
return (
|
||||
<Card className="card-border">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-2xl font-semibold">
|
||||
Pagamento <ServicosPedidosSituacoesBadge situacao={situacao} />
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">Emolumento</span>
|
||||
<span className="font-medium">{FormatMoney(emolumento)}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">Tx. Judiciária</span>
|
||||
<span className="font-medium">{FormatMoney(taxa_judiciaria)}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">ISS</span>
|
||||
<span className="font-medium">{FormatMoney(valor_iss)}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">Fundesp</span>
|
||||
<span className="font-medium">{FormatMoney(fundesp)}</span>
|
||||
</div>
|
||||
|
||||
<Separator className="border-cart-border" />
|
||||
|
||||
<div className="flex items-center justify-between text-xl">
|
||||
<span className="text-muted-foreground font-semibold">Total</span>
|
||||
<span className="font-semibold">{FormatMoney(total)}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,110 +1,726 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { CreditCard, Package, UserSquare2 } from 'lucide-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
CardTitle
|
||||
} from '@/components/ui/card';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
FormMessage
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { ResetFormIfData } from '@/shared/actions/form/ResetFormIfData';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import GEmolumentoServicoSelect from '@/packages/administrativo/components/GEmolumento/GEmolumentoServicoSelect';
|
||||
import GUsuarioSelect from '@/packages/administrativo/components/GUsuario/GUsuarioSelect';
|
||||
import TPessoaTableFormDialog from '@/packages/administrativo/components/TPessoa/TPessoaTableFormDialog';
|
||||
import TServicoTipoSelect from '@/packages/administrativo/components/TServicoTipo/TServicoTipoSelect';
|
||||
import TPessoaInterface from '@/packages/administrativo/interfaces/TPessoa/TPessoaInterface';
|
||||
import HandleSelectTServicoTipoAction from '@/packages/servicos/actions/TServicoPedido/HandleSelectTServicoTipoAction';
|
||||
import { TServicoItemPedidoFormTable } from '@/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoFormTable';
|
||||
import { useTServicoItemPedidoCalculoHook } from '@/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoCalculoHook';
|
||||
import { useTServicoItemPedidoIndexHook } from '@/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoIndexHook';
|
||||
import { useTServicoItemPedidoLocalAddHook } from '@/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoLocalAddHook';
|
||||
import { useTServicoPedidoFormHook } from '@/packages/servicos/hooks/TServicoPedido/useTServicoPedidoFormHook';
|
||||
import { useTServicoPedidoLoadParamsHook } from '@/packages/servicos/hooks/TServicoPedido/useTServicoPedidoLoadParamsHook';
|
||||
import { useTServicoPedidoSaveHook } from '@/packages/servicos/hooks/TServicoPedido/useTServicoPedidoSaveHook';
|
||||
import { useTServicoPedidoShowHook } from '@/packages/servicos/hooks/TServicoPedido/useTServicoPedidoShowHook';
|
||||
import TServicoItemPedidoAddInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoAddInterface';
|
||||
import { TServicoPedidoFormInterface } from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoFormInterface';
|
||||
import TServicoPedidoInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface';
|
||||
import { FormatCPFCNPJForm } from '@/shared/actions/CPF/FormatCPFCNPJForm';
|
||||
import { UnmaskCPFCNPJForm } from '@/shared/actions/CPF/UnmaskCPFCNPJForm';
|
||||
import { parseNumberInput } from '@/shared/actions/form/parseNumberInput';
|
||||
import ConfirmDialog from '@/shared/components/confirmDialog/ConfirmDialog';
|
||||
import LoadingButton from '@/shared/components/loadingButton/LoadingButton';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
import {
|
||||
StepNavigator,
|
||||
StepNavigatorRef,
|
||||
StepSection
|
||||
} from '@/shared/components/step/stepNavigator';
|
||||
import TipoPagamentoSelect from '@/shared/components/tipoPagamento/TipoPagamentoSelect';
|
||||
|
||||
import { useTServicoPedidoFormHook } from '../../hooks/TServicoPedido/useTServicoPedidoFormHook';
|
||||
import { TServicoPedidoFormInterface } from '../../interfaces/TServicoPedido/TServicoPedidoFormInterface';
|
||||
|
||||
/**
|
||||
* Formulário de cadastro/edição de Natureza
|
||||
* Baseado nos campos da tabela G_NATUREZA
|
||||
*/
|
||||
export default function TServicoPedidoForm({
|
||||
isOpen,
|
||||
data,
|
||||
onClose,
|
||||
onSave,
|
||||
buttonIsLoading,
|
||||
}: TServicoPedidoFormInterface) {
|
||||
|
||||
export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedidoFormInterface) {
|
||||
|
||||
const router = useRouter();
|
||||
const form = useTServicoPedidoFormHook({});
|
||||
const { setValue, reset, watch } = form;
|
||||
|
||||
// Atualiza o formulário quando recebe dados para edição
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [isAdding, setIsAdding] = useState(false);
|
||||
const [isPessoaFormOpen, setIsPessoaFormOpen] = useState(false);
|
||||
const [isSaveConfirmOpen, setIsSaveConfirmOpen] = useState(false);
|
||||
const [isCancelDialogOpen, setIsCancelDialogOpen] = useState(false)
|
||||
const [selectedPessoaTipo, setSelectedPessoaTipo] = useState('');
|
||||
const [shouldKeepFormOpen, setShouldKeepFormOpen] = useState(false)
|
||||
|
||||
const ref = useRef<StepNavigatorRef>(null);
|
||||
|
||||
// Controles de formulário
|
||||
const handleClosePessoaForm = useCallback(() => setIsPessoaFormOpen(false), []);
|
||||
const handleOpenSaveConfirm = useCallback(() => setIsSaveConfirmOpen(true), []);
|
||||
const handleCloseSaveConfirm = useCallback(() => setIsSaveConfirmOpen(false), []);
|
||||
|
||||
// Hooks
|
||||
// const playSuccess = useSoundHook("/sounds/success.mp3");
|
||||
const { setResponse } = useResponse()
|
||||
const { saveTServicoPedido } = useTServicoPedidoSaveHook();
|
||||
const { showTServicoPedido } = useTServicoPedidoShowHook();
|
||||
const { TServicoItemPedidoLocal, localAddTServicoItemPedido, setLocalTServicoItemPedido } = useTServicoItemPedidoLocalAddHook(setValue);
|
||||
const { addTServicoItemPedido } = useTServicoItemPedidoCalculoHook(setValue);
|
||||
const { indexTServicoItemPedido } = useTServicoItemPedidoIndexHook();
|
||||
const { TServicoPedidoParams, loadParamsTServicoPedido } =
|
||||
useTServicoPedidoLoadParamsHook();
|
||||
|
||||
// Acompanha as alterações, nos campos definidos
|
||||
const selectedServicoTipo = watch('servico_tipo');
|
||||
const selectedEmolumento = watch('emolumento');
|
||||
|
||||
const handleFormError = useCallback((errors: any) => {
|
||||
console.group("Erros de validação do formulário");
|
||||
console.log("Campos com erro:", errors);
|
||||
console.groupEnd();
|
||||
}, []);
|
||||
|
||||
// Envia a requisição para a API
|
||||
const handleSavePedido = useCallback(async (data: TServicoPedidoInterface) => {
|
||||
|
||||
// Ativa o botão de loading
|
||||
setIsSaving(true);
|
||||
|
||||
// Guarda a resposta da APi
|
||||
const response = await saveTServicoPedido(data);
|
||||
|
||||
// Desativa o botão de loading
|
||||
setIsSaving(false);
|
||||
|
||||
// Verifica se devo redirecionar a pagina
|
||||
if (response?.servico_pedido_id > 0) {
|
||||
|
||||
// Toca o som do sistema
|
||||
// playSuccess()
|
||||
|
||||
}
|
||||
|
||||
// Verifica se devo redirecionar a pagina
|
||||
if (response?.servico_pedido_id > 0 && !shouldKeepFormOpen) {
|
||||
|
||||
router.replace(`/servicos/balcao/detalhes/${response.servico_pedido_id}`);
|
||||
|
||||
}
|
||||
|
||||
}, [saveTServicoPedido, shouldKeepFormOpen]);
|
||||
|
||||
// Modal de confirmação de serviço
|
||||
const handleSubmitWithConfirmation = useCallback(() => {
|
||||
|
||||
// Envia o formulário
|
||||
form.handleSubmit(handleSavePedido, handleFormError)();
|
||||
|
||||
}, [form, handleSavePedido, handleFormError]);
|
||||
|
||||
// Busca os itens do Pedido
|
||||
const fetchPedidoItens = useCallback(async (id: number) => {
|
||||
|
||||
const pedidoItens = {
|
||||
servico_pedido_id: id
|
||||
}
|
||||
|
||||
// Busca os itens do pedido
|
||||
const response = await indexTServicoItemPedido(pedidoItens);
|
||||
|
||||
// Verifica se os dados foram localizados
|
||||
if (response?.data?.length) {
|
||||
|
||||
// Atualiza os dados dos itens locais
|
||||
setLocalTServicoItemPedido(response.data);
|
||||
|
||||
// Atualiza os itens do formulário
|
||||
setValue('itens', response.data);
|
||||
|
||||
}
|
||||
}, [indexTServicoItemPedido, setValue, setLocalTServicoItemPedido]);
|
||||
|
||||
// Busca o pedido Principal
|
||||
const fetchPedido = useCallback(async () => {
|
||||
|
||||
// Busca o pedido principal
|
||||
const response = await showTServicoPedido({ servico_pedido_id });
|
||||
|
||||
// Verifica se o pedido foi localizado
|
||||
if (response?.servico_pedido_id) {
|
||||
|
||||
// Atualiza os dados do formulário
|
||||
reset(response);
|
||||
|
||||
// Carrega os itens do pedido
|
||||
fetchPedidoItens(response.servico_pedido_id);
|
||||
|
||||
}
|
||||
|
||||
}, [servico_pedido_id, showTServicoPedido, reset, fetchPedidoItens]);
|
||||
|
||||
const handleAddItemWithPessoa = useCallback(async (selectedTPessoa: TPessoaInterface) => {
|
||||
|
||||
// Habilita o loading
|
||||
setIsAdding(true)
|
||||
|
||||
// Constroi um novo item
|
||||
const newItem = await addTServicoItemPedido({
|
||||
servico_tipo: selectedServicoTipo,
|
||||
emolumento: selectedEmolumento,
|
||||
pessoa: selectedTPessoa
|
||||
});
|
||||
|
||||
// Verifica se existe um novo item
|
||||
if (!newItem) return;
|
||||
|
||||
// Obtem o indice atual
|
||||
const index = TServicoItemPedidoLocal.length;
|
||||
|
||||
// Define a posição do item
|
||||
newItem.index = index
|
||||
|
||||
// Atualiza o estado
|
||||
localAddTServicoItemPedido(newItem);
|
||||
|
||||
// Atualiza os itens do formulário
|
||||
form.setValue(`itens.${index}`, newItem);
|
||||
|
||||
// Desabilita o loading
|
||||
setIsAdding(false)
|
||||
|
||||
}, [
|
||||
addTServicoItemPedido,
|
||||
selectedServicoTipo,
|
||||
selectedEmolumento,
|
||||
TServicoItemPedidoLocal.length,
|
||||
localAddTServicoItemPedido,
|
||||
form,
|
||||
]);
|
||||
|
||||
// Controla o formulário de cancelamento de pedido
|
||||
const handleOpenCancelDialog = useCallback(
|
||||
|
||||
async () => {
|
||||
|
||||
// Fecha a confirmação
|
||||
setIsCancelDialogOpen(true)
|
||||
|
||||
}, []
|
||||
|
||||
)
|
||||
|
||||
// Controle de redirecionamento
|
||||
const handleConfirmCancel = useCallback(
|
||||
|
||||
async () => {
|
||||
|
||||
// Redireciona o usuário
|
||||
router.replace(`/servicos/balcao/`);
|
||||
|
||||
}, []
|
||||
|
||||
)
|
||||
|
||||
// Controle do formulário de cancelamento do Pedido
|
||||
const handleCloseCancelDialog = useCallback(
|
||||
|
||||
async () => {
|
||||
|
||||
// Fecha o formulário
|
||||
setIsCancelDialogOpen(false)
|
||||
|
||||
}, []
|
||||
|
||||
)
|
||||
|
||||
// Controle de itens
|
||||
const handleAddItemBasic = useCallback(async () => {
|
||||
|
||||
setIsAdding(true)
|
||||
|
||||
// Prepara e valida os dados de item do pedido
|
||||
const payload: TServicoItemPedidoAddInterface = {
|
||||
servico_tipo: selectedServicoTipo,
|
||||
emolumento: selectedEmolumento
|
||||
}
|
||||
|
||||
// Verifica se os dados foram criados corretamente
|
||||
if (!payload) return;
|
||||
|
||||
// Obtem o resultado da adição do item
|
||||
const newItem = await addTServicoItemPedido(payload);
|
||||
|
||||
// Se tiver um novo item, adiciona o mesmo na tela
|
||||
if (newItem) localAddTServicoItemPedido(newItem);
|
||||
|
||||
setIsAdding(false)
|
||||
|
||||
}, [addTServicoItemPedido, selectedServicoTipo, selectedEmolumento, localAddTServicoItemPedido]);
|
||||
|
||||
// Habilita o formulário de pessoas
|
||||
const handleOpenPessoaForm = useCallback((tipoPessoa: string) => {
|
||||
|
||||
setSelectedPessoaTipo(tipoPessoa);
|
||||
setIsPessoaFormOpen(true);
|
||||
|
||||
}, []);
|
||||
|
||||
// Adiciona o item a tabela e verifica se deve ou não montar a subview da linha da tabela
|
||||
const handleSelectServicoTipo = useCallback(() => {
|
||||
|
||||
const response = HandleSelectTServicoTipoAction({
|
||||
servico: selectedServicoTipo,
|
||||
emolumento: selectedEmolumento,
|
||||
onOpenPessoaForm: handleOpenPessoaForm,
|
||||
onAddItem: handleAddItemBasic
|
||||
})
|
||||
|
||||
// Verifica se existem erros
|
||||
if (response?.status) {
|
||||
setResponse(response)
|
||||
}
|
||||
|
||||
}, [selectedServicoTipo, selectedEmolumento, handleOpenPessoaForm, handleAddItemBasic]);
|
||||
|
||||
// Cálculo automático dos totais
|
||||
const calcularTotais = useCallback(() => {
|
||||
if (!TServicoItemPedidoLocal || !TServicoItemPedidoLocal.length) {
|
||||
setValue("valor_pedido", 0);
|
||||
setValue("valor_pago", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const total = TServicoItemPedidoLocal.reduce((acc, item) => {
|
||||
const valor = Number(item.valor ?? 0);
|
||||
return acc + valor;
|
||||
}, 0);
|
||||
|
||||
setValue("valor_pedido", total, { shouldDirty: true });
|
||||
|
||||
// opcional: manter valor pago igual ao pedido
|
||||
const valorPagoAtual = watch("valor_pago");
|
||||
if (!valorPagoAtual || valorPagoAtual === 0) {
|
||||
setValue("valor_pago", total, { shouldDirty: true });
|
||||
}
|
||||
}, [TServicoItemPedidoLocal, setValue, watch]);
|
||||
|
||||
// Dispara a busca do pedido
|
||||
useEffect(() => {
|
||||
ResetFormIfData(form, data);
|
||||
}, [data, form]);
|
||||
|
||||
function onError(error: any) {
|
||||
console.log('Erro no formulário:', error);
|
||||
}
|
||||
// Se existir pedido_id, busca o pedido
|
||||
if (servico_pedido_id) fetchPedido();
|
||||
|
||||
}, [servico_pedido_id, fetchPedido]);
|
||||
|
||||
// Dispara a busca de itens
|
||||
useEffect(() => {
|
||||
|
||||
// Dispara a busca dos itens
|
||||
setValue('itens', TServicoItemPedidoLocal, { shouldDirty: true });
|
||||
|
||||
}, [TServicoItemPedidoLocal, setValue]);
|
||||
|
||||
// Dispara a busca de parâmetros
|
||||
useEffect(() => {
|
||||
|
||||
loadParamsTServicoPedido();
|
||||
|
||||
}, []);
|
||||
|
||||
// Monitora mudanças na lista de itens
|
||||
useEffect(() => {
|
||||
calcularTotais();
|
||||
}, [TServicoItemPedidoLocal, calcularTotais]);
|
||||
|
||||
// Memoriza os dados para não renderizar novamente
|
||||
const sections: StepSection[] = useMemo(() => [
|
||||
{
|
||||
key: 'pedido',
|
||||
id: 'selectPedido',
|
||||
icon: <Package className="h-4 w-4" />,
|
||||
title: 'Pedido',
|
||||
description: 'Dados gerais do pedido.'
|
||||
},
|
||||
{
|
||||
key: 'servicoPedidoItem',
|
||||
id: 'selectServicoPedidoItem',
|
||||
icon: <UserSquare2 className="h-4 w-4" />,
|
||||
title: 'Itens',
|
||||
description: 'Itens/serviços do pedido.'
|
||||
},
|
||||
{
|
||||
key: 'payment',
|
||||
id: 'selectPayment',
|
||||
icon: <CreditCard className="h-4 w-4" />,
|
||||
title: 'Pagamento',
|
||||
description: 'Forma e dados de pagamento.'
|
||||
}
|
||||
], []);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) onClose(null, false);
|
||||
}}
|
||||
>
|
||||
<DialogContent className="w-full max-w-full p-6 sm:max-w-3xl md:max-w-2xl lg:max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-lg sm:text-xl">Formulário de Gramática</DialogTitle>
|
||||
<DialogDescription className="text-muted-foreground text-sm">
|
||||
Formulário de Gramática
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
{/* Formulário principal */}
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSave, onError)} className="space-y-6">
|
||||
{/* GRID MOBILE FIRST */}
|
||||
<div className="grid w-full grid-cols-12 gap-4">
|
||||
{/* Palavra */}
|
||||
<div className="col-span-12 sm:col-span-6 md:col-span-12">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="apresentante"
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-1 sm:col-span-2">
|
||||
<FormLabel>Palavra</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
type="text"
|
||||
<div>
|
||||
<h3 className='text-4xl font-bold mb-4'>Pedido</h3>
|
||||
<Form {...form}>
|
||||
<form>
|
||||
<div className="flex gap-4">
|
||||
|
||||
{/* Seção1 */}
|
||||
<main className="flex-1">
|
||||
<div className="flex flex-col gap-4">
|
||||
|
||||
<Card role="presentation" id="selectPedido" className="scroll-mt-6">
|
||||
<CardHeader>
|
||||
<CardTitle><h4 className="text-3xl">Pedido</h4></CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid grid-cols-12 gap-4">
|
||||
{/* Escrevente */}
|
||||
<div className="col-span-12 md:col-span-12">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="escrevente_id"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="font-semibold">Escrevente/Tabelião</FormLabel>
|
||||
<GUsuarioSelect field={field} />
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{/* Apresentante */}
|
||||
<div className="col-span-12 md:col-span-8">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="apresentante"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Apresentante</FormLabel>
|
||||
<FormControl><Input {...field} type="text" /></FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{/* CPF */}
|
||||
<div className="col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cpfcnpj_apresentante"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>CPF/CNPJ</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field}
|
||||
type="text"
|
||||
value={FormatCPFCNPJForm(field.value)}
|
||||
onChange={(e) => {
|
||||
const raw = UnmaskCPFCNPJForm(e.target.value);
|
||||
field.onChange(raw);
|
||||
}}
|
||||
maxLength={14}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{/* Pessoa Selo */}
|
||||
<div className="col-span-12 md:col-span-8">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="selo_pessoa_nome"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Pessoa Selo</FormLabel>
|
||||
<FormControl><Input {...field} type="text" /></FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{/* Pessoa CPF */}
|
||||
<div className="col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="selo_pessoa_cpfcnpj"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>CPF/CNPJ</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field}
|
||||
type="text"
|
||||
value={FormatCPFCNPJForm(field.value)}
|
||||
onChange={(e) => {
|
||||
const raw = UnmaskCPFCNPJForm(e.target.value);
|
||||
field.onChange(raw);
|
||||
}}
|
||||
maxLength={14}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Seção 2 */}
|
||||
<Card role="presentation" id="selectServicoPedidoItem" className="scroll-mt-6">
|
||||
<CardHeader>
|
||||
<CardTitle><h4 className="text-3xl">Itens</h4></CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid grid-cols-12 gap-4">
|
||||
<div className="col-span-12 md:col-span-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="servico_tipo"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Serviços</FormLabel>
|
||||
<TServicoTipoSelect field={field} />
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-12 md:col-span-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="emolumento"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Emolumentos</FormLabel>
|
||||
<GEmolumentoServicoSelect sistema_id={2} field={field} />
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-12 text-end">
|
||||
<LoadingButton
|
||||
text={`+ Adicionar`}
|
||||
textLoading="Adicionando..."
|
||||
onClick={handleSelectServicoTipo}
|
||||
loading={isAdding}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-12">
|
||||
<TServicoItemPedidoFormTable
|
||||
form={form}
|
||||
params={TServicoPedidoParams}
|
||||
data={TServicoItemPedidoLocal} />
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Seção 3 */}
|
||||
<Card role="presentation" id="selectPayment" className="scroll-mt-6">
|
||||
<CardHeader>
|
||||
<CardTitle><h4 className="text-3xl">Pagamento</h4></CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid grid-cols-12 gap-4">
|
||||
<div className="col-span-12 md:col-span-8">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="pagador_nome"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Requerente</FormLabel>
|
||||
<FormControl><Input {...field} type="text" /></FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="pagador_cpfcnpj"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>CPF/CNPJ</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field}
|
||||
type="text"
|
||||
value={FormatCPFCNPJForm(field.value)}
|
||||
onChange={(e) => {
|
||||
const raw = UnmaskCPFCNPJForm(e.target.value);
|
||||
field.onChange(raw);
|
||||
}}
|
||||
maxLength={14}
|
||||
/></FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="valor_pedido"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Valor do Pedido</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number"
|
||||
onChange={(e) => field.onChange(parseNumberInput(e))}
|
||||
readOnly={true}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="valor_pago"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Valor Pago</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number"
|
||||
onChange={(e) => field.onChange(parseNumberInput(e))} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-12 md:col-span-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tipo_pagamento"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Forma Pagamento</FormLabel>
|
||||
<TipoPagamentoSelect field={field} />
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
{/* Rodapé */}
|
||||
<DialogFooter className="mt-6 flex flex-col justify-end gap-2 sm:flex-row">
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline" type="button">
|
||||
Cancelar
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<LoadingButton
|
||||
text="Salvar"
|
||||
textLoading="Salvando..."
|
||||
type="submit"
|
||||
loading={buttonIsLoading}
|
||||
/>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</main>
|
||||
|
||||
{/* Sidebar */}
|
||||
<aside className="hidden w-[360px] lg:block">
|
||||
<div className="sticky top-4 z-10 max-h-[calc(100vh-2rem)] overflow-auto flex flex-col gap-4">
|
||||
<Card className="card-border">
|
||||
<CardContent>
|
||||
<StepNavigator
|
||||
ref={ref}
|
||||
sections={sections}
|
||||
defaultActive="pedido"
|
||||
scrollOffset={16}
|
||||
spyLockMs={600}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="card-border">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-2xl font-semibold">Ações</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch
|
||||
id="permanecer_formulario"
|
||||
checked={shouldKeepFormOpen}
|
||||
onCheckedChange={(checked) => {
|
||||
setShouldKeepFormOpen(checked);
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor="permanecer_formulario">Permanecer no formulário</Label>
|
||||
</div>
|
||||
<Button
|
||||
className="w-full"
|
||||
variant="outline"
|
||||
type='button'
|
||||
onClick={handleOpenCancelDialog}>
|
||||
Cancelar
|
||||
</Button>
|
||||
<LoadingButton
|
||||
text="Salvar"
|
||||
textLoading="Salvando..."
|
||||
onClick={handleOpenSaveConfirm}
|
||||
loading={isSaving}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{/* Cofirmação de envio de dados */}
|
||||
{isSaveConfirmOpen && (
|
||||
<ConfirmDialog
|
||||
isOpen={isSaveConfirmOpen}
|
||||
title="Confirmar pedido"
|
||||
description="Atenção"
|
||||
message="Deseja confirmar o pedido?"
|
||||
confirmText="Sim, confirmar"
|
||||
cancelText="Cancelar"
|
||||
onConfirm={handleSubmitWithConfirmation}
|
||||
onCancel={handleCloseSaveConfirm}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Confirma o cancelamento do pedido */}
|
||||
{isCancelDialogOpen && (
|
||||
<ConfirmDialog
|
||||
isOpen={isCancelDialogOpen}
|
||||
title="Cancelamento de pedido"
|
||||
description="Atenção"
|
||||
message="Deseja cancelar o pedido? Os dados não serão salvos!"
|
||||
confirmText="Sim, cancelar"
|
||||
cancelText="Fechar"
|
||||
onConfirm={handleConfirmCancel}
|
||||
onCancel={handleCloseCancelDialog}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Modal TPessoa */}
|
||||
{isPessoaFormOpen && (
|
||||
<TPessoaTableFormDialog
|
||||
isOpen={isPessoaFormOpen}
|
||||
tipoPessoa={selectedPessoaTipo}
|
||||
onClose={handleClosePessoaForm}
|
||||
onSave={handleAddItemWithPessoa}
|
||||
buttonIsLoading={isSaving}
|
||||
/>
|
||||
)}
|
||||
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ export default function TServicoPedidoIndex() {
|
|||
* Busca inicial dos dados
|
||||
*/
|
||||
useEffect(() => {
|
||||
// indexTServicoPedido();
|
||||
indexTServicoPedido();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
|
@ -119,12 +119,13 @@ export default function TServicoPedidoIndex() {
|
|||
title={'Pedidos'}
|
||||
description={'Pedidos de Autenticação/Reconhecimento'}
|
||||
buttonText={'Novo pedido'}
|
||||
buttonAction={() => {
|
||||
handleOpenForm(null);
|
||||
}}
|
||||
href='/servicos/balcao/pedido'
|
||||
/>
|
||||
{/* Tabela de andamentos */}
|
||||
<TServicoPedidoTable data={TServicoPedido} onEdit={handleOpenForm} onDelete={handleConfirmDelete} />
|
||||
<TServicoPedidoTable
|
||||
data={TServicoPedido}
|
||||
onEdit={handleOpenForm}
|
||||
onDelete={handleConfirmDelete} />
|
||||
{/* Modal de confirmação */}
|
||||
{isConfirmOpen && (
|
||||
<ConfirmDialog
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
'use client';
|
||||
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import TServicoPedidoTableInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoTableInterface';
|
||||
import { DataTable } from '@/shared/components/dataTable/DataTable';
|
||||
|
||||
import TServicoPedidoColumns from './TServicoPedidoColumns';
|
||||
import TServicoPedidoTableInterface from '../../interfaces/TServicoPedido/TServicoPedidoTableInterface';
|
||||
|
||||
/**
|
||||
* Componente principal da tabela de Naturezas
|
||||
|
|
@ -12,12 +13,16 @@ export default function TServicoPedidoTable({ data, onEdit, onDelete }: TServico
|
|||
const columns = TServicoPedidoColumns(onEdit, onDelete);
|
||||
return (
|
||||
<div>
|
||||
<DataTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
filterColumn="palavra"
|
||||
filterPlaceholder="Buscar por descrição da natureza..."
|
||||
/>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<DataTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
filterColumn="apresentante"
|
||||
filterPlaceholder="Buscar por apresentante..."
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
import TServicoItemPedidoInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import API from '@/shared/services/api/Api';
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
|
||||
|
||||
|
||||
async function executeTServicoItemPedidoAtivarData(data: TServicoItemPedidoInterface): Promise<ApiResponseInterface> {
|
||||
|
||||
const api = new API();
|
||||
|
||||
return api.send({
|
||||
|
||||
method: Methods.PUT,
|
||||
endpoint: `servicos/balcao/t_servico_itempedido/${data.servico_itempedido_id}/ativar`,
|
||||
body: data,
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const TServicoItemPedidoAtivarData = withClientErrorHandler(executeTServicoItemPedidoAtivarData);
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import API from '@/shared/services/api/Api';
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
|
||||
|
||||
import TServicoItemPedidoInterface from '../../interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
|
||||
async function executeTServicoItemPedidoCancelarData(data: TServicoItemPedidoInterface): Promise<ApiResponseInterface> {
|
||||
|
||||
const api = new API();
|
||||
|
||||
return api.send({
|
||||
|
||||
method: Methods.PUT,
|
||||
endpoint: `servicos/balcao/t_servico_itempedido/${data.servico_itempedido_id}/cancelar`,
|
||||
body: data,
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const TServicoItemPedidoCancelarData = withClientErrorHandler(executeTServicoItemPedidoCancelarData);
|
||||
|
|
@ -1,15 +1,16 @@
|
|||
import TServicoItemPedidoInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import API from '@/shared/services/api/Api';
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
|
||||
|
||||
async function executeTServicoItemPedidoIndexData(): Promise<ApiResponseInterface> {
|
||||
const api = new API();
|
||||
|
||||
async function executeTServicoItemPedidoIndexData(data: TServicoItemPedidoInterface): Promise<ApiResponseInterface> {
|
||||
const api = new API();
|
||||
return api.send({
|
||||
method: Methods.GET,
|
||||
endpoint: `servicos/t_servico_itempedido/`,
|
||||
endpoint: `servicos/balcao/t_servico_itempedido/pedido/${data.servico_pedido_id}`,
|
||||
});
|
||||
}
|
||||
|
||||
export const TServicoItemPedidoIndexData = withClientErrorHandler(executeTServicoItemPedidoIndexData);
|
||||
export const TServicoItemPedidoIndexData = withClientErrorHandler(executeTServicoItemPedidoIndexData);
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import TServicoItemPedidoInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import API from '@/shared/services/api/Api';
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
|
||||
|
||||
|
||||
async function executeTServicoItemPedidoShowData(data: TServicoItemPedidoInterface): Promise<ApiResponseInterface> {
|
||||
const api = new API();
|
||||
return api.send({
|
||||
method: Methods.GET,
|
||||
endpoint: `servicos/balcao/t_servico_itempedido/pedido/${data.servico_pedido_id}`,
|
||||
});
|
||||
}
|
||||
|
||||
export const TServicoItemPedidoShowData = withClientErrorHandler(executeTServicoItemPedidoShowData);
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import TServicoPedidoInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface';
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import API from '@/shared/services/api/Api';
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
|
||||
|
||||
|
||||
async function executeTServicoPedidoAtivarData(data: TServicoPedidoInterface): Promise<ApiResponseInterface> {
|
||||
|
||||
const api = new API();
|
||||
|
||||
return api.send({
|
||||
method: Methods.PUT,
|
||||
endpoint: `servicos/balcao/t_servico_pedido/${data.servico_pedido_id}/ativar`,
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
export const TServicoPedidoAtivarData = withClientErrorHandler(executeTServicoPedidoAtivarData);
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import TServicoPedidoInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface';
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import API from '@/shared/services/api/Api';
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
|
||||
|
||||
|
||||
async function executeTServicoPedidoCancelarData(data: TServicoPedidoInterface): Promise<ApiResponseInterface> {
|
||||
|
||||
const api = new API();
|
||||
|
||||
return api.send({
|
||||
method: Methods.PUT,
|
||||
endpoint: `servicos/balcao/t_servico_pedido/${data.servico_pedido_id}/cancelar`,
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
export const TServicoPedidoCancelarData = withClientErrorHandler(executeTServicoPedidoCancelarData);
|
||||
|
|
@ -10,7 +10,7 @@ async function executeTServicoPedidoDeleteData(data: TServicoPedidoInterface): P
|
|||
|
||||
return api.send({
|
||||
method: Methods.DELETE,
|
||||
endpoint: `servico/t_servico_pedido/${data.servico_pedido_id}`,
|
||||
endpoint: `servicos/balcao/t_servico_pedido/${data.servico_pedido_id}`,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ async function executeTServicoPedidoIndexData(): Promise<ApiResponseInterface> {
|
|||
|
||||
return api.send({
|
||||
method: Methods.GET,
|
||||
endpoint: `servico/t_servico_pedido/`,
|
||||
endpoint: `servicos/balcao/t_servico_pedido/`,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import API from '@/shared/services/api/Api';
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
|
||||
|
||||
async function executeTServicoPedidoLoadParamsData(): Promise<ApiResponseInterface> {
|
||||
const api = new API();
|
||||
|
||||
return api.send({
|
||||
method: Methods.GET,
|
||||
endpoint: `servicos/balcao/t_servico_pedido/load-params`,
|
||||
});
|
||||
}
|
||||
|
||||
export const TServicoPedidoLoadParamsData = withClientErrorHandler(executeTServicoPedidoLoadParamsData);
|
||||
|
|
@ -15,7 +15,7 @@ async function executeTServicoPedidoSaveData(data: TServicoPedidoInterface): Pro
|
|||
// Executa a requisição para a API com o método apropriado e envia os dados no corpo
|
||||
return api.send({
|
||||
method: isUpdate ? Methods.PUT : Methods.POST, // PUT se atualizar, POST se criar
|
||||
endpoint: `servico/t_servico_pedido/${data.servico_pedido_id || ''}`, // endpoint dinâmico
|
||||
endpoint: `servicos/balcao/t_servico_pedido/${data.servico_pedido_id || ''}`, // endpoint dinâmico
|
||||
body: data, // payload enviado para a API
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
import TServicoPedidoInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface';
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import API from '@/shared/services/api/Api';
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
|
||||
|
||||
|
||||
async function executeTServicoPedidoShowData(data: TServicoPedidoInterface): Promise<ApiResponseInterface> {
|
||||
const api = new API();
|
||||
return api.send({
|
||||
method: Methods.GET,
|
||||
endpoint: `servicos/balcao/t_servico_pedido/${data.servico_pedido_id}`,
|
||||
});
|
||||
}
|
||||
|
||||
export const TServicoPedidoShowData = withClientErrorHandler(executeTServicoPedidoShowData);
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import TServicoItemPedidoInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import { TServicoItemPedidoAtivarService } from '@/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoAtivarService';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
|
||||
export const useTServicoItemPedidoAtivarHook = () => {
|
||||
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [TServicoItemPedido, setTServicoItemPedido] = useState<TServicoItemPedidoInterface | null>(null);
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const ativarTServicoItemPedido = async (data: TServicoItemPedidoInterface) => {
|
||||
|
||||
const response = await TServicoItemPedidoAtivarService(data);
|
||||
|
||||
setTServicoItemPedido(response.data);
|
||||
|
||||
setResponse(response);
|
||||
|
||||
setIsOpen(false);
|
||||
|
||||
return response.data;
|
||||
|
||||
};
|
||||
|
||||
return { TServicoItemPedido, ativarTServicoItemPedido, isOpen, setIsOpen };
|
||||
};
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { FieldValues, UseFormSetValue } from 'react-hook-form';
|
||||
|
||||
|
||||
import { GCalculoServicoService } from '@/packages/administrativo/services/GCalculo/GCalculoServicoService';
|
||||
import TServicoPedidoItemPreparePayload from '@/packages/servicos/actions/TServicoPedidoItem/TServicoPedidoItemPreparePayload';
|
||||
import TServicoItemPedidoAddInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoAddInterface';
|
||||
import TServicoItemPedidoCalculoResponseInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoCalculoResponseInterface';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
|
||||
|
||||
export function useTServicoItemPedidoCalculoHook<TFormValues extends FieldValues>(setValue?: UseFormSetValue<TFormValues>) {
|
||||
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [TServicoItemPedido, setTServicoItemPedido] = useState<TServicoItemPedidoCalculoResponseInterface[]>([]);
|
||||
|
||||
const addTServicoItemPedido = async (data: TServicoItemPedidoAddInterface) => {
|
||||
|
||||
// Trata os dados do payload
|
||||
const payload = TServicoPedidoItemPreparePayload(data);
|
||||
|
||||
if (payload.status) {
|
||||
|
||||
setResponse(payload)
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Realiza a busca do item
|
||||
const response = await GCalculoServicoService(payload, data);
|
||||
|
||||
// Verifico se tenho código de resposta
|
||||
if (response.status) {
|
||||
|
||||
// Exibo a resposta em tela
|
||||
setResponse(response)
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Verifica se tem status de erro
|
||||
if (response.status) {
|
||||
|
||||
return {
|
||||
|
||||
'status': response.status,
|
||||
'message': 'Erro ao processar dados'
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Atualiza o estado com fallback seguro
|
||||
setTServicoItemPedido((prev) => {
|
||||
|
||||
const safePrev = Array.isArray(prev) ? prev : [];
|
||||
const novoArray = [...safePrev, response];
|
||||
|
||||
if (setValue) {
|
||||
|
||||
// Protege contra sobrescrita incorreta do formulário
|
||||
setValue('itens', novoArray, { shouldDirty: true });
|
||||
|
||||
}
|
||||
|
||||
return novoArray;
|
||||
|
||||
});
|
||||
|
||||
return response;
|
||||
|
||||
};
|
||||
|
||||
return {
|
||||
TServicoItemPedido,
|
||||
setTServicoItemPedido,
|
||||
addTServicoItemPedido,
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import TServicoItemPedidoInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import { TServicoItemPedidoCancelarService } from '@/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoCancelarService';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
export const useTServicoItemPedidoCancelarHook = () => {
|
||||
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [TServicoItemPedido, setTServicoItemPedido] = useState<TServicoItemPedidoInterface | null>(null);
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const cancelarTServicoItemPedido = async (data: TServicoItemPedidoInterface) => {
|
||||
|
||||
const response = await TServicoItemPedidoCancelarService(data);
|
||||
|
||||
setTServicoItemPedido(response.data);
|
||||
|
||||
setResponse(response);
|
||||
|
||||
setIsOpen(false);
|
||||
|
||||
return response.data;
|
||||
|
||||
};
|
||||
|
||||
return { TServicoItemPedido, cancelarTServicoItemPedido, isOpen, setIsOpen };
|
||||
};
|
||||
|
|
@ -2,23 +2,29 @@
|
|||
|
||||
import { useState } from 'react';
|
||||
|
||||
import TServicoItemPedidoIndexResponseInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoCalculoResponseInterface';
|
||||
import TServicoItemPedidoInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import { TServicoItemPedidoIndexService } from '@/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoIndexService';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
import TServicoItemPedidoInterface from '../../interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import { TServicoItemPedidoIndexService } from '../../services/TServicoItemPedido/TServicoItemPedidoIndexService';
|
||||
|
||||
|
||||
export const useTServicoItemPedidoIndexHook = () => {
|
||||
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [TServicoItemPedido, setTServicoItemPedido] = useState<TServicoItemPedidoInterface[]>([]);
|
||||
const [TServicoItemPedido, setTServicoItemPedido] = useState<TServicoItemPedidoIndexResponseInterface[]>([]);
|
||||
|
||||
const indexTServicoItemPedido = async (data: TServicoItemPedidoInterface) => {
|
||||
|
||||
const response = await TServicoItemPedidoIndexService(data);
|
||||
|
||||
const indexTServicoItemPedido = async () => {
|
||||
const response = await TServicoItemPedidoIndexService();
|
||||
// Armazena os dados consultados
|
||||
setTServicoItemPedido(response.data);
|
||||
// Define a resposta (toast, modal, feedback, etc.)
|
||||
|
||||
setResponse(response);
|
||||
|
||||
// Retorno imediato dos valores
|
||||
return response
|
||||
|
||||
};
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { FieldValues, UseFormSetValue } from 'react-hook-form';
|
||||
|
||||
import { default as TServicoItemPedidoAddResponseInterface, default as TServicoItemPedidoIndexResponseInterface } from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoCalculoResponseInterface';
|
||||
|
||||
|
||||
export function useTServicoItemPedidoLocalAddHook<TFormValues extends FieldValues>(setValue?: UseFormSetValue<TFormValues>) {
|
||||
|
||||
const [TServicoItemPedidoLocal, setLocalTServicoItemPedido] = useState<TServicoItemPedidoIndexResponseInterface[]>([]);
|
||||
|
||||
const localAddTServicoItemPedido = (item: TServicoItemPedidoAddResponseInterface) => {
|
||||
|
||||
setLocalTServicoItemPedido((prev) => {
|
||||
|
||||
const updated = [...prev, item];
|
||||
|
||||
if (setValue) setValue("itens", updated);
|
||||
|
||||
return updated;
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
const localClearTServicoItemPedido = () => {
|
||||
|
||||
setLocalTServicoItemPedido([]);
|
||||
|
||||
if (setValue) setValue("itens", []);
|
||||
|
||||
};
|
||||
|
||||
return {
|
||||
TServicoItemPedidoLocal,
|
||||
localAddTServicoItemPedido,
|
||||
setLocalTServicoItemPedido,
|
||||
localClearTServicoItemPedido,
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
import TServicoItemPedidoInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import { TServicoItemPedidoShowService } from '@/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoShowService';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
|
||||
|
||||
export const useTServicoItemPedidoShowHook = () => {
|
||||
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [TServicoItemPedido, setTServicoItemPedido] = useState<TServicoItemPedidoInterface>();
|
||||
|
||||
const showTServicoItemPedido = async (data: TServicoItemPedidoInterface) => {
|
||||
|
||||
const response = await TServicoItemPedidoShowService(data);
|
||||
|
||||
setTServicoItemPedido(response.data);
|
||||
|
||||
setResponse(response);
|
||||
|
||||
return response.data
|
||||
|
||||
};
|
||||
|
||||
return { TServicoItemPedido, showTServicoItemPedido };
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import TServicoPedidoInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface';
|
||||
import { TServicoPedidoAtivarService } from '@/packages/servicos/services/TServicoPedido/TServicoPedidoAtivarService';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
export const useTServicoPedidoAtivarHook = () => {
|
||||
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [TServicoPedido, setTServicoPedido] = useState<TServicoPedidoInterface | null>(null);
|
||||
|
||||
// controla se o formulário está aberto ou fechado
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const ativarTServicoPedido = async (data: TServicoPedidoInterface) => {
|
||||
|
||||
const response = await TServicoPedidoAtivarService(data);
|
||||
|
||||
// Armazena os dados da resposta
|
||||
setTServicoPedido(response.data);
|
||||
|
||||
// Define os dados da resposta (toast, modal, etc.)
|
||||
setResponse(response);
|
||||
|
||||
// Fecha o formulário automaticamente após salvar
|
||||
setIsOpen(false);
|
||||
|
||||
// Retorna os valores de forma imediata
|
||||
return response.data;
|
||||
|
||||
};
|
||||
|
||||
return { TServicoPedido, ativarTServicoPedido, isOpen, setIsOpen };
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import TServicoPedidoInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface';
|
||||
import { TServicoPedidoCancelarService } from '@/packages/servicos/services/TServicoPedido/TServicoPedidoCancelarService';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
export const useTServicoPedidoCancelarHook = () => {
|
||||
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [TServicoPedido, setTServicoPedido] = useState<TServicoPedidoInterface | null>(null);
|
||||
|
||||
// controla se o formulário está aberto ou fechado
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const cancelarTServicoPedido = async (data: TServicoPedidoInterface) => {
|
||||
|
||||
const response = await TServicoPedidoCancelarService(data);
|
||||
|
||||
// Armazena os dados da resposta
|
||||
setTServicoPedido(response.data);
|
||||
|
||||
// Define os dados da resposta (toast, modal, etc.)
|
||||
setResponse(response);
|
||||
|
||||
// Fecha o formulário automaticamente após salvar
|
||||
setIsOpen(false);
|
||||
|
||||
// Retorna os valores de forma imediata
|
||||
return response.data;
|
||||
|
||||
};
|
||||
|
||||
return { TServicoPedido, cancelarTServicoPedido, isOpen, setIsOpen };
|
||||
};
|
||||
|
|
@ -1,13 +1,26 @@
|
|||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
import { TServicoPedidoFormValues, TServicoPedidoSchema } from '../../schemas/TServicoPedido/TServicoPedidoSchema';
|
||||
import { TServicoPedidoFormSchema, TServicoPedidoFormValues } from '@/packages/servicos/schemas/TServicoPedido/TServicoPedidoFormSchema';
|
||||
|
||||
export function useTServicoPedidoFormHook(defaults?: Partial<TServicoPedidoFormValues>) {
|
||||
return useForm<TServicoPedidoFormValues>({
|
||||
resolver: zodResolver(TServicoPedidoSchema),
|
||||
resolver: zodResolver(TServicoPedidoFormSchema),
|
||||
defaultValues: {
|
||||
servico_pedido_id: 0,
|
||||
escrevente_id: 0,
|
||||
apresentante: "",
|
||||
cpfcnpj_apresentante: "",
|
||||
selo_pessoa_nome: "",
|
||||
selo_pessoa_cpfcnpj: "",
|
||||
servico_tipo: null,
|
||||
emolumento: null,
|
||||
itens: [],
|
||||
pagador_nome: "",
|
||||
pagador_cpfcnpj: "",
|
||||
valor_pedido: 0,
|
||||
valor_pago: 0,
|
||||
situacao: "F",
|
||||
tipo_pagamento: null,
|
||||
...defaults,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue