From e39422776e10004faf000261f6414d6a49bb3acf Mon Sep 17 00:00:00 2001 From: keven Date: Mon, 27 Oct 2025 15:29:51 -0300 Subject: [PATCH] =?UTF-8?q?[MVPTN-37]=20feat(CRUD):=20=20Implementa=C3=A7?= =?UTF-8?q?=C3=A3o=20inicial=20do=20CRUD=20de=20servi=C3=A7os=20de=20balc?= =?UTF-8?q?=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 482 +++++++++++++++++ package.json | 6 + .../administrativo/censec/page.tsx | 5 + .../administrativo/imoveis/dashboard/page.tsx | 9 + .../administrativo/pessoas/dashboard/page.tsx | 9 + src/app/(protected)/servicos/balcao/page.tsx | 7 + .../servicos/balcao/pedido/page.tsx | 90 ++++ .../(protected)/servicos/dashboard/page.tsx | 7 + src/components/app-sidebar.tsx | 33 +- src/components/ui/badge.tsx | 46 ++ src/components/ui/button.tsx | 50 +- src/components/ui/card.tsx | 67 ++- src/components/ui/input.tsx | 19 +- src/components/ui/progress.tsx | 31 ++ src/components/ui/scroll-area.tsx | 58 ++ src/components/ui/select.tsx | 89 +-- .../components/TImovel/TImovelDashboard.tsx | 378 +++++++++++++ .../components/TPessoa/TPessoaDashboard.tsx | 506 ++++++++++++++++++ .../TServicoItemPedidoColumns.tsx | 78 +++ .../TServicoItemPedidoForm.tsx | 205 +++++++ .../TServicoItemPedidoIndex.tsx | 161 ++++++ .../TServicoItemPedidoResumo.tsx | 92 ++++ .../TServicoItemPedidoTable.tsx | 23 + .../TServicoPedido/TServicoPedidoColumns.tsx | 78 +++ .../TServicoPedidoDashboard.tsx | 318 +++++++++++ .../TServicoPedido/TServicoPedidoForm.tsx | 110 ++++ .../TServicoPedido/TServicoPedidoIndex.tsx | 153 ++++++ .../TServicoPedido/TServicoPedidoTable.tsx | 23 + .../TServicoItemPedidoDeleteData.ts | 16 + .../TServicoItemPedidoIndexData.ts | 15 + .../TServicoItemPedidoSaveData.ts | 23 + .../TServicoPedidoDeleteData.ts | 17 + .../TServicoPedido/TServicoPedidoIndexData.ts | 15 + .../TServicoPedido/TServicoPedidoSaveData.ts | 23 + .../useTServicoItemPedidoDeleteHook.ts | 21 + .../useTServicoItemPedidoFormHook.ts | 14 + .../useTServicoItemPedidoIndexHook.ts | 28 + .../useTServicoItemPedidoSaveHook.ts | 35 ++ .../useTServicoPedidoDeleteHook.ts | 17 + .../useTServicoPedidoFormHook.ts | 14 + .../useTServicoPedidoIndexHook.ts | 27 + .../useTServicoPedidoSaveHook.ts | 35 ++ .../TServicoItemPedidoFormInterface.ts | 9 + .../TServicoItemPedidoIntefarce.ts | 66 +++ .../TServicoItemPedidoTableInterface.ts | 7 + .../TServicoPedidoFormInterface.ts | 9 + .../TServicoPedido/TServicoPedidoInterface.ts | 15 + .../TServicoPedidoTableInterface.ts | 7 + .../TServicoItemPedidoSchema.ts | 70 +++ .../TServicoPedido/TServicoPedidoSchema.ts | 19 + .../TServicoItemPedidoDeleteService.ts | 14 + .../TServicoItemPedidoIndexService.ts | 10 + .../TServicoItemPedidoSaveService.ts | 12 + .../TServicoPedidoDeleteService.ts | 13 + .../TServicoPedidoIndexService.ts | 10 + .../TServicoPedidoSaveService.ts | 11 + 56 files changed, 3606 insertions(+), 99 deletions(-) create mode 100644 src/app/(protected)/(administrativo)/administrativo/censec/page.tsx create mode 100644 src/app/(protected)/(administrativo)/administrativo/imoveis/dashboard/page.tsx create mode 100644 src/app/(protected)/(administrativo)/administrativo/pessoas/dashboard/page.tsx create mode 100644 src/app/(protected)/servicos/balcao/page.tsx create mode 100644 src/app/(protected)/servicos/balcao/pedido/page.tsx create mode 100644 src/app/(protected)/servicos/dashboard/page.tsx create mode 100644 src/components/ui/badge.tsx create mode 100644 src/components/ui/progress.tsx create mode 100644 src/components/ui/scroll-area.tsx create mode 100644 src/packages/administrativo/components/TImovel/TImovelDashboard.tsx create mode 100644 src/packages/administrativo/components/TPessoa/TPessoaDashboard.tsx create mode 100644 src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoColumns.tsx create mode 100644 src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoForm.tsx create mode 100644 src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoIndex.tsx create mode 100644 src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoResumo.tsx create mode 100644 src/packages/servicos/components/TServicoItemPedido/TServicoItemPedidoTable.tsx create mode 100644 src/packages/servicos/components/TServicoPedido/TServicoPedidoColumns.tsx create mode 100644 src/packages/servicos/components/TServicoPedido/TServicoPedidoDashboard.tsx create mode 100644 src/packages/servicos/components/TServicoPedido/TServicoPedidoForm.tsx create mode 100644 src/packages/servicos/components/TServicoPedido/TServicoPedidoIndex.tsx create mode 100644 src/packages/servicos/components/TServicoPedido/TServicoPedidoTable.tsx create mode 100644 src/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoDeleteData.ts create mode 100644 src/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoIndexData.ts create mode 100644 src/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoSaveData.ts create mode 100644 src/packages/servicos/data/TServicoPedido/TServicoPedidoDeleteData.ts create mode 100644 src/packages/servicos/data/TServicoPedido/TServicoPedidoIndexData.ts create mode 100644 src/packages/servicos/data/TServicoPedido/TServicoPedidoSaveData.ts create mode 100644 src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoDeleteHook.ts create mode 100644 src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoFormHook.ts create mode 100644 src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoIndexHook.ts create mode 100644 src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoSaveHook.ts create mode 100644 src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoDeleteHook.ts create mode 100644 src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoFormHook.ts create mode 100644 src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoIndexHook.ts create mode 100644 src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoSaveHook.ts create mode 100644 src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoFormInterface.ts create mode 100644 src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce.ts create mode 100644 src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoTableInterface.ts create mode 100644 src/packages/servicos/interfaces/TServicoPedido/TServicoPedidoFormInterface.ts create mode 100644 src/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface.ts create mode 100644 src/packages/servicos/interfaces/TServicoPedido/TServicoPedidoTableInterface.ts create mode 100644 src/packages/servicos/schemas/TServicoItemPedido/TServicoItemPedidoSchema.ts create mode 100644 src/packages/servicos/schemas/TServicoPedido/TServicoPedidoSchema.ts create mode 100644 src/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoDeleteService.ts create mode 100644 src/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoIndexService.ts create mode 100644 src/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoSaveService.ts create mode 100644 src/packages/servicos/services/TServicoPedido/TServicoPedidoDeleteService.ts create mode 100644 src/packages/servicos/services/TServicoPedido/TServicoPedidoIndexService.ts create mode 100644 src/packages/servicos/services/TServicoPedido/TServicoPedidoSaveService.ts 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 ( + { + if (!open) onClose(null, false); + }} + > + + + Formulário de Gramática + + Formulário de Gramática + + + {/* Formulário principal */} +
+ + {/* GRID MOBILE FIRST */} +
+ {/* Palavra */} +
+ ( + + Palavra + + + + + + )} + /> +
+ {/* Prefixo */} +
+ ( + + Prefixo + + + + + + )} + /> +
+ {/* Singular Masculino */} +
+ ( + + Sufixo Masculino Singular + + + + + + )} + /> +
+ {/* Plural Masculino */} +
+ ( + + Sufixo Masculino Plural + + + + + + )} + /> +
+ {/* Singular Feminino */} +
+ ( + + Sufixo Feminino Singular + + + + + + )} + /> +
+ {/* Plural Feminino */} +
+ ( + + Sufixo Feminino Plural + + + + + + )} + /> +
+
+ {/* Rodapé */} + + + + + + +
+ +
+
+ ); +} 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 ( + { + if (!open) onClose(null, false); + }} + > + + + Formulário de Gramática + + Formulário de Gramática + + + {/* Formulário principal */} +
+ + {/* GRID MOBILE FIRST */} +
+ {/* Palavra */} +
+ ( + + Palavra + + + + + + )} + /> +
+
+ {/* Rodapé */} + + + + + + +
+ +
+
+ ); +} 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);