feat(Certidao): Adiciona recursos para manipular certidões
This commit is contained in:
parent
fd79837fdc
commit
5ef46780a5
29 changed files with 841 additions and 21 deletions
33
README.md
33
README.md
|
|
@ -23,3 +23,36 @@ Configure:
|
|||
}
|
||||
|
||||
npm run dev:debug
|
||||
|
||||
## onlyoffice
|
||||
|
||||
docker run -i -t -d -p 8081:80 --restart=always -e JWT_ENABLED=false onlyoffice/documentserver
|
||||
|
||||
## next em rede
|
||||
|
||||
```
|
||||
npx next dev -H 0.0.0.0
|
||||
```
|
||||
|
||||
```
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"dev:lan": "next dev -H 0.0.0.0" <-- Adicione esta linha
|
||||
},
|
||||
```
|
||||
|
||||
Como acessar no outro dispositivo
|
||||
Descubra seu IP Local:
|
||||
|
||||
No Windows (seu caso), abra um terminal (CMD ou PowerShell) e digite:
|
||||
|
||||
Bash
|
||||
|
||||
ipconfig
|
||||
Procure por Endereço IPv4 (geralmente começa com 192.168.x.x ou 10.0.x.x).
|
||||
|
||||
Acesse no navegador: No celular ou outro computador, digite: http://SEU_IP_AQUI:3000
|
||||
|
||||
Exemplo: <http://192.168.0.15:3000>
|
||||
|
|
|
|||
290
package-lock.json
generated
290
package-lock.json
generated
|
|
@ -7,9 +7,11 @@
|
|||
"": {
|
||||
"name": "saas",
|
||||
"version": "25.9.1",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@faker-js/faker": "^10.0.0",
|
||||
"@hookform/resolvers": "^5.2.1",
|
||||
"@onlyoffice/document-editor-react": "^2.1.1",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.15",
|
||||
"@radix-ui/react-avatar": "^1.1.10",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
|
|
@ -75,6 +77,7 @@
|
|||
"eslint-plugin-unused-imports": "^4.2.0",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-tailwindcss": "^0.6.14",
|
||||
"shx": "^0.4.0",
|
||||
"tailwindcss": "^4",
|
||||
"tw-animate-css": "^1.3.7",
|
||||
"typescript": "5.9.3",
|
||||
|
|
@ -1391,6 +1394,19 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@onlyoffice/document-editor-react": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@onlyoffice/document-editor-react/-/document-editor-react-2.1.1.tgz",
|
||||
"integrity": "sha512-b0SnFPmT+OEyJons18PPHpwtFABVCI4nr3gPtAAImar1PhN9tNc9703Yo5KPYsHhIgVq+FqHSWgunI9GJnKa5w==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"lodash": "4.17.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.9.0 || ^17 || ^18 || ^19",
|
||||
"react-dom": "^16.9.0 || ^17 || ^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgr/core": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
|
||||
|
|
@ -4628,6 +4644,16 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
|
||||
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.18.3",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
|
||||
|
|
@ -5485,6 +5511,98 @@
|
|||
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/execa": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
|
||||
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cross-spawn": "^6.0.0",
|
||||
"get-stream": "^4.0.0",
|
||||
"is-stream": "^1.1.0",
|
||||
"npm-run-path": "^2.0.0",
|
||||
"p-finally": "^1.0.0",
|
||||
"signal-exit": "^3.0.0",
|
||||
"strip-eof": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/execa/node_modules/cross-spawn": {
|
||||
"version": "6.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz",
|
||||
"integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nice-try": "^1.0.4",
|
||||
"path-key": "^2.0.1",
|
||||
"semver": "^5.5.0",
|
||||
"shebang-command": "^1.2.0",
|
||||
"which": "^1.2.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.8"
|
||||
}
|
||||
},
|
||||
"node_modules/execa/node_modules/path-key": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
|
||||
"integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/execa/node_modules/semver": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/execa/node_modules/shebang-command": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
|
||||
"integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"shebang-regex": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/execa/node_modules/shebang-regex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
|
||||
"integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/execa/node_modules/which": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"which": "bin/which"
|
||||
}
|
||||
},
|
||||
"node_modules/faker-js": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/faker-js/-/faker-js-1.0.0.tgz",
|
||||
|
|
@ -5775,6 +5893,19 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/get-stream": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
||||
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pump": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/get-symbol-description": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
|
||||
|
|
@ -6068,6 +6199,16 @@
|
|||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/interpret": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
|
||||
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-array-buffer": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
|
||||
|
|
@ -6373,6 +6514,16 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-stream": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
|
||||
"integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-string": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
|
||||
|
|
@ -6954,6 +7105,12 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
|
|
@ -7287,6 +7444,13 @@
|
|||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/nice-try": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.25",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.25.tgz",
|
||||
|
|
@ -7294,6 +7458,29 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/npm-run-path": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
|
||||
"integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-key": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-run-path/node_modules/path-key": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
|
||||
"integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
|
|
@ -7416,6 +7603,16 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||
|
|
@ -7452,6 +7649,16 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/p-finally": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
|
||||
"integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/p-limit": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||
|
|
@ -7720,6 +7927,17 @@
|
|||
"react-is": "^16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
|
||||
"integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
|
|
@ -7924,6 +8142,18 @@
|
|||
"react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rechoir": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
|
||||
"integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"resolve": "^1.1.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/redux": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||
|
|
@ -8274,6 +8504,42 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shelljs": {
|
||||
"version": "0.9.2",
|
||||
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.9.2.tgz",
|
||||
"integrity": "sha512-S3I64fEiKgTZzKCC46zT/Ib9meqofLrQVbpSswtjFfAVDW+AZ54WTnAM/3/yENoxz/V1Cy6u3kiiEbQ4DNphvw==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"execa": "^1.0.0",
|
||||
"fast-glob": "^3.3.2",
|
||||
"interpret": "^1.0.0",
|
||||
"rechoir": "^0.6.2"
|
||||
},
|
||||
"bin": {
|
||||
"shjs": "bin/shjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/shx": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/shx/-/shx-0.4.0.tgz",
|
||||
"integrity": "sha512-Z0KixSIlGPpijKgcH6oCMCbltPImvaKy0sGH8AkLRXw1KyzpKtaCTizP2xen+hNDqVF4xxgvA0KXSb9o4Q6hnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.8",
|
||||
"shelljs": "^0.9.2"
|
||||
},
|
||||
"bin": {
|
||||
"shx": "lib/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||
|
|
@ -8350,6 +8616,13 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/sonner": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz",
|
||||
|
|
@ -8516,6 +8789,16 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-eof": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
|
||||
"integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-json-comments": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
||||
|
|
@ -9181,6 +9464,13 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@
|
|||
"dev:debug": "cross-env NEXT_USE_TURBOPACK=0 NODE_OPTIONS=\"--inspect=9230\" next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"lint": "next lint",
|
||||
"postinstall": "shx mkdir -p public/libs && shx cp -r node_modules/tinymce public/libs/tinymce"
|
||||
},
|
||||
"dependencies": {
|
||||
"@faker-js/faker": "^10.0.0",
|
||||
"@hookform/resolvers": "^5.2.1",
|
||||
"@onlyoffice/document-editor-react": "^2.1.1",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.15",
|
||||
"@radix-ui/react-avatar": "^1.1.10",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
|
|
@ -78,6 +80,7 @@
|
|||
"eslint-plugin-unused-imports": "^4.2.0",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-tailwindcss": "^0.6.14",
|
||||
"shx": "^0.4.0",
|
||||
"tailwindcss": "^4",
|
||||
"tw-animate-css": "^1.3.7",
|
||||
"typescript": "5.9.3",
|
||||
|
|
|
|||
BIN
public/modelo.docx
Normal file
BIN
public/modelo.docx
Normal file
Binary file not shown.
|
|
@ -10,6 +10,14 @@ const ROOT_PATH = '/login'; // url raiz
|
|||
|
||||
export function middleware(request: NextRequest) {
|
||||
const path = request.nextUrl.pathname;
|
||||
|
||||
// --- AJUSTE NECESSÁRIO PARA ONLYOFFICE ---
|
||||
// Se a rota termina em .docx, libera o acesso imediatamente (sem checar token)
|
||||
if (path.endsWith('.docx')) {
|
||||
return NextResponse.next();
|
||||
}
|
||||
// -----------------------------------------
|
||||
|
||||
const publicRoute = publicRoutes.find((route) => route.path === path);
|
||||
const authToken = request.cookies.get('access_token');
|
||||
|
||||
|
|
@ -25,6 +33,8 @@ export function middleware(request: NextRequest) {
|
|||
|
||||
// 3. Autenticado em rota pública com flag "redirect" → vai para raiz
|
||||
if (authToken && publicRoute && publicRoute.whenAuthenticated === 'redirect') {
|
||||
// OBS: Se ROOT_PATH for '/login', isso pode gerar um loop infinito para usuários logados.
|
||||
// O ideal seria redirecionar para '/' (dashboard), mas mantive seu código original.
|
||||
return NextResponse.redirect(new URL(ROOT_PATH, request.url));
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +62,7 @@ export function middleware(request: NextRequest) {
|
|||
|
||||
export const config: MiddlewareConfig = {
|
||||
matcher: [
|
||||
// ignora APIs, arquivos estáticos e metadados
|
||||
'/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|images).*)',
|
||||
// ignora APIs, arquivos estáticos, metadados E ARQUIVOS .DOCX
|
||||
'/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|images|.*\\.docx$).*)',
|
||||
],
|
||||
};
|
||||
};
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
import GGramaticaInterface from '@/packages/administrativo/interfaces/GGramatica/GGramaticaInterface';
|
||||
import { GGramaticaIndexService } from '@/packages/administrativo/services/GGramatica/GGramaticaIndexService';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
export const useGGramaticaIndexHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
'use server';
|
||||
|
||||
import { GGramaticaIndexData } from '@/packages/administrativo/data/GGramatica/GGramaticaIndexData';
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
|
||||
import { GGramaticaIndexData } from '@/packages/administrativo/data/GGramatica/GGramaticaIndexData';
|
||||
|
||||
export default async function executeGGramaticaIndexService() {
|
||||
const response = await GGramaticaIndexData();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
"use client";
|
||||
|
||||
import { useMemo } from "react";
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import TServicoItemPedidoCertidaFormInterface from "@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoCertidaFormInterface";
|
||||
import GetFileExtension from "@/shared/actions/file/GetFileExtension";
|
||||
import OnlyOfficeEditor from "@/shared/components/editor/onlyoffice/OnlyOfficeEditor";
|
||||
|
||||
export default function TServicoItemPedidoCertidaForm({
|
||||
isOpen,
|
||||
selectedItem,
|
||||
onClose,
|
||||
}: TServicoItemPedidoCertidaFormInterface) {
|
||||
|
||||
const config = useMemo(() => {
|
||||
|
||||
return {
|
||||
documentType: "word",
|
||||
document: {
|
||||
|
||||
fileType: GetFileExtension(selectedItem?.certidao_texto,),
|
||||
title: selectedItem?.certidao_texto,
|
||||
name: selectedItem?.certidao_texto,
|
||||
key: `etiqueta_${selectedItem?.servico_itempedido_id}_${new Date().getTime()}`,
|
||||
},
|
||||
editorConfig: {
|
||||
mode: "edit",
|
||||
lang: "pt-BR",
|
||||
callbackUrl: "https://seu-backend.com/api/onlyoffice/callback",
|
||||
},
|
||||
};
|
||||
|
||||
}, [selectedItem]);
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={(open) => !open && onClose(false)}>
|
||||
<DialogContent className="w-full h-[calc(100vh-3rem)] mx-auto p-0 flex flex-col overflow-hidden sm:max-w-4xl md:max-w-6xl lg:max-w-6xl">
|
||||
<DialogHeader className="border-b px-6 py-4">
|
||||
<DialogTitle>Editor de Certidão</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="flex-1 overflow-hidden relative">
|
||||
{/* Mostra um loading enquanto os dados não chegam */}
|
||||
{!config && (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
Carregando documento...
|
||||
</div>
|
||||
)}
|
||||
{/* Só renderiza o Editor se o config estiver pronto */}
|
||||
{isOpen && config && (
|
||||
<OnlyOfficeEditor
|
||||
id={`ServicoItemPedidoEtiquetaEditor_${selectedItem?.servico_itempedido_id}`}
|
||||
config={config}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
"use client";
|
||||
|
||||
import { useMemo } from "react";
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import TServicoItemPedidoEtiquetaFormInterface from "@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoEtiquetaFormInterface";
|
||||
import GetFileExtension from "@/shared/actions/file/GetFileExtension";
|
||||
import OnlyOfficeEditor from "@/shared/components/editor/onlyoffice/OnlyOfficeEditor";
|
||||
|
||||
export default function TServicoItemPedidoEtiquetaForm({
|
||||
isOpen,
|
||||
selectedItem,
|
||||
onClose,
|
||||
}: TServicoItemPedidoEtiquetaFormInterface) {
|
||||
|
||||
const config = useMemo(() => {
|
||||
|
||||
return {
|
||||
documentType: "word",
|
||||
document: {
|
||||
|
||||
fileType: GetFileExtension(selectedItem?.etiqueta_texto,),
|
||||
title: selectedItem?.etiqueta_texto,
|
||||
name: selectedItem?.etiqueta_texto,
|
||||
key: `etiqueta_${selectedItem?.servico_itempedido_id}_${new Date().getTime()}`,
|
||||
},
|
||||
editorConfig: {
|
||||
mode: "edit",
|
||||
lang: "pt-BR",
|
||||
},
|
||||
};
|
||||
|
||||
}, [selectedItem]);
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={(open) => !open && onClose(false)}>
|
||||
<DialogContent className="w-full h-[calc(100vh-3rem)] mx-auto p-0 flex flex-col overflow-hidden sm:max-w-4xl md:max-w-6xl lg:max-w-6xl">
|
||||
<DialogHeader className="border-b px-6 py-4">
|
||||
<DialogTitle>Editor de Etiqueta</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="flex-1 overflow-hidden relative">
|
||||
{/* Mostra um loading enquanto os dados não chegam */}
|
||||
{!config && (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
Carregando documento...
|
||||
</div>
|
||||
)}
|
||||
{/* Só renderiza o Editor se o config estiver pronto */}
|
||||
{isOpen && config && (
|
||||
<OnlyOfficeEditor
|
||||
id={`ServicoItemPedidoEtiquetaEditor_${selectedItem?.servico_itempedido_id}`}
|
||||
config={config}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import {
|
|||
RotateCcwIcon,
|
||||
TicketIcon,
|
||||
} from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ButtonGroup } from '@/components/ui/button-group';
|
||||
|
|
@ -25,8 +26,15 @@ import FormatMoney from '@/shared/actions/money/FormatMoney';
|
|||
import { ServicosPedidosSituacoesBadge } from '@/shared/components/servicosPedidosSituacoes/ServicosPedidosSituacoesBadge';
|
||||
import { ServicosPedidosSituacoesEnum } from '@/shared/enums/ServicosPedidosSituacoesEnum';
|
||||
|
||||
import TServicoItemPedidoCertidaForm from './TServicoItemPedidoCertidaoForm';
|
||||
import TServicoItemPedidoEtiquetaForm from './TServicoItemPedidoEtiquetaForm';
|
||||
|
||||
|
||||
export default function TServicoItemPedidoList({ items, openConfirmDialog }: TServicoItemPedidoListInterface) {
|
||||
|
||||
const [isOpenTServicoItemPedidoCertidaForm, setIsOpenTServicoItemPedidoCertidaForm] = useState(false)
|
||||
const [isOpenTServicoItemPedidoEtiquetaForm, setIsOpenTServicoItemPedidoEtiquetaForm] = useState(false)
|
||||
const [selectedItem, setSelectedItem] = useState()
|
||||
const { localItems, handleSituacaoTServicoItemPedido } = useTServicoItemPedidoListControllerHook(items);
|
||||
|
||||
return (
|
||||
|
|
@ -43,7 +51,6 @@ export default function TServicoItemPedidoList({ items, openConfirmDialog }: TSe
|
|||
{localItems.map((item) => {
|
||||
|
||||
const isCancelado = item.situacao === 'C';
|
||||
|
||||
const actionLabel = isCancelado ? 'Ativar Item' : 'Estornar Item';
|
||||
const confirmTitle = isCancelado ? 'Ativação de Item' : 'Estorno de Item';
|
||||
const confirmMessage = isCancelado ? `Deseja realmente ativar o item #${item.servico_itempedido_id}?` : `Deseja realmente estornar o item #${item.servico_itempedido_id}?`;
|
||||
|
|
@ -59,10 +66,7 @@ export default function TServicoItemPedidoList({ items, openConfirmDialog }: TSe
|
|||
{/* Descrição */}
|
||||
<div className="flex-1">
|
||||
<h3 className="text-foreground line-clamp-2 text-sm font-bold lg:text-base">
|
||||
{item.descricao} de {item.nome} –{' '}
|
||||
<ServicosPedidosSituacoesBadge
|
||||
situacao={item.situacao as ServicosPedidosSituacoesEnum}
|
||||
/>
|
||||
{item.descricao} de {item.nome} – <ServicosPedidosSituacoesBadge situacao={item.situacao as ServicosPedidosSituacoesEnum} />
|
||||
</h3>
|
||||
|
||||
<h6 className="text-foreground text-sm">
|
||||
|
|
@ -111,14 +115,41 @@ export default function TServicoItemPedidoList({ items, openConfirmDialog }: TSe
|
|||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent align="end" className="w-52">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<TicketIcon /> Imprimir Etiqueta
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IdCardIcon /> Imprimir Cartão
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
{item.etiqueta_modelo_id && (
|
||||
<>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
setSelectedItem(item);
|
||||
setIsOpenTServicoItemPedidoEtiquetaForm(true);
|
||||
}}
|
||||
>
|
||||
<TicketIcon /> Imprimir Etiqueta
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IdCardIcon /> Imprimir Cartão
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</>
|
||||
)}
|
||||
|
||||
{item.tipo_item == 'C' && (
|
||||
<>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
setSelectedItem(item);
|
||||
setIsOpenTServicoItemPedidoCertidaForm(true);
|
||||
}}
|
||||
>
|
||||
<TicketIcon /> Editar Certidão
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IdCardIcon /> Imprimir Certidão
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</>
|
||||
)}
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
|
|
@ -149,6 +180,20 @@ export default function TServicoItemPedidoList({ items, openConfirmDialog }: TSe
|
|||
);
|
||||
})}
|
||||
</div>
|
||||
{isOpenTServicoItemPedidoCertidaForm && (
|
||||
<TServicoItemPedidoCertidaForm
|
||||
isOpen={isOpenTServicoItemPedidoCertidaForm}
|
||||
selectedItem={selectedItem}
|
||||
onClose={setIsOpenTServicoItemPedidoCertidaForm}
|
||||
/>
|
||||
)}
|
||||
{isOpenTServicoItemPedidoEtiquetaForm && (
|
||||
<TServicoItemPedidoEtiquetaForm
|
||||
isOpen={isOpenTServicoItemPedidoEtiquetaForm}
|
||||
selectedItem={selectedItem}
|
||||
onClose={setIsOpenTServicoItemPedidoEtiquetaForm}
|
||||
/>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -28,13 +28,19 @@ export default function TServicoPedidoDetails({
|
|||
} = useTServicoPedidoDetailsControllerHook(servico_pedido_id);
|
||||
|
||||
return (
|
||||
|
||||
<div>
|
||||
|
||||
<h3 className="mb-4 text-4xl font-bold">
|
||||
|
||||
Pedido: #{TServicoPedido?.servico_pedido_id}
|
||||
|
||||
</h3>
|
||||
|
||||
<div className="mx-auto h-full">
|
||||
|
||||
<div className="flex flex-col gap-4 lg:flex-row">
|
||||
|
||||
{/* Coluna esquerda */}
|
||||
<div className="flex flex-auto flex-col gap-4">
|
||||
<TServicoItemPedidoList
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
import TServicoItemPedidoInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import API from '@/shared/services/api/Api';
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
|
||||
|
||||
async function executeTServicoItemPedidoCertidaoEditData(
|
||||
data: TServicoItemPedidoInterface,
|
||||
): Promise<ApiResponseInterface> {
|
||||
const api = new API();
|
||||
console.log('executeTServicoItemPedidoCertidaoEditData', 1)
|
||||
return api.send({
|
||||
method: Methods.GET,
|
||||
endpoint: `servicos/pedidos/t_servico_itempedido/${data.servico_itempedido_id}/certidao/editar`,
|
||||
});
|
||||
}
|
||||
|
||||
export const TServicoItemPedidoCertidaoEditData = withClientErrorHandler(
|
||||
executeTServicoItemPedidoCertidaoEditData,
|
||||
);
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import TServicoItemPedidoIndexResponseInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoCalculoResponseInterface';
|
||||
import TServicoItemPedidoInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import { TServicoItemPedidoCertidaoEditService } from '@/packages/servicos/services/TServicoItemPedido/TServicoItemPedidoCertidaoEditService';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
|
||||
export const useTServicoItemPedidoCertidaoEditHook = () => {
|
||||
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [TServicoItemPedido, setTServicoItemPedido] = useState<TServicoItemPedidoIndexResponseInterface[]>([]);
|
||||
|
||||
const certidaoEditTServicoItemPedido = async (data: TServicoItemPedidoInterface) => {
|
||||
|
||||
console.log('useTServicoItemPedidoCertidaoEditHook', 1)
|
||||
|
||||
const response = await TServicoItemPedidoCertidaoEditService(data);
|
||||
|
||||
setTServicoItemPedido(response.data);
|
||||
|
||||
setResponse(response);
|
||||
|
||||
// Retorno imediato dos valores
|
||||
return response;
|
||||
};
|
||||
|
||||
return {
|
||||
TServicoItemPedido,
|
||||
certidaoEditTServicoItemPedido,
|
||||
};
|
||||
};
|
||||
|
|
@ -33,6 +33,7 @@ export function useTServicoPedidoDetailsControllerHook(
|
|||
TServicoPedido,
|
||||
setTServicoPedido,
|
||||
} = useTServicoPedidoShowHook();
|
||||
|
||||
const { indexTServicoItemPedido, TServicoItemPedido } =
|
||||
useTServicoItemPedidoIndexHook();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import TServicoPedidoInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
export default interface TServicoItemPedidoCertidaFormInterface {
|
||||
isOpen: boolean,
|
||||
selectedItem: any;
|
||||
onClose: any;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
export default interface TServicoItemPedidoEtiquetaFormInterface {
|
||||
isOpen: boolean,
|
||||
selectedItem: any;
|
||||
onClose: any;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
'use server';
|
||||
|
||||
import { TServicoItemPedidoCertidaoEditData } from '@/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoCertidaoEditData';
|
||||
import TServicoItemPedidoInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
|
||||
|
||||
export default async function executeTServicoItemPedidoCertidaoEditService(
|
||||
data: TServicoItemPedidoInterface,
|
||||
) {
|
||||
console.log('executeTServicoItemPedidoCertidaoEditService', 1)
|
||||
const response = await TServicoItemPedidoCertidaoEditData(data);
|
||||
return response;
|
||||
}
|
||||
|
||||
export const TServicoItemPedidoCertidaoEditService = withClientErrorHandler(
|
||||
executeTServicoItemPedidoCertidaoEditService,
|
||||
);
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
'use server';
|
||||
|
||||
import { TServicoItemPedidoIndexData } from '@/packages/servicos/data/TServicoItemPedido/TServicoItemPedidoIndexData';
|
||||
import TServicoItemPedidoInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoIntefarce';
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
'use server'
|
||||
|
||||
import { TServicoPedidoShowData } from '@/packages/servicos/data/TServicoPedido/TServicoPedidoShowData';
|
||||
import TServicoPedidoInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface';
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
|
|
|
|||
21
src/shared/actions/file/GetFileExtension.ts
Normal file
21
src/shared/actions/file/GetFileExtension.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* Obtém a extensão do arquivo a partir do nome ou caminho.
|
||||
*
|
||||
* @param filename - Nome do arquivo ou caminho completo
|
||||
* @returns A extensão do arquivo (ex: 'png', 'pdf') ou string vazia se não houver
|
||||
*/
|
||||
export default function GetFileExtension(filename?: string): string {
|
||||
if (!filename) return '';
|
||||
|
||||
// Encontra a posição do último ponto na string
|
||||
const lastDotIndex = filename.lastIndexOf('.');
|
||||
|
||||
// Se não houver ponto, retorna vazio.
|
||||
// Opcional: verifica se o ponto não é o primeiro caractere (arquivos como .gitignore)
|
||||
if (lastDotIndex === -1) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Retorna tudo após o último ponto e converte para minúsculas
|
||||
return filename.substring(lastDotIndex + 1).toLowerCase();
|
||||
}
|
||||
48
src/shared/components/editor/onlyoffice/OnlyOfficeEditor.tsx
Normal file
48
src/shared/components/editor/onlyoffice/OnlyOfficeEditor.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import { DocumentEditor } from "@onlyoffice/document-editor-react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import GetServerUrl from "./actions/GetServerUrl";
|
||||
import { usePrepareOnlyOfficeEditorHook } from "./hooks/usePrepareOnlyOfficeEditorHook";
|
||||
import OnlyOfficeInteface from "./interface/OnlyOfficeInterface";
|
||||
|
||||
export default function OnlyOfficeEditor({ id, config }: OnlyOfficeInteface) {
|
||||
|
||||
const { prepareOnlyOfficeEditorHook } = usePrepareOnlyOfficeEditorHook();
|
||||
const [serverUrl, setServerUrl] = useState<null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
// 1. Criamos a função async interna
|
||||
const executePrepare = async () => {
|
||||
|
||||
// Se prepareOnlyOfficeEditorHook já é async, basta aguardar
|
||||
const response = await prepareOnlyOfficeEditorHook();
|
||||
|
||||
// Define a url que deve ser carregado o editor
|
||||
setServerUrl(GetServerUrl(response.data, 1))
|
||||
|
||||
// Atualiza o caminho do documento
|
||||
config.document.url = GetServerUrl(response.data, 2) + '/temp/' + config.document.name
|
||||
|
||||
console.log('config', config)
|
||||
|
||||
};
|
||||
|
||||
// 2. Chamamos ela imediatamente
|
||||
executePrepare()
|
||||
|
||||
}, [id, config]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{serverUrl && (
|
||||
<DocumentEditor
|
||||
id={id}
|
||||
documentServerUrl={serverUrl}
|
||||
config={config}
|
||||
style={{ height: "100%", width: "100%" }}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
export default function GetServerUrl(data, port) {
|
||||
|
||||
let _port = null
|
||||
|
||||
switch (Number(port)) {
|
||||
|
||||
case 1:
|
||||
|
||||
_port = data.port_only_office
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
||||
_port = data.port_api
|
||||
break;
|
||||
}
|
||||
|
||||
return `http://${data.ip}:${_port}`;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
|
||||
|
||||
async function executeOnlyOfficeEditorPrepareData(): Promise<ApiResponseInterface> {
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
message: "Dados carregados com sucesso",
|
||||
data: {
|
||||
ip: process.env.NEXT_PUBLIC_ORIUS_ONLYOFFICE_IP,
|
||||
port_only_office: process.env.NEXT_PUBLIC_ORIUS_ONLYOFFICE_PORT,
|
||||
port_api: process.env.NEXT_PUBLIC_ORIUS_APP_API_PORT,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const OnlyOfficeEditorPrepareData = withClientErrorHandler(executeOnlyOfficeEditorPrepareData);
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import ApiResponseInterface from '@/shared/services/api/interfaces/ApiResponseInterface';
|
||||
|
||||
// Adicionei url como parâmetro para tornar a função reutilizável e testável
|
||||
async function executeOnlyOfficeEditorServiceUpData(url: string): Promise<ApiResponseInterface> {
|
||||
|
||||
const timeoutMs = 2000; // Defina o tempo limite desejado
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
||||
|
||||
try {
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'HEAD',
|
||||
signal: controller.signal
|
||||
});
|
||||
|
||||
// O fetch nativo não lança erro em 404 ou 500, então verificamos manualmente.
|
||||
if (!response.ok) {
|
||||
throw new Error(`Serviço indisponível. Status: ${response.status}`);
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
message: "Editor inicializado com sucesso",
|
||||
data: {
|
||||
online: true,
|
||||
status: response.status
|
||||
}
|
||||
};
|
||||
|
||||
} finally {
|
||||
|
||||
// Isso garante que o timer seja limpo, quer a requisição funcione ou falhe (erro propagado)
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export const OnlyOfficeEditorServiceUpData = withClientErrorHandler(executeOnlyOfficeEditorServiceUpData);
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { object } from 'zod';
|
||||
|
||||
import GGramaticaInterface from '@/packages/administrativo/interfaces/GGramatica/GGramaticaInterface';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
import { OnlyOfficeEditorServiceUpData } from '../data/OnlyOfficeEditorServiceUpData';
|
||||
import { OnlyOfficeEditorPrepareService } from '../services/OnlyOfficeEditorPrepareService';
|
||||
|
||||
export const usePrepareOnlyOfficeEditorHook = () => {
|
||||
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [onlyOfficeEditor, setOnlyOfficeEditor] = useState<GGramaticaInterface[]>([]);
|
||||
const [serviceUpData, setServiceUpData] = useState<object>(object);
|
||||
|
||||
const prepareOnlyOfficeEditorHook = async () => {
|
||||
|
||||
// Busca as confgiurações do editor
|
||||
const response = await OnlyOfficeEditorPrepareService();
|
||||
|
||||
// Define a url do editor
|
||||
const urlServer = `http://${response.data.ip}:${response.data.port_only_office}`
|
||||
|
||||
// Busca as confgiurações do editor
|
||||
const responseServiceUp = await OnlyOfficeEditorServiceUpData(urlServer);
|
||||
|
||||
if (responseServiceUp.status != 200) {
|
||||
setResponse({
|
||||
status: responseServiceUp.status,
|
||||
detail: 'Não foi possivel conectar ao editor',
|
||||
message: 'Não foi possivel conectar ao editor'
|
||||
})
|
||||
}
|
||||
|
||||
// Armazena os dados consultados
|
||||
setOnlyOfficeEditor(response.data);
|
||||
|
||||
// Define a resposta (toast, modal, feedback, etc.)
|
||||
setResponse(response);
|
||||
|
||||
// Retorna os dados imediatamente
|
||||
return response;
|
||||
|
||||
};
|
||||
|
||||
return {
|
||||
onlyOfficeEditor,
|
||||
prepareOnlyOfficeEditorHook,
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export default interface OnlyOfficeInteface {
|
||||
id: string;
|
||||
config: object;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
'use server';
|
||||
|
||||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import { OnlyOfficeEditorPrepareData } from '@/shared/components/editor/onlyoffice/data/OnlyOfficeEditorPrepareData';
|
||||
|
||||
export default async function executeOnlyOfficeEditorPrepareService() {
|
||||
const response = await OnlyOfficeEditorPrepareData();
|
||||
return response;
|
||||
}
|
||||
|
||||
export const OnlyOfficeEditorPrepareService = withClientErrorHandler(executeOnlyOfficeEditorPrepareService);
|
||||
|
|
@ -17,7 +17,7 @@ export default class API {
|
|||
|
||||
try {
|
||||
// Verifica se todos os dados estão corretos
|
||||
this.ApiSchema.url = process.env.NEXT_PUBLIC_ORIUS_APP_API_URL;
|
||||
this.ApiSchema.url = process.env.NEXT_PUBLIC_ORIUS_APP_API_URL + ':' + process.env.NEXT_PUBLIC_ORIUS_APP_API_PORT + '/';
|
||||
this.ApiSchema.prefix = process.env.NEXT_PUBLIC_ORIUS_APP_API_PREFIX;
|
||||
this.ApiSchema.endpoint = _data.endpoint;
|
||||
this.ApiSchema.contentType = process.env.NEXT_PUBLIC_ORIUS_APP_API_CONTENT_TYPE;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue