feat(initial): 🎉 Initialize Next.js app directory template
This commit is contained in:
parent
d3319cc9e5
commit
9dfd4666e6
@ -1,3 +1,57 @@
|
|||||||
|
// 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-config-next eslint-config-standard eslint-plugin-import eslint-plugin-n eslint-plugin-promise eslint-plugin-react eslint-plugin-tailwindcss
|
||||||
|
|
||||||
|
// for TypeScript
|
||||||
|
// yarn add -D @typescript-eslint/parser
|
||||||
|
|
||||||
{
|
{
|
||||||
"extends": "next/core-web-vitals"
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es2021": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"standard",
|
||||||
|
"next/core-web-vitals",
|
||||||
|
"plugin:react/recommended",
|
||||||
|
"plugin:tailwindcss/recommended"
|
||||||
|
],
|
||||||
|
"overrides": [],
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": "latest",
|
||||||
|
"sourceType": "module",
|
||||||
|
"project": "./tsconfig.json"
|
||||||
|
},
|
||||||
|
"plugins": ["react", "tailwindcss"],
|
||||||
|
"rules": {
|
||||||
|
"react-hooks/exhaustive-deps": "off",
|
||||||
|
"react/react-in-jsx-scope": "off",
|
||||||
|
"react/prop-types": "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"] }],
|
||||||
|
"quotes": ["error", "double"],
|
||||||
|
"indent": [
|
||||||
|
"error",
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
"SwitchCase": 1,
|
||||||
|
"flatTernaryExpressions": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
42
.vscode/settings.json
vendored
Normal file
42
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.detectIndentation": false,
|
||||||
|
"search.exclude": {
|
||||||
|
"package-lock.json": true
|
||||||
|
},
|
||||||
|
"eslint.validate": [
|
||||||
|
"javascript",
|
||||||
|
"javascriptreact",
|
||||||
|
"typescript",
|
||||||
|
"typescriptreact",
|
||||||
|
],
|
||||||
|
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.addMissingImports": "explicit",
|
||||||
|
"source.fixAll.eslint": "explicit"
|
||||||
|
},
|
||||||
|
"cSpell.words": [
|
||||||
|
"anio",
|
||||||
|
"CATALOGOS",
|
||||||
|
"compania",
|
||||||
|
"datatable",
|
||||||
|
"descripcion",
|
||||||
|
"direccion",
|
||||||
|
"esnext",
|
||||||
|
"guatemala",
|
||||||
|
"headlessui",
|
||||||
|
"orbis",
|
||||||
|
"Orbis",
|
||||||
|
"orbisapi",
|
||||||
|
"REFCURSOR",
|
||||||
|
"rosetta",
|
||||||
|
"sesion",
|
||||||
|
"Sesion",
|
||||||
|
"SQLERRM",
|
||||||
|
"tailwindcss",
|
||||||
|
"toastify",
|
||||||
|
"ubicacion",
|
||||||
|
"unoptimized"
|
||||||
|
],
|
||||||
|
}
|
14
config/default.json
Normal file
14
config/default.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"constants": {
|
||||||
|
"plataforma": "web",
|
||||||
|
"publicPath": "/orbistemplate",
|
||||||
|
"urlServerImages" : "https://gt.via-asesores.com/smartoperation-api/dtsrv/dev/operation?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTso",
|
||||||
|
"urlWebApi": "https://gt.via-asesores.com/smartoperation-api/api/dev/operation?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTso",
|
||||||
|
"urlUploadApi": "https://gt.via-asesores.com/smartoperation-api/upload/dev/operation?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTso",
|
||||||
|
"appTitle": "OrbisTemplate",
|
||||||
|
"idApp": "orbistemplate",
|
||||||
|
"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": "/orbistemplate",
|
||||||
|
"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": "OrbisTemplate",
|
||||||
|
"idApp": "orbistemplate",
|
||||||
|
"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": "/orbistemplate",
|
||||||
|
"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": "OrbisTemplate",
|
||||||
|
"idApp": "orbistemplate",
|
||||||
|
"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": "/orbistemplate",
|
||||||
|
"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": "OrbisTemplate",
|
||||||
|
"idApp": "orbistemplate",
|
||||||
|
"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,4 +1,36 @@
|
|||||||
|
import config from "config";
|
||||||
|
|
||||||
|
const constants = config.get('constants')
|
||||||
|
|
||||||
|
const rewrites = async () => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: "/orbisapi/:path*",
|
||||||
|
destination: "http://localhost:9000/:path*" // Proxy to Backend
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
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,
|
||||||
|
swcMinify: true,
|
||||||
|
eslint: {
|
||||||
|
ignoreDuringBuilds: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
26
package.json
26
package.json
@ -9,18 +9,36 @@
|
|||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"config": "^3.3.11",
|
||||||
|
"js-cookie": "^3.0.5",
|
||||||
|
"js-md5": "^0.8.3",
|
||||||
|
"next": "14.2.3",
|
||||||
|
"node-forge": "^1.3.1",
|
||||||
|
"pristinejs": "^1.1.0",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"next": "14.2.3"
|
"react-dropzone-component": "^3.2.0",
|
||||||
|
"react-simple-hook-store": "^0.0.6",
|
||||||
|
"react-toastify": "^10.0.5",
|
||||||
|
"rosetta": "^1.1.0",
|
||||||
|
"vComponents": "git+https://2bdcc0300e0ed5ac01f9dcd51368f7ac74fdb85a@git.via-asesores.com/libraries/v-components.git",
|
||||||
|
"via-ui": "git+https://2bdcc0300e0ed5ac01f9dcd51368f7ac74fdb85a@git.via-asesores.com/libraries/via-ui.git"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5",
|
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
|
"eslint": "^9.1.1",
|
||||||
|
"eslint-config-next": "^14.2.3",
|
||||||
|
"eslint-config-standard": "^17.1.0",
|
||||||
|
"eslint-plugin-import": "^2.29.1",
|
||||||
|
"eslint-plugin-n": "^17.3.1",
|
||||||
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
|
"eslint-plugin-react": "^7.34.1",
|
||||||
|
"eslint-plugin-tailwindcss": "^3.15.1",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"eslint": "^8",
|
"typescript": "^5",
|
||||||
"eslint-config-next": "14.2.3"
|
"via-tailwind": "git+https://2bdcc0300e0ed5ac01f9dcd51368f7ac74fdb85a@git.via-asesores.com/libraries/via-tailwind.git"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 25 KiB |
@ -1,33 +0,0 @@
|
|||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--foreground-rgb: 0, 0, 0;
|
|
||||||
--background-start-rgb: 214, 219, 220;
|
|
||||||
--background-end-rgb: 255, 255, 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root {
|
|
||||||
--foreground-rgb: 255, 255, 255;
|
|
||||||
--background-start-rgb: 0, 0, 0;
|
|
||||||
--background-end-rgb: 0, 0, 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
color: rgb(var(--foreground-rgb));
|
|
||||||
background: linear-gradient(
|
|
||||||
to bottom,
|
|
||||||
transparent,
|
|
||||||
rgb(var(--background-end-rgb))
|
|
||||||
)
|
|
||||||
rgb(var(--background-start-rgb));
|
|
||||||
}
|
|
||||||
|
|
||||||
@layer utilities {
|
|
||||||
.text-balance {
|
|
||||||
text-wrap: balance;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +1,23 @@
|
|||||||
import type { Metadata } from "next";
|
import "@/styles/globals.css";
|
||||||
import { Inter } from "next/font/google";
|
|
||||||
import "./globals.css";
|
|
||||||
|
|
||||||
const inter = Inter({ subsets: ["latin"] });
|
import { Providers } from "@/components/providers";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export default function RootLayout({ children,}: Readonly<{children: React.ReactNode;}>) {
|
||||||
title: "Create Next App",
|
|
||||||
description: "Generated by create next app",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function RootLayout({
|
|
||||||
children,
|
|
||||||
}: Readonly<{
|
|
||||||
children: React.ReactNode;
|
|
||||||
}>) {
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="es" suppressHydrationWarning>
|
||||||
<body className={inter.className}>{children}</body>
|
<head />
|
||||||
|
<body>
|
||||||
|
<Providers>
|
||||||
|
{children}
|
||||||
|
</Providers>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
9
src/app/mantenimientos/cliente/[[...slug]]/page.tsx
Normal file
9
src/app/mantenimientos/cliente/[[...slug]]/page.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const ClientePage = () => {
|
||||||
|
return (
|
||||||
|
<div>ClientePage</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ClientePage
|
9
src/app/mantenimientos/tiposClientes/page.tsx
Normal file
9
src/app/mantenimientos/tiposClientes/page.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const TipoClientesPage = () => {
|
||||||
|
return (
|
||||||
|
<div>TipoClientesPage</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TipoClientesPage
|
116
src/app/page.jsx
Normal file
116
src/app/page.jsx
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import Image from "next/image"
|
||||||
|
import { useEffect } from "react"
|
||||||
|
import { useRouter } from "next/navigation"
|
||||||
|
import { toast } from "react-toastify"
|
||||||
|
import md5 from "js-md5"
|
||||||
|
import { execute } from "@/helper/clientApi"
|
||||||
|
import useI18n from "@/hooks/useI18n"
|
||||||
|
import useLoading from "@/hooks/useLoading"
|
||||||
|
import FormLogin from "@/components/Login/FormLogin"
|
||||||
|
import presets from "@/utils/globalPresets"
|
||||||
|
import environment from "@/utils/environment"
|
||||||
|
import useGlobalContainer from "@/hooks/useGlobalContainer"
|
||||||
|
import useHasMounted from "@/hooks/useHasMounted"
|
||||||
|
|
||||||
|
const LoginPage = () => {
|
||||||
|
const global = useGlobalContainer()
|
||||||
|
const router = useRouter()
|
||||||
|
const i18n = useI18n()
|
||||||
|
const loading = useLoading()
|
||||||
|
const hasMounted = useHasMounted()
|
||||||
|
const homePath = presets.locations.welcome
|
||||||
|
|
||||||
|
const loginUsuario = async (datos) => {
|
||||||
|
loading.start()
|
||||||
|
if (datos && datos !== null) {
|
||||||
|
const hash = md5.create()
|
||||||
|
hash.update(datos.password.trim())
|
||||||
|
try {
|
||||||
|
const resultado = await execute("SPR_LOGIN", [datos.email.toLowerCase().trim(), hash.hex()])
|
||||||
|
loading.stop()
|
||||||
|
if (resultado === undefined) {
|
||||||
|
toast.error(i18n.t("common.errorApi"), presets.toaster)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (resultado[0].status === "ERROR") {
|
||||||
|
toast.error(resultado[0].message, presets.toaster)
|
||||||
|
} else if (resultado[0].status === "WARNING") {
|
||||||
|
toast.warning(resultado[0].message, presets.toaster)
|
||||||
|
} else if (resultado[0].token) {
|
||||||
|
const user = {
|
||||||
|
email: resultado[0].correo_electronico,
|
||||||
|
nombre_usuario: resultado[0].nombre_completo,
|
||||||
|
// img_user: resultado[0].foto,
|
||||||
|
token: resultado[0].token,
|
||||||
|
es_admin: resultado[0].es_admin,
|
||||||
|
compania: resultado[0].nombre_compania,
|
||||||
|
departamento: resultado[0].nombre_departamento,
|
||||||
|
tiempo_expiracion: resultado[0].tiempo_expiracion,
|
||||||
|
fecha_inicio_sesion: resultado[0].fecha_inicio_sesion,
|
||||||
|
fecha_fin_sesion: resultado[0].fecha_fin_sesion,
|
||||||
|
theme: resultado[0].theme,
|
||||||
|
i18n: process.env.defaultLocale
|
||||||
|
}
|
||||||
|
const constante = {
|
||||||
|
apptitle: process.env.apptitle,
|
||||||
|
max_mb_upload: process.env.maxMbUpload
|
||||||
|
}
|
||||||
|
await environment.login(user.token, user)
|
||||||
|
toast.success(`Bienvenido ${user.nombre_usuario}`, presets.toaster)
|
||||||
|
await global.setUserObj(user)
|
||||||
|
await global.setConstanteObj(constante)
|
||||||
|
await global.setToken(resultado[0].token)
|
||||||
|
await global.setTheme(user.theme)
|
||||||
|
await i18n.locale(user.i18n)
|
||||||
|
router.push(homePath)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
toast.error(i18n.t("common.errorApi") + error, presets.toaster)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getEnv = async () => {
|
||||||
|
const env = await environment.getEnvUser()
|
||||||
|
if (env && env.token) {
|
||||||
|
router.push(presets.locations.welcome)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// when page is mounted
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasMounted) {
|
||||||
|
getEnv()
|
||||||
|
}
|
||||||
|
}, [hasMounted])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={"via-login-page"}>
|
||||||
|
<div className={"via-login-layout"}>
|
||||||
|
{/* <!-- Tarjeta de Login --> */}
|
||||||
|
<div className={"via-card"}>
|
||||||
|
<div className={"via-login-header"}>
|
||||||
|
<div className={"size-64 shrink-0"}>
|
||||||
|
<Image src={presets.images.logo} alt="logo" className={"via-login-logo"} width={100} height={100} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="align-center flex w-full p-4 ">
|
||||||
|
<div className={"via-login-form"}>
|
||||||
|
{/* <!-- Formulario --> */}
|
||||||
|
<FormLogin onLogin={loginUsuario} />
|
||||||
|
{/* <!-- Fin Formulario --> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={"via-login-background"}
|
||||||
|
style={{ backgroundImage: `url(${presets.images.loginFondo})`, minHeight: "75vh", backgroundSize: "cover" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LoginPage
|
113
src/app/page.tsx
113
src/app/page.tsx
@ -1,113 +0,0 @@
|
|||||||
import Image from "next/image";
|
|
||||||
|
|
||||||
export default function Home() {
|
|
||||||
return (
|
|
||||||
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
|
||||||
<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">
|
|
||||||
Get started by editing
|
|
||||||
<code className="font-mono font-bold">src/app/page.tsx</code>
|
|
||||||
</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:size-auto lg:bg-none">
|
|
||||||
<a
|
|
||||||
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=appdir-template&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
By{" "}
|
|
||||||
<Image
|
|
||||||
src="/vercel.svg"
|
|
||||||
alt="Vercel Logo"
|
|
||||||
className="dark:invert"
|
|
||||||
width={100}
|
|
||||||
height={24}
|
|
||||||
priority
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="relative z-[-1] flex place-items-center before:absolute before:h-[300px] before:w-full 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-full 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 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 sm:before:w-[480px] sm:after:w-[240px] before:lg:h-[360px]">
|
|
||||||
<Image
|
|
||||||
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
|
|
||||||
src="/next.svg"
|
|
||||||
alt="Next.js Logo"
|
|
||||||
width={180}
|
|
||||||
height={37}
|
|
||||||
priority
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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
|
|
||||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&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"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<h2 className="mb-3 text-2xl font-semibold">
|
|
||||||
Docs{" "}
|
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
|
||||||
->
|
|
||||||
</span>
|
|
||||||
</h2>
|
|
||||||
<p className="m-0 max-w-[30ch] text-sm opacity-50">
|
|
||||||
Find in-depth information about Next.js features and API.
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a
|
|
||||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-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"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<h2 className="mb-3 text-2xl font-semibold">
|
|
||||||
Learn{" "}
|
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
|
||||||
->
|
|
||||||
</span>
|
|
||||||
</h2>
|
|
||||||
<p className="m-0 max-w-[30ch] text-sm opacity-50">
|
|
||||||
Learn about Next.js in an interactive course with quizzes!
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a
|
|
||||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&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"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<h2 className="mb-3 text-2xl font-semibold">
|
|
||||||
Templates{" "}
|
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
|
||||||
->
|
|
||||||
</span>
|
|
||||||
</h2>
|
|
||||||
<p className="m-0 max-w-[30ch] text-sm opacity-50">
|
|
||||||
Explore starter templates for Next.js.
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a
|
|
||||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&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"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<h2 className="mb-3 text-2xl font-semibold">
|
|
||||||
Deploy{" "}
|
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
|
||||||
->
|
|
||||||
</span>
|
|
||||||
</h2>
|
|
||||||
<p className="m-0 max-w-[30ch] text-balance text-sm opacity-50">
|
|
||||||
Instantly deploy your Next.js site to a shareable URL with Vercel.
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
}
|
|
9
src/app/seguridad/compania/page.tsx
Normal file
9
src/app/seguridad/compania/page.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const CompaniaPage = () => {
|
||||||
|
return (
|
||||||
|
<div>CompaniaPage</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CompaniaPage
|
9
src/app/seguridad/departamento/page.tsx
Normal file
9
src/app/seguridad/departamento/page.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const DepartamentoPage = () => {
|
||||||
|
return (
|
||||||
|
<div>DepartamentoPage</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DepartamentoPage
|
141
src/components/Login/FormLogin.jsx
Normal file
141
src/components/Login/FormLogin.jsx
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
import Pristine from 'pristinejs'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { UserIcon, EyeIcon, EyeSlashIcon, KeyIcon } from '@heroicons/react/24/solid'
|
||||||
|
import functions from 'v-functions'
|
||||||
|
import useI18n from '@/hooks/useI18n'
|
||||||
|
import presets from '@/utils/globalPresets'
|
||||||
|
import useHasMounted from '@/hooks/useHasMounted'
|
||||||
|
|
||||||
|
let validateLogin = null
|
||||||
|
|
||||||
|
const FormLogin = ({ onLogin }) => {
|
||||||
|
const i18n = useI18n()
|
||||||
|
const hasMounted = useHasMounted()
|
||||||
|
const [viewPassword, setViewPassword] = useState(false)
|
||||||
|
const [isInputValid, setIsInputValid] = useState(false)
|
||||||
|
|
||||||
|
const validate = (event) => {
|
||||||
|
if (event) {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
}
|
||||||
|
if (validateLogin && validateLogin !== null) {
|
||||||
|
const resulValidate = validateLogin.validate()
|
||||||
|
setIsInputValid(resulValidate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const doLogin = (event) => {
|
||||||
|
if (event) {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
}
|
||||||
|
if (isInputValid === true) {
|
||||||
|
const emailLogin = document.getElementById('usuario')
|
||||||
|
const passwordLogin = document.getElementById('clave')
|
||||||
|
const datos = {
|
||||||
|
email: functions.toUpperCaseAndTrim(emailLogin.value),
|
||||||
|
password: functions.trim(passwordLogin.value)
|
||||||
|
}
|
||||||
|
setIsInputValid(false) // para prevenir doble click
|
||||||
|
onLogin(datos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// when page is mounted
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasMounted) {
|
||||||
|
const helem = document.getElementById('frmLogin')
|
||||||
|
validateLogin = new Pristine(helem, presets.pristine, false)
|
||||||
|
const helemUsuario = document.getElementById('usuario')
|
||||||
|
helemUsuario.focus()
|
||||||
|
}
|
||||||
|
}, [hasMounted])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleKeyDown = (event) => {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
validate(event)
|
||||||
|
if (isInputValid === true) {
|
||||||
|
doLogin(event)
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('keydown', handleKeyDown)
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('keydown', handleKeyDown)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form id="frmLogin" name="frmLogin" method="post" onSubmit={(event) => doLogin(event)} noValidate >
|
||||||
|
<div className="flex w-full flex-col space-y-4 px-4 ">
|
||||||
|
<div className="form-group flex flex-col">
|
||||||
|
<div className="via-label">
|
||||||
|
{ i18n.t('login.user') }
|
||||||
|
<div className="inline-flex font-semibold text-red-500">(*)</div>
|
||||||
|
</div>
|
||||||
|
<div className="relative w-full">
|
||||||
|
<input
|
||||||
|
id="usuario"
|
||||||
|
name="usuario"
|
||||||
|
required
|
||||||
|
placeholder=" "
|
||||||
|
type="email"
|
||||||
|
data-pristine-required-message={i18n.t('login.validacion_correo')}
|
||||||
|
className={'via-input'}
|
||||||
|
onChange={(e) => { validate(e) }}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className={'via-append-input'}
|
||||||
|
onClick={(e) => { e.stopPropagation() }}
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
<UserIcon className="size-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-group flex flex-col">
|
||||||
|
<div className={'via-label'}>
|
||||||
|
{ i18n.t('login.password') }
|
||||||
|
<div className="inline-flex font-semibold text-red-500">(*)</div>
|
||||||
|
</div>
|
||||||
|
<div className="relative w-full">
|
||||||
|
<input
|
||||||
|
id="clave"
|
||||||
|
name="clave"
|
||||||
|
required
|
||||||
|
placeholder=" "
|
||||||
|
type={viewPassword === false ? 'password' : 'text'}
|
||||||
|
data-pristine-required-message={i18n.t('login.validacion_password')}
|
||||||
|
className={'via-input'}
|
||||||
|
onChange={(e) => { validate(e) }}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className={'via-append-input'}
|
||||||
|
onClick={(e) => { e.stopPropagation(); e.preventDefault(); setViewPassword(!viewPassword) }}
|
||||||
|
>
|
||||||
|
{ viewPassword === false && <EyeIcon className="size-5" /> }
|
||||||
|
{ viewPassword === true && <EyeSlashIcon className="size-5" /> }
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={'via-div-actions'}>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={!isInputValid}
|
||||||
|
className={`${'via-button'} ${(isInputValid ? 'bg-theme-app-500' : 'bg-red-400')} mx-0 w-full justify-center shadow-md`}
|
||||||
|
>
|
||||||
|
<KeyIcon className="size-5 pr-2" />
|
||||||
|
{ i18n.t('login.connect') }
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FormLogin
|
163
src/components/SessionTimeout/index.jsx
Normal file
163
src/components/SessionTimeout/index.jsx
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
import React, { Fragment, useEffect, useRef, useState } from 'react'
|
||||||
|
import { Dialog, Transition } from '@headlessui/react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import useHasMounted from '@/hooks/useHasMounted'
|
||||||
|
|
||||||
|
export default function SessionTimeout ({ i18n, user, onTimeout, onCancelTimeout }) {
|
||||||
|
const TIME = 30
|
||||||
|
const hasMounted = useHasMounted()
|
||||||
|
const countTimerRef = useRef()
|
||||||
|
const [tick, setTick] = useState(0)
|
||||||
|
const [countTimer, setCountTimer] = useState() // contador que lleva el control de tiempo en segundos para mostrar antes de cerrar sesion
|
||||||
|
const [timerIsOn, setTimerIsOn] = useState(false) // verifica si el dialogo debe ser mostrado
|
||||||
|
const idleTimer = useRef(null) // variable de control para el proceso de conteo
|
||||||
|
|
||||||
|
// realiza el conteo regresivo
|
||||||
|
const timedCount = () => {
|
||||||
|
if (countTimerRef.current <= 0) {
|
||||||
|
clearInterval(idleTimer.current)
|
||||||
|
setTimerIsOn(false)
|
||||||
|
setCountTimer(TIME)
|
||||||
|
onTimeout()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setCountTimer(countTimerRef.current - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inicia el conteo regresivo
|
||||||
|
const startIdleMonitor = (expiracion = 0) => {
|
||||||
|
if (expiracion < TIME * 1000) {
|
||||||
|
countTimerRef.current = Math.round(expiracion / 1000) // tiempo restante
|
||||||
|
} else {
|
||||||
|
countTimerRef.current = TIME
|
||||||
|
}
|
||||||
|
setCountTimer(countTimerRef.current)
|
||||||
|
setTimerIsOn(true)
|
||||||
|
timedCount()
|
||||||
|
idleTimer.current = setInterval(timedCount, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
const calendarizeIdle = () => {
|
||||||
|
// const fecha_inicio_sesion = new Date(user.fecha_inicio_sesion.slice(0, -1)) // uso de localtime quita Z al final del string
|
||||||
|
const fecha_fin_sesion = new Date(user?.fecha_fin_sesion?.slice(0, -1)) // uso de localtime quita Z al final del string
|
||||||
|
// const fecha_fin_sesion = new Date(user.fecha_fin_sesion)
|
||||||
|
const expiracion = Math.round(fecha_fin_sesion.getTime() - (new Date()).getTime()) // valida cuando se realiza un F5 o reload del navegador (user.tiempo_expiracion * 60 * 1000)
|
||||||
|
if (expiracion <= 0) {
|
||||||
|
return // no debe calendarizar porque la sesion ya vencio
|
||||||
|
}
|
||||||
|
const timeInMillis = expiracion - (TIME * 1000)
|
||||||
|
const processTimer = setTimeout(startIdleMonitor, timeInMillis > 0 ? timeInMillis : 0, expiracion)
|
||||||
|
return () => clearTimeout(processTimer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cancela el conteo regresivo aumentando el tiempo de expiracion
|
||||||
|
const stopIdleMonitor = async () => {
|
||||||
|
await onCancelTimeout()
|
||||||
|
clearInterval(idleTimer.current)
|
||||||
|
setTimerIsOn(false)
|
||||||
|
setCountTimer(TIME)
|
||||||
|
// force rerender to update view
|
||||||
|
setTick((tick) => tick + 1)
|
||||||
|
// await new Promise(resolve => setTimeout(resolve, 2000)) // espera obligada para actualizacion DB
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (timerIsOn === false && tick > 0) {
|
||||||
|
return calendarizeIdle()
|
||||||
|
}
|
||||||
|
}, [timerIsOn, tick])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
countTimerRef.current = countTimer
|
||||||
|
}, [countTimer])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!user || user === null) {
|
||||||
|
if (idleTimer && idleTimer.current) {
|
||||||
|
clearInterval(idleTimer.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return () => clearInterval(idleTimer.current)
|
||||||
|
}, [user])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasMounted) {
|
||||||
|
return calendarizeIdle()
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [hasMounted])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{ timerIsOn && timerIsOn === true &&
|
||||||
|
<Transition appear show as={Fragment}>
|
||||||
|
<Dialog as='div' className='relative' style={{ zIndex: 999 }} onClose={() => { }}>
|
||||||
|
<Transition.Child
|
||||||
|
as={Fragment}
|
||||||
|
enter='ease-out duration-300'
|
||||||
|
enterFrom='opacity-0'
|
||||||
|
enterTo='opacity-100'
|
||||||
|
leave='ease-in duration-200'
|
||||||
|
leaveFrom='opacity-100'
|
||||||
|
leaveTo='opacity-0'
|
||||||
|
>
|
||||||
|
<div className='fixed inset-0 bg-black/25' />
|
||||||
|
</Transition.Child>
|
||||||
|
|
||||||
|
<div className='fixed inset-0 overflow-y-auto'>
|
||||||
|
<div className='flex min-h-full items-center justify-center p-4 text-center'>
|
||||||
|
<Transition.Child
|
||||||
|
as={Fragment}
|
||||||
|
enter='ease-out duration-300'
|
||||||
|
enterFrom='opacity-0 scale-95'
|
||||||
|
enterTo='opacity-100 scale-100'
|
||||||
|
leave='ease-in duration-200'
|
||||||
|
leaveFrom='opacity-100 scale-100'
|
||||||
|
leaveTo='opacity-0 scale-95'
|
||||||
|
>
|
||||||
|
<Dialog.Panel className='w-full max-w-md overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all'>
|
||||||
|
<Dialog.Title
|
||||||
|
as='h3'
|
||||||
|
className='text-lg font-medium leading-6 text-gray-900'
|
||||||
|
>
|
||||||
|
{i18n.t('common.sessionToFinish')}
|
||||||
|
</Dialog.Title>
|
||||||
|
<div className='mt-2'>
|
||||||
|
<p className='text-lg font-extrabold text-gray-500'>
|
||||||
|
{countTimer}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-4 flex w-full flex-row-reverse'>
|
||||||
|
<button
|
||||||
|
type='button'
|
||||||
|
className='mr-2 inline-flex justify-center rounded-md border border-transparent bg-red-100 px-4 py-2 text-sm font-medium text-red-900 hover:bg-red-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-2'
|
||||||
|
onClick={() => { stopIdleMonitor() }}
|
||||||
|
>
|
||||||
|
{i18n.t('common.sessionContinue')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Dialog.Panel>
|
||||||
|
</Transition.Child>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
</Transition>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionTimeout.propTypes = {
|
||||||
|
i18n: PropTypes.object,
|
||||||
|
user: PropTypes.object,
|
||||||
|
onTimeout: PropTypes.func,
|
||||||
|
onCancelTimeout: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionTimeout.defaultProps = {
|
||||||
|
i18n: { t: () => { return 'txtNone' } },
|
||||||
|
user: {},
|
||||||
|
onTimeout: () => {},
|
||||||
|
onCancelTimeout: () => {}
|
||||||
|
}
|
37
src/components/providers.tsx
Normal file
37
src/components/providers.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import LoadingProvider from "@/plugins/LoadingContext";
|
||||||
|
import I18nProvider from "@/plugins/i18nContext";
|
||||||
|
import presets from "@/utils/globalPresets";
|
||||||
|
import ResponsiveContainer from "@/layout/ResponsiveContainer"
|
||||||
|
|
||||||
|
import { Portal } from "via-ui/portal"
|
||||||
|
import { ToastContainer } from "react-toastify"
|
||||||
|
import { ThemeProvider } from "via-ui/theme-provider"
|
||||||
|
|
||||||
|
export function Providers({ children }: Readonly<{ children: React.ReactNode }>) {
|
||||||
|
return (
|
||||||
|
<ThemeProvider
|
||||||
|
attribute="class"
|
||||||
|
defaultTheme="system"
|
||||||
|
enableSystem
|
||||||
|
>
|
||||||
|
<I18nProvider locale={"es"} dict={""}>
|
||||||
|
<LoadingProvider>
|
||||||
|
<Portal>
|
||||||
|
{/* @ts-ignore */}
|
||||||
|
<ToastContainer
|
||||||
|
{...presets.toaster}
|
||||||
|
toastClassName={"rounded-lg bg-white text-black shadow-md dark:!bg-black dark:text-white"}
|
||||||
|
style={{ zIndex: 99999 }}
|
||||||
|
/>
|
||||||
|
</Portal>
|
||||||
|
<ResponsiveContainer>
|
||||||
|
{children}
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</LoadingProvider>
|
||||||
|
</I18nProvider>
|
||||||
|
</ThemeProvider>
|
||||||
|
)
|
||||||
|
}
|
108
src/helper/clientApi.js
Normal file
108
src/helper/clientApi.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
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) => {
|
||||||
|
try {
|
||||||
|
// 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
|
||||||
|
} catch (error) {
|
||||||
|
console.log('error', error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.ts
Normal file
9
src/hooks/useGlobalContainer.ts
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
|
20
src/hooks/useHasMounted.ts
Normal file
20
src/hooks/useHasMounted.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
/**
|
||||||
|
* useHasMounted is a React hook that checks if the component has mounted in the DOM.
|
||||||
|
* This is useful for preventing server-side code from running on the client-side.
|
||||||
|
*
|
||||||
|
* @link https://www.joshwcomeau.com/snippets/react-hooks/use-has-mounted/
|
||||||
|
*
|
||||||
|
* @returns {boolean} hasMounted - A boolean value that is initially false and changes to true once the component mounts.
|
||||||
|
*/
|
||||||
|
const useHasMounted = (): boolean => {
|
||||||
|
const [hasMounted, setHasMounted] = React.useState<boolean>(false)
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
setHasMounted(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return hasMounted
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useHasMounted
|
9
src/hooks/useI18n.ts
Normal file
9
src/hooks/useI18n.ts
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
|
21
src/hooks/useLoading.ts
Normal file
21
src/hooks/useLoading.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { LoadingContext, LoadingContextProps } from "@/plugins/LoadingContext"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook de React para acceder al contexto de carga.
|
||||||
|
* Esto es útil para casos de uso como mostrar un indicador de carga en la interfaz de usuario.
|
||||||
|
*
|
||||||
|
* @returns {LoadingContextProps} El contexto de carga.
|
||||||
|
* @throws {Error} Si se intenta usar fuera de un LoadingProvider.
|
||||||
|
*/
|
||||||
|
function useLoading (): LoadingContextProps {
|
||||||
|
const loading = React.useContext(LoadingContext)
|
||||||
|
|
||||||
|
if (!loading) {
|
||||||
|
throw new Error("useLoading must be used within a LoadingProvider")
|
||||||
|
}
|
||||||
|
|
||||||
|
return loading
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useLoading
|
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: ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
setTitle: (store, newState) => {
|
||||||
|
store.setState({
|
||||||
|
title: newState
|
||||||
|
})
|
||||||
|
},
|
||||||
|
setUsuarioPermisos: (store, newState) => {
|
||||||
|
store.setState({
|
||||||
|
usuarioPermisos: newState
|
||||||
|
})
|
||||||
|
},
|
||||||
|
setValueForEasyMDE: (store, newState) => {
|
||||||
|
store.setState({
|
||||||
|
valueEasyMDE: newState
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
224
src/layout/ResponsiveContainer.jsx
Normal file
224
src/layout/ResponsiveContainer.jsx
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { useRouter } from "next/navigation"
|
||||||
|
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"
|
||||||
|
import { useTheme } from "next-themes"
|
||||||
|
|
||||||
|
export const LayoutContext = React.createContext()
|
||||||
|
|
||||||
|
const Footer = dynamic(() => { return import("vComponents/Footer") }, { ssr: false })
|
||||||
|
const Sidebar = dynamic(() => { return import("via-ui/sidebar") }, { ssr: false })
|
||||||
|
const Navbar = dynamic(() => { return import("vComponents/Navbar") }, { ssr: false })
|
||||||
|
|
||||||
|
const ResponsiveContainer = ({ children }) => {
|
||||||
|
const router = useRouter()
|
||||||
|
const loading = useLoading()
|
||||||
|
const hasMounted = useHasMounted()
|
||||||
|
const i18n = useI18n()
|
||||||
|
const { theme, setTheme } = useTheme()
|
||||||
|
|
||||||
|
const [sidebarOpen, setSidebarOpen] = React.useState(true)
|
||||||
|
const [menu, setMenu] = React.useState([])
|
||||||
|
const [title, setTitle] = useStore(s => s.title, a => a.setTitle)
|
||||||
|
const [userObj, setUserObj] = React.useState()
|
||||||
|
const [token, setToken] = React.useState("")
|
||||||
|
const [constanteObj, setConstanteObj] = React.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 response = await execute(sprInfoSesion, [env.token, opcion])
|
||||||
|
if (environment.validaResultadoDB(response, i18n, toast, false) === true) {
|
||||||
|
// console.log('setPreferences', response)
|
||||||
|
if (opcion === "en" || opcion === "es") {
|
||||||
|
env.user.i18n = opcion
|
||||||
|
// setLanguage(opcion)
|
||||||
|
}
|
||||||
|
if (opcion === "light" || opcion === "dark") {
|
||||||
|
env.user.theme = opcion
|
||||||
|
setTheme("light")
|
||||||
|
}
|
||||||
|
environment.setEnvUser(env.user)
|
||||||
|
if (environment.validaResultadoDB(response, i18n, toast, false) === true) {
|
||||||
|
if (response && response[0]) {
|
||||||
|
toast.success(response[0].response, presets.toaster)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 containerWrapper = React.useMemo(() => ({
|
||||||
|
userObj,
|
||||||
|
setUserObj,
|
||||||
|
constanteObj,
|
||||||
|
setConstanteObj,
|
||||||
|
token,
|
||||||
|
setToken,
|
||||||
|
setTheme,
|
||||||
|
setTitle
|
||||||
|
}), [userObj, setUserObj, constanteObj, setConstanteObj, token, setToken, setTheme, setTitle])
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
getMenu()
|
||||||
|
}, [token])
|
||||||
|
|
||||||
|
// when page is mounted
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (hasMounted) {
|
||||||
|
getEnv().then(() => {
|
||||||
|
getMenu()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [hasMounted])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LayoutContext.Provider value={containerWrapper}>
|
||||||
|
|
||||||
|
<div className={"flex h-screen overflow-hidden"}>
|
||||||
|
{/* Sidebar */}
|
||||||
|
{userObj && userObj.nombre_usuario &&
|
||||||
|
<Sidebar
|
||||||
|
sidebarOpen={sidebarOpen}
|
||||||
|
setSidebarOpen={setSidebarOpen}
|
||||||
|
menu={menu}
|
||||||
|
presets={presets}
|
||||||
|
userObj={userObj}
|
||||||
|
environment={environment}
|
||||||
|
setTitle={setTitle}
|
||||||
|
onClickLogout={() => doLogout()}
|
||||||
|
router={router}
|
||||||
|
i18n={i18n}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
|
{/* Content area */}
|
||||||
|
<div className={"relative flex w-full flex-1 flex-col overflow-y-auto overflow-x-hidden"}>
|
||||||
|
|
||||||
|
{/* Site header */}
|
||||||
|
{userObj && userObj.nombre_usuario &&
|
||||||
|
<Navbar
|
||||||
|
sidebarOpen={sidebarOpen}
|
||||||
|
setSidebarOpen={setSidebarOpen}
|
||||||
|
onClickLogout={() => doLogout()}
|
||||||
|
onClickProfile={() => router.push(`${presets.locations.profile}/${environment.getTime()}`)}
|
||||||
|
// MenuOptions={() => <UserOptionsMenu setPreferences={setPreferences} theme={theme} i18n={i18n} />}
|
||||||
|
i18n={i18n}
|
||||||
|
theme={theme}
|
||||||
|
setPreferences={setPreferences}
|
||||||
|
title={title}
|
||||||
|
userObj={userObj}
|
||||||
|
router={router}
|
||||||
|
presets={presets}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
|
<main className={userObj && userObj.nombre_usuario ? "responsive-container" : ""}>
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{userObj && userObj.nombre_usuario &&
|
||||||
|
<SessionTimeout i18n={i18n} user={userObj} onTimeout={() => onTimeout()} onCancelTimeout={() => onCancelTimeout()} />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<Footer version={process.env.version} label={i18n.t("common.version") || "version"} />
|
||||||
|
</div>
|
||||||
|
</LayoutContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ResponsiveContainer
|
26
src/lib/utils.ts
Normal file
26
src/lib/utils.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { twMerge } from "tailwind-merge"
|
||||||
|
|
||||||
|
export function cn (...inputs: (string | Record<string, boolean>)[]): string {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatDate(input: string | number): string {
|
||||||
|
const date = new Date(input)
|
||||||
|
return date.toLocaleDateString("en-US", {
|
||||||
|
month: "long",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function absoluteUrl(path: string) {
|
||||||
|
return `${process.env.publicPath}${path}`
|
||||||
|
}
|
55
src/plugins/LoadingContext.tsx
Normal file
55
src/plugins/LoadingContext.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import dynamic from "next/dynamic"
|
||||||
|
import presets from "@/utils/globalPresets"
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const LoadingSpinner = dynamic(() => import("vComponents/dist/Loading"), { ssr: false })
|
||||||
|
|
||||||
|
/** ----------------------------------------------------------------------------------------------
|
||||||
|
* LoadingContext
|
||||||
|
* ----------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
export interface LoadingContextProps {
|
||||||
|
loading: boolean
|
||||||
|
setLoading: (loading: boolean) => void
|
||||||
|
start: () => void
|
||||||
|
stop: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LoadingContext = React.createContext<LoadingContextProps>({
|
||||||
|
loading: false,
|
||||||
|
setLoading: (loading: boolean) => {},
|
||||||
|
start: () => {},
|
||||||
|
stop: () => {}
|
||||||
|
})
|
||||||
|
|
||||||
|
/** ----------------------------------------------------------------------------------------------
|
||||||
|
* LoadingProvider
|
||||||
|
* ----------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
interface LoadingProviderProps {
|
||||||
|
children: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const LoadingProvider = ({ children }: LoadingProviderProps) => {
|
||||||
|
const [loading, setLoading] = React.useState<boolean>(false)
|
||||||
|
|
||||||
|
const loadingWrapper = React.useMemo(() => ({
|
||||||
|
loading,
|
||||||
|
setLoading,
|
||||||
|
start: () => setLoading(true),
|
||||||
|
stop: () => setLoading(false)
|
||||||
|
}), [loading])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LoadingContext.Provider value={loadingWrapper}>
|
||||||
|
{children}
|
||||||
|
{/* @ts-ignore */}
|
||||||
|
<LoadingSpinner loading={loading} image={presets.images.imageLoader} background={"backgroundLoader"} color={"colorLoader"} />
|
||||||
|
</LoadingContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LoadingProvider
|
74
src/plugins/i18nContext.jsx
Normal file
74
src/plugins/i18nContext.jsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import rosetta from "rosetta"
|
||||||
|
import { execute } from "@/helper/clientApi"
|
||||||
|
import useHasMounted from "@/hooks/useHasMounted"
|
||||||
|
|
||||||
|
const i18n = rosetta()
|
||||||
|
const defaultLanguage = "es"
|
||||||
|
const languages = ["es", "en"]
|
||||||
|
const contentLanguageMap = { es: "es-GT", en: "en-US" }
|
||||||
|
const I18nContext = React.createContext()
|
||||||
|
|
||||||
|
// default language
|
||||||
|
i18n.locale(defaultLanguage)
|
||||||
|
|
||||||
|
const I18nProvider = ({ children, locale, dict }) => {
|
||||||
|
const activeLocaleRef = React.useRef(locale || defaultLanguage)
|
||||||
|
const [, setTick] = React.useState(0)
|
||||||
|
const firstRender = React.useRef(true)
|
||||||
|
const [langIsLoaded, setLangIsLoaded] = React.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 = {}
|
||||||
|
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 page is mounted
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (hasMounted) {
|
||||||
|
setLanguage()
|
||||||
|
}
|
||||||
|
}, [hasMounted, activeLocaleRef.current])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<I18nContext.Provider value={i18nWrapper}>{children}</I18nContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { defaultLanguage, languages, contentLanguageMap, I18nContext }
|
||||||
|
|
||||||
|
export default I18nProvider
|
43
src/styles/additional-styles/404.css
Normal file
43
src/styles/additional-styles/404.css
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
@-moz-keyframes rocket-movement { 100% {-moz-transform: translate(1200px,-600px);} }
|
||||||
|
@-webkit-keyframes rocket-movement {100% {-webkit-transform: translate(1200px,-600px); } }
|
||||||
|
@keyframes rocket-movement { 100% {transform: translate(1200px,-600px);} }
|
||||||
|
@-moz-keyframes spin-earth { 100% { -moz-transform: rotate(-360deg); transition: transform 20s; } }
|
||||||
|
@-webkit-keyframes spin-earth { 100% { -webkit-transform: rotate(-360deg); transition: transform 20s; } }
|
||||||
|
@keyframes spin-earth{ 100% { -webkit-transform: rotate(-360deg); transform:rotate(-360deg); transition: transform 20s; } }
|
||||||
|
|
||||||
|
@-moz-keyframes move-astronaut {
|
||||||
|
100% { -moz-transform: translate(-160px, -160px);}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes move-astronaut {
|
||||||
|
100% { -webkit-transform: translate(-160px, -160px);}
|
||||||
|
}
|
||||||
|
@keyframes move-astronaut{
|
||||||
|
100% { -webkit-transform: translate(-160px, -160px); transform:translate(-160px, -160px); }
|
||||||
|
}
|
||||||
|
@-moz-keyframes rotate-astronaut {
|
||||||
|
100% { -moz-transform: rotate(-720deg);}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes rotate-astronaut {
|
||||||
|
100% { -webkit-transform: rotate(-720deg);}
|
||||||
|
}
|
||||||
|
@keyframes rotate-astronaut{
|
||||||
|
100% { -webkit-transform: rotate(-720deg); transform:rotate(-720deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes orbit {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg) translateX(50px) rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg) translateX(50px) rotate(-360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blink {
|
||||||
|
0%, 100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
59
src/styles/additional-styles/dropzone.css
Normal file
59
src/styles/additional-styles/dropzone.css
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
@import "react-dropzone-component/styles/filepicker.css";
|
||||||
|
@import 'dropzone/dist/min/dropzone.min.css';
|
||||||
|
|
||||||
|
.dropzone.dz-clickable {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone .dz-preview {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
height: 80px !important;
|
||||||
|
min-height: 80px !important;
|
||||||
|
margin: 0px !important;
|
||||||
|
padding: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone .dz-preview .dz-image {
|
||||||
|
border-radius: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 120px;
|
||||||
|
height: 80px !important;
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
z-index: 10;
|
||||||
|
margin: 0px !important;
|
||||||
|
padding: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone .dz-preview .dz-image img {
|
||||||
|
display: block;
|
||||||
|
max-height: 80px !important;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone .dz-preview .dz-details {
|
||||||
|
z-index: 20;
|
||||||
|
position: absolute;
|
||||||
|
top: 8px !important;
|
||||||
|
left: 0;
|
||||||
|
margin: 0px !important;
|
||||||
|
padding: 0px !important;
|
||||||
|
opacity: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
min-width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
height: 80px !important;
|
||||||
|
padding: 2em 1em;
|
||||||
|
text-align: center;
|
||||||
|
color: rgba(0,0,0,.9);
|
||||||
|
line-height: 150%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filepicker-file-icon {
|
||||||
|
margin: 5px !important;
|
||||||
|
padding: 1px !important;
|
||||||
|
}
|
7
src/styles/additional-styles/toastify.css
Normal file
7
src/styles/additional-styles/toastify.css
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@import 'react-toastify/dist/ReactToastify.css';
|
||||||
|
|
||||||
|
.Toastify__toast-container--top-center {
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
19
src/styles/component-styles/datatable.css
Normal file
19
src/styles/component-styles/datatable.css
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
.via-states-datatable {
|
||||||
|
@apply text-xs font-semibold mr-2 px-2.5 py-0.5 rounded;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-icon-active {
|
||||||
|
@apply text-green-800 dark:text-green-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-icon-inactive {
|
||||||
|
@apply text-red-800 dark:text-red-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-detalle-datatable {
|
||||||
|
@apply text-white bg-blue-700 hover:bg-blue-800 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-badge-datatable {
|
||||||
|
@apply text-white -right-3 -top-2 text-xs bg-red-500 border-white dark:border-gray-900;
|
||||||
|
}
|
112
src/styles/component-styles/loading.css
Normal file
112
src/styles/component-styles/loading.css
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
.backgroundLoader {
|
||||||
|
@apply bg-white backdrop-blur-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colorLoader {
|
||||||
|
@apply bg-theme-app-500 dark:bg-theme-app-700 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.div_loading {
|
||||||
|
@apply rounded-lg border border-gray-200 shadow-md sm:p-6 md:p-8 dark:border-gray-700 z-50;
|
||||||
|
position: absolute;
|
||||||
|
height: 35%;
|
||||||
|
width: 30%;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
-webkit-transform: translate(-50%, -50%);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 200px;
|
||||||
|
height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner > div {
|
||||||
|
height: 100%;
|
||||||
|
width: 8px;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 3px;
|
||||||
|
-webkit-animation: sk-stretchdelay 1.8s infinite ease-in-out;
|
||||||
|
animation: sk-stretchdelay 1.8s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner div:nth-child(1) {
|
||||||
|
-webkit-animation-delay: -1.6s;
|
||||||
|
animation-delay: -1.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner div:nth-child(2) {
|
||||||
|
-webkit-animation-delay: -1.4s;
|
||||||
|
animation-delay: -1.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner div:nth-child(3) {
|
||||||
|
-webkit-animation-delay: -1.2s;
|
||||||
|
animation-delay: -1.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner div:nth-child(4) {
|
||||||
|
-webkit-animation-delay: -1.0s;
|
||||||
|
animation-delay: -1.0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes sk-stretchdelay {
|
||||||
|
0%, 40%, 100% { -webkit-transform: scaleY(0.4) }
|
||||||
|
20% { -webkit-transform: scaleY(1.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes sk-stretchdelay {
|
||||||
|
0%, 40%, 100% {
|
||||||
|
transform: scaleY(0.4);
|
||||||
|
-webkit-transform: scaleY(0.4);
|
||||||
|
} 20% {
|
||||||
|
transform: scaleY(1.0);
|
||||||
|
-webkit-transform: scaleY(1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lds-facebook {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lds-facebook div {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
left: 8px;
|
||||||
|
width: 16px;
|
||||||
|
background: #fff;
|
||||||
|
animation: lds-facebook 1.2s cubic-bezier(0, 0.5, 0.5, 1) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lds-facebook div:nth-child(1) {
|
||||||
|
left: 8px;
|
||||||
|
animation-delay: -0.24s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lds-facebook div:nth-child(2) {
|
||||||
|
left: 32px;
|
||||||
|
animation-delay: -0.12s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lds-facebook div:nth-child(3) {
|
||||||
|
left: 56px;
|
||||||
|
animation-delay: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes lds-facebook {
|
||||||
|
0% {
|
||||||
|
top: 8px;
|
||||||
|
height: 64px;
|
||||||
|
}
|
||||||
|
50%, 100% {
|
||||||
|
top: 24px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
}
|
0
src/styles/component-styles/navbar.css
Normal file
0
src/styles/component-styles/navbar.css
Normal file
167
src/styles/component-styles/sidebar.css
Normal file
167
src/styles/component-styles/sidebar.css
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
.via-bg-sidebar {
|
||||||
|
/* Base */
|
||||||
|
@apply bg-theme-app-500 dark:bg-theme-app-900
|
||||||
|
/* Desktop */
|
||||||
|
md:rounded-none
|
||||||
|
/* Mobile */
|
||||||
|
rounded-t-lg !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-bg-popover-sidebar {
|
||||||
|
/* Base */
|
||||||
|
@apply bg-gray-100 dark:bg-gray-800
|
||||||
|
space-y-2 rounded-lg border p-1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* options-sidebar */
|
||||||
|
|
||||||
|
.via-options-sidebar {
|
||||||
|
/* Base */
|
||||||
|
@apply rounded-lg transition-colors duration-500 font-thin text-md shadow-md px-2 py-1.5 border text-left truncate
|
||||||
|
/* Light */
|
||||||
|
bg-white/10 hover:bg-white/30 text-white/85 hover:text-white border-white/30
|
||||||
|
/* Dark */
|
||||||
|
dark:bg-white/15 dark:hover:bg-white/20 dark:text-white/85 dark:hover:text-white
|
||||||
|
!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-options-sidebar-active {
|
||||||
|
/* Base */
|
||||||
|
@apply rounded-lg transition-colors duration-500 font-thin text-md shadow-md px-2 py-1.5 border-l-4
|
||||||
|
/* Light */
|
||||||
|
bg-white/50 hover:bg-white/30 text-theme-app-800 hover:text-theme-app-900
|
||||||
|
/* Dark */
|
||||||
|
dark:bg-white/30 dark:hover:bg-white/40 dark:text-white/85 dark:hover:text-white
|
||||||
|
!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-options-sidebar-collapse {
|
||||||
|
/* Base */
|
||||||
|
@apply rounded-none transition-colors duration-500 font-thin text-md justify-center pb-0.5 pt-2 px-0.5 line-clamp-2 text-balance
|
||||||
|
/* Light */
|
||||||
|
hover:bg-white/30 text-white/85 hover:text-white
|
||||||
|
/* Dark */
|
||||||
|
dark:bg-white/15 dark:hover:bg-white/20 dark:text-white/85 dark:hover:text-white
|
||||||
|
|
||||||
|
!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-options-sidebar-collapse-active {
|
||||||
|
/* Base */
|
||||||
|
@apply rounded-none transition-colors duration-500 font-thin text-md justify-center py-0.5 pt-2 px-0.5 border-l-4
|
||||||
|
/* Light */
|
||||||
|
bg-white/50 hover:bg-white/30 text-theme-app-800 hover:text-theme-app-900
|
||||||
|
/* Dark */
|
||||||
|
dark:bg-white/30 dark:hover:bg-white/40 dark:text-white/85 dark:hover:text-white
|
||||||
|
!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-icons-sidebar {
|
||||||
|
@apply !text-theme-app-950 bg-blue-100 rounded-md border drop-shadow-md h-6 w-6 min-h-6 min-w-6 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-icons-sidebar-collapse {
|
||||||
|
@apply !text-theme-app-950 bg-blue-100 rounded-md border drop-shadow-md h-7 w-7 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-collapse-options-sidebar {
|
||||||
|
@apply relative duration-300 ease-in-out overflow-hidden rounded-bl-md border-l-2 border-b-2 space-y-2 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sub-options-sidebar */
|
||||||
|
.via-sub-options-sidebar {
|
||||||
|
/* Base */
|
||||||
|
@apply rounded-lg transition-colors duration-500 font-thin shadow-md justify-start items-center text-md px-1.5 py-1
|
||||||
|
/* Light */
|
||||||
|
bg-white/20 hover:bg-white/30 text-white/85 hover:text-white
|
||||||
|
/* Dark */
|
||||||
|
dark:bg-white/15 dark:hover:bg-white/20 dark:text-white/85 dark:hover:text-white
|
||||||
|
!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-sub-options-sidebar-active {
|
||||||
|
/* Base */
|
||||||
|
@apply rounded-lg transition-colors duration-500 font-thin shadow-md justify-start items-center text-md px-1.5 py-1 border-l-4
|
||||||
|
/* Light */
|
||||||
|
bg-white/50 hover:bg-white/30 text-theme-app-800 hover:text-theme-app-900
|
||||||
|
/* Dark */
|
||||||
|
dark:bg-white/30 dark:hover:bg-white/40 dark:text-white/85 dark:hover:text-white
|
||||||
|
!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-sub-options-sidebar-collapse {
|
||||||
|
/* Base */
|
||||||
|
@apply rounded-lg transition-colors duration-500 font-thin shadow-md justify-start items-center text-md py-0.5 px-1.5
|
||||||
|
/* Light */
|
||||||
|
bg-white hover:bg-gray-300 text-gray-700 hover:text-gray-800 border border-gray-300
|
||||||
|
/* Dark */
|
||||||
|
dark:bg-gray-800 dark:hover:bg-gray-900 dark:text-gray-200 dark:hover:text-gray-300
|
||||||
|
!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-sub-options-sidebar-collapse-active {
|
||||||
|
/* Base */
|
||||||
|
@apply rounded-lg transition-colors duration-500 font-thin shadow-md justify-start items-center text-md py-0.5 px-1.5 border-l-4
|
||||||
|
/* Light */
|
||||||
|
bg-white/50 hover:bg-white/30 text-theme-app-800 hover:text-theme-app-900
|
||||||
|
/* Dark */
|
||||||
|
dark:bg-gray-900 dark:hover:bg-gray-950 dark:text-gray-300 dark:hover:text-gray-400 dark:border-gray-200
|
||||||
|
!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icons for sub-options-sidebar */
|
||||||
|
|
||||||
|
.via-icons-sub-sidebar {
|
||||||
|
@apply !text-theme-app-950 bg-cyan-50 rounded-md h-6 w-6 min-h-6 min-w-6 drop-shadow-md !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-icons-sub-sidebar-collapse {
|
||||||
|
@apply !text-theme-app-950 bg-cyan-50 rounded-md h-8 w-8 min-h-6 min-w-6 drop-shadow-md !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sidebar */
|
||||||
|
.via-footer-options-sidebar {
|
||||||
|
/* Base */
|
||||||
|
@apply bg-white/10 hover:bg-white/30 text-white/85 hover:text-white border-white/30 border rounded-lg text-md space-x-2 px-2 py-1.5 dark:text-theme-app-50 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-separator-sidebar {
|
||||||
|
@apply h-[1.5px] bg-white/75 my-2 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-drawer-count {
|
||||||
|
@apply inline-flex items-center w-8 justify-center mr-1 px-2 py-2 text-sm font-thin leading-none bg-teal-800 text-white rounded-full
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-app-title-sidebar {
|
||||||
|
/* Base */
|
||||||
|
@apply text-theme-app-50 dark:text-theme-app-50 hover:bg-theme-app-800 dark:hover:bg-theme-app-950 rounded-lg !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-user-info-sidebar {
|
||||||
|
@apply text-white text-base bg-theme-app-700 dark:bg-theme-app-900 hover:bg-theme-app-800 dark:hover:bg-theme-app-950 cursor-default !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-input-search-sidebar {
|
||||||
|
@apply rounded-lg h-8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-badge-sidebar {
|
||||||
|
@apply bg-red-500 text-white rounded-full text-[10px] px-2 py-1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-badge-sidebar-collapse {
|
||||||
|
@apply absolute top-0 right-0 bg-red-500 text-white rounded-full text-[10px] px-1 py-0.5 border-2 border-white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-count-sidebar {
|
||||||
|
@apply bg-green-500 text-white rounded-full text-[10px] px-2 py-1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-count-sidebar-collapse {
|
||||||
|
@apply absolute top-0 right-3 bg-green-500 text-white rounded-full text-[10px] px-1.5 py-0.5 border-2 border-white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-drawer-button {
|
||||||
|
@apply bg-theme-app-600 hover:bg-theme-app-700 flex items-center justify-between rounded-lg border border-transparent p-2 font-thin leading-5 text-white transition-colors duration-150 focus:outline-none active:bg-purple-600 !important;
|
||||||
|
}
|
47
src/styles/globals.css
Normal file
47
src/styles/globals.css
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css2?family=Inter'); /* Inter */
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Material+Icons+Round'); /* Material Icons */
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Roboto'); /* Roboto */
|
||||||
|
@import url('https://www.via-asesores.com/fonts/din-webfont.css'); /* DIN Web */
|
||||||
|
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
/* ===== Scrollbar CSS ===== */
|
||||||
|
@layer utilities {
|
||||||
|
/* Firefox */
|
||||||
|
* {
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: theme('colors.theme-app.600') rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * {
|
||||||
|
@apply border-pink-500;
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* Additional Styles */
|
||||||
|
@import 'additional-styles/toastify.css';
|
||||||
|
@import 'additional-styles/dropzone.css';
|
||||||
|
@import 'additional-styles/404.css';
|
||||||
|
|
||||||
|
/* Component Styles */
|
||||||
|
/* @import 'component-styles/navbar.css'; → use vComponents styles instead */
|
||||||
|
@import 'component-styles/loading.css';
|
||||||
|
@import 'component-styles/sidebar.css';
|
||||||
|
@import 'component-styles/datatable.css';
|
||||||
|
|
||||||
|
/* VIA UI Styles */
|
||||||
|
/* @import 'component-styles/via-ui.css'; */
|
||||||
|
|
||||||
|
/* Page Styles */
|
||||||
|
@import 'page-styles/common.css';
|
||||||
|
@import 'page-styles/login.css';
|
||||||
|
|
||||||
|
/* vComponent Styles */
|
||||||
|
@import 'vComponents/styles/generated/globals.min.css';
|
||||||
|
@import 'vComponents/styles/generated/component-styles/navbar.min.css';
|
||||||
|
@import 'vComponents/styles/generated/component-styles/sidebar.min.css';
|
||||||
|
|
||||||
|
/* Analytics Lib Styles */
|
||||||
|
/* @import 'analytics-lib/styles/generated/output.css'; */
|
98
src/styles/page-styles/common.css
Normal file
98
src/styles/page-styles/common.css
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
.via-card {
|
||||||
|
@apply block rounded-md shadow-md w-full border-gray-300 border drop-shadow-lg bg-white dark:bg-[#4E4E4E] shadow-[#D1D1D1] hover:shadow-[#00000033];
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-label {
|
||||||
|
@apply block text-gray-500 dark:text-gray-300 text-[14px] xl:text-[15px] font-medium mb-1 pl-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-input {
|
||||||
|
@apply w-full text-md bg-background text-foreground rounded-lg border-l-gray-100 border border-gray-300 focus:ring-stone-500 focus:border-stone-500 dark:border-stone-600 dark:placeholder-gray-400 dark:focus:border-stone-500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-input:disabled {
|
||||||
|
@apply bg-gray-300 text-gray-700 dark:bg-gray-800 dark:text-gray-300 cursor-not-allowed !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-input:not(div) {
|
||||||
|
@apply px-2 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-input:not(textarea) {
|
||||||
|
@apply h-8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
select.via-input {
|
||||||
|
@apply py-0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-input-focus {
|
||||||
|
@apply border-stone-500 border-[2px] !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invalid-feedback {
|
||||||
|
@apply h-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-input-prepend {
|
||||||
|
@apply w-full text-sm text-foreground rounded-l-lg border border-gray-300 focus:ring-stone-500 focus:border-stone-500 dark:border-stone-600 dark:placeholder-gray-400 dark:focus:border-stone-500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-append-input {
|
||||||
|
@apply w-8 absolute top-0 -right-1 h-full text-sm font-medium text-white bg-theme-app-500 dark:bg-theme-app-900 rounded-r-lg border border-theme-app-900 hover:bg-theme-app-600 focus:ring-4 focus:outline-none focus:ring-theme-app-300 dark:hover:bg-theme-app-900 dark:focus:ring-theme-app-800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-append-input svg, .via-append-input-extra svg {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateY(-50%) translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-append-input-extra {
|
||||||
|
@apply absolute top-0 right-0 py-1 px-3 mr-[1.7rem] w-auto h-full text-sm font-medium text-white rounded-full bg-red-700 rounded-r-md hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-button {
|
||||||
|
@apply cursor-pointer inline-flex items-center h-8 px-2 m-1 text-white ease-linear transition-colors duration-150 rounded-md border border-gray-300 dark:border-gray-700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-div-actions {
|
||||||
|
@apply flex w-full justify-center flex-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-no {
|
||||||
|
@apply text-red-700 dark:text-red-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-yes {
|
||||||
|
@apply text-green-700 dark:text-green-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-translate {
|
||||||
|
@apply -translate-x-1/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-opacity {
|
||||||
|
@apply bg-opacity-25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-img-preview {
|
||||||
|
@apply h-16 max-h-16 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.responsive-container {
|
||||||
|
@apply w-full h-full mx-auto bg-background items-center pb-10 overflow-auto p-2 transition-colors duration-350 ease-in-out text-[#0F0F0F] dark:text-[#F1F1F1] !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-title {
|
||||||
|
@apply font-semibold text-[#0F0F0F] dark:text-[#F1F1F1]
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-subtitle {
|
||||||
|
@apply text-[#606060] dark:text-[#AAAAAA]
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-text {
|
||||||
|
@apply text-[#131313] dark:text-[#FFFFFF]
|
||||||
|
}
|
23
src/styles/page-styles/login.css
Normal file
23
src/styles/page-styles/login.css
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
.via-login-page {
|
||||||
|
@apply flex flex-wrap w-screen h-screen bg-gray-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-login-layout {
|
||||||
|
@apply flex flex-shrink w-full h-full md:w-1/2 lg:w-1/3 bg-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-login-header {
|
||||||
|
@apply flex w-full p-4 justify-center overflow-hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-login-logo {
|
||||||
|
@apply w-64 h-64 bg-center bg-auto bg-no-repeat object-contain !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-login-background {
|
||||||
|
@apply hidden flex-shrink h-full md:w-1/2 lg:w-2/3 md:flex bg-center bg-contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-login-form {
|
||||||
|
@apply flex w-full flex-col space-y-4;
|
||||||
|
}
|
212
src/styles/ui-styles/via-ui.css
Normal file
212
src/styles/ui-styles/via-ui.css
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
.main-container {
|
||||||
|
@apply grid gap-x-5 gap-y-3 2xl:gap-y-8 my-2 2xl:my-4 text-slate-700 justify-center content-around;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
@apply flex flex-col w-full rounded-lg border duration-300 items-center bg-white dark:bg-[#272727] shadow-[#D1D1D1] hover:shadow-[#00000033];
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
@apply flex flex-col w-full rounded-t-lg border-b duration-300 items-center bg-white dark:bg-[#272727] shadow-[#D1D1D1] hover:shadow-[#00000033];
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-card {
|
||||||
|
@apply bg-gradient-to-br dark:bg-gradient-to-br from-theme-app-600 to-theme-app-400 dark:from-theme-app-800 dark:to-theme-app-600 flex h-12 w-full items-center justify-center rounded-t-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-items {
|
||||||
|
@apply grid grid-cols-2 justify-start text-white font-medium gap-2 items-center w-full py-2 ;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-header {
|
||||||
|
@apply font-semibold md:ml-2 ml-1 text-white justify-start left-0 ;
|
||||||
|
overflow:hidden;
|
||||||
|
height: auto;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
display: block;
|
||||||
|
display: -webkit-box;
|
||||||
|
overflow: hidden !important;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loading {
|
||||||
|
0%, 100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-loading {
|
||||||
|
animation: loading 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tooltip styles */
|
||||||
|
|
||||||
|
.tooltip-container {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-box {
|
||||||
|
@apply !absolute;
|
||||||
|
background-color: #555;
|
||||||
|
color: #fff;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-top {
|
||||||
|
bottom: 100%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-bottom {
|
||||||
|
top: 100%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-left {
|
||||||
|
right: 100%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-right {
|
||||||
|
left: 100%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tabs styles */
|
||||||
|
.tabs {
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabsContentWrapper {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabsContent {
|
||||||
|
/* position: absolute; */
|
||||||
|
transition: transform 0.6s ease-in-out;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabsContent {
|
||||||
|
@apply w-full;
|
||||||
|
transition: transform 0.6s ease-in-out, opacity 0.6s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabsContent[data-active="false"] {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabsContent[data-active="true"] {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabsList {
|
||||||
|
@apply flex w-full rounded-t-lg border-b duration-300 items-center bg-white dark:bg-[#272727] shadow-[#D1D1D1] hover:shadow-[#00000033] p-1;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabsTrigger {
|
||||||
|
@apply bg-white dark:bg-[#3D3D3D] text-gray-500 dark:text-gray-200 hover:text-gray-700 dark:hover:text-gray-300 active:!bg-gray-100 dark:active:!bg-[#3D3D3D] font-medium transition-colors duration-500 delay-1000 ease-in-out;
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: center;
|
||||||
|
transition: background-color 0.75s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabsTrigger[data-active="true"] {
|
||||||
|
@apply bg-white text-theme-app-500 dark:text-theme-app-900 font-bold hover:font-extrabold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabsIndicator {
|
||||||
|
@apply bg-theme-app-500 dark:bg-theme-app-900;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
height: 4px;
|
||||||
|
transition: left 0.75s ease, right 0.75s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-left-in {
|
||||||
|
animation: slide-left-in 0.75s forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-right-in {
|
||||||
|
animation: slide-right-in 0.75s forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-left-out {
|
||||||
|
animation: slide-left-out 0.75s forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-right-out {
|
||||||
|
animation: slide-right-out 0.75s forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-left-in {
|
||||||
|
from { transform: translateX(100%); }
|
||||||
|
to { transform: translateX(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-right-in {
|
||||||
|
from { transform: translateX(-100%); }
|
||||||
|
to { transform: translateX(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-left-out {
|
||||||
|
from { transform: translateX(0); }
|
||||||
|
to { transform: translateX(-100%); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-right-out {
|
||||||
|
from { transform: translateX(0); }
|
||||||
|
to { transform: translateX(100%); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* checkbox styles */
|
||||||
|
|
||||||
|
|
||||||
|
.filter-button{
|
||||||
|
@apply items-center hover:bg-theme-app-400 dark:hover:bg-theme-app-700 rounded-lg grid grid-cols-2 h-10 px-4 gap-2 text-slate-700 hover:text-white dark:text-white font-medium duration-300 dark:hover:text-white;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Accordion > .AccordionTrigger:first-child > div:first-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Accordion > .AccordionTrigger:last-child > div:last-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tooltip-indicator {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-left: 6px solid transparent;
|
||||||
|
border-right: 6px solid transparent;
|
||||||
|
border-bottom: 8px solid gray;
|
||||||
|
position: absolute;
|
||||||
|
top: -8px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 50;
|
||||||
|
}
|
365
src/utils/environment.js
Normal file
365
src/utils/environment.js
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
import Cookie from 'js-cookie'
|
||||||
|
import functions from 'v-functions'
|
||||||
|
import presets from './globalPresets'
|
||||||
|
import { findWhere } from 'underscore'
|
||||||
|
import { execute } from '@/helper/clientApi'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Environment
|
||||||
|
* @property {function} getResultParameters - Funcion para obtener los parametros de un resultado
|
||||||
|
* @property {function} buildFunctiontsHeaders - Funcion para construir las funciones de los headers
|
||||||
|
* @property {function} setEnvUser - Funcion para guardar el usuario en el localstorage
|
||||||
|
* @property {function} getEnvUser - Funcion para obtener el usuario del localstorage
|
||||||
|
* @property {function} logout - Funcion para cerrar sesion
|
||||||
|
* @property {function} login - Funcion para iniciar sesion
|
||||||
|
* @property {function} getTime - Funcion para obtener la hora actual
|
||||||
|
* @property {function} validaResultadoDB - Funcion para validar el resultado de una peticion a la base de datos
|
||||||
|
* @property {function} getFileParams - Funcion para obtener los parametros de un archivo
|
||||||
|
* @property {function} validaPermisos - Funcion para validar los permisos de un usuario
|
||||||
|
* @property {function} i18nHeaders - Funcion para traducir los headers
|
||||||
|
*
|
||||||
|
* @type {Environment}
|
||||||
|
* @exports environment
|
||||||
|
* @description Este archivo contiene las funciones globales de la aplicacion
|
||||||
|
* @example
|
||||||
|
* import environment from '@/utils/environment'
|
||||||
|
*
|
||||||
|
* environment.getResultParameters(confParameters, item, mainParameters)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const environment = {
|
||||||
|
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
|
83
src/utils/globalPresets.ts
Normal file
83
src/utils/globalPresets.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
const theme = 'blue'
|
||||||
|
|
||||||
|
const presets = {
|
||||||
|
appTitle: 'Orbis Template',
|
||||||
|
theme: `${theme}`,
|
||||||
|
svgIconUrl: 'https://www.via-asesores.com/logos/logo_icons/orbisprocess_icon.svg',
|
||||||
|
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/logos/logo_icons/orbisprocess_icon.svg',
|
||||||
|
logo: 'https://www.via-asesores.com/logos/logo_vertical/orbisprocess_vertical_logo.svg',
|
||||||
|
imageLoader: 'https://www.via-asesores.com/logos/logo_horizontal/orbisprocess_horizontal_logo.svg',
|
||||||
|
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'
|
||||||
|
},
|
||||||
|
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
|
@ -1,20 +1,48 @@
|
|||||||
import type { Config } from "tailwindcss";
|
import type { Config } from "tailwindcss"
|
||||||
|
import { standard, standardThemes } from "via-tailwind"
|
||||||
|
|
||||||
|
const themeAppColors = {
|
||||||
|
50: "#b3e5fc",
|
||||||
|
100: "#81d4fa",
|
||||||
|
200: "#4fc3f7",
|
||||||
|
300: "#29b6f6",
|
||||||
|
400: "#03a9f4",
|
||||||
|
500: "#0288d1",
|
||||||
|
600: "#0277bd",
|
||||||
|
700: "#0260a0",
|
||||||
|
800: "#024484",
|
||||||
|
900: "#022865",
|
||||||
|
950: "#011c4c"
|
||||||
|
}
|
||||||
|
|
||||||
|
const themeTextColors = {
|
||||||
|
principal: "#334155",
|
||||||
|
disabled: "#cbd5e1"
|
||||||
|
}
|
||||||
|
|
||||||
const config: Config = {
|
const config: Config = {
|
||||||
|
darkMode: "class",
|
||||||
content: [
|
content: [
|
||||||
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
|
"./src/**/*.{js,ts,jsx,tsx,mdx}",
|
||||||
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
|
"./node_modules/analytics-lib/dist/**/*.{js,ts,jsx,tsx}",
|
||||||
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
|
"./node_modules/vComponents/**/*.{js,ts,jsx,tsx}",
|
||||||
|
"./node_modules/via-ui/dist/**/*.{js,ts,jsx,tsx}"
|
||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
backgroundImage: {
|
colors: {
|
||||||
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
|
"theme-text": themeTextColors,
|
||||||
"gradient-conic":
|
"theme-app": themeAppColors
|
||||||
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
|
}
|
||||||
},
|
}
|
||||||
},
|
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [
|
||||||
};
|
standard,
|
||||||
export default config;
|
standardThemes({
|
||||||
|
"theme-app": themeAppColors,
|
||||||
|
"theme-text": themeTextColors
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default config
|
||||||
|
@ -18,9 +18,11 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"],
|
||||||
}
|
"vComponents/*": ["./node_modules/vComponents/dist/components/*"],
|
||||||
|
"via-ui/*": ["./node_modules/via-ui/dist/components/*"]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", ".next/types/**/*.ts"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user