diff --git a/package-lock.json b/package-lock.json
index fa8c604..9c71c6f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,8 @@
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-popover": "^1.1.15",
+ "@radix-ui/react-progress": "^1.1.7",
+ "@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",
@@ -30,7 +32,9 @@
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"cookies-next": "^6.1.0",
+ "date-fns": "^4.1.0",
"faker-js": "^1.0.0",
+ "framer-motion": "^12.23.24",
"input-otp": "^1.4.2",
"js-cookie": "^3.0.5",
"jsonwebtoken": "^9.0.2",
@@ -42,6 +46,7 @@
"react-dom": "19.1.0",
"react-hook-form": "^7.62.0",
"react-masked-text": "^1.0.5",
+ "recharts": "^3.3.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
"tinymce": "^8.1.2",
@@ -49,6 +54,7 @@
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
+ "@types/date-fns": "^2.5.3",
"@types/js-cookie": "^3.0.6",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^20",
@@ -1962,6 +1968,30 @@
}
}
},
+ "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",
+ "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-roving-focus": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz",
@@ -1993,6 +2023,37 @@
}
}
},
+ "node_modules/@radix-ui/react-scroll-area": {
+ "version": "1.2.10",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz",
+ "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/number": "1.1.1",
+ "@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-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-select": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz",
@@ -2353,6 +2414,32 @@
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
"license": "MIT"
},
+ "node_modules/@reduxjs/toolkit": {
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.9.2.tgz",
+ "integrity": "sha512-ZAYu/NXkl/OhqTz7rfPaAhY0+e8Fr15jqNxte/2exKUxvHyQ/hcqmdekiN1f+Lcw3pE+34FCgX+26zcUE3duCg==",
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/spec": "^1.0.0",
+ "@standard-schema/utils": "^0.3.0",
+ "immer": "^10.0.3",
+ "redux": "^5.0.1",
+ "redux-thunk": "^3.1.0",
+ "reselect": "^5.1.0"
+ },
+ "peerDependencies": {
+ "react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
+ "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rtsao/scc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
@@ -2360,6 +2447,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@standard-schema/spec": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
+ "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
+ "license": "MIT"
+ },
"node_modules/@standard-schema/utils": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
@@ -2714,6 +2807,76 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@types/d3-array": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz",
+ "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-color": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
+ "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-ease": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
+ "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-interpolate": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
+ "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-color": "*"
+ }
+ },
+ "node_modules/@types/d3-path": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
+ "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-scale": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
+ "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-time": "*"
+ }
+ },
+ "node_modules/@types/d3-shape": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz",
+ "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-path": "*"
+ }
+ },
+ "node_modules/@types/d3-time": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
+ "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-timer": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
+ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/date-fns": {
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/@types/date-fns/-/date-fns-2.5.3.tgz",
+ "integrity": "sha512-4KVPD3g5RjSgZtdOjvI/TDFkLNUHhdoWxmierdQbDeEg17Rov0hbBYtIzNaQA67ORpteOhvR9YEMTb6xeDCang==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -2790,6 +2953,12 @@
"@types/react": "^19.2.0"
}
},
+ "node_modules/@types/use-sync-external-store": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
+ "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
+ "license": "MIT"
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.46.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.1.tgz",
@@ -3900,6 +4069,127 @@
"devOptional": true,
"license": "MIT"
},
+ "node_modules/d3-array": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
+ "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
+ "license": "ISC",
+ "dependencies": {
+ "internmap": "1 - 2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-color": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+ "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-ease": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
+ "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-format": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
+ "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-interpolate": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+ "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-color": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-path": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
+ "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-scale": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+ "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2.10.0 - 3",
+ "d3-format": "1 - 3",
+ "d3-interpolate": "1.2.0 - 3",
+ "d3-time": "2.1.1 - 3",
+ "d3-time-format": "2 - 4"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-shape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
+ "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-path": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
+ "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time-format": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+ "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-time": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-timer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
+ "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/damerau-levenshtein": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
@@ -3961,6 +4251,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/date-fns": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
+ "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/kossnocorp"
+ }
+ },
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
@@ -3979,6 +4279,12 @@
}
}
},
+ "node_modules/decimal.js-light": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
+ "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==",
+ "license": "MIT"
+ },
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -4280,6 +4586,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/es-toolkit": {
+ "version": "1.41.0",
+ "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.41.0.tgz",
+ "integrity": "sha512-bDd3oRmbVgqZCJS6WmeQieOrzpl3URcWBUVDXxOELlUW2FuW+0glPOz1n0KnRie+PdyvUZcXz2sOn00c6pPRIA==",
+ "license": "MIT",
+ "workspaces": [
+ "docs",
+ "benchmarks"
+ ]
+ },
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@@ -4927,6 +5243,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/eventemitter3": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
+ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
+ "license": "MIT"
+ },
"node_modules/faker-js": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/faker-js/-/faker-js-1.0.0.tgz",
@@ -5081,6 +5403,33 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/framer-motion": {
+ "version": "12.23.24",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.24.tgz",
+ "integrity": "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-dom": "^12.23.23",
+ "motion-utils": "^12.23.6",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -5412,6 +5761,16 @@
"node": ">= 4"
}
},
+ "node_modules/immer": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz",
+ "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -5464,6 +5823,15 @@
"node": ">= 0.4"
}
},
+ "node_modules/internmap": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/is-array-buffer": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
@@ -6530,6 +6898,21 @@
"node": ">= 18"
}
},
+ "node_modules/motion-dom": {
+ "version": "12.23.23",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz",
+ "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-utils": "^12.23.6"
+ }
+ },
+ "node_modules/motion-utils": {
+ "version": "12.23.6",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz",
+ "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
+ "license": "MIT"
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -7179,6 +7562,29 @@
"integrity": "sha512-WichrlCXehL0apIfIgOdi2mjBE03tdMi8wXF+DhHe2ySWYxXCkP88aqDBaJZWUMa3Jp8p2h71u7TpC7EzEjXYw==",
"license": "ISC"
},
+ "node_modules/react-redux": {
+ "version": "9.2.0",
+ "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",
+ "dependencies": {
+ "@types/use-sync-external-store": "^0.0.6",
+ "use-sync-external-store": "^1.4.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^18.2.25 || ^19",
+ "react": "^18.0 || ^19",
+ "redux": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-remove-scroll": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
@@ -7248,6 +7654,48 @@
}
}
},
+ "node_modules/recharts": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.3.0.tgz",
+ "integrity": "sha512-Vi0qmTB0iz1+/Cz9o5B7irVyUjX2ynvEgImbgMt/3sKRREcUM07QiYjS1QpAVrkmVlXqy5gykq4nGWMz9AS4Rg==",
+ "license": "MIT",
+ "dependencies": {
+ "@reduxjs/toolkit": "1.x.x || 2.x.x",
+ "clsx": "^2.1.1",
+ "decimal.js-light": "^2.5.1",
+ "es-toolkit": "^1.39.3",
+ "eventemitter3": "^5.0.1",
+ "immer": "^10.1.1",
+ "react-redux": "8.x.x || 9.x.x",
+ "reselect": "5.1.1",
+ "tiny-invariant": "^1.3.3",
+ "use-sync-external-store": "^1.2.2",
+ "victory-vendor": "^37.0.2"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/redux": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
+ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
+ "license": "MIT"
+ },
+ "node_modules/redux-thunk": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
+ "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "redux": "^5.0.0"
+ }
+ },
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -7292,6 +7740,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/reselect": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
+ "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
+ "license": "MIT"
+ },
"node_modules/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
@@ -7944,6 +8398,12 @@
"node": ">=18"
}
},
+ "node_modules/tiny-invariant": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
+ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
+ "license": "MIT"
+ },
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
@@ -8336,6 +8796,28 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
+ "node_modules/victory-vendor": {
+ "version": "37.3.6",
+ "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz",
+ "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==",
+ "license": "MIT AND ISC",
+ "dependencies": {
+ "@types/d3-array": "^3.0.3",
+ "@types/d3-ease": "^3.0.0",
+ "@types/d3-interpolate": "^3.0.1",
+ "@types/d3-scale": "^4.0.2",
+ "@types/d3-shape": "^3.1.0",
+ "@types/d3-time": "^3.0.0",
+ "@types/d3-timer": "^3.0.0",
+ "d3-array": "^3.1.6",
+ "d3-ease": "^3.0.1",
+ "d3-interpolate": "^3.0.1",
+ "d3-scale": "^4.0.2",
+ "d3-shape": "^3.1.0",
+ "d3-time": "^3.0.0",
+ "d3-timer": "^3.0.1"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
index f0749ee..1fe27a2 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,8 @@
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-popover": "^1.1.15",
+ "@radix-ui/react-progress": "^1.1.7",
+ "@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",
@@ -32,7 +34,9 @@
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"cookies-next": "^6.1.0",
+ "date-fns": "^4.1.0",
"faker-js": "^1.0.0",
+ "framer-motion": "^12.23.24",
"input-otp": "^1.4.2",
"js-cookie": "^3.0.5",
"jsonwebtoken": "^9.0.2",
@@ -44,6 +48,7 @@
"react-dom": "19.1.0",
"react-hook-form": "^7.62.0",
"react-masked-text": "^1.0.5",
+ "recharts": "^3.3.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
"tinymce": "^8.1.2",
@@ -51,6 +56,7 @@
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
+ "@types/date-fns": "^2.5.3",
"@types/js-cookie": "^3.0.6",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^20",
diff --git a/src/app/(protected)/(administrativo)/administrativo/censec/page.tsx b/src/app/(protected)/(administrativo)/administrativo/censec/page.tsx
new file mode 100644
index 0000000..d5077cc
--- /dev/null
+++ b/src/app/(protected)/(administrativo)/administrativo/censec/page.tsx
@@ -0,0 +1,5 @@
+export default function TCensecPage() {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/src/app/(protected)/(administrativo)/administrativo/imoveis/dashboard/page.tsx b/src/app/(protected)/(administrativo)/administrativo/imoveis/dashboard/page.tsx
new file mode 100644
index 0000000..13011a1
--- /dev/null
+++ b/src/app/(protected)/(administrativo)/administrativo/imoveis/dashboard/page.tsx
@@ -0,0 +1,9 @@
+'use client';
+
+import TImovelDashboard from "@/packages/administrativo/components/TImovel/TImovelDashboard";
+
+export default function TImovelDashboardPage() {
+ return (
+
+ );
+}
diff --git a/src/app/(protected)/(administrativo)/administrativo/pessoas/dashboard/page.tsx b/src/app/(protected)/(administrativo)/administrativo/pessoas/dashboard/page.tsx
new file mode 100644
index 0000000..f95fe9f
--- /dev/null
+++ b/src/app/(protected)/(administrativo)/administrativo/pessoas/dashboard/page.tsx
@@ -0,0 +1,9 @@
+'use client';
+
+import TPessoaDashboard from "@/packages/administrativo/components/TPessoa/TPessoaDashboard";
+
+export default function TPessoaDashboardPage() {
+ return (
+
+ );
+}
diff --git a/src/app/(protected)/servicos/balcao/page.tsx b/src/app/(protected)/servicos/balcao/page.tsx
new file mode 100644
index 0000000..cc3187a
--- /dev/null
+++ b/src/app/(protected)/servicos/balcao/page.tsx
@@ -0,0 +1,7 @@
+import TServicoPedidoIndex from "@/packages/servicos/components/TServicoPedido/TServicoPedidoIndex";
+
+export default function TServicoPedidoPage() {
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/src/app/(protected)/servicos/balcao/pedido/page.tsx b/src/app/(protected)/servicos/balcao/pedido/page.tsx
new file mode 100644
index 0000000..12d4839
--- /dev/null
+++ b/src/app/(protected)/servicos/balcao/pedido/page.tsx
@@ -0,0 +1,90 @@
+import { Card, CardContent } from "@/components/ui/card";
+import TServicoItemPedidoResumo from "@/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoResumo";
+
+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() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/app/(protected)/servicos/dashboard/page.tsx b/src/app/(protected)/servicos/dashboard/page.tsx
new file mode 100644
index 0000000..df1548f
--- /dev/null
+++ b/src/app/(protected)/servicos/dashboard/page.tsx
@@ -0,0 +1,7 @@
+import TServicoPedidoDashboard from "@/packages/servicos/components/TServicoPedido/TServicoPedidoDashboard";
+
+export default function TServicoPedidoPage() {
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx
index 1a23482..857ada2 100644
--- a/src/components/app-sidebar.tsx
+++ b/src/components/app-sidebar.tsx
@@ -1,15 +1,15 @@
'use client';
-import * as React from 'react';
import {
Bot,
Frame,
GalleryVerticalEnd,
- House,
HouseIcon,
SquareTerminal,
- UsersIcon,
+ UsersIcon
} from 'lucide-react';
+import Image from 'next/image';
+import * as React from 'react';
import { NavMain } from '@/components/nav-main';
import { NavProjects } from '@/components/nav-projects';
@@ -24,9 +24,8 @@ import {
SidebarMenuItem,
SidebarRail,
} from '@/components/ui/sidebar';
-
import useGUsuarioGetJWTHook from '@/shared/hooks/auth/useGUsuarioGetJWTHook';
-import Image from 'next/image';
+
// This is sample data.
const data = {
@@ -44,12 +43,32 @@ const data = {
},
],
},
+ {
+ title: 'Servicos',
+ url: '#',
+ icon: UsersIcon,
+ isActive: false,
+ items: [
+ {
+ title: 'Dashboard',
+ url: '/servicos/dashboard/',
+ },
+ {
+ title: 'Balcão',
+ url: '/servicos/balcao/',
+ },
+ ],
+ },
{
title: 'Pessoas',
url: '#',
icon: UsersIcon,
isActive: false,
items: [
+ {
+ title: 'Dashboard',
+ url: '/administrativo/pessoas/dashboard',
+ },
{
title: 'Físicas',
url: '/administrativo/pessoas/fisicas',
@@ -66,6 +85,10 @@ const data = {
icon: HouseIcon,
isActive: false,
items: [
+ {
+ title: 'Dashboard',
+ url: '/administrativo/imoveis/dashboard',
+ },
{
title: 'Urbanos',
url: '/administrativo/imoveis/urbanos',
diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx
new file mode 100644
index 0000000..fd3a406
--- /dev/null
+++ b/src/components/ui/badge.tsx
@@ -0,0 +1,46 @@
+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"
+
+const badgeVariants = cva(
+ "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
+ {
+ variants: {
+ variant: {
+ default:
+ "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
+ secondary:
+ "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
+ destructive:
+ "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
+ outline:
+ "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+function Badge({
+ className,
+ variant,
+ asChild = false,
+ ...props
+}: React.ComponentProps<"span"> &
+ VariantProps & { asChild?: boolean }) {
+ const Comp = asChild ? Slot : "span"
+
+ return (
+
+ )
+}
+
+export { Badge, badgeVariants }
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index b579275..21409a0 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -1,36 +1,40 @@
-import * as React from 'react';
-import { Slot } from '@radix-ui/react-slot';
-import { cva, type VariantProps } from 'class-variance-authority';
+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 { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
{
variants: {
variant: {
- default: 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
- 'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
+ "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
- 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
- secondary: 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
- ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
- link: 'text-primary underline-offset-4 hover:underline',
+ "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
+ secondary:
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ ghost:
+ "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
+ link: "text-primary underline-offset-4 hover:underline",
},
size: {
- default: 'h-9 px-4 py-2 has-[>svg]:px-3',
- sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
- lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
- icon: 'size-9',
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
+ icon: "size-9",
+ "icon-sm": "size-8",
+ "icon-lg": "size-10",
},
},
defaultVariants: {
- variant: 'default',
- size: 'default',
+ variant: "default",
+ size: "default",
},
- },
-);
+ }
+)
function Button({
className,
@@ -38,11 +42,11 @@ function Button({
size,
asChild = false,
...props
-}: React.ComponentProps<'button'> &
+}: React.ComponentProps<"button"> &
VariantProps & {
- asChild?: boolean;
+ asChild?: boolean
}) {
- const Comp = asChild ? Slot : 'button';
+ const Comp = asChild ? Slot : "button"
return (
- );
+ )
}
-export { Button, buttonVariants };
+export { Button, buttonVariants }
diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx
index 8dd598f..681ad98 100644
--- a/src/components/ui/card.tsx
+++ b/src/components/ui/card.tsx
@@ -1,75 +1,92 @@
-import * as React from 'react';
+import * as React from "react"
-import { cn } from '@/lib/utils';
+import { cn } from "@/lib/utils"
-function Card({ className, ...props }: React.ComponentProps<'div'>) {
+function Card({ className, ...props }: React.ComponentProps<"div">) {
return (
- );
+ )
}
-function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
+function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
- );
+ )
}
-function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
+function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
- );
+ )
}
-function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
+function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
- );
+ )
}
-function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
+function CardAction({ className, ...props }: React.ComponentProps<"div">) {
return (
- );
+ )
}
-function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
- return ;
+function CardContent({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
}
-function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
+function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
- );
+ )
}
-export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent };
+export {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardAction,
+ CardDescription,
+ CardContent,
+}
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
index 147cfce..8916905 100644
--- a/src/components/ui/input.tsx
+++ b/src/components/ui/input.tsx
@@ -1,22 +1,21 @@
-import * as React from 'react';
+import * as React from "react"
-import { cn } from '@/lib/utils';
+import { cn } from "@/lib/utils"
-function Input({ className, value, type, ...props }: React.ComponentProps<'input'>) {
+function Input({ className, type, ...props }: React.ComponentProps<"input">) {
return (
- );
+ )
}
-export { Input };
+export { Input }
diff --git a/src/components/ui/progress.tsx b/src/components/ui/progress.tsx
new file mode 100644
index 0000000..e7a416c
--- /dev/null
+++ b/src/components/ui/progress.tsx
@@ -0,0 +1,31 @@
+"use client"
+
+import * as React from "react"
+import * as ProgressPrimitive from "@radix-ui/react-progress"
+
+import { cn } from "@/lib/utils"
+
+function Progress({
+ className,
+ value,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
+
+export { Progress }
diff --git a/src/components/ui/scroll-area.tsx b/src/components/ui/scroll-area.tsx
new file mode 100644
index 0000000..8e4fa13
--- /dev/null
+++ b/src/components/ui/scroll-area.tsx
@@ -0,0 +1,58 @@
+"use client"
+
+import * as React from "react"
+import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
+
+import { cn } from "@/lib/utils"
+
+function ScrollArea({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+ {children}
+
+
+
+
+ )
+}
+
+function ScrollBar({
+ className,
+ orientation = "vertical",
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
+
+export { ScrollArea, ScrollBar }
diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx
index 070c9b8..25e5439 100644
--- a/src/components/ui/select.tsx
+++ b/src/components/ui/select.tsx
@@ -1,30 +1,36 @@
-'use client';
+"use client"
-import * as React from 'react';
-import * as SelectPrimitive from '@radix-ui/react-select';
-import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
+import * as React from "react"
+import * as SelectPrimitive from "@radix-ui/react-select"
+import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
-import { cn } from '@/lib/utils';
+import { cn } from "@/lib/utils"
-function Select({ ...props }: React.ComponentProps) {
- return ;
+function Select({
+ ...props
+}: React.ComponentProps) {
+ return
}
-function SelectGroup({ ...props }: React.ComponentProps) {
- return ;
+function SelectGroup({
+ ...props
+}: React.ComponentProps) {
+ return
}
-function SelectValue({ ...props }: React.ComponentProps) {
- return ;
+function SelectValue({
+ ...props
+}: React.ComponentProps) {
+ return
}
function SelectTrigger({
className,
- size = 'default',
+ size = "default",
children,
...props
}: React.ComponentProps & {
- size?: 'sm' | 'default';
+ size?: "sm" | "default"
}) {
return (
@@ -41,13 +47,14 @@ function SelectTrigger({
- );
+ )
}
function SelectContent({
className,
children,
- position = 'popper',
+ position = "popper",
+ align = "center",
...props
}: React.ComponentProps) {
return (
@@ -55,20 +62,21 @@ function SelectContent({
{children}
@@ -76,17 +84,20 @@ function SelectContent({
- );
+ )
}
-function SelectLabel({ className, ...props }: React.ComponentProps) {
+function SelectLabel({
+ className,
+ ...props
+}: React.ComponentProps) {
return (
- );
+ )
}
function SelectItem({
@@ -99,7 +110,7 @@ function SelectItem({
data-slot="select-item"
className={cn(
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
- className,
+ className
)}
{...props}
>
@@ -110,7 +121,7 @@ function SelectItem({
{children}
- );
+ )
}
function SelectSeparator({
@@ -120,10 +131,10 @@ function SelectSeparator({
return (
- );
+ )
}
function SelectScrollUpButton({
@@ -133,12 +144,15 @@ function SelectScrollUpButton({
return (
- );
+ )
}
function SelectScrollDownButton({
@@ -148,12 +162,15 @@ function SelectScrollDownButton({
return (
- );
+ )
}
export {
@@ -167,4 +184,4 @@ export {
SelectSeparator,
SelectTrigger,
SelectValue,
-};
+}
diff --git a/src/packages/administrativo/components/TImovel/TImovelDashboard.tsx b/src/packages/administrativo/components/TImovel/TImovelDashboard.tsx
new file mode 100644
index 0000000..1f28cd3
--- /dev/null
+++ b/src/packages/administrativo/components/TImovel/TImovelDashboard.tsx
@@ -0,0 +1,378 @@
+'use client'
+
+import { motion } from 'framer-motion'
+import {
+ AlertTriangle,
+ Building2,
+ CheckCircle2,
+ Home,
+ Layers3,
+ MapPin,
+ Ruler
+} from 'lucide-react'
+import React, { useEffect, useState } from 'react'
+import {
+ Area,
+ AreaChart,
+ Bar,
+ BarChart,
+ CartesianGrid,
+ Cell,
+ ResponsiveContainer,
+ Tooltip,
+ XAxis,
+ YAxis
+} from 'recharts'
+
+import { Badge } from '@/components/ui/badge'
+import { Button } from '@/components/ui/button'
+import {
+ Card,
+ CardContent,
+ CardHeader,
+ CardTitle
+} from '@/components/ui/card'
+import { Progress } from '@/components/ui/progress'
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
+
+
+// =====================
+// Types
+// =====================
+
+type Kpis = {
+ totalImoveis: number
+ totalUnidades: number
+ mediaPorImovel: number
+ geoReferenciados: number
+ semArea: number
+ novosMes: number
+ tendenciaMes: number
+}
+
+type AreaStats = {
+ media: number
+ minima: number
+ maxima: number
+}
+
+type Distribuicao = { label: string; total: number }
+
+type Qualidade = {
+ geoReferenciadoPct: number
+ areaPreenchidaPct: number
+ enderecoCompletoPct: number
+ inconsistencias: number
+}
+
+type ApiResponse = {
+ kpis: Kpis
+ area: AreaStats
+ tiposClasse: Distribuicao[]
+ tiposRegistro: Distribuicao[]
+ distribuicaoUF: Distribuicao[]
+ distribuicaoCidade: Distribuicao[]
+ auditoria: Distribuicao[]
+ evolucao: { mes: string; total: number }[]
+ qualidade: Qualidade
+}
+
+// =====================
+// Mock de fallback
+// =====================
+
+const MOCK: ApiResponse = {
+ kpis: {
+ totalImoveis: 1240,
+ totalUnidades: 8950,
+ mediaPorImovel: 7.2,
+ geoReferenciados: 5620,
+ semArea: 230,
+ novosMes: 110,
+ tendenciaMes: 5.8
+ },
+ area: {
+ media: 82.4,
+ minima: 30.5,
+ maxima: 250.0
+ },
+ tiposClasse: [
+ { label: 'Urbano', total: 780 },
+ { label: 'Rural', total: 420 },
+ { label: 'Não informado', total: 40 }
+ ],
+ tiposRegistro: [
+ { label: 'Matrícula', total: 900 },
+ { label: 'Transcrição', total: 280 },
+ { label: 'Outros', total: 60 }
+ ],
+ distribuicaoUF: [
+ { label: 'GO', total: 540 },
+ { label: 'DF', total: 230 },
+ { label: 'MT', total: 150 },
+ { label: 'TO', total: 120 }
+ ],
+ distribuicaoCidade: [
+ { label: 'Goiânia', total: 320 },
+ { label: 'Anápolis', total: 220 },
+ { label: 'Aparecida de Goiânia', total: 210 },
+ { label: 'Trindade', total: 180 },
+ { label: 'Formosa', total: 160 },
+ { label: 'Catalão', total: 140 },
+ { label: 'Luziânia', total: 120 },
+ { label: 'Rio Verde', total: 110 },
+ { label: 'Itumbiara', total: 90 },
+ { label: 'Jataí', total: 80 }
+ ],
+ auditoria: [
+ { label: 'Unidades sem área', total: 230 },
+ { label: 'Imóveis sem UF', total: 15 },
+ { label: 'Sem logradouro', total: 48 }
+ ],
+ evolucao: Array.from({ length: 12 }, (_, i) => ({
+ mes: new Date(2025, i).toLocaleString('pt-BR', { month: 'short' }),
+ total: 100 + i * 25 + (i % 2 === 0 ? 40 : 0)
+ })),
+ qualidade: {
+ geoReferenciadoPct: 72.5,
+ areaPreenchidaPct: 88.2,
+ enderecoCompletoPct: 93.4,
+ inconsistencias: 48
+ }
+}
+
+// =====================
+// Função de fetch (com fallback)
+// =====================
+
+async function fetchApi(periodo: string, uf: string | null): Promise {
+ const params = new URLSearchParams()
+ params.set('periodo', periodo)
+ if (uf) params.set('uf', uf)
+
+ try {
+ const ctrl = new AbortController()
+ const timeout = setTimeout(() => ctrl.abort(), 6000)
+ const res = await fetch(`/api/dashboard/imoveis?${params.toString()}`, { signal: ctrl.signal })
+ clearTimeout(timeout)
+ if (!res.ok) throw new Error('Erro HTTP')
+ return await res.json()
+ } catch {
+ return MOCK
+ }
+}
+
+// =====================
+// Subcomponentes
+// =====================
+
+function Kpi({
+ icon: Icon,
+ label,
+ value,
+ hint,
+ trend
+}: {
+ icon: any
+ label: string
+ value: React.ReactNode
+ hint?: string
+ trend?: number
+}) {
+ const trendColor =
+ trend == null ? '' : trend > 0 ? 'text-emerald-600' : trend < 0 ? 'text-rose-600' : 'text-muted-foreground'
+ const prefix = trend != null && trend > 0 ? '+' : ''
+ return (
+
+
+ {label}
+
+
+
+ {value}
+
+ {hint && {hint}}
+ {trend != null && (
+ {prefix}{trend.toFixed(1)}%
+ )}
+
+
+
+ )
+}
+
+function DataProgress({ label, value, goal }: { label: string; value: number; goal: number }) {
+ const color = value >= goal ? 'text-emerald-600' : 'text-amber-600'
+ return (
+
+
+ {label}
+
+ {value.toFixed(1)}% (meta {goal}%)
+
+
+
+
+ )
+}
+
+// =====================
+// Main Component
+// =====================
+
+export default function DashboardImoveis() {
+ const [periodo, setPeriodo] = useState('12m')
+ const [uf, setUf] = useState(null)
+ const [data, setData] = useState(null)
+ const [loading, setLoading] = useState(true)
+
+ useEffect(() => {
+ setLoading(true)
+ fetchApi(periodo, uf).then((d) => {
+ setData(d)
+ setLoading(false)
+ })
+ }, [periodo, uf])
+
+ const COLORS = ['#1A292F', '#8FB6C1', '#D1E6EA', '#F36F28', '#EAECEA']
+
+ return (
+
+ {/* Header */}
+
+
+
+ Painel de Imóveis e Unidades
+
+
Gestão cadastral, georreferenciamento e auditoria
+
+
+
+
+
+
+
+
+
+
+
+ {/* KPIs */}
+
+
+
+
+
+
+
+
+ {/* Evolução */}
+
+ Evolução de Cadastros
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Distribuição por UF e Cidades */}
+
+
+ Imóveis por UF
+
+
+
+
+
+
+
+
+ {(data?.distribuicaoUF ?? []).map((_, i) => (
+ |
+ ))}
+
+
+
+
+
+
+
+ Top 10 Cidades
+
+
+
+
+
+
+
+
+ {(data?.distribuicaoCidade ?? []).map((_, i) => (
+ |
+ ))}
+
+
+
+
+
+
+
+ {/* Qualidade de Dados */}
+
+ Qualidade de Dados
+
+
+
+
+
+
+
+
+
Área média cadastrada
+
{data?.area.media.toFixed(1)} m²
+
+
+
+
+ {data?.qualidade.inconsistencias ?? 0} inconsistências
+
+
+
+
+
+
+ Fonte: VIEW VW_T_IMOVEL_ANALYTICS — fallback automático para mock.
+
+
+ )
+}
diff --git a/src/packages/administrativo/components/TPessoa/TPessoaDashboard.tsx b/src/packages/administrativo/components/TPessoa/TPessoaDashboard.tsx
new file mode 100644
index 0000000..c3128ca
--- /dev/null
+++ b/src/packages/administrativo/components/TPessoa/TPessoaDashboard.tsx
@@ -0,0 +1,506 @@
+'use client'
+
+import { motion } from "framer-motion";
+import { Building2, CalendarClock, Loader2, Mail, Users } from "lucide-react";
+import React, { useEffect, useMemo, useState } from "react";
+import {
+ Area,
+ AreaChart,
+ Bar,
+ BarChart,
+ CartesianGrid,
+ Cell,
+ Legend,
+ Pie,
+ PieChart,
+ ResponsiveContainer,
+ Tooltip,
+ XAxis,
+ YAxis,
+} from "recharts";
+
+import { Badge } from "@/components/ui/badge";
+import { Button } from "@/components/ui/button";
+import {
+ Card,
+ CardContent,
+ CardHeader,
+ CardTitle,
+} from "@/components/ui/card";
+import { Input } from "@/components/ui/input";
+import { Progress } from "@/components/ui/progress";
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
+
+
+// =====================
+// Types
+// =====================
+
+type SexoDistribuicao = { genero: string; total: number };
+
+type EvolucaoCadastro = { ano: number; mes: number; total: number };
+
+type CategoriaValor = { label: string; total: number };
+
+type Kpis = {
+ total: number;
+ fisicas: number;
+ juridicas: number;
+ mediaIdade: number | null;
+ pctCpfCnpjValidos: number;
+ pctEmailPreenchido: number;
+ novosMes: number;
+ tendenciaMes: number; // variação % em relação ao mês anterior
+};
+
+type Qualidade = {
+ email: number;
+ enderecoCompleto: number;
+ telefoneValido: number;
+ cpfInvalido: number; // quantidade
+};
+
+type ApiResponse = {
+ kpis: Kpis;
+ sexo: SexoDistribuicao[];
+ evolucao: EvolucaoCadastro[];
+ estadoCivil: CategoriaValor[];
+ faixasEtarias: CategoriaValor[];
+ profissoesTop10: CategoriaValor[];
+ ufDistribuicao: CategoriaValor[];
+ cidadesTop10: CategoriaValor[];
+ qualidade: Qualidade;
+};
+
+// =====================
+// Mock (fallback)
+// =====================
+
+const MOCK: ApiResponse = {
+ kpis: {
+ total: 12876,
+ fisicas: 11234,
+ juridicas: 1642,
+ mediaIdade: 39,
+ pctCpfCnpjValidos: 87.4,
+ pctEmailPreenchido: 91.2,
+ novosMes: 328,
+ tendenciaMes: 6.3,
+ },
+ sexo: [
+ { genero: "Masculino", total: 5840 },
+ { genero: "Feminino", total: 5210 },
+ { genero: "Não informado", total: 184 }
+ ],
+ evolucao: Array.from({ length: 12 }, (_, i) => ({ ano: 2025, mes: i + 1, total: 120 + i * 15 + (i % 2 === 0 ? 30 : 0) })),
+ estadoCivil: [
+ { label: "Solteiro(a)", total: 4312 },
+ { label: "Casado(a)", total: 5120 },
+ { label: "Divorciado(a)", total: 812 },
+ { label: "Viúvo(a)", total: 210 },
+ ],
+ faixasEtarias: [
+ { label: "<18", total: 420 },
+ { label: "18-30", total: 3420 },
+ { label: "31-45", total: 5180 },
+ { label: "46-60", total: 2780 },
+ { label: "60+", total: 1076 },
+ ],
+ profissoesTop10: [
+ { label: "Estudante", total: 780 },
+ { label: "Comerciante", total: 620 },
+ { label: "Professor(a)", total: 570 },
+ { label: "Autônomo(a)", total: 510 },
+ { label: "Servidor(a) Público(a)", total: 450 },
+ { label: "Engenheiro(a)", total: 430 },
+ { label: "Advogado(a)", total: 410 },
+ { label: "Médico(a)", total: 385 },
+ { label: "Enfermeiro(a)", total: 360 },
+ { label: "Agricultor(a)", total: 350 },
+ ],
+ ufDistribuicao: [
+ { label: "GO", total: 5080 },
+ { label: "DF", total: 1840 },
+ { label: "MG", total: 980 },
+ { label: "SP", total: 820 },
+ { label: "BA", total: 740 },
+ ],
+ cidadesTop10: [
+ { label: "Goiânia", total: 2200 },
+ { label: "Aparecida de Goiânia", total: 980 },
+ { label: "Anápolis", total: 640 },
+ { label: "Formosa", total: 510 },
+ { label: "Trindade", total: 480 },
+ { label: "Luziânia", total: 465 },
+ { label: "Catalão", total: 430 },
+ { label: "Rio Verde", total: 415 },
+ { label: "Itumbiara", total: 400 },
+ { label: "Jataí", total: 395 },
+ ],
+ qualidade: {
+ email: 91.2,
+ enderecoCompleto: 83.4,
+ telefoneValido: 77.9,
+ cpfInvalido: 248,
+ },
+};
+
+// =====================
+// Helpers
+// =====================
+
+const monthName = (m: number) => new Date(2025, m - 1, 1).toLocaleDateString("pt-BR", { month: "short" }).replace(".", "");
+
+async function fetchApi(periodo: string, uf: string | null, cidade: string | null): Promise {
+ const params = new URLSearchParams();
+ params.set("periodo", periodo); // ex: "12m", "24m", "ytd"
+ if (uf) params.set("uf", uf);
+ if (cidade) params.set("cidade", cidade);
+
+ try {
+ const ctrl = new AbortController();
+ const to = setTimeout(() => ctrl.abort(), 6000);
+ const res = await fetch(`/api/dashboard/pessoas?${params.toString()}`, { signal: ctrl.signal });
+ clearTimeout(to);
+ if (!res.ok) throw new Error("HTTP error");
+ const data = (await res.json()) as ApiResponse;
+ return data;
+ } catch {
+ // fallback para mock
+ return MOCK;
+ }
+}
+
+// =====================
+// Subcomponents
+// =====================
+
+function Kpi({ icon: Icon, label, value, hint, trend }: { icon: any; label: string; value: React.ReactNode; hint?: string; trend?: number }) {
+ const trendColor = trend == null ? "" : trend > 0 ? "text-emerald-600" : trend < 0 ? "text-rose-600" : "text-muted-foreground";
+ const trendPrefix = trend == null ? "" : trend > 0 ? "+" : "";
+ return (
+
+
+ {label}
+
+
+
+ {value}
+
+ {hint && {hint}}
+ {trend != null && (
+ {trendPrefix}{trend.toFixed(1)}%
+ )}
+
+
+
+ );
+}
+
+function Section({ title, description, children, right = null }: { title: string; description?: string; children: React.ReactNode; right?: React.ReactNode | null }) {
+ return (
+
+
+
+
{title}
+ {description &&
{description}
}
+
+ {right}
+
+ {children}
+
+ );
+}
+
+function DataProgress({ label, value, goal }: { label: string; value: number; goal: number }) {
+ const color = value >= goal ? "text-emerald-600" : "text-amber-600";
+ return (
+
+
+ {label}
+ {value.toFixed(1)}% (meta {goal}%)
+
+
+
+ );
+}
+
+// =====================
+// Main Component
+// =====================
+
+export default function TPessoaDashboard() {
+ const [periodo, setPeriodo] = useState("12m");
+ const [uf, setUf] = useState(null);
+ const [cidade, setCidade] = useState(null);
+ const [data, setData] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ setLoading(true);
+ fetchApi(periodo, uf, cidade).then((d) => {
+ setData(d);
+ setLoading(false);
+ });
+ }, [periodo, uf, cidade]);
+
+ const evolucaoFmt = useMemo(() => {
+ return (data?.evolucao ?? []).map((d) => ({
+ mes: `${monthName(d.mes)}/${String(d.ano).slice(2)}`,
+ total: d.total,
+ }));
+ }, [data]);
+
+ const sexoFmt = useMemo(() => (data?.sexo ?? []).map((s) => ({ name: s.genero, value: s.total })), [data]);
+
+ const COLORS = ["#0ea5e9", "#22c55e", "#a3a3a3", "#a78bfa", "#fb7185", "#fbbf24"]; // não fixa cores globais, apenas define fallback estável
+
+ return (
+
+ {/* Header */}
+
+
+
+ Painel de Pessoas
+
+
Análise demográfica, documental e cadastral
+
+
+
+
+
+
+
+ setCidade(e.target.value || null)} />
+
+
+
+
+
+ {/* KPIs */}
+
+ : data?.kpis.total.toLocaleString("pt-BR")} hint={`${data?.kpis.novosMes ?? 0} novos no mês`} trend={data?.kpis.tendenciaMes} />
+ : (data?.kpis.mediaIdade ?? 0)} hint="anos" />
+ : `${data?.kpis.pctCpfCnpjValidos.toFixed(1)}%`} />
+ : `${data?.kpis.pctEmailPreenchido.toFixed(1)}%`} />
+
+
+ {/* Evolução & Sexo */}
+
+
+
+ Evolução de Cadastros
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Distribuição por Sexo
+
+
+
+
+
+
+
+ {sexoFmt.map((entry, index) => (
+ |
+ ))}
+
+
+
+
+
+
+
+ {/* Estado Civil & Faixa etária */}
+
+
+
+ Estado Civil
+
+
+
+
+
+
+
+
+
+ {(data?.estadoCivil ?? []).map((_, i) => (
+ |
+ ))}
+
+
+
+
+
+
+
+
+ Faixas Etárias
+
+
+
+
+
+
+
+
+
+ {(data?.faixasEtarias ?? []).map((_, i) => (
+ |
+ ))}
+
+
+
+
+
+
+
+ {/* Geografia */}
+
+
+
+ Distribuição por UF
+
+
+
+
+
+
+
+
+
+ {(data?.ufDistribuicao ?? []).map((_, i) => (
+ |
+ ))}
+
+
+
+
+
+
+
+
+ Top 10 Cidades
+
+
+
+
+
+
+
+
+
+ {(data?.cidadesTop10 ?? []).map((_, i) => (
+ |
+ ))}
+
+
+
+
+
+
+
+ {/* Profissões */}
+
+
+
+
+
+
+
+
+
+
+ {(data?.profissoesTop10 ?? []).map((_, i) => (
+ |
+ ))}
+
+
+
+
+
+
+
+ {/* Qualidade de Dados */}
+
+
+
+ Cobertura
+
+
+
+
+
+
+
+
+ Indicadores
+
+
+ % CPF/CNPJ válidos
+ {data?.kpis.pctCpfCnpjValidos.toFixed(1)}%
+
+
+ % E-mail preenchido
+ {data?.kpis.pctEmailPreenchido.toFixed(1)}%
+
+
+ Registros com CPF inconsistente
+ {data?.qualidade.cpfInvalido.toLocaleString("pt-BR")}
+
+
+
+
+
+ Ações rápidas
+
+
+
+
+
+
+
+
+
+
Fonte de dados: API /api/dashboard/pessoas — fallback automático para mock se indisponível.
+
+ );
+}
diff --git a/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoColumns.tsx b/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoColumns.tsx
new file mode 100644
index 0000000..b48305c
--- /dev/null
+++ b/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoColumns.tsx
@@ -0,0 +1,78 @@
+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[] {
+ 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 (
+
+
+
+
+
+
+
+ onEdit(natureza, true)}>
+
+ Editar
+
+
+
+
+ onDelete(natureza, true)}
+ >
+
+ Remover
+
+
+
+
+ );
+ },
+ enableSorting: false,
+ enableHiding: false,
+ },
+ ];
+}
diff --git a/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoForm.tsx b/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoForm.tsx
new file mode 100644
index 0000000..babbdee
--- /dev/null
+++ b/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoForm.tsx
@@ -0,0 +1,205 @@
+'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 (
+
+ );
+}
diff --git a/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoIndex.tsx b/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoIndex.tsx
new file mode 100644
index 0000000..97eb904
--- /dev/null
+++ b/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoIndex.tsx
@@ -0,0 +1,161 @@
+'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(null);
+ const [isFormOpen, setIsFormOpen] = useState(false);
+
+ // Estado para saber qual item será deletado
+ const [itemToDelete, setItemToDelete] = useState(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 ;
+ }
+
+ return (
+
+ {/* Cabeçalho */}
+ {
+ handleOpenForm(null);
+ }}
+ />
+ {/* Tabela de andamentos */}
+
+ {/* Modal de confirmação */}
+ {isConfirmOpen && (
+
+ )}
+ {/* Formulário de criação/edição */}
+ {isFormOpen && (
+
+ )}
+
+ );
+}
diff --git a/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoResumo.tsx b/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoResumo.tsx
new file mode 100644
index 0000000..f284493
--- /dev/null
+++ b/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoResumo.tsx
@@ -0,0 +1,92 @@
+import { format } from "date-fns"
+import { ptBR } from "date-fns/locale"
+
+import { Badge } from "@/components/ui/badge"
+import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
+import { ScrollArea } from "@/components/ui/scroll-area"
+import { Separator } from "@/components/ui/separator"
+
+interface PedidoItem {
+ id: number
+ descricao: string
+ valor: number
+}
+
+interface PedidoResumoProps {
+ numeroPedido: number
+ dataPedido: string
+ itens: PedidoItem[]
+}
+
+export default function TServicoItemPedidoResumo({
+ numeroPedido,
+ dataPedido,
+ itens,
+}: PedidoResumoProps) {
+ const total = itens.reduce((acc, item) => acc + item.valor, 0)
+
+ return (
+
+
+
+ Pedido Nº {numeroPedido}
+
+ {format(new Date(dataPedido), "dd/MM/yyyy HH:mm", { locale: ptBR })}
+
+
+
+
+
+
+ {itens.map((item) => (
+
+
+ {item.descricao}
+
+
+ R$ {item.valor.toFixed(2).replace(".", ",")}
+
+
+ ))}
+
+
+
+
+
+
+ Total
+
+ R$ {total.toFixed(2).replace(".", ",")}
+
+
+
+ )
+}
diff --git a/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoTable.tsx b/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoTable.tsx
new file mode 100644
index 0000000..6e87f4d
--- /dev/null
+++ b/src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoTable.tsx
@@ -0,0 +1,23 @@
+'use client';
+
+import { DataTable } from '@/shared/components/dataTable/DataTable';
+
+import TServicoItemPedidoTableInterface from '../../interfaces/TServicoItemPedido/TServicoItemPedidoTableInterface';
+import TServicoItemPedidoColumns from './TServicoItemPedidoColumns';
+
+/**
+ * Componente principal da tabela de Naturezas
+ */
+export default function TServicoItemPedidoTable({ data, onEdit, onDelete }: TServicoItemPedidoTableInterface) {
+ const columns = TServicoItemPedidoColumns(onEdit, onDelete);
+ return (
+
+
+
+ );
+}
diff --git a/src/packages/servicos/components/TServicoPedido/TServicoPedidoColumns.tsx b/src/packages/servicos/components/TServicoPedido/TServicoPedidoColumns.tsx
new file mode 100644
index 0000000..7dc34b7
--- /dev/null
+++ b/src/packages/servicos/components/TServicoPedido/TServicoPedidoColumns.tsx
@@ -0,0 +1,78 @@
+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 TServicoPedidoInterface from '../../interfaces/TServicoPedido/TServicoPedidoInterface';
+
+export default function TServicoPedidoColumns(
+ onEdit: (item: TServicoPedidoInterface, isEditingFormStatus: boolean) => void,
+ onDelete: (item: TServicoPedidoInterface, isEditingFormStatus: boolean) => void,
+): ColumnDef[] {
+ 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 (
+
+
+
+
+
+
+
+ onEdit(natureza, true)}>
+
+ Editar
+
+
+
+
+ onDelete(natureza, true)}
+ >
+
+ Remover
+
+
+
+
+ );
+ },
+ enableSorting: false,
+ enableHiding: false,
+ },
+ ];
+}
diff --git a/src/packages/servicos/components/TServicoPedido/TServicoPedidoDashboard.tsx b/src/packages/servicos/components/TServicoPedido/TServicoPedidoDashboard.tsx
new file mode 100644
index 0000000..c0605e9
--- /dev/null
+++ b/src/packages/servicos/components/TServicoPedido/TServicoPedidoDashboard.tsx
@@ -0,0 +1,318 @@
+'use client'
+
+import { motion } from 'framer-motion'
+import {
+ Activity,
+ AlertTriangle,
+ DollarSign,
+ FileText, Layers,
+ Loader2
+} from 'lucide-react'
+import { useEffect, useState } from 'react'
+import {
+ Bar,
+ BarChart,
+ CartesianGrid,
+ Cell,
+ Legend,
+ Line,
+ LineChart,
+ Pie,
+ PieChart,
+ ResponsiveContainer,
+ Tooltip,
+ XAxis, YAxis
+} from 'recharts'
+
+import { Badge } from '@/components/ui/badge'
+import {
+ Card,
+ CardContent,
+ CardHeader,
+ CardTitle
+} from '@/components/ui/card'
+import { Progress } from '@/components/ui/progress'
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
+
+
+// ========================
+// Tipos
+// ========================
+
+type Kpis = {
+ totalPedidos: number
+ totalItens: number
+ valorTotalPedidos: number
+ valorTotalPago: number
+ mediaDiferenca: number
+}
+
+type Evolucao = { mes: string; totalPedidos: number; somaPedidos: number }
+
+type Situacao = { status: string; total: number }
+
+type ServicoTipo = { servico_tipo: string; total: number; valor_total: number }
+
+type Receita = { tipo: string; valor: number }
+
+type Produtividade = { escrevente: string; totalPedidos: number; valorTotal: number }
+
+type Qualidade = { itensSemValor: number; pedidosSemData: number; itensSemTipo: number }
+
+type DashboardResponse = {
+ kpis: Kpis
+ evolucao: Evolucao[]
+ situacoes: Situacao[]
+ tiposServico: ServicoTipo[]
+ receitas: Receita[]
+ produtividade: Produtividade[]
+ certidoesPorMes: { mes: string; total: number }[]
+ qualidade: Qualidade
+}
+
+// ========================
+// Mock (fallback)
+// ========================
+
+const MOCK: DashboardResponse = {
+ kpis: {
+ totalPedidos: 1845,
+ totalItens: 5630,
+ valorTotalPedidos: 425000,
+ valorTotalPago: 413200,
+ mediaDiferenca: 6.3,
+ },
+ evolucao: Array.from({ length: 12 }, (_, i) => ({
+ mes: new Date(2025, i).toLocaleString('pt-BR', { month: 'short' }),
+ totalPedidos: 100 + i * 20,
+ somaPedidos: 25000 + i * 3000
+ })),
+ situacoes: [
+ { status: 'Ativo', total: 1240 },
+ { status: 'Finalizado', total: 480 },
+ { status: 'Cancelado', total: 125 },
+ ],
+ tiposServico: [
+ { servico_tipo: 'Certidão', total: 3100, valor_total: 135000 },
+ { servico_tipo: 'Registro', total: 1800, valor_total: 98000 },
+ { servico_tipo: 'Averbação', total: 730, valor_total: 46000 },
+ { servico_tipo: 'Outros', total: 200, valor_total: 12000 },
+ ],
+ receitas: [
+ { tipo: 'Emolumentos', valor: 135000 },
+ { tipo: 'Fundesp', valor: 28000 },
+ { tipo: 'Taxa Judiciária', valor: 8000 },
+ { tipo: 'ISS', valor: 12500 },
+ ],
+ produtividade: [
+ { escrevente: 'João Silva', totalPedidos: 420, valorTotal: 82000 },
+ { escrevente: 'Maria Souza', totalPedidos: 380, valorTotal: 76000 },
+ { escrevente: 'Carlos Lima', totalPedidos: 300, valorTotal: 69000 },
+ ],
+ certidoesPorMes: Array.from({ length: 12 }, (_, i) => ({
+ mes: new Date(2025, i).toLocaleString('pt-BR', { month: 'short' }),
+ total: 60 + i * 10
+ })),
+ qualidade: {
+ itensSemValor: 14,
+ pedidosSemData: 9,
+ itensSemTipo: 6
+ }
+}
+
+// ========================
+// Helper (mock fetch)
+// ========================
+
+async function fetchDashboard(): Promise {
+ try {
+ const res = await fetch('/api/dashboard/servicos')
+ if (!res.ok) throw new Error('Erro HTTP')
+ return await res.json()
+ } catch {
+ return MOCK
+ }
+}
+
+// ========================
+// Componente principal
+// ========================
+
+export default function TServicoPedidoDashboard() {
+ const [periodo, setPeriodo] = useState('12m')
+ const [data, setData] = useState(null)
+ const [loading, setLoading] = useState(true)
+
+ useEffect(() => {
+ setLoading(true)
+ fetchDashboard().then((d) => {
+ setData(d)
+ setLoading(false)
+ })
+ }, [periodo])
+
+ const COLORS = ['#1A292F', '#8FB6C1', '#D1E6EA', '#F36F28', '#EAECEA']
+
+ return (
+
+ {/* Header */}
+
+
+
+ Dashboard — Serviços e Pedidos
+
+
Análise operacional, financeira e produtiva
+
+
+
+
+
+ {/* KPIs */}
+
+
+
+
+
+
+
+
+ {/* Evolução temporal */}
+
+ Evolução de Pedidos
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Situação */}
+
+ Pedidos por Situação
+
+
+
+
+
+ {(data?.situacoes ?? []).map((_, i) => (
+ |
+ ))}
+
+
+
+
+
+
+ {/* Tipos de serviço */}
+
+ Distribuição por Tipo de Serviço
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Receitas */}
+
+ Receitas (Emolumentos e Taxas)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Produtividade */}
+
+ Produtividade por Escrevente
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Qualidade */}
+
+ Qualidade de Dados
+
+
+
+
+
+
+
+
+ Fonte: VIEW VW_T_SERVICO_ANALYTICS — fallback automático para mock.
+
+
+ )
+}
+
+// ========================
+// Subcomponentes
+// ========================
+
+function Kpi({ icon: Icon, label, value }: { icon: any; label: string; value: any }) {
+ return (
+
+
+ {label}
+
+
+ {value ?? }
+
+ )
+}
+
+function Quality({ label, value }: { label: string; value: number }) {
+ const pct = Math.min(100, (value / 50) * 100)
+ return (
+
+
{label}
+
+
0 ? 'destructive' : 'outline'}>{value}
+
+ )
+}
+
+function formatCurrency(v?: number) {
+ if (!v) return 'R$ 0,00'
+ return v.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' })
+}
diff --git a/src/packages/servicos/components/TServicoPedido/TServicoPedidoForm.tsx b/src/packages/servicos/components/TServicoPedido/TServicoPedidoForm.tsx
new file mode 100644
index 0000000..ea3e993
--- /dev/null
+++ b/src/packages/servicos/components/TServicoPedido/TServicoPedidoForm.tsx
@@ -0,0 +1,110 @@
+'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 { 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) {
+ const form = useTServicoPedidoFormHook({});
+
+ // 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 (
+
+ );
+}
diff --git a/src/packages/servicos/components/TServicoPedido/TServicoPedidoIndex.tsx b/src/packages/servicos/components/TServicoPedido/TServicoPedidoIndex.tsx
new file mode 100644
index 0000000..dedf0e0
--- /dev/null
+++ b/src/packages/servicos/components/TServicoPedido/TServicoPedidoIndex.tsx
@@ -0,0 +1,153 @@
+'use client';
+
+import { useCallback, useEffect, useState } from 'react';
+
+
+import { useTServicoPedidoDeleteHook } from '@/packages/servicos/hooks/TServicoPedido/useTServicoPedidoDeleteHook';
+import { useTServicoPedidoIndexHook } from '@/packages/servicos/hooks/TServicoPedido/useTServicoPedidoIndexHook';
+import { useTServicoPedidoSaveHook } from '@/packages/servicos/hooks/TServicoPedido/useTServicoPedidoSaveHook';
+import TServicoPedidoInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface';
+import ConfirmDialog from '@/shared/components/confirmDialog/ConfirmDialog';
+import { useConfirmDialog } from '@/shared/components/confirmDialog/useConfirmDialog';
+import Header from '@/shared/components/structure/Header';
+
+import TServicoPedidoForm from './TServicoPedidoForm';
+import TServicoPedidoTable from './TServicoPedidoTable';
+
+export default function TServicoPedidoIndex() {
+
+ // Controle de estado do botão
+ const [buttonIsLoading, setButtonIsLoading] = useState(false);
+
+ // Hooks para leitura e salvamento
+ const { TServicoPedido, indexTServicoPedido } = useTServicoPedidoIndexHook();
+ const { saveTServicoPedido } = useTServicoPedidoSaveHook();
+ const { deleteTServicoPedido } = useTServicoPedidoDeleteHook();
+
+ // Estados
+ const [selectedData, setSelectedData] = useState(null);
+ const [isFormOpen, setIsFormOpen] = useState(false);
+
+ // Estado para saber qual item será deletado
+ const [itemToDelete, setItemToDelete] = useState(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: TServicoPedidoInterface | 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: TServicoPedidoInterface) => {
+ // Coloca o botão em estado de loading
+ setButtonIsLoading(true);
+
+ // Aguarda salvar o registro
+ await saveTServicoPedido(formData);
+
+ // Remove o botão em estado de loading
+ setButtonIsLoading(false);
+
+ // Atualiza a lista de dados
+ indexTServicoPedido();
+ },
+ [saveTServicoPedido, indexTServicoPedido, handleCloseForm],
+ );
+
+ /**
+ * Quando o usuário clica em "remover" na tabela
+ */
+ const handleConfirmDelete = useCallback(
+ (item: TServicoPedidoInterface) => {
+ // 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 deleteTServicoPedido(itemToDelete);
+
+ // Atualiza a lista
+ await indexTServicoPedido();
+
+ // Limpa o item selecionado
+ setItemToDelete(null);
+
+ // Fecha o modal
+ handleCancel();
+ }, [itemToDelete, indexTServicoPedido, handleCancel]);
+
+ /**
+ * Busca inicial dos dados
+ */
+ useEffect(() => {
+ // indexTServicoPedido();
+ }, []);
+
+ return (
+
+ {/* Cabeçalho */}
+ {
+ handleOpenForm(null);
+ }}
+ />
+ {/* Tabela de andamentos */}
+
+ {/* Modal de confirmação */}
+ {isConfirmOpen && (
+
+ )}
+ {/* Formulário de criação/edição */}
+ {isFormOpen && (
+
+ )}
+
+ );
+}
diff --git a/src/packages/servicos/components/TServicoPedido/TServicoPedidoTable.tsx b/src/packages/servicos/components/TServicoPedido/TServicoPedidoTable.tsx
new file mode 100644
index 0000000..db4d5c9
--- /dev/null
+++ b/src/packages/servicos/components/TServicoPedido/TServicoPedidoTable.tsx
@@ -0,0 +1,23 @@
+'use client';
+
+import { DataTable } from '@/shared/components/dataTable/DataTable';
+
+import TServicoPedidoTableInterface from '../../interfaces/TServicoPedido/TServicoPedidoTableInterface';
+import TServicoPedidoColumns from './TServicoPedidoColumns';
+
+/**
+ * Componente principal da tabela de Naturezas
+ */
+export default function TServicoPedidoTable({ data, onEdit, onDelete }: TServicoPedidoTableInterface) {
+ const columns = TServicoPedidoColumns(onEdit, onDelete);
+ return (
+
+
+
+ );
+}
diff --git a/src/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoDeleteData.ts b/src/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoDeleteData.ts
new file mode 100644
index 0000000..264828e
--- /dev/null
+++ b/src/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoDeleteData.ts
@@ -0,0 +1,16 @@
+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 executeTServicoItemPedidoDeleteData(data: TServicoItemPedidoInterface): Promise {
+ const api = new API();
+ return api.send({
+ method: Methods.DELETE,
+ endpoint: `servicos/t_servico_itempedido/${data.servico_itempedido_id}`,
+ });
+}
+
+export const TServicoItemPedidoDeleteData = withClientErrorHandler(executeTServicoItemPedidoDeleteData);
diff --git a/src/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoIndexData.ts b/src/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoIndexData.ts
new file mode 100644
index 0000000..db1e311
--- /dev/null
+++ b/src/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoIndexData.ts
@@ -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 executeTServicoItemPedidoIndexData(): Promise {
+ const api = new API();
+
+ return api.send({
+ method: Methods.GET,
+ endpoint: `servicos/t_servico_itempedido/`,
+ });
+}
+
+export const TServicoItemPedidoIndexData = withClientErrorHandler(executeTServicoItemPedidoIndexData);
diff --git a/src/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoSaveData.ts b/src/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoSaveData.ts
new file mode 100644
index 0000000..9912cf9
--- /dev/null
+++ b/src/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoSaveData.ts
@@ -0,0 +1,23 @@
+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 executeTServicoItemPedidoSaveData(data: TServicoItemPedidoInterface): Promise {
+ // Verifica se existe ID para decidir se é atualização (PUT) ou criação (POST)
+ const isUpdate = Boolean(data.servico_itempedido_id);
+
+ // Instancia o cliente da API
+ const api = new API();
+
+ // 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: `servicos/t_servico_itempedido/${data.servico_itempedido_id || ''}`, // endpoint dinâmico
+ body: data, // payload enviado para a API
+ });
+}
+
+export const TServicoItemPedidoSaveData = withClientErrorHandler(executeTServicoItemPedidoSaveData);
diff --git a/src/packages/servicos/data/TServicoPedido/TServicoPedidoDeleteData.ts b/src/packages/servicos/data/TServicoPedido/TServicoPedidoDeleteData.ts
new file mode 100644
index 0000000..226517a
--- /dev/null
+++ b/src/packages/servicos/data/TServicoPedido/TServicoPedidoDeleteData.ts
@@ -0,0 +1,17 @@
+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 TServicoPedidoInterface from '../../interfaces/TServicoPedido/TServicoPedidoInterface';
+
+async function executeTServicoPedidoDeleteData(data: TServicoPedidoInterface): Promise {
+ const api = new API();
+
+ return api.send({
+ method: Methods.DELETE,
+ endpoint: `servico/t_servico_pedido/${data.servico_pedido_id}`,
+ });
+}
+
+export const TServicoPedidoDeleteData = withClientErrorHandler(executeTServicoPedidoDeleteData);
diff --git a/src/packages/servicos/data/TServicoPedido/TServicoPedidoIndexData.ts b/src/packages/servicos/data/TServicoPedido/TServicoPedidoIndexData.ts
new file mode 100644
index 0000000..5cfa3e9
--- /dev/null
+++ b/src/packages/servicos/data/TServicoPedido/TServicoPedidoIndexData.ts
@@ -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 executeTServicoPedidoIndexData(): Promise {
+ const api = new API();
+
+ return api.send({
+ method: Methods.GET,
+ endpoint: `servico/t_servico_pedido/`,
+ });
+}
+
+export const TServicoPedidoIndexData = withClientErrorHandler(executeTServicoPedidoIndexData);
diff --git a/src/packages/servicos/data/TServicoPedido/TServicoPedidoSaveData.ts b/src/packages/servicos/data/TServicoPedido/TServicoPedidoSaveData.ts
new file mode 100644
index 0000000..f3eed76
--- /dev/null
+++ b/src/packages/servicos/data/TServicoPedido/TServicoPedidoSaveData.ts
@@ -0,0 +1,23 @@
+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 TServicoPedidoInterface from '../../interfaces/TServicoPedido/TServicoPedidoInterface';
+
+async function executeTServicoPedidoSaveData(data: TServicoPedidoInterface): Promise {
+ // Verifica se existe ID para decidir se é atualização (PUT) ou criação (POST)
+ const isUpdate = Boolean(data.servico_pedido_id);
+
+ // Instancia o cliente da API
+ const api = new API();
+
+ // 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
+ body: data, // payload enviado para a API
+ });
+}
+
+export const TServicoPedidoSaveData = withClientErrorHandler(executeTServicoPedidoSaveData);
diff --git a/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoDeleteHook.ts b/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoDeleteHook.ts
new file mode 100644
index 0000000..7722e32
--- /dev/null
+++ b/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoDeleteHook.ts
@@ -0,0 +1,21 @@
+import { useState } from 'react';
+
+import { useResponse } from '@/shared/components/response/ResponseContext';
+
+import TServicoItemPedidoInterface from '../../interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
+import { TServicoItemPedidoDeleteService } from '../../services/TServicoItemPedido/TServicoItemPedidoDeleteService';
+
+export const useTServicoItemPedidoDeleteHook = () => {
+ const { setResponse } = useResponse();
+
+ const [TServicoItemPedido, setTServicoItemPedido] = useState();
+
+ const deleteTServicoItemPedido = async (data: TServicoItemPedidoInterface) => {
+ const response = await TServicoItemPedidoDeleteService(data);
+
+ setTServicoItemPedido(data);
+ setResponse(response);
+ };
+
+ return { TServicoItemPedido, deleteTServicoItemPedido };
+};
diff --git a/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoFormHook.ts b/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoFormHook.ts
new file mode 100644
index 0000000..760f1d2
--- /dev/null
+++ b/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoFormHook.ts
@@ -0,0 +1,14 @@
+import { zodResolver } from '@hookform/resolvers/zod';
+import { useForm } from 'react-hook-form';
+
+import { TServicoItemPedidoFormValues, TServicoItemPedidoSchema } from '../../schemas/TServicoItemPedido/TServicoItemPedidoSchema';
+
+export function useTServicoItemPedidoFormHook(defaults?: Partial) {
+ return useForm({
+ resolver: zodResolver(TServicoItemPedidoSchema),
+ defaultValues: {
+ servico_itempedido_id: 0,
+ ...defaults,
+ },
+ });
+}
diff --git a/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoIndexHook.ts b/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoIndexHook.ts
new file mode 100644
index 0000000..002c56d
--- /dev/null
+++ b/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoIndexHook.ts
@@ -0,0 +1,28 @@
+'use client';
+
+import { useState } from 'react';
+
+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([]);
+
+ const indexTServicoItemPedido = async () => {
+ const response = await TServicoItemPedidoIndexService();
+ // Armazena os dados consultados
+ setTServicoItemPedido(response.data);
+ // Define a resposta (toast, modal, feedback, etc.)
+ setResponse(response);
+ };
+
+ return {
+ TServicoItemPedido,
+ indexTServicoItemPedido,
+ };
+};
diff --git a/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoSaveHook.ts b/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoSaveHook.ts
new file mode 100644
index 0000000..0ba40a2
--- /dev/null
+++ b/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoSaveHook.ts
@@ -0,0 +1,35 @@
+'use client';
+
+import { useState } from 'react';
+
+import { useResponse } from '@/shared/components/response/ResponseContext';
+
+import TServicoItemPedidoInterface from '../../interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
+import { TServicoItemPedidoSaveService } from '../../services/TServicoItemPedido/TServicoItemPedidoSaveService';
+
+export const useTServicoItemPedidoSaveHook = () => {
+ const { setResponse } = useResponse();
+
+ const [TServicoItemPedido, setTServicoItemPedido] = useState(null);
+
+ // controla se o formulário está aberto ou fechado
+ const [isOpen, setIsOpen] = useState(false);
+
+ const saveTServicoItemPedido = async (data: TServicoItemPedidoInterface) => {
+ const response = await TServicoItemPedidoSaveService(data);
+
+ // Armazena os dados da resposta
+ setTServicoItemPedido(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 { TServicoItemPedido, saveTServicoItemPedido, isOpen, setIsOpen };
+};
diff --git a/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoDeleteHook.ts b/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoDeleteHook.ts
new file mode 100644
index 0000000..f8f0476
--- /dev/null
+++ b/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoDeleteHook.ts
@@ -0,0 +1,17 @@
+import { useState } from 'react';
+
+import { useResponse } from '@/shared/components/response/ResponseContext';
+
+import TServicoPedidoInterface from '../../interfaces/TServicoPedido/TServicoPedidoInterface';
+import { TServicoPedidoDeleteService } from '../../services/TServicoPedido/TServicoPedidoDeleteService';
+
+export const useTServicoPedidoDeleteHook = () => {
+ const { setResponse } = useResponse();
+ const [TServicoPedido, setTServicoPedido] = useState();
+ const deleteTServicoPedido = async (data: TServicoPedidoInterface) => {
+ const response = await TServicoPedidoDeleteService(data);
+ setTServicoPedido(data);
+ setResponse(response);
+ };
+ return { TServicoPedido, deleteTServicoPedido };
+};
diff --git a/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoFormHook.ts b/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoFormHook.ts
new file mode 100644
index 0000000..697c882
--- /dev/null
+++ b/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoFormHook.ts
@@ -0,0 +1,14 @@
+import { zodResolver } from '@hookform/resolvers/zod';
+import { useForm } from 'react-hook-form';
+
+import { TServicoPedidoFormValues, TServicoPedidoSchema } from '../../schemas/TServicoPedido/TServicoPedidoSchema';
+
+export function useTServicoPedidoFormHook(defaults?: Partial) {
+ return useForm({
+ resolver: zodResolver(TServicoPedidoSchema),
+ defaultValues: {
+ servico_pedido_id: 0,
+ ...defaults,
+ },
+ });
+}
diff --git a/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoIndexHook.ts b/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoIndexHook.ts
new file mode 100644
index 0000000..88f9491
--- /dev/null
+++ b/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoIndexHook.ts
@@ -0,0 +1,27 @@
+'use client';
+
+import { useState } from 'react';
+
+import { useResponse } from '@/shared/components/response/ResponseContext';
+
+import TServicoPedidoInterface from '../../interfaces/TServicoPedido/TServicoPedidoInterface';
+import { TServicoPedidoIndexService } from '../../services/TServicoPedido/TServicoPedidoIndexService';
+
+export const useTServicoPedidoIndexHook = () => {
+ const { setResponse } = useResponse();
+
+ const [TServicoPedido, setTServicoPedido] = useState([]);
+
+ const indexTServicoPedido = async () => {
+ const response = await TServicoPedidoIndexService();
+ // Armazena os dados consultados
+ setTServicoPedido(response.data);
+ // Define a resposta (toast, modal, feedback, etc.)
+ setResponse(response);
+ };
+
+ return {
+ TServicoPedido,
+ indexTServicoPedido,
+ };
+};
diff --git a/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoSaveHook.ts b/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoSaveHook.ts
new file mode 100644
index 0000000..8883f3b
--- /dev/null
+++ b/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoSaveHook.ts
@@ -0,0 +1,35 @@
+'use client';
+
+import { useState } from 'react';
+
+import { useResponse } from '@/shared/components/response/ResponseContext';
+
+import TServicoPedidoInterface from '../../interfaces/TServicoPedido/TServicoPedidoInterface';
+import { TServicoPedidoSaveService } from '../../services/TServicoPedido/TServicoPedidoSaveService';
+
+export const useTServicoPedidoSaveHook = () => {
+ const { setResponse } = useResponse();
+
+ const [TServicoPedido, setTServicoPedido] = useState(null);
+
+ // controla se o formulário está aberto ou fechado
+ const [isOpen, setIsOpen] = useState(false);
+
+ const saveTServicoPedido = async (data: TServicoPedidoInterface) => {
+ const response = await TServicoPedidoSaveService(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, saveTServicoPedido, isOpen, setIsOpen };
+};
diff --git a/src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoFormInterface.ts b/src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoFormInterface.ts
new file mode 100644
index 0000000..e418f33
--- /dev/null
+++ b/src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoFormInterface.ts
@@ -0,0 +1,9 @@
+import { TServicoItemPedidoFormValues } from '../../schemas/TServicoItemPedido/TServicoItemPedidoSchema';
+
+export interface TServicoItemPedidoFormInterface {
+ isOpen: boolean;
+ data: TServicoItemPedidoFormValues | null;
+ onClose: (item: null, isFormStatus: boolean) => void;
+ onSave: (data: TServicoItemPedidoFormValues) => void;
+ buttonIsLoading: boolean;
+}
diff --git a/src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce.ts b/src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce.ts
new file mode 100644
index 0000000..d4dec7c
--- /dev/null
+++ b/src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce.ts
@@ -0,0 +1,66 @@
+export default interface TServicoItemPedidoInterface {
+ servico_itempedido_id?: number
+ servico_pedido_id?: number
+ servico_tipo_id?: number
+ valor?: number
+ qtd?: number
+ pessoa_id?: number
+ impressao_etiqueta?: string
+ situacao?: string
+ etiqueta_numero?: number
+ pessoa_auxiliar_id?: number
+ pessoa_sp_abono_rep?: string
+ tipo_item?: string
+ imprimir?: string
+ observacao?: string
+ impressao_direta?: string
+ selo_livro_id?: number
+ emolumento?: number
+ fundesp?: number
+ taxa_judiciaria?: number
+ desconto?: number
+ desc_complementar?: string
+ valor_manual?: string
+ valor_documento?: number
+ outra_taxa1?: number
+ emolumento_item_id?: number
+ certidao_impressa?: string
+ certidao_ato_id?: number
+ emolumento_id?: number
+ certidao_previsao?: string | Date
+ certidao_ato_antigo?: string
+ certidao_data_emissao?: string | Date
+ certidao_texto?: string | null // BLOB -> texto longo ou base64
+ ato_antigo_tipo?: string
+ valor_iss?: number
+ id_ato_isentado?: number
+ motivo_isencao?: string
+ pessoas_etiquetas?: number
+ abonador?: string
+ servico_cartao?: string
+ valor_informacoes_centrais?: number
+ situacao_diferido?: string
+ sigla_numero?: string
+ motivo_diferido?: string
+ nome_juridico?: string
+ etiqueta_apenas_frente?: string
+ indexacao_id?: number
+ certidao_data_lavratura?: string | Date
+ nfse_id?: number
+ qtd_pagina_certidao?: number
+ placa?: string
+ dut?: string
+ etiqueta_unica?: string
+ fundo_abonador?: string
+ instrumento_publico?: string
+ data_lavratura_abono?: string | Date
+ valor_base_calculo?: number
+ valor_avaliacao?: number
+ ato_abonado?: number
+ transferencia_veiculo?: string
+ usar_a4?: string
+ cpf_abono_rep?: string
+ vrcext?: number
+ valor_fundo_selo?: number
+ averbacao?: string
+}
diff --git a/src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoTableInterface.ts b/src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoTableInterface.ts
new file mode 100644
index 0000000..abff7e9
--- /dev/null
+++ b/src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoTableInterface.ts
@@ -0,0 +1,7 @@
+import TServicoItemPedidoInterface from "./TServicoItemPedidoIntefarce";
+
+export default interface TServicoItemPedidoTableInterface {
+ data?: TServicoItemPedidoInterface[];
+ onEdit: (item: TServicoItemPedidoInterface, isEditingFormStatus: boolean) => void;
+ onDelete: (item: TServicoItemPedidoInterface, isEditingFormStatus: boolean) => void;
+}
diff --git a/src/packages/servicos/interfaces/TServicoPedido/TServicoPedidoFormInterface.ts b/src/packages/servicos/interfaces/TServicoPedido/TServicoPedidoFormInterface.ts
new file mode 100644
index 0000000..cd375ef
--- /dev/null
+++ b/src/packages/servicos/interfaces/TServicoPedido/TServicoPedidoFormInterface.ts
@@ -0,0 +1,9 @@
+import { TServicoPedidoFormValues } from '../../schemas/TServicoPedido/TServicoPedidoSchema';
+
+export interface TServicoPedidoFormInterface {
+ isOpen: boolean;
+ data: TServicoPedidoFormValues | null;
+ onClose: (item: null, isFormStatus: boolean) => void;
+ onSave: (data: TServicoPedidoFormValues) => void;
+ buttonIsLoading: boolean;
+}
diff --git a/src/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface.ts b/src/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface.ts
new file mode 100644
index 0000000..c2e3d06
--- /dev/null
+++ b/src/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface.ts
@@ -0,0 +1,15 @@
+export default interface TServicoPedidoInterface {
+ servico_pedido_id?: number;
+ valor_pedido?: number;
+ valor_pago?: number;
+ usuario_id?: number;
+ data_pedido?: string;
+ mensalista_livrocaixa_id?: number;
+ observacao?: string;
+ escrevente_id?: number;
+ situacao?: string;
+ estornado?: string;
+ apresentante?: string;
+ nfse_id?: number;
+ cpfcnpj_apresentante?: string;
+}
\ No newline at end of file
diff --git a/src/packages/servicos/interfaces/TServicoPedido/TServicoPedidoTableInterface.ts b/src/packages/servicos/interfaces/TServicoPedido/TServicoPedidoTableInterface.ts
new file mode 100644
index 0000000..e11f147
--- /dev/null
+++ b/src/packages/servicos/interfaces/TServicoPedido/TServicoPedidoTableInterface.ts
@@ -0,0 +1,7 @@
+import TServicoPedidoInterface from './TServicoPedidoInterface';
+
+export default interface TServicoPedidoTableInterface {
+ data?: TServicoPedidoInterface[];
+ onEdit: (item: TServicoPedidoInterface, isEditingFormStatus: boolean) => void;
+ onDelete: (item: TServicoPedidoInterface, isEditingFormStatus: boolean) => void;
+}
diff --git a/src/packages/servicos/schemas/TServicoItemPedido/TServicoItemPedidoSchema.ts b/src/packages/servicos/schemas/TServicoItemPedido/TServicoItemPedidoSchema.ts
new file mode 100644
index 0000000..89bfc54
--- /dev/null
+++ b/src/packages/servicos/schemas/TServicoItemPedido/TServicoItemPedidoSchema.ts
@@ -0,0 +1,70 @@
+import z from "zod"
+
+export const TServicoItemPedidoSchema = z.object({
+ servico_itempedido_id: z.number().optional(),
+ servico_pedido_id: z.number().optional(),
+ servico_tipo_id: z.number().optional(),
+ valor: z.number().optional(),
+ qtd: z.number().optional(),
+ pessoa_id: z.number().optional(),
+ impressao_etiqueta: z.string().optional(),
+ situacao: z.string().optional(),
+ etiqueta_numero: z.number().optional(),
+ pessoa_auxiliar_id: z.number().optional(),
+ pessoa_sp_abono_rep: z.string().optional(),
+ tipo_item: z.string().optional(),
+ imprimir: z.string().optional(),
+ observacao: z.string().optional(),
+ impressao_direta: z.string().optional(),
+ selo_livro_id: z.number().optional(),
+ emolumento: z.number().optional(),
+ fundesp: z.number().optional(),
+ taxa_judiciaria: z.number().optional(),
+ desconto: z.number().optional(),
+ desc_complementar: z.string().optional(),
+ valor_manual: z.string().optional(),
+ valor_documento: z.number().optional(),
+ outra_taxa1: z.number().optional(),
+ emolumento_item_id: z.number().optional(),
+ certidao_impressa: z.string().optional(),
+ certidao_ato_id: z.number().optional(),
+ emolumento_id: z.number().optional(),
+ certidao_previsao: z.union([z.string(), z.date()]).optional(),
+ certidao_ato_antigo: z.string().optional(),
+ certidao_data_emissao: z.union([z.string(), z.date()]).optional(),
+ certidao_texto: z.string().nullable().optional(),
+ ato_antigo_tipo: z.string().optional(),
+ valor_iss: z.number().optional(),
+ id_ato_isentado: z.number().optional(),
+ motivo_isencao: z.string().optional(),
+ pessoas_etiquetas: z.number().optional(),
+ abonador: z.string().optional(),
+ servico_cartao: z.string().optional(),
+ valor_informacoes_centrais: z.number().optional(),
+ situacao_diferido: z.string().optional(),
+ sigla_numero: z.string().optional(),
+ motivo_diferido: z.string().optional(),
+ nome_juridico: z.string().optional(),
+ etiqueta_apenas_frente: z.string().optional(),
+ indexacao_id: z.number().optional(),
+ certidao_data_lavratura: z.union([z.string(), z.date()]).optional(),
+ nfse_id: z.number().optional(),
+ qtd_pagina_certidao: z.number().optional(),
+ placa: z.string().optional(),
+ dut: z.string().optional(),
+ etiqueta_unica: z.string().optional(),
+ fundo_abonador: z.string().optional(),
+ instrumento_publico: z.string().optional(),
+ data_lavratura_abono: z.union([z.string(), z.date()]).optional(),
+ valor_base_calculo: z.number().optional(),
+ valor_avaliacao: z.number().optional(),
+ ato_abonado: z.number().optional(),
+ transferencia_veiculo: z.string().optional(),
+ usar_a4: z.string().optional(),
+ cpf_abono_rep: z.string().optional(),
+ vrcext: z.number().optional(),
+ valor_fundo_selo: z.number().optional(),
+ averbacao: z.string().optional(),
+})
+
+export type TServicoItemPedidoFormValues = z.infer
diff --git a/src/packages/servicos/schemas/TServicoPedido/TServicoPedidoSchema.ts b/src/packages/servicos/schemas/TServicoPedido/TServicoPedidoSchema.ts
new file mode 100644
index 0000000..8fffc16
--- /dev/null
+++ b/src/packages/servicos/schemas/TServicoPedido/TServicoPedidoSchema.ts
@@ -0,0 +1,19 @@
+import z from "zod";
+
+export const TServicoPedidoSchema = z.object({
+ servico_pedido_id: z.number().optional,
+ valor_pedido: z.number().optional,
+ valor_pago: z.number().optional,
+ usuario_id: z.number().optional,
+ data_pedido: z.string().optional,
+ mensalista_livrocaixa_id: z.number().optional,
+ observacao: z.string().optional,
+ escrevente_id: z.number().optional,
+ situacao: z.string().optional,
+ estornado: z.string().optional,
+ apresentante: z.string().optional,
+ nfse_id: z.number().optional,
+ cpfcnpj_apresentante: z.string().optional,
+});
+
+export type TServicoPedidoFormValues = z.infer;
\ No newline at end of file
diff --git a/src/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoDeleteService.ts b/src/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoDeleteService.ts
new file mode 100644
index 0000000..fe5f7cd
--- /dev/null
+++ b/src/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoDeleteService.ts
@@ -0,0 +1,14 @@
+
+import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
+
+import { TServicoItemPedidoDeleteData } from '../../data/TServicoItemPedido/TServicoItemPedidoDeleteData';
+import TServicoItemPedidoInterface from '../../interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
+
+
+async function executeTServicoItemPedidoDeleteService(data: TServicoItemPedidoInterface) {
+ const response = await TServicoItemPedidoDeleteData(data);
+
+ return response;
+}
+
+export const TServicoItemPedidoDeleteService = withClientErrorHandler(executeTServicoItemPedidoDeleteService);
diff --git a/src/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoIndexService.ts b/src/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoIndexService.ts
new file mode 100644
index 0000000..37403fd
--- /dev/null
+++ b/src/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoIndexService.ts
@@ -0,0 +1,10 @@
+import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
+
+import { TServicoItemPedidoIndexData } from '../../data/TServicoItemPedido/TServicoItemPedidoIndexData';
+
+export default async function executeTServicoItemPedidoIndexService() {
+ const response = await TServicoItemPedidoIndexData();
+ return response;
+}
+
+export const TServicoItemPedidoIndexService = withClientErrorHandler(executeTServicoItemPedidoIndexService);
diff --git a/src/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoSaveService.ts b/src/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoSaveService.ts
new file mode 100644
index 0000000..080ded3
--- /dev/null
+++ b/src/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoSaveService.ts
@@ -0,0 +1,12 @@
+import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
+
+import { TServicoItemPedidoSaveData } from '../../data/TServicoItemPedido/TServicoItemPedidoSaveData';
+import TServicoItemPedidoInterface from '../../interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
+
+
+async function executeTServicoItemPedidoSaveService(data: TServicoItemPedidoInterface) {
+ const response = await TServicoItemPedidoSaveData(data);
+ return response;
+}
+
+export const TServicoItemPedidoSaveService = withClientErrorHandler(executeTServicoItemPedidoSaveService);
diff --git a/src/packages/servicos/services/TServicoPedido/TServicoPedidoDeleteService.ts b/src/packages/servicos/services/TServicoPedido/TServicoPedidoDeleteService.ts
new file mode 100644
index 0000000..65fdb18
--- /dev/null
+++ b/src/packages/servicos/services/TServicoPedido/TServicoPedidoDeleteService.ts
@@ -0,0 +1,13 @@
+
+import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
+
+import { TServicoPedidoDeleteData } from '../../data/TServicoPedido/TServicoPedidoDeleteData';
+import TServicoPedidoInterface from '../../interfaces/TServicoPedido/TServicoPedidoInterface';
+
+
+async function executeTServicoPedidoDeleteService(data: TServicoPedidoInterface) {
+ const response = await TServicoPedidoDeleteData(data);
+ return response;
+}
+
+export const TServicoPedidoDeleteService = withClientErrorHandler(executeTServicoPedidoDeleteService);
diff --git a/src/packages/servicos/services/TServicoPedido/TServicoPedidoIndexService.ts b/src/packages/servicos/services/TServicoPedido/TServicoPedidoIndexService.ts
new file mode 100644
index 0000000..73607d5
--- /dev/null
+++ b/src/packages/servicos/services/TServicoPedido/TServicoPedidoIndexService.ts
@@ -0,0 +1,10 @@
+import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
+
+import { TServicoPedidoIndexData } from '../../data/TServicoPedido/TServicoPedidoIndexData';
+
+export default async function executeTServicoPedidoIndexService() {
+ const response = await TServicoPedidoIndexData();
+ return response;
+}
+
+export const TServicoPedidoIndexService = withClientErrorHandler(executeTServicoPedidoIndexService);
diff --git a/src/packages/servicos/services/TServicoPedido/TServicoPedidoSaveService.ts b/src/packages/servicos/services/TServicoPedido/TServicoPedidoSaveService.ts
new file mode 100644
index 0000000..d207c7e
--- /dev/null
+++ b/src/packages/servicos/services/TServicoPedido/TServicoPedidoSaveService.ts
@@ -0,0 +1,11 @@
+import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
+
+import { TServicoPedidoSaveData } from '../../data/TServicoPedido/TServicoPedidoSaveData';
+import TServicoPedidoInterface from '../../interfaces/TServicoPedido/TServicoPedidoInterface';
+
+async function executeTServicoPedidoSaveService(data: TServicoPedidoInterface) {
+ const response = await TServicoPedidoSaveData(data);
+ return response;
+}
+
+export const TServicoPedidoSaveService = withClientErrorHandler(executeTServicoPedidoSaveService);