feat(initial): 🎉 Initialize Next.js template
This commit is contained in:
parent
54d2c520e5
commit
db28a17bf8
@ -1,3 +1,50 @@
|
|||||||
|
// devDependencies required
|
||||||
|
// - eslint
|
||||||
|
// - eslint-config-next
|
||||||
|
// - eslint-config-standard
|
||||||
|
// - eslint-plugin-import
|
||||||
|
// - eslint-plugin-n
|
||||||
|
// - eslint-plugin-promise
|
||||||
|
// - eslint-plugin-react
|
||||||
|
// - eslint-plugin-tailwindcss
|
||||||
|
|
||||||
|
// command yarn install
|
||||||
|
|
||||||
|
// yarn add -D eslint eslint-plugin-react eslint-config-next eslint-config-standard eslint-plugin-tailwindcss eslint-plugin-n eslint-plugin-promise
|
||||||
|
|
||||||
{
|
{
|
||||||
"extends": "next/core-web-vitals"
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es2021": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:react/recommended",
|
||||||
|
"next/core-web-vitals",
|
||||||
|
"standard",
|
||||||
|
"plugin:tailwindcss/recommended"
|
||||||
|
],
|
||||||
|
"overrides": [],
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": "latest",
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": ["react", "tailwindcss"],
|
||||||
|
"rules": {
|
||||||
|
"react-hooks/exhaustive-deps": "off",
|
||||||
|
"tailwindcss/no-custom-classname": "off",
|
||||||
|
"tailwindcss/classnames-order": "error",
|
||||||
|
"camelcase": "off",
|
||||||
|
"react-hooks/rules-of-hooks": "off",
|
||||||
|
"object-curly-spacing": [2, "always"],
|
||||||
|
"no-console": ["warn", { "allow": ["warn", "error"] }],
|
||||||
|
"indent": [
|
||||||
|
"error",
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
"SwitchCase": 1,
|
||||||
|
"flatTernaryExpressions": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
9
.gitignore
vendored
9
.gitignore
vendored
@ -4,7 +4,6 @@
|
|||||||
/node_modules
|
/node_modules
|
||||||
/.pnp
|
/.pnp
|
||||||
.pnp.js
|
.pnp.js
|
||||||
.yarn/install-state.gz
|
|
||||||
|
|
||||||
# testing
|
# testing
|
||||||
/coverage
|
/coverage
|
||||||
@ -24,6 +23,7 @@
|
|||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
.env*.local
|
.env*.local
|
||||||
@ -34,3 +34,10 @@ yarn-error.log*
|
|||||||
# typescript
|
# typescript
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
next-env.d.ts
|
next-env.d.ts
|
||||||
|
|
||||||
|
.env*.local
|
||||||
|
yarn.lock
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
#yarn
|
||||||
|
/.yarn
|
13
.vscode/settings.json
vendored
Normal file
13
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.detectIndentation": false,
|
||||||
|
"search.exclude": {
|
||||||
|
"package-lock.json": true
|
||||||
|
},
|
||||||
|
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.addMissingImports": true,
|
||||||
|
"source.fixAll.eslint": true
|
||||||
|
}
|
||||||
|
}
|
8
LICENSE
Normal file
8
LICENSE
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
ISC License:
|
||||||
|
|
||||||
|
Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
Copyright (c) 1995-2003 by Internet Software Consortium
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
config/default.json
Normal file
14
config/default.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"constants": {
|
||||||
|
"plataforma": "web",
|
||||||
|
"publicPath": "/smartoperation",
|
||||||
|
"urlServerImages" : "https://gt.via-asesores.com/smartoperation/orbisapi/dtsrv/dev/operation?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTso",
|
||||||
|
"urlWebApi": "https://gt.via-asesores.com/smartoperation/orbisapi/api/dev/operation?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTso",
|
||||||
|
"urlUploadApi": "https://gt.via-asesores.com/smartoperation/orbisapi/upload/dev/operation?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTso",
|
||||||
|
"appTitle": "SmartOperation",
|
||||||
|
"idApp": "smartoperation",
|
||||||
|
"publicKey":"-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA205Ag8sXnqc0XsPa4NiS tZSca+3afzgkMdpotsIOphZxketyBLs4QOKYsAHGw51R68fbx5oLmDCn7a4n4ZtT u39ksIQg1lwQ3y7pqfb9BbYZKhtYigL8URUVrsQ5EuZxk9BOHHez59gizNzM+Vp0 zlnOuJVZdVdp3d+d1z+oE3ejsdXLGFEjAblo8GNQxTgxOXJk2VQ+4yQX5QN+mEYS FQpJqP9z5Y+/SVXlD3e943XjuNOFZwSG2uVkW3tuKsvGBOA38xLKydY9hb5y0WdM E0/hnOvB6gfIOovSmdTonDF3224iGQJa8RXss3SN+6NeLnhJQYGBri6U4sa0lNR/ 5vip/VCzaHliYERTztT2NgW6WUZAEW05gjN6Qid2eB7lKs/ND3BQkDHUKqouNDO1 xookeBqSg7fT/l3D6D7QzJE5Jc+bdZUDrr2MeYXehzbGg8sUBXJZbOu6GUkDSM5Y C8r/SnZhhA0ancQZZW/t4TmFNiLiGrqNS4uJf4UHKKsmXHCKDKB/bdlp60lTl6YF ocGzW6tBPdDFD7S5UTPqg//ob6mvuPFJ0E6t8Le60P+UiZIdmINe9dX9darS0VNH +eCVLj1J7iQNyXrelD5sE7xhAvQ3+jp3Q4mXWVgOZi1Uh/+/iNXDxrAtzKipYAOg zuyH0DDtO3E4JSiv4qr8o+UCAwEAAQ== -----END PUBLIC KEY-----",
|
||||||
|
"maxMbUpload": 4,
|
||||||
|
"defaultLocale": "es"
|
||||||
|
}
|
||||||
|
}
|
14
config/gt.json
Normal file
14
config/gt.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"constants": {
|
||||||
|
"plataforma": "web",
|
||||||
|
"publicPath": "/smartoperation",
|
||||||
|
"urlServerImages" : "https://gt.via-asesores.com/smartoperation/orbisapi/dtsrv/dev/orbis?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTMw",
|
||||||
|
"urlWebApi": "https://gt.via-asesores.com/smartoperation/orbisapi/api/dev/orbis?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTMw",
|
||||||
|
"urlUploadApi": "https://gt.via-asesores.com/smartoperation/orbisapi/upload/dev/orbis?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTMw",
|
||||||
|
"appTitle": "SmartOperation",
|
||||||
|
"idApp": "smartoperation",
|
||||||
|
"publicKey":"-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA205Ag8sXnqc0XsPa4NiS tZSca+3afzgkMdpotsIOphZxketyBLs4QOKYsAHGw51R68fbx5oLmDCn7a4n4ZtT u39ksIQg1lwQ3y7pqfb9BbYZKhtYigL8URUVrsQ5EuZxk9BOHHez59gizNzM+Vp0 zlnOuJVZdVdp3d+d1z+oE3ejsdXLGFEjAblo8GNQxTgxOXJk2VQ+4yQX5QN+mEYS FQpJqP9z5Y+/SVXlD3e943XjuNOFZwSG2uVkW3tuKsvGBOA38xLKydY9hb5y0WdM E0/hnOvB6gfIOovSmdTonDF3224iGQJa8RXss3SN+6NeLnhJQYGBri6U4sa0lNR/ 5vip/VCzaHliYERTztT2NgW6WUZAEW05gjN6Qid2eB7lKs/ND3BQkDHUKqouNDO1 xookeBqSg7fT/l3D6D7QzJE5Jc+bdZUDrr2MeYXehzbGg8sUBXJZbOu6GUkDSM5Y C8r/SnZhhA0ancQZZW/t4TmFNiLiGrqNS4uJf4UHKKsmXHCKDKB/bdlp60lTl6YF ocGzW6tBPdDFD7S5UTPqg//ob6mvuPFJ0E6t8Le60P+UiZIdmINe9dX9darS0VNH +eCVLj1J7iQNyXrelD5sE7xhAvQ3+jp3Q4mXWVgOZi1Uh/+/iNXDxrAtzKipYAOg zuyH0DDtO3E4JSiv4qr8o+UCAwEAAQ== -----END PUBLIC KEY-----",
|
||||||
|
"maxMbUpload": 4,
|
||||||
|
"defaultLocale": "es"
|
||||||
|
}
|
||||||
|
}
|
14
config/testing.json
Normal file
14
config/testing.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"constants": {
|
||||||
|
"plataforma": "web",
|
||||||
|
"publicPath": "/smartoperation",
|
||||||
|
"urlServerImages" : "https://localhost:3000/smartoperation/orbisapi/dtsrv/dev/orbis?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTMw",
|
||||||
|
"urlWebApi": "https://localhost:3000/smartoperation/orbisapi/api/dev/orbis?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTMw",
|
||||||
|
"urlUploadApi": "https://localhost:3000/smartoperation/orbisapi/upload/dev/orbis?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTMw",
|
||||||
|
"appTitle": "SmartOperation",
|
||||||
|
"idApp": "smartoperation",
|
||||||
|
"publicKey":"-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA205Ag8sXnqc0XsPa4NiS tZSca+3afzgkMdpotsIOphZxketyBLs4QOKYsAHGw51R68fbx5oLmDCn7a4n4ZtT u39ksIQg1lwQ3y7pqfb9BbYZKhtYigL8URUVrsQ5EuZxk9BOHHez59gizNzM+Vp0 zlnOuJVZdVdp3d+d1z+oE3ejsdXLGFEjAblo8GNQxTgxOXJk2VQ+4yQX5QN+mEYS FQpJqP9z5Y+/SVXlD3e943XjuNOFZwSG2uVkW3tuKsvGBOA38xLKydY9hb5y0WdM E0/hnOvB6gfIOovSmdTonDF3224iGQJa8RXss3SN+6NeLnhJQYGBri6U4sa0lNR/ 5vip/VCzaHliYERTztT2NgW6WUZAEW05gjN6Qid2eB7lKs/ND3BQkDHUKqouNDO1 xookeBqSg7fT/l3D6D7QzJE5Jc+bdZUDrr2MeYXehzbGg8sUBXJZbOu6GUkDSM5Y C8r/SnZhhA0ancQZZW/t4TmFNiLiGrqNS4uJf4UHKKsmXHCKDKB/bdlp60lTl6YF ocGzW6tBPdDFD7S5UTPqg//ob6mvuPFJ0E6t8Le60P+UiZIdmINe9dX9darS0VNH +eCVLj1J7iQNyXrelD5sE7xhAvQ3+jp3Q4mXWVgOZi1Uh/+/iNXDxrAtzKipYAOg zuyH0DDtO3E4JSiv4qr8o+UCAwEAAQ== -----END PUBLIC KEY-----",
|
||||||
|
"maxMbUpload": 4,
|
||||||
|
"defaultLocale": "es"
|
||||||
|
}
|
||||||
|
}
|
14
config/www.json
Normal file
14
config/www.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"constants": {
|
||||||
|
"plataforma": "web",
|
||||||
|
"publicPath": "/smartoperation",
|
||||||
|
"urlServerImages" : "https://www.via-asesores.com/smartoperation/orbisapi/dtsrv/prod/orbis?apikey=MDJmNTEwOWUtNWY2ZC00OGJlLThjZGQtNWM4NmEyNmZmN2U5",
|
||||||
|
"urlWebApi": "https://www.via-asesores.com/smartoperation/orbisapi/api/prod/orbis?apikey=MDJmNTEwOWUtNWY2ZC00OGJlLThjZGQtNWM4NmEyNmZmN2U5",
|
||||||
|
"urlUploadApi": "https://www.via-asesores.com/smartoperation/orbisapi/upload/prod/orbis?apikey=MDJmNTEwOWUtNWY2ZC00OGJlLThjZGQtNWM4NmEyNmZmN2U5",
|
||||||
|
"appTitle": "SmartOperation",
|
||||||
|
"idApp": "smartoperation",
|
||||||
|
"publicKey":"-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA205Ag8sXnqc0XsPa4NiS tZSca+3afzgkMdpotsIOphZxketyBLs4QOKYsAHGw51R68fbx5oLmDCn7a4n4ZtT u39ksIQg1lwQ3y7pqfb9BbYZKhtYigL8URUVrsQ5EuZxk9BOHHez59gizNzM+Vp0 zlnOuJVZdVdp3d+d1z+oE3ejsdXLGFEjAblo8GNQxTgxOXJk2VQ+4yQX5QN+mEYS FQpJqP9z5Y+/SVXlD3e943XjuNOFZwSG2uVkW3tuKsvGBOA38xLKydY9hb5y0WdM E0/hnOvB6gfIOovSmdTonDF3224iGQJa8RXss3SN+6NeLnhJQYGBri6U4sa0lNR/ 5vip/VCzaHliYERTztT2NgW6WUZAEW05gjN6Qid2eB7lKs/ND3BQkDHUKqouNDO1 xookeBqSg7fT/l3D6D7QzJE5Jc+bdZUDrr2MeYXehzbGg8sUBXJZbOu6GUkDSM5Y C8r/SnZhhA0ancQZZW/t4TmFNiLiGrqNS4uJf4UHKKsmXHCKDKB/bdlp60lTl6YF ocGzW6tBPdDFD7S5UTPqg//ob6mvuPFJ0E6t8Le60P+UiZIdmINe9dX9darS0VNH +eCVLj1J7iQNyXrelD5sE7xhAvQ3+jp3Q4mXWVgOZi1Uh/+/iNXDxrAtzKipYAOg zuyH0DDtO3E4JSiv4qr8o+UCAwEAAQ== -----END PUBLIC KEY-----",
|
||||||
|
"maxMbUpload": 4,
|
||||||
|
"defaultLocale": "es"
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,44 @@
|
|||||||
|
const config = require('config')
|
||||||
|
const constants = config.get('constants')
|
||||||
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
|
|
||||||
|
const rewrites = async () => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/orbisapi/:path*',
|
||||||
|
destination: 'http://localhost:9000/:path*' // Proxy to Backend
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const redirects = async () => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/mantenimientos',
|
||||||
|
destination: constants.publicPath,
|
||||||
|
basePath: true,
|
||||||
|
permanent: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
|
env: {
|
||||||
|
...constants
|
||||||
|
},
|
||||||
|
images: {
|
||||||
|
domains: ['www.via-asesores.com', 'gt.via-asesores.com'],
|
||||||
|
unoptimized: true
|
||||||
|
},
|
||||||
|
assetPrefix: constants.publicPath,
|
||||||
|
basePath: constants.publicPath,
|
||||||
|
compiler: {
|
||||||
|
styledComponents: true
|
||||||
|
},
|
||||||
|
rewrites,
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
|
swcMinify: true
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = nextConfig
|
module.exports = nextConfig
|
||||||
|
31
package.json
31
package.json
@ -1,27 +1,48 @@
|
|||||||
{
|
{
|
||||||
"name": "next-template",
|
"name": "next-template",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
|
"description": "My Next.js project",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.via-asesores.com/jmaritar/next-template"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"operations",
|
||||||
|
"orbis",
|
||||||
|
"smart",
|
||||||
|
"route",
|
||||||
|
"sales",
|
||||||
|
"delivery"
|
||||||
|
],
|
||||||
|
"author": "guatemala@via-asesores.com",
|
||||||
|
"license": "ISC",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
|
"generate": "next build && next export",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"next": "14.0.4",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18"
|
||||||
"next": "14.0.4"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5",
|
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
"autoprefixer": "^10.0.1",
|
"autoprefixer": "^10.0.1",
|
||||||
|
"eslint": "^8.56.0",
|
||||||
|
"eslint-config-next": "^14.0.4",
|
||||||
|
"eslint-config-standard": "^17.1.0",
|
||||||
|
"eslint-plugin-n": "^16.5.0",
|
||||||
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
|
"eslint-plugin-react": "^7.33.2",
|
||||||
|
"eslint-plugin-tailwindcss": "^3.13.0",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"tailwindcss": "^3.3.0",
|
"tailwindcss": "^3.3.0",
|
||||||
"eslint": "^8",
|
"typescript": "^5"
|
||||||
"eslint-config-next": "14.0.4"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
public/images/cancel.png
Normal file
BIN
public/images/cancel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
103
src/helper/clientApi.js
Normal file
103
src/helper/clientApi.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import forge from 'node-forge'
|
||||||
|
|
||||||
|
const constants = {
|
||||||
|
urlWebApi: process.env.urlWebApi,
|
||||||
|
urlUploadApi: process.env.urlUploadApi,
|
||||||
|
publicKey: process.env.publicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
const uris = {
|
||||||
|
procedure: '',
|
||||||
|
upload: '/upload'
|
||||||
|
}
|
||||||
|
|
||||||
|
const encryptRsa = function (obj) {
|
||||||
|
const encoded = forge.util.encodeUtf8(obj)
|
||||||
|
const publicKey = forge.pki.publicKeyFromPem(constants.publicKey)
|
||||||
|
const encrypted = publicKey.encrypt(encoded, 'RSA-OAEP', {
|
||||||
|
md: forge.md.sha256.create(),
|
||||||
|
mgf1: forge.mgf1.create()
|
||||||
|
})
|
||||||
|
const base64 = forge.util.encode64(encrypted)
|
||||||
|
return base64
|
||||||
|
}
|
||||||
|
|
||||||
|
const callWs = async (uri, json) => {
|
||||||
|
// Send the form data to our API and get a response.
|
||||||
|
const response = await fetch(uri, {
|
||||||
|
// Body of the request is the JSON data we created above.
|
||||||
|
body: JSON.stringify(json),
|
||||||
|
// Tell the server we're sending JSON.
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
// The method is POST because we are sending data.
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get the response data from server as JSON.
|
||||||
|
// If server returns the name submitted, that means the form works.
|
||||||
|
const result = await response.json()
|
||||||
|
return result.data // return data rows
|
||||||
|
}
|
||||||
|
|
||||||
|
const callUpload = (fileToUpload) => {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
// console.log('callUpload', constants.urlWebApi)
|
||||||
|
const params = { method: 'POST', body: fileToUpload }
|
||||||
|
// console.log('callUpload', params)
|
||||||
|
fetch(constants.urlUploadApi, params)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then((json) => {
|
||||||
|
// console.log('response upload', json)
|
||||||
|
resolve(json)
|
||||||
|
}).catch((error) => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const upload = async (fileUpload) => {
|
||||||
|
return await callUpload(fileUpload)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { upload }
|
||||||
|
|
||||||
|
const execute = async (spName, params, encriptado = 0, loading = false, connInfo = undefined) => {
|
||||||
|
let model = {}
|
||||||
|
if (typeof spName === 'string') {
|
||||||
|
model.nombre = spName
|
||||||
|
model.loading = loading
|
||||||
|
// verifica que los parametros vengan como Array
|
||||||
|
model.parametros = params ?? []
|
||||||
|
// si la información se envía encriptada
|
||||||
|
if (encriptado === 1) {
|
||||||
|
const paramsToEncrypt = {
|
||||||
|
nombre: spName,
|
||||||
|
parametros: params
|
||||||
|
}
|
||||||
|
const paramsEncryptedString = encryptRsa(JSON.stringify(paramsToEncrypt))
|
||||||
|
|
||||||
|
model.nombre = ''
|
||||||
|
model.encriptado = 1
|
||||||
|
model.parametros = paramsEncryptedString
|
||||||
|
}
|
||||||
|
} else if (typeof spName === 'object') {
|
||||||
|
if (encriptado === 1) {
|
||||||
|
const paramsEncryptedString = encryptRsa(JSON.stringify(spName))
|
||||||
|
model.parametros = paramsEncryptedString
|
||||||
|
model.encriptado = 1
|
||||||
|
model.loading = loading
|
||||||
|
} else {
|
||||||
|
model = spName
|
||||||
|
model.loading = loading
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connInfo) {
|
||||||
|
return await callWs(connInfo.api + '/' + connInfo.env + '/' + connInfo.exposeRoute + '?apikey=' + connInfo.apikey, model)
|
||||||
|
}
|
||||||
|
return await callWs(constants.urlWebApi + uris.procedure, model)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { execute }
|
9
src/hooks/useGlobalContainer.js
Normal file
9
src/hooks/useGlobalContainer.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { useContext } from 'react'
|
||||||
|
import { LayoutContext } from '@/layout/ResponsiveContainer'
|
||||||
|
|
||||||
|
const useGlobalContainer = () => {
|
||||||
|
const container = useContext(LayoutContext)
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useGlobalContainer
|
54
src/hooks/useGlobalFilters.js
Normal file
54
src/hooks/useGlobalFilters.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
import functions from 'v-functions'
|
||||||
|
|
||||||
|
const safeGetPathname = () => {
|
||||||
|
return typeof window !== 'undefined' ? window.location.pathname : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const useGlobalFilters = () => {
|
||||||
|
const [rutaActual, setRutaActual] = useState(safeGetPathname())
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setRutaActual(safeGetPathname())
|
||||||
|
}, [safeGetPathname()])
|
||||||
|
|
||||||
|
const getFiltersFromLocalStorage = () => {
|
||||||
|
const storedFilters = functions.getDecodeStorage('globalFilters')
|
||||||
|
const parsedFilters = storedFilters ? JSON.parse(storedFilters) : {}
|
||||||
|
return parsedFilters[rutaActual] || {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setFilters = (keyOrObject, value) => {
|
||||||
|
const prevFilters = getFiltersFromLocalStorage()
|
||||||
|
let updatedFilters
|
||||||
|
|
||||||
|
if (typeof keyOrObject === 'object' && value === undefined) {
|
||||||
|
updatedFilters = { ...prevFilters, ...keyOrObject }
|
||||||
|
} else {
|
||||||
|
updatedFilters = { ...prevFilters, [keyOrObject]: value }
|
||||||
|
}
|
||||||
|
|
||||||
|
const storedFilters = functions.getDecodeStorage('globalFilters')
|
||||||
|
const globalFilters = storedFilters ? JSON.parse(storedFilters) : {}
|
||||||
|
functions.setEncodeStorage(
|
||||||
|
'globalFilters',
|
||||||
|
JSON.stringify({ ...globalFilters, [rutaActual]: updatedFilters })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearFiltersForRoute = () => {
|
||||||
|
const storedFilters = functions.getDecodeStorage('globalFilters')
|
||||||
|
const globalFilters = storedFilters ? JSON.parse(storedFilters) : {}
|
||||||
|
functions.setEncodeStorage('globalFilters', JSON.stringify({ ...globalFilters, [rutaActual]: {} }))
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearAllFilters = () => {
|
||||||
|
functions.setEncodeStorage('globalFilters', JSON.stringify({}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const filters = getFiltersFromLocalStorage()
|
||||||
|
|
||||||
|
return [filters, setFilters, clearFiltersForRoute, clearAllFilters]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useGlobalFilters
|
13
src/hooks/useHasMounted.js
Normal file
13
src/hooks/useHasMounted.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
const useHasMounted = () => {
|
||||||
|
const [hasMounted, setHasMounted] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setHasMounted(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return hasMounted
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useHasMounted
|
9
src/hooks/useI18n.js
Normal file
9
src/hooks/useI18n.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { useContext } from 'react'
|
||||||
|
import { I18nContext } from '@/plugins/i18nContext'
|
||||||
|
|
||||||
|
const useI18n = () => {
|
||||||
|
const i18n = useContext(I18nContext)
|
||||||
|
return i18n
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useI18n
|
9
src/hooks/useLoading.js
Normal file
9
src/hooks/useLoading.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { useContext } from 'react'
|
||||||
|
import { LoadingContext } from '@/plugins/LoadingContext'
|
||||||
|
|
||||||
|
const useLoading = () => {
|
||||||
|
const loading = useContext(LoadingContext)
|
||||||
|
return loading
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useLoading
|
120
src/hooks/useLocalStorage.js
Normal file
120
src/hooks/useLocalStorage.js
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import { useState, useEffect, useCallback } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import functions from 'v-functions'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Función para parsear JSON. Maneja los valores 'undefined' y errores de parseo.
|
||||||
|
* @param {string | null} value - El valor JSON como string para parsear.
|
||||||
|
* @returns {any} El objeto JavaScript parseado o undefined si hay un error.
|
||||||
|
*/
|
||||||
|
function parseJSON (value) {
|
||||||
|
try {
|
||||||
|
return value === 'undefined' ? undefined : JSON.parse(value ?? '')
|
||||||
|
} catch {
|
||||||
|
console.error('Error al parsear', { value })
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook personalizado para interactuar con el localStorage del navegador.
|
||||||
|
* Permite almacenar, actualizar y recuperar un valor de localStorage.
|
||||||
|
*
|
||||||
|
* @param {string} key - La clave bajo la cual almacenar el valor en localStorage.
|
||||||
|
* @param {any} initialValue - El valor inicial a usar si no hay nada en localStorage.
|
||||||
|
* @returns {Array} Un array con el valor almacenado y la función para actualizarlo.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* // Uso en un componente React funcional
|
||||||
|
* const MyComponent = () => {
|
||||||
|
* // Utiliza el hook para almacenar un valor en localStorage
|
||||||
|
* const [name, setName] = useLocalStorage('name', 'Nombre inicial');
|
||||||
|
*
|
||||||
|
* return (
|
||||||
|
* <div>
|
||||||
|
* <input
|
||||||
|
* type="text"
|
||||||
|
* value={name}
|
||||||
|
* onChange={(e) => setName(e.target.value)}
|
||||||
|
* />
|
||||||
|
* <p>El nombre es: {name}</p>
|
||||||
|
* </div>
|
||||||
|
* );
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
const useLocalStorage = (key, initialValue) => {
|
||||||
|
const [storedValue, setStoredValue] = useState(initialValue)
|
||||||
|
const [initialized, setInitialized] = useState(false)
|
||||||
|
|
||||||
|
const readValue = useCallback(() => {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
return initialValue
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// const item = window.localStorage.getItem(key)
|
||||||
|
const item = functions.getDecodeStorage(key)
|
||||||
|
return item ? parseJSON(item) : initialValue
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`Error al leer la clave ${key} del localStorage:`, error)
|
||||||
|
return initialValue
|
||||||
|
}
|
||||||
|
}, [key, initialValue])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setInitialized(true)
|
||||||
|
setStoredValue(readValue())
|
||||||
|
}, [readValue])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!initialized) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleStorageChange = (event) => {
|
||||||
|
if (event.key && event.key !== key) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setStoredValue(readValue())
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('storage', handleStorageChange)
|
||||||
|
window.addEventListener('local-storage', handleStorageChange)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('storage', handleStorageChange)
|
||||||
|
window.removeEventListener('local-storage', handleStorageChange)
|
||||||
|
}
|
||||||
|
}, [key, readValue, initialized])
|
||||||
|
|
||||||
|
const setValue = (value) => {
|
||||||
|
if (typeof window === 'undefined' || !initialized) {
|
||||||
|
console.warn(`Intentando establecer la clave ${key} del localStorage en un entorno no cliente.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const newValue = value instanceof Function ? value(storedValue) : value
|
||||||
|
// window.localStorage.setItem(key, JSON.stringify(newValue))
|
||||||
|
functions.setEncodeStorage(key, JSON.stringify(newValue))
|
||||||
|
setStoredValue(newValue)
|
||||||
|
window.dispatchEvent(new Event('local-storage'))
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`Error al establecer la clave ${key} en el localStorage:`, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [storedValue, setValue]
|
||||||
|
}
|
||||||
|
|
||||||
|
useLocalStorage.propTypes = {
|
||||||
|
key: PropTypes.string.isRequired,
|
||||||
|
initialValue: PropTypes.any
|
||||||
|
}
|
||||||
|
|
||||||
|
useLocalStorage.defaultProps = {
|
||||||
|
initialValue: null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useLocalStorage
|
76
src/hooks/useRoute.js
Normal file
76
src/hooks/useRoute.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { createContext, useContext, useState, useEffect } from 'react'
|
||||||
|
import environment from '@/utils/environment'
|
||||||
|
|
||||||
|
export const RouteContext = createContext()
|
||||||
|
|
||||||
|
export const useRoute = () => {
|
||||||
|
return useContext(RouteContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RouteProvider = ({ children }) => {
|
||||||
|
const [breadcrumbsList, setBreadcrumbsList] = useState([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const storedBreadcrumbs = JSON.parse(sessionStorage.getItem('breadcrumbsList')) || []
|
||||||
|
if (storedBreadcrumbs.length !== 0) {
|
||||||
|
setBreadcrumbsList(storedBreadcrumbs)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
sessionStorage.setItem('breadcrumbsList', JSON.stringify(breadcrumbsList))
|
||||||
|
}, [breadcrumbsList])
|
||||||
|
|
||||||
|
const addBreadcrumb = (title, location) => {
|
||||||
|
const timestamp = '/' + environment.getTime()
|
||||||
|
if (location.endsWith(timestamp)) {
|
||||||
|
location = location.replace(timestamp, '')
|
||||||
|
} else if (location.endsWith('[...index]')) {
|
||||||
|
location = location.replace('/[...index]', '')
|
||||||
|
}
|
||||||
|
|
||||||
|
setBreadcrumbsList(prev => {
|
||||||
|
const lastBreadcrumb = prev[prev.length - 1]
|
||||||
|
if (lastBreadcrumb && lastBreadcrumb.location === location && lastBreadcrumb.title === title) {
|
||||||
|
return prev
|
||||||
|
}
|
||||||
|
return [...prev, { title, location }]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const breadcrumbsListArr = () => {
|
||||||
|
return breadcrumbsList.slice(0, breadcrumbsList.length - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const truncateBreadcrumbs = (index) => {
|
||||||
|
setBreadcrumbsList(prev => prev.slice(0, index))
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handlePopState = () => {
|
||||||
|
setBreadcrumbsList(prev => {
|
||||||
|
const newArr = [...prev]
|
||||||
|
newArr.pop()
|
||||||
|
return newArr
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('popstate', handlePopState)
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('popstate', handlePopState)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const value = {
|
||||||
|
breadcrumbsListArr,
|
||||||
|
addBreadcrumb,
|
||||||
|
truncateBreadcrumbs,
|
||||||
|
breadcrumbsList // Incluir breadcrumbsList en el valor del contexto
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RouteContext.Provider value={value}>
|
||||||
|
{children}
|
||||||
|
</RouteContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
35
src/hooks/useScreenType.js
Normal file
35
src/hooks/useScreenType.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import mq from 'js-mq'
|
||||||
|
|
||||||
|
const useScreenType = () => {
|
||||||
|
const [isMobile, setIsMobile] = useState(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
||||||
|
try {
|
||||||
|
mq.register([
|
||||||
|
{ name: 'mobile', query: '(max-width: 767px)' },
|
||||||
|
{ name: 'desktop', query: '(min-width: 768px)' }
|
||||||
|
])
|
||||||
|
mq.on('mobile', (e) => {
|
||||||
|
setIsMobile(true)
|
||||||
|
})
|
||||||
|
mq.on('desktop', (e) => {
|
||||||
|
setIsMobile(false)
|
||||||
|
})
|
||||||
|
const arrayEstadoMq = mq.getState()
|
||||||
|
if (arrayEstadoMq.length && (arrayEstadoMq[0] === 'not-mobile' || arrayEstadoMq[0] === 'desktop')) {
|
||||||
|
setIsMobile(false)
|
||||||
|
} else {
|
||||||
|
setIsMobile(true)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Error al registrar mq breackpoints - ${e.message}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return isMobile
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useScreenType
|
38
src/hooks/useStore.ts
Normal file
38
src/hooks/useStore.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { createStore } from 'react-simple-hook-store'
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
title: string;
|
||||||
|
usuarioPermisos: object | null;
|
||||||
|
valueEasyMDE: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IActions {
|
||||||
|
setTitle: (newState: string) => void;
|
||||||
|
setUsuarioPermisos: (newState: object | null) => void;
|
||||||
|
setValueForEasyMDE: (newState: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const { useStore, store } = createStore<IState, IActions>(
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
usuarioPermisos: null,
|
||||||
|
valueEasyMDE: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
setTitle: (store, newState) => {
|
||||||
|
store.setState({
|
||||||
|
title: newState
|
||||||
|
})
|
||||||
|
},
|
||||||
|
setUsuarioPermisos: (store, newState) => {
|
||||||
|
store.setState({
|
||||||
|
usuarioPermisos: newState
|
||||||
|
})
|
||||||
|
},
|
||||||
|
setValueForEasyMDE: (store, newState) => {
|
||||||
|
store.setState({
|
||||||
|
valueEasyMDE: newState
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
272
src/layout/ResponsiveContainer.jsx
Normal file
272
src/layout/ResponsiveContainer.jsx
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
import { useEffect, useState, createContext, useMemo } from 'react'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import { execute } from '@/helper/clientApi'
|
||||||
|
import environment from '@/utils/environment'
|
||||||
|
import presets from '@/utils/globalPresets'
|
||||||
|
import dynamic from 'next/dynamic'
|
||||||
|
import useLoading from '@/hooks/useLoading'
|
||||||
|
import { useStore } from '@/hooks/useStore'
|
||||||
|
import useHasMounted from '@/hooks/useHasMounted'
|
||||||
|
import useI18n from '@/hooks/useI18n'
|
||||||
|
import SessionTimeout from '@/components/SessionTimeout'
|
||||||
|
import UserOptionsMenu from '@/components/widgets/UserOptionsMenu'
|
||||||
|
import { toast } from 'react-toastify'
|
||||||
|
|
||||||
|
export const LayoutContext = createContext()
|
||||||
|
|
||||||
|
const Footer = dynamic(() => { return import('vComponents/dist/Footer') }, { ssr: false })
|
||||||
|
const Sidebar = dynamic(() => { return import('vComponents/dist/Sidebar') }, { ssr: false })
|
||||||
|
const Navbar = dynamic(() => { return import('vComponents/dist/Navbar') }, { ssr: false })
|
||||||
|
|
||||||
|
const ResponsiveContainer = ({ children }) => {
|
||||||
|
const router = useRouter()
|
||||||
|
const loading = useLoading()
|
||||||
|
const hasMounted = useHasMounted()
|
||||||
|
const i18n = useI18n()
|
||||||
|
const [_i18n, setI18n] = useState({ t: () => { return 'txtNone' } })
|
||||||
|
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(true)
|
||||||
|
const [menu, setMenu] = useState([])
|
||||||
|
const [title, setTitle] = useStore(s => s.title, a => a.setTitle)
|
||||||
|
const [userObj, setUserObj] = useState()
|
||||||
|
const [token, setToken] = useState('')
|
||||||
|
const [theme, setTheme] = useState(null)
|
||||||
|
const [constanteObj, setConstanteObj] = useState('')
|
||||||
|
|
||||||
|
const doLogout = async () => {
|
||||||
|
const redirectPath = await environment.logout()
|
||||||
|
await i18n.locale('es')
|
||||||
|
setUserObj(null)
|
||||||
|
setConstanteObj(null)
|
||||||
|
setTheme(null)
|
||||||
|
router.push(redirectPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// se ejecuta cuando expira la sesion
|
||||||
|
const onTimeout = () => {
|
||||||
|
doLogout()
|
||||||
|
}
|
||||||
|
|
||||||
|
// se ejecuta cuando el usuario indica explicitamente que sigue conectado en la sesion
|
||||||
|
const onCancelTimeout = async () => {
|
||||||
|
const sprUpdateSesion = 'SPR_SESION_U'
|
||||||
|
const result = await execute(sprUpdateSesion, [token])
|
||||||
|
if (environment.validaResultadoDB(result) === true) {
|
||||||
|
const updateUserObj = { ...userObj }
|
||||||
|
updateUserObj.tiempo_expiracion = result[0].tiempo_expiracion
|
||||||
|
updateUserObj.fecha_fin_sesion = result[0].fecha_fin_sesion
|
||||||
|
setUserObj(updateUserObj)
|
||||||
|
await environment.login(token, updateUserObj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setPreferences = async (opcion) => {
|
||||||
|
const env = await environment.getEnvUser()
|
||||||
|
// console.log((new Date()).toString(),'setPreferences userObj', userObj)
|
||||||
|
const sprInfoSesion = 'SPR_INFO_USUARIOS'
|
||||||
|
const response3 = await execute(sprInfoSesion, [env.token, opcion])
|
||||||
|
if (environment.validaResultadoDB(response3, i18n, toast, false) === true) {
|
||||||
|
// console.log('setPreferences', response3)
|
||||||
|
if (opcion === 'en' || opcion === 'es') {
|
||||||
|
env.user.i18n = opcion
|
||||||
|
// setLanguage(opcion)
|
||||||
|
}
|
||||||
|
if (opcion === 'light' || opcion === 'dark') {
|
||||||
|
env.user.theme = opcion
|
||||||
|
setTheme(opcion)
|
||||||
|
}
|
||||||
|
environment.setEnvUser(env.user)
|
||||||
|
if (environment.validaResultadoDB(response3, i18n, toast, false) === true) {
|
||||||
|
if (response3 && response3[0]) {
|
||||||
|
toast.success(response3[0].response, presets.toaster)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBackKeyDown = () => {
|
||||||
|
if (router.asPath === '/') {
|
||||||
|
// cuando esta en la pagina principal cierra la app
|
||||||
|
if (navigator.app) {
|
||||||
|
navigator.app.exitApp()
|
||||||
|
} else if (navigator.device) {
|
||||||
|
navigator.device.exitApp()
|
||||||
|
} else {
|
||||||
|
window.close()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.history.back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const validaPermisosRuta = async (token) => {
|
||||||
|
if (router.pathname.includes('/admin')) {
|
||||||
|
loading.start()
|
||||||
|
const tienePermiso = await environment.validaPermisos(token, 'S', 'N', 'N', 'N')
|
||||||
|
loading.stop()
|
||||||
|
if (tienePermiso === false) {
|
||||||
|
router.push(presets.locations.welcome)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (router.pathname.includes('/mantenimientos')) {
|
||||||
|
loading.start()
|
||||||
|
const tienePermiso = await environment.validaPermisos(token, 'N', 'S', 'N', 'N')
|
||||||
|
loading.stop()
|
||||||
|
if (tienePermiso === false) {
|
||||||
|
router.push(presets.locations.welcome)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getMenu = async () => {
|
||||||
|
loading.start()
|
||||||
|
setMenu([])
|
||||||
|
if (token && token !== null) {
|
||||||
|
const options = await execute('SPR_MENU_S', [token, 'BO', null])
|
||||||
|
setMenu(options)
|
||||||
|
}
|
||||||
|
loading.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
const getEnv = async () => {
|
||||||
|
try {
|
||||||
|
const env = await environment.getEnvUser()
|
||||||
|
|
||||||
|
if (!env || !env.token) {
|
||||||
|
doLogout()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setUserObj(env.user)
|
||||||
|
setConstanteObj(env.constante)
|
||||||
|
setToken(env.token)
|
||||||
|
setTheme(env.user.theme || 'light')
|
||||||
|
if (!env.user.i18n) {
|
||||||
|
const browserLanguage = window.navigator.language
|
||||||
|
if (browserLanguage === 'en' || browserLanguage === 'en-US') {
|
||||||
|
setPreferences('en')
|
||||||
|
} else {
|
||||||
|
setPreferences('es')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setPreferences(env.user.idioma)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
doLogout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTheme = () => {
|
||||||
|
if (!theme || theme != null) {
|
||||||
|
return theme
|
||||||
|
}
|
||||||
|
return 'light'
|
||||||
|
}
|
||||||
|
|
||||||
|
const containerWrapper = useMemo(() => ({
|
||||||
|
userObj,
|
||||||
|
setUserObj,
|
||||||
|
constanteObj,
|
||||||
|
setConstanteObj,
|
||||||
|
token,
|
||||||
|
setToken,
|
||||||
|
setTheme,
|
||||||
|
setTitle
|
||||||
|
}), [userObj, setUserObj, constanteObj, setConstanteObj, token, setToken, setTheme, setTitle])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setI18n(i18n)
|
||||||
|
}, [i18n])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getMenu()
|
||||||
|
}, [token])
|
||||||
|
|
||||||
|
// when page is mounted
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasMounted) {
|
||||||
|
getEnv().then(() => {
|
||||||
|
getMenu()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [hasMounted])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (process.browser && window.cordova) {
|
||||||
|
document.addEventListener('backbutton', onBackKeyDown, false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LayoutContext.Provider value={containerWrapper}>
|
||||||
|
|
||||||
|
<div className={`flex h-screen overflow-hidden ${getTheme()}`} >
|
||||||
|
{/* Sidebar */}
|
||||||
|
{
|
||||||
|
userObj && userObj.nombre_usuario &&
|
||||||
|
|
||||||
|
<Sidebar
|
||||||
|
sidebarOpen={sidebarOpen}
|
||||||
|
setSidebarOpen={setSidebarOpen}
|
||||||
|
menu={menu}
|
||||||
|
sidebarStyles={'via-bg-sidebar'}
|
||||||
|
appTitleStyles='via-apptitle-sidebar'
|
||||||
|
userInfoStyles='via-userinfo-sidebar'
|
||||||
|
optionStyles={'via-options-sidebar'}
|
||||||
|
iconOptionStyles={'via-icons-sidebar'}
|
||||||
|
suboptionStyles={'via-suboptions-sidebar'}
|
||||||
|
iconSuboptionStyles={'via-icons-subsidebar'}
|
||||||
|
onClickLogout={() => doLogout()}
|
||||||
|
setTitle={setTitle}
|
||||||
|
userObj={userObj}
|
||||||
|
environment={environment}
|
||||||
|
presets={presets}
|
||||||
|
router={router}
|
||||||
|
i18n={_i18n}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
|
{/* Content area */}
|
||||||
|
<div className={`${sidebarOpen ? 'relative' : 'absolute'} flex h-screen w-full flex-1 flex-col overflow-y-auto overflow-x-hidden bg-gray-100 dark:bg-gray-700`}>
|
||||||
|
|
||||||
|
{/* Site header */}
|
||||||
|
{userObj && userObj.nombre_usuario &&
|
||||||
|
|
||||||
|
<Navbar
|
||||||
|
sidebarOpen={sidebarOpen}
|
||||||
|
setSidebarOpen={setSidebarOpen}
|
||||||
|
navbarStyles="border-b via-navbar"
|
||||||
|
menuButtonStyles="via-menu-btn-navbar"
|
||||||
|
userMenuButtonStyles="via-usermenu-btn-navbar"
|
||||||
|
userOptionStyles="via-useroptions-navbar"
|
||||||
|
userOptionSelectedStyles="via-useroptions-selected-navbar"
|
||||||
|
onClickLogout={() => doLogout()}
|
||||||
|
onClickProfile={() => router.push(`${presets.locations.profile}/${environment.getTime()}`)}
|
||||||
|
MenuOptions={() => <UserOptionsMenu setPreferences={setPreferences} theme={theme} i18n={i18n} />}
|
||||||
|
title={title}
|
||||||
|
userObj={userObj}
|
||||||
|
router={router}
|
||||||
|
presets={presets}
|
||||||
|
|
||||||
|
/>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div className={userObj && userObj.nombre_usuario ? 'responsive-container' : ''}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
{
|
||||||
|
userObj && userObj.nombre_usuario &&
|
||||||
|
<SessionTimeout i18n={_i18n} user={userObj} onTimeout={() => onTimeout()} onCancelTimeout={() => onCancelTimeout()} />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<Footer />
|
||||||
|
</LayoutContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ResponsiveContainer
|
13
src/lib/utils.js
Normal file
13
src/lib/utils.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
|
||||||
|
export function cn (...inputs) {
|
||||||
|
const classes = inputs
|
||||||
|
.filter((input) => input)
|
||||||
|
.flatMap((input) =>
|
||||||
|
typeof input === 'object'
|
||||||
|
? Object.entries(input).filter(([, value]) => value).map(([key]) => key)
|
||||||
|
: input.split(' ')
|
||||||
|
)
|
||||||
|
|
||||||
|
return twMerge(...classes)
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { Html, Head, Main, NextScript } from 'next/document'
|
import { Html, Head, Main, NextScript } from 'next/document'
|
||||||
|
|
||||||
export default function Document() {
|
export default function Document () {
|
||||||
return (
|
return (
|
||||||
<Html lang="en">
|
<Html lang="en">
|
||||||
<Head />
|
<Head />
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
|
||||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
|
||||||
|
|
||||||
type Data = {
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function handler(
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse<Data>
|
|
||||||
) {
|
|
||||||
res.status(200).json({ name: 'John Doe' })
|
|
||||||
}
|
|
@ -3,17 +3,17 @@ import { Inter } from 'next/font/google'
|
|||||||
|
|
||||||
const inter = Inter({ subsets: ['latin'] })
|
const inter = Inter({ subsets: ['latin'] })
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home () {
|
||||||
return (
|
return (
|
||||||
<main
|
<main
|
||||||
className={`flex min-h-screen flex-col items-center justify-between p-24 ${inter.className}`}
|
className={`flex min-h-screen flex-col items-center justify-between p-24 ${inter.className}`}
|
||||||
>
|
>
|
||||||
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
|
<div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex">
|
||||||
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
|
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:dark:bg-zinc-800/30">
|
||||||
Get started by editing
|
Get started by editing
|
||||||
<code className="font-mono font-bold">src/pages/index.tsx</code>
|
<code className="font-mono font-bold">src/pages/index.tsx</code>
|
||||||
</p>
|
</p>
|
||||||
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
|
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white lg:static lg:h-auto lg:w-auto lg:bg-none dark:from-black dark:via-black">
|
||||||
<a
|
<a
|
||||||
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
|
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
|
||||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
|
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
|
||||||
@ -33,7 +33,7 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative flex place-items-center before:absolute before:h-[300px] before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700/10 after:dark:from-sky-900 after:dark:via-[#0141ff]/40 before:lg:h-[360px]">
|
<div className="relative flex place-items-center before:absolute before:h-[300px] before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:lg:h-[360px] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700/10 after:dark:from-sky-900 after:dark:via-[#0141ff]/40">
|
||||||
<Image
|
<Image
|
||||||
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
|
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
|
||||||
src="/next.svg"
|
src="/next.svg"
|
||||||
@ -44,20 +44,20 @@ export default function Home() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-32 grid text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left">
|
<div className="mb-32 grid text-center lg:mb-0 lg:w-full lg:max-w-5xl lg:grid-cols-4 lg:text-left">
|
||||||
<a
|
<a
|
||||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
|
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
|
||||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
<h2 className={'mb-3 text-2xl font-semibold'}>
|
||||||
Docs{' '}
|
Docs{' '}
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||||
->
|
->
|
||||||
</span>
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
<p className={'m-0 max-w-[30ch] text-sm opacity-50'}>
|
||||||
Find in-depth information about Next.js features and API.
|
Find in-depth information about Next.js features and API.
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
@ -68,13 +68,13 @@ export default function Home() {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
<h2 className={'mb-3 text-2xl font-semibold'}>
|
||||||
Learn{' '}
|
Learn{' '}
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||||
->
|
->
|
||||||
</span>
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
<p className={'m-0 max-w-[30ch] text-sm opacity-50'}>
|
||||||
Learn about Next.js in an interactive course with quizzes!
|
Learn about Next.js in an interactive course with quizzes!
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
@ -85,13 +85,13 @@ export default function Home() {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
<h2 className={'mb-3 text-2xl font-semibold'}>
|
||||||
Templates{' '}
|
Templates{' '}
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||||
->
|
->
|
||||||
</span>
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
<p className={'m-0 max-w-[30ch] text-sm opacity-50'}>
|
||||||
Discover and deploy boilerplate example Next.js projects.
|
Discover and deploy boilerplate example Next.js projects.
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
@ -102,13 +102,13 @@ export default function Home() {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
<h2 className={`mb-3 text-2xl font-semibold`}>
|
<h2 className={'mb-3 text-2xl font-semibold'}>
|
||||||
Deploy{' '}
|
Deploy{' '}
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||||
->
|
->
|
||||||
</span>
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
|
<p className={'m-0 max-w-[30ch] text-sm opacity-50'}>
|
||||||
Instantly deploy your Next.js site to a shareable URL with Vercel.
|
Instantly deploy your Next.js site to a shareable URL with Vercel.
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
|
26
src/plugins/LoadingContext.jsx
Normal file
26
src/plugins/LoadingContext.jsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { createContext, useContext, useState } from 'react'
|
||||||
|
import dynamic from 'next/dynamic'
|
||||||
|
import presets from '@/utils/globalPresets'
|
||||||
|
|
||||||
|
const LoadingSpinner = dynamic(() => { return import('vComponents/dist/Loading') }, { ssr: false })
|
||||||
|
export const LoadingContext = createContext()
|
||||||
|
|
||||||
|
const LoadingProvider = ({ children }) => {
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
|
||||||
|
const loadingWrapper = {
|
||||||
|
loading,
|
||||||
|
setLoading,
|
||||||
|
start: () => { setLoading(true) },
|
||||||
|
stop: () => { setLoading(false) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LoadingContext.Provider value={ loadingWrapper }>
|
||||||
|
{ children }
|
||||||
|
<LoadingSpinner loading={loading} image={presets.images.imageLoader} background={'backgroundLoader'} color={'colorLoader'} />
|
||||||
|
</LoadingContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LoadingProvider
|
91
src/plugins/i18nContext.jsx
Normal file
91
src/plugins/i18nContext.jsx
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import { createContext, useState, useRef, useEffect } from 'react'
|
||||||
|
import rosetta from 'rosetta'
|
||||||
|
// import rosetta from 'rosetta/debug'
|
||||||
|
import { execute } from '@/helper/clientApi'
|
||||||
|
import useHasMounted from '@/hooks/useHasMounted'
|
||||||
|
import environment from '@/utils/environment'
|
||||||
|
// import { sprCatalogosS } from '@/js/spr'
|
||||||
|
// import { getEnv } from '@/js/funciones'
|
||||||
|
|
||||||
|
const i18n = rosetta()
|
||||||
|
|
||||||
|
export const defaultLanguage = 'es'
|
||||||
|
export const languages = ['es', 'en']
|
||||||
|
export const contentLanguageMap = { es: 'es-GT', en: 'en-US' }
|
||||||
|
|
||||||
|
export const I18nContext = createContext()
|
||||||
|
|
||||||
|
// default language
|
||||||
|
i18n.locale(defaultLanguage)
|
||||||
|
|
||||||
|
const I18nProvider = ({ children, locale, dict }) => {
|
||||||
|
const activeLocaleRef = useRef(locale || defaultLanguage)
|
||||||
|
const [, setTick] = useState(0)
|
||||||
|
const firstRender = useRef(true)
|
||||||
|
const [langIsLoaded, setLangIsLoaded] = useState(false)
|
||||||
|
const hasMounted = useHasMounted()
|
||||||
|
|
||||||
|
const i18nWrapper = {
|
||||||
|
activeLocale: activeLocaleRef.current,
|
||||||
|
langIsLoaded,
|
||||||
|
t: (...args) => i18n.t(...args),
|
||||||
|
locale: (l, dict) => {
|
||||||
|
i18n.locale(l)
|
||||||
|
activeLocaleRef.current = l
|
||||||
|
if (dict) {
|
||||||
|
i18n.set(l, dict)
|
||||||
|
}
|
||||||
|
// force rerender to update view
|
||||||
|
setTick((tick) => tick + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setLanguage = async () => {
|
||||||
|
let msgs = {}
|
||||||
|
const env = await environment.getEnvUser()
|
||||||
|
const response2 = await execute('SPR_PROY_SESION_S', [env.token])
|
||||||
|
// TODO: implementar idioma del usuario
|
||||||
|
// if (response2[0].status !== 'ERROR') {
|
||||||
|
// // const options = await execute(sprCatalogosS, ['datosUsuario', await getEnv(i18n)])
|
||||||
|
// const options = await execute(sprCatalogosS, ['datosUsuario', env.token])
|
||||||
|
// locale = options[0].idioma
|
||||||
|
// } else {
|
||||||
|
// locale = defaultLanguage
|
||||||
|
// }
|
||||||
|
locale = defaultLanguage
|
||||||
|
// si la app ya esta renderizada se cargan los textos
|
||||||
|
if (hasMounted) {
|
||||||
|
const i18nDb = await execute('SPR_I18N_T', [locale])
|
||||||
|
msgs = i18nDb.reduce((obj, elm) => {
|
||||||
|
obj[elm.id_mensaje_padre] = { ...obj[elm.id_mensaje_padre], [elm.id_mensaje]: elm.mensaje }
|
||||||
|
return obj
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
i18nWrapper.locale(locale, msgs)
|
||||||
|
setLangIsLoaded(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// for initial SSR render
|
||||||
|
if (locale && firstRender.current === true) {
|
||||||
|
firstRender.current = false
|
||||||
|
setLanguage()
|
||||||
|
}
|
||||||
|
|
||||||
|
// // when locale is updated
|
||||||
|
// useEffect(() => {
|
||||||
|
// setLanguage()
|
||||||
|
// }, [activeLocaleRef.current])
|
||||||
|
|
||||||
|
// when page is mounted
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasMounted) {
|
||||||
|
setLanguage()
|
||||||
|
}
|
||||||
|
}, [hasMounted, activeLocaleRef.current])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<I18nContext.Provider value={i18nWrapper}>{children}</I18nContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default I18nProvider
|
371
src/utils/environment.js
Normal file
371
src/utils/environment.js
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
import Cookie from 'js-cookie'
|
||||||
|
import functions from 'v-functions'
|
||||||
|
import { execute } from '../helper/clientApi'
|
||||||
|
import presets from './globalPresets'
|
||||||
|
import { findWhere } from 'underscore'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Objeto con funciones comunes de ambiente
|
||||||
|
*/
|
||||||
|
const environment = {
|
||||||
|
/**
|
||||||
|
* @brief Obtiene el token de los Cookies y el usuario del LocalStorage
|
||||||
|
* @param {*} callback funcion a ejecutar cuando se obtuvieron los datos
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
getFormatRandomNumber: () => {
|
||||||
|
const getRandomId = () => {
|
||||||
|
return String(Math.floor(Math.random() * 10000))
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentDate = new Date()
|
||||||
|
|
||||||
|
let fixName = `${currentDate.getFullYear()}`
|
||||||
|
fixName += `${(currentDate.getMonth() + 1).toString().padStart(2, '0')}`
|
||||||
|
fixName += `${currentDate.getDate().toString().padStart(2, '0')}`
|
||||||
|
fixName += `${currentDate.getHours().toString().padStart(2, '0')}`
|
||||||
|
fixName += `${currentDate.getMinutes().toString().padStart(2, '0')}`
|
||||||
|
fixName += `${currentDate.getMilliseconds().toString()}`
|
||||||
|
fixName += `_${getRandomId()}`
|
||||||
|
|
||||||
|
return fixName
|
||||||
|
},
|
||||||
|
|
||||||
|
getResultParameters: (confParameters, item, mainParameters) => {
|
||||||
|
const resultParameters = []
|
||||||
|
if (confParameters != null && confParameters.length) {
|
||||||
|
confParameters.forEach((orParam) => {
|
||||||
|
if (orParam.type === 'param') {
|
||||||
|
const _parameters = [...mainParameters]
|
||||||
|
const arrParam = _parameters.filter((paramSel) => (paramSel.name === orParam.id))
|
||||||
|
if (arrParam.length) {
|
||||||
|
resultParameters.push(arrParam[0].value)
|
||||||
|
} else {
|
||||||
|
resultParameters.push(null)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (item != null && item[orParam.id] != null) {
|
||||||
|
resultParameters.push(item[orParam.id])
|
||||||
|
} else {
|
||||||
|
resultParameters.push(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return resultParameters
|
||||||
|
},
|
||||||
|
buildFunctiontsHeaders: (baseHeaders, iconResponse = () => {}, substituteValOnForm) => {
|
||||||
|
const newHeaders = []
|
||||||
|
if (baseHeaders != null && baseHeaders.length) {
|
||||||
|
for (let i = 0; i < baseHeaders.length; i++) {
|
||||||
|
const field = baseHeaders[i]
|
||||||
|
if (field.substituteValOnForm != null && substituteValOnForm != null) {
|
||||||
|
field.substituteValOnForm = (head, _model, _field, _isEdit) => { return substituteValOnForm(head, _model, _field, _isEdit) }
|
||||||
|
}
|
||||||
|
if (field.mappingRules != null && field.mappingRules.length) {
|
||||||
|
const _mappingRules = [...field.mappingRules]
|
||||||
|
// Insertar Funcion para substituteVal
|
||||||
|
const rulesValue = _mappingRules.filter((rule) => (rule.type === 'value' || rule.type === 'icon' || rule.type === 'format' || rule.type === 'fieldValue'))
|
||||||
|
if (rulesValue.length) {
|
||||||
|
field.substituteVal = (item) => {
|
||||||
|
const id = field.value
|
||||||
|
const rules = [...rulesValue]
|
||||||
|
if (rules.length) {
|
||||||
|
for (let i = 0; i < rules.length; i++) {
|
||||||
|
const rule = { ...rules[i] }
|
||||||
|
const numberRuleValue = Number(rule.value)
|
||||||
|
const numberFieldValue = Number(item[rule.field])
|
||||||
|
const areNums = !isNaN(numberRuleValue) && !isNaN(numberFieldValue)
|
||||||
|
let response = rule.result
|
||||||
|
if (rule.type === 'icon') {
|
||||||
|
response = iconResponse(item[id], rule.result, item)
|
||||||
|
}
|
||||||
|
if (rule.rule === 'equal') {
|
||||||
|
if ((!areNums && item[rule.field] === rule.value) || (areNums && numberFieldValue === numberRuleValue)) {
|
||||||
|
return response
|
||||||
|
} else if ((rule.value === null || rule.value === '') && (item[rule.field] === null || item[rule.field] === '')) {
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
} else if (rule.rule === 'greater_than') {
|
||||||
|
if ((!areNums && item[rule.field] > rule.value) || (areNums && numberFieldValue > numberRuleValue)) {
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
} else if (rule.rule === 'less_than') {
|
||||||
|
if ((!areNums && item[rule.field] < rule.value) || (areNums && numberFieldValue < numberRuleValue)) {
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
} else if (rule.rule === 'not_equal') {
|
||||||
|
if ((!areNums && item[rule.field] !== rule.value) || (areNums && numberFieldValue !== numberRuleValue)) {
|
||||||
|
return response
|
||||||
|
} else if ((rule.value === null || rule.value === '') && (item[rule.field] !== null || item[rule.field] !== '')) {
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rule.type === 'format') {
|
||||||
|
const isNum = !isNaN(numberFieldValue)
|
||||||
|
try {
|
||||||
|
if (rule.rule === 'number') {
|
||||||
|
if (isNum) {
|
||||||
|
return functions.formatNumber(numberFieldValue, rule.result)
|
||||||
|
}
|
||||||
|
return functions.formatNumber(item[rule.field], rule.result)
|
||||||
|
} else if (rule.rule === 'date') {
|
||||||
|
if (isNum) {
|
||||||
|
return functions.formatDate(numberFieldValue, rule.result)
|
||||||
|
}
|
||||||
|
return functions.formatDate(item[rule.field], rule.result)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return item[id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rule.type === 'fieldValue') {
|
||||||
|
try {
|
||||||
|
return item[rule.result]
|
||||||
|
} catch (e) {
|
||||||
|
return item[id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return item[id]
|
||||||
|
}
|
||||||
|
return item[id]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
field.substituteVal = field.substituteVal || null
|
||||||
|
}
|
||||||
|
// Insertar Funcion para classItem
|
||||||
|
const rulesClass = _mappingRules.filter((rule) => (rule.type === 'class'))
|
||||||
|
if (rulesClass.length) {
|
||||||
|
field.classItem = (item) => {
|
||||||
|
const rules = [...rulesClass]
|
||||||
|
let resultClass = ''
|
||||||
|
if (rules.length) {
|
||||||
|
for (let i = 0; i < rules.length; i++) {
|
||||||
|
const rule = { ...rules[i] }
|
||||||
|
const numberRuleValue = Number(rule.value)
|
||||||
|
const numberFieldValue = Number(item[rule.field])
|
||||||
|
const areNums = !isNaN(numberRuleValue) && !isNaN(numberFieldValue)
|
||||||
|
if (rule.rule === 'equal') {
|
||||||
|
if ((!areNums && item[rule.field] === rule.value) || (areNums && numberFieldValue === numberRuleValue)) {
|
||||||
|
resultClass = `${resultClass} ${rule.result}`
|
||||||
|
} else if ((rule.value === null || rule.value === '') && (item[rule.field] === null || item[rule.field] === '')) {
|
||||||
|
resultClass = `${resultClass} ${rule.result}`
|
||||||
|
}
|
||||||
|
} else if (rule.rule === 'greater_than') {
|
||||||
|
if ((!areNums && item[rule.field] > rule.value) || (areNums && numberFieldValue > numberRuleValue)) {
|
||||||
|
resultClass = `${resultClass} ${rule.result}`
|
||||||
|
}
|
||||||
|
} else if (rule.rule === 'less_than') {
|
||||||
|
if ((!areNums && item[rule.field] < rule.value) || (areNums && numberFieldValue < numberRuleValue)) {
|
||||||
|
resultClass = `${resultClass} ${rule.result}`
|
||||||
|
}
|
||||||
|
} else if (rule.rule === 'not_equal') {
|
||||||
|
if ((!areNums && item[rule.field] !== rule.value) || (areNums && numberFieldValue !== numberRuleValue)) {
|
||||||
|
resultClass = `${resultClass} ${rule.result}`
|
||||||
|
} else if ((rule.value === null || rule.value === '') && (item[rule.field] !== null || item[rule.field] !== '')) {
|
||||||
|
resultClass = `${resultClass} ${rule.result}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resultClass
|
||||||
|
}
|
||||||
|
return resultClass
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
field.classItem = null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
field.classItem = null
|
||||||
|
field.substituteVal = field.substituteVal || null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field.showInForm != null && field.showInForm === true) {
|
||||||
|
if (field.formatDefinition != null && field.formatDefinition.action != null) {
|
||||||
|
if (field.formatDefinition.action === 'format') {
|
||||||
|
field.format = (val, definition = field.formatDefinition) => {
|
||||||
|
if (val != null) {
|
||||||
|
if (definition.value === 'lowercase') {
|
||||||
|
const valString = String(val)
|
||||||
|
return valString.toLowerCase()
|
||||||
|
} else if (definition.value === 'uppercase') {
|
||||||
|
const valString = String(val)
|
||||||
|
return valString.toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
field.format = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newHeaders.push({ ...field })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newHeaders
|
||||||
|
},
|
||||||
|
setEnvUser: (user) => {
|
||||||
|
functions.setEncodeStorage(`${process.env.idApp}/${process.env.NODE_ENV}`, user)
|
||||||
|
},
|
||||||
|
getEnvUser: () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const token = Cookie.get(`${process.env.idApp}:${process.env.NODE_ENV}`)
|
||||||
|
const user = functions.getDecodeStorage(`${process.env.idApp}/${process.env.NODE_ENV}`)
|
||||||
|
if (!token || !user) {
|
||||||
|
resolve({ token: undefined, user: undefined, redirectPath: '/login' })
|
||||||
|
}
|
||||||
|
resolve({ token, user })
|
||||||
|
})
|
||||||
|
},
|
||||||
|
logout: () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
Cookie.remove(`${process.env.idApp}:${process.env.NODE_ENV}`)
|
||||||
|
functions.setEncodeStorage(`${process.env.idApp}/${process.env.NODE_ENV}`, '')
|
||||||
|
resolve('/')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
login: (token, user) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
Cookie.set(`${process.env.idApp}:${process.env.NODE_ENV}`, token)
|
||||||
|
functions.setEncodeStorage(`${process.env.idApp}/${process.env.NODE_ENV}`, user)
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getTime: () => {
|
||||||
|
// return (new Date()).getTime()
|
||||||
|
return 1668220842700
|
||||||
|
},
|
||||||
|
|
||||||
|
validaResultadoDB: (resultado, i18n, toast, showOKMessage = false) => {
|
||||||
|
const showToast = (i18n, toast, message, type, i18nCode = null) => {
|
||||||
|
const displayMessage = message
|
||||||
|
|
||||||
|
// if (displayMessage.includes(':console-message:')) {
|
||||||
|
// console.warn(displayMessage.replace(':console-message:', ''))
|
||||||
|
// } else
|
||||||
|
if (toast && showOKMessage) {
|
||||||
|
const cleanedMessage = displayMessage.replace(':no-display:', '')
|
||||||
|
toast[type](
|
||||||
|
<span dangerouslySetInnerHTML={{ __html: cleanedMessage }} />,
|
||||||
|
presets.toaster
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resultado) {
|
||||||
|
showToast(i18n, toast, i18n.t('common.errorApi'), 'error')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(resultado) && resultado.length > 0) {
|
||||||
|
const { status, message, mensaje, i18n: i18nCode } = resultado[0]
|
||||||
|
|
||||||
|
if (status === 'ERROR' || status === 'error' || status === 'WARNING' || status === 'warning' || status === 'INFO' || status === 'info') {
|
||||||
|
if (i18n === 'session.inactive' || i18n === 'session.inactiva' || message === 'Sesión inactiva') {
|
||||||
|
// if (store.state.sessionInactive === false) {
|
||||||
|
// store.actions.setSessionInactive(true)
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
showToast(i18n, toast, (message || mensaje), status === 'ERROR' ? 'error' : 'warning', i18nCode)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status === 'OK' || status === 'ok' || status === 'SUCCESS' || status === 'success') && showOKMessage) {
|
||||||
|
showToast(i18n, toast, (message || mensaje), 'success', i18nCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
|
||||||
|
getFileParams (model, headers, value, prefix) {
|
||||||
|
const head = findWhere(headers, { value })
|
||||||
|
const { filename, extension } = functions.getFilePattern(model[value])
|
||||||
|
const params = {}
|
||||||
|
if (head.logicalName && head.logicalName !== null) {
|
||||||
|
if (typeof head.logicalName === 'function') {
|
||||||
|
params.logico = head.logicalName(model)
|
||||||
|
} else {
|
||||||
|
params.logico = head.logicalName
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
params.logico = filename
|
||||||
|
}
|
||||||
|
if (prefix && prefix !== null) {
|
||||||
|
params.logico = `${prefix}${params.logico}`
|
||||||
|
}
|
||||||
|
if (head.logicalExtension && head.logicalExtension !== null) {
|
||||||
|
if (typeof head.logicalExtension === 'function') {
|
||||||
|
params.ext = head.logicalExtension(model)
|
||||||
|
} else {
|
||||||
|
params.ext = head.logicalExtension
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
params.ext = extension
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
},
|
||||||
|
|
||||||
|
validaPermisos: async (token, administra, configura, graba_modifica, consulta) => {
|
||||||
|
let permisos = await execute('FUN_INFO_SESION_ENTIDAD', [token])
|
||||||
|
if (permisos === undefined || permisos.length <= 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (permisos[0].status === 'ERROR') {
|
||||||
|
return false
|
||||||
|
} else if (permisos[0].status === 'WARNING') {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
permisos = permisos[0]
|
||||||
|
const secVal = []
|
||||||
|
if (permisos.administra === 'S') {
|
||||||
|
return true
|
||||||
|
} else if (permisos.configura === 'S') {
|
||||||
|
secVal.push(2)
|
||||||
|
} else if (permisos.graba_modifica === 'S') {
|
||||||
|
secVal.push(3)
|
||||||
|
} else if (permisos.consulta === 'S') {
|
||||||
|
secVal.push(4)
|
||||||
|
}
|
||||||
|
if (configura === 'S' && secVal.includes(2) === true) {
|
||||||
|
return true
|
||||||
|
} else if (graba_modifica === 'S' && secVal.includes(3) === true) {
|
||||||
|
return true
|
||||||
|
} else if (consulta === 'S' && secVal.includes(4) === true) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
i18nHeaders: (i18n, headers) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const newHeaders = []
|
||||||
|
for (const hds of headers) {
|
||||||
|
if (hds.i18n && hds.i18n.length > 0) {
|
||||||
|
hds.text = i18n.t(hds.i18n)
|
||||||
|
}
|
||||||
|
if (hds.pristineMessages) {
|
||||||
|
Object.keys(hds.pristineMessages).forEach((msg) => {
|
||||||
|
if (msg.includes('-params') === false) {
|
||||||
|
if (hds.pristineMessages[`${msg}-params`]) {
|
||||||
|
hds.inputProps[`data-pristine-${msg}-message`] = hds.pristineMessages[msg]
|
||||||
|
? i18n.t(hds.pristineMessages[msg], hds.pristineMessages[`${msg}-params`])
|
||||||
|
: 'txtNone'
|
||||||
|
} else {
|
||||||
|
hds.inputProps[`data-pristine-${msg}-message`] = hds.pristineMessages[msg]
|
||||||
|
? i18n.t(hds.pristineMessages[msg])
|
||||||
|
: 'txtNone'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
newHeaders.push(hds)
|
||||||
|
}
|
||||||
|
resolve(newHeaders)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default environment
|
84
src/utils/globalPresets.js
Normal file
84
src/utils/globalPresets.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
const theme = 'blue'
|
||||||
|
|
||||||
|
const presets = {
|
||||||
|
appTitle: 'Orbis Template',
|
||||||
|
theme: `${theme}`,
|
||||||
|
svgIconUrl: 'https://www.via-asesores.com/svgicons/smartoperation/',
|
||||||
|
images: {
|
||||||
|
loginFondo: 'https://www.via-asesores.com/backgrounds/smartoperation/SmartOperation_background.png',
|
||||||
|
welcomeFondo: 'https://www.via-asesores.com/backgrounds/smartoperation/SmartOperation_background.png',
|
||||||
|
icon: 'https://www.via-asesores.com/icons/smartoperation/SmartOperation_icon_light.png',
|
||||||
|
logo: 'https://www.via-asesores.com/logos/smartOperations.png',
|
||||||
|
imageLoader: 'https://www.via-asesores.com/logos/logo_via.png',
|
||||||
|
noImageFound: 'https://www.via-asesores.com/smartsalesnprofit/images/LogoViasaClaroTransparente_600x.png',
|
||||||
|
onError: 'https://www.via-asesores.com/smartsalesnprofit/images/LogoViasaClaroTransparente_600x.png',
|
||||||
|
noDataFound: `${process.env.publicPath}/images/cancel.png`
|
||||||
|
},
|
||||||
|
locations: {
|
||||||
|
login: '/',
|
||||||
|
welcome: '/dashboard',
|
||||||
|
welcomeTemp: '/welcome',
|
||||||
|
profile: '/seguridad/profile'
|
||||||
|
},
|
||||||
|
toaster: {
|
||||||
|
position: 'top-center',
|
||||||
|
autoClose: 5000,
|
||||||
|
hideProgressBar: false,
|
||||||
|
closeOnClick: true,
|
||||||
|
pauseOnHover: true,
|
||||||
|
draggable: true,
|
||||||
|
theme: 'light'
|
||||||
|
},
|
||||||
|
pristine: {
|
||||||
|
// class of the parent element where the error/success class is added
|
||||||
|
classTo: 'form-group',
|
||||||
|
errorClass: 'ring-red-400',
|
||||||
|
successClass: 'has-success',
|
||||||
|
// class of the parent element where error text element is appended
|
||||||
|
errorTextParent: 'form-group',
|
||||||
|
// type of element to create for the error text
|
||||||
|
errorTextTag: 'div',
|
||||||
|
// class of the error text element
|
||||||
|
errorTextClass: 'text-help text-red-500 text-sm py-1'
|
||||||
|
},
|
||||||
|
graphOptions: {
|
||||||
|
interaction: {
|
||||||
|
dragNodes: false,
|
||||||
|
dragView: true,
|
||||||
|
hover: true
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
hierarchical: {
|
||||||
|
enabled: true,
|
||||||
|
levelSeparation: 200,
|
||||||
|
nodeSpacing: 200,
|
||||||
|
treeSpacing: 200,
|
||||||
|
blockShifting: true,
|
||||||
|
edgeMinimization: true,
|
||||||
|
parentCentralization: true,
|
||||||
|
direction: 'LR', // UD, DU, LR, RL
|
||||||
|
sortMethod: 'hubsize', // hubsize, directed
|
||||||
|
shakeTowards: 'leaves' // roots, leaves
|
||||||
|
}
|
||||||
|
},
|
||||||
|
edges: {
|
||||||
|
color: '#000000'
|
||||||
|
},
|
||||||
|
height: '700px',
|
||||||
|
physics: {
|
||||||
|
enabled: false,
|
||||||
|
// maxVelocity: 50,
|
||||||
|
// minVelocity: 0.1,
|
||||||
|
// solver: "barnesHut",
|
||||||
|
stabilization: {
|
||||||
|
enabled: true,
|
||||||
|
iterations: 1000,
|
||||||
|
updateInterval: 100,
|
||||||
|
onlyDynamicEdges: false,
|
||||||
|
fit: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default presets
|
Loading…
Reference in New Issue
Block a user