ejercicio tarjeta de crédito completado
This commit is contained in:
parent
3da466041b
commit
35321e9955
0
.env.development
Normal file
0
.env.development
Normal file
3
.eslintrc.json
Normal file
3
.eslintrc.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends": "next/core-web-vitals"
|
||||||
|
}
|
14
config/default.json
Normal file
14
config/default.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"constants": {
|
||||||
|
"plataforma": "web",
|
||||||
|
"publicPath": "/smartcollector",
|
||||||
|
"urlServerImages" : "https://gt.via-asesores.com/smartcollector/orbisapi/dtsrv/dev/smartcollector?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTsc",
|
||||||
|
"urlWebApi": "https://gt.via-asesores.com/smartcollector/orbisapi/api/dev/smartcollector?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTsc",
|
||||||
|
"urlUploadApi": "https://gt.via-asesores.com/smartcollector/orbisapi/upload/dev/smartcollector?apikey=NTAzYzZlOTItMDcwZC00Zjg4LTljODMtNzBkNGQ5YjZhZTsc",
|
||||||
|
"appTitle": "SmartCollector",
|
||||||
|
"idApp": "smartcollector",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
83
helper/clientApi.js
Normal file
83
helper/clientApi.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import forge from 'node-forge'
|
||||||
|
|
||||||
|
const constants = {
|
||||||
|
urlWebApi: process.env.urlWebApi,
|
||||||
|
urlUploadApi: process.env.urlUploadApi,
|
||||||
|
publicKey: process.env.publicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
const uris = {
|
||||||
|
procedure: '',
|
||||||
|
upload: '/upload'
|
||||||
|
}
|
||||||
|
|
||||||
|
const encryptRsa = function (obj) {
|
||||||
|
const encoded = forge.util.encodeUtf8(obj)
|
||||||
|
const publicKey = forge.pki.publicKeyFromPem(constants.publicKey)
|
||||||
|
const encrypted = publicKey.encrypt(encoded, 'RSA-OAEP', {
|
||||||
|
md: forge.md.sha256.create(),
|
||||||
|
mgf1: forge.mgf1.create()
|
||||||
|
})
|
||||||
|
const base64 = forge.util.encode64(encrypted)
|
||||||
|
return base64
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const callWs = async (uri, json) => {
|
||||||
|
// Send the form data to our API and get a response.
|
||||||
|
const response = await fetch(uri, {
|
||||||
|
// Body of the request is the JSON data we created above.
|
||||||
|
body: JSON.stringify(json),
|
||||||
|
// Tell the server we're sending JSON.
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
// The method is POST because we are sending data.
|
||||||
|
method: 'POST',
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get the response data from server as JSON.
|
||||||
|
// If server returns the name submitted, that means the form works.
|
||||||
|
const result = await response.json()
|
||||||
|
return result.data // return data rows
|
||||||
|
}
|
||||||
|
|
||||||
|
const 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
hooks/useGlobalContainer.js
Normal file
9
hooks/useGlobalContainer.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { useContext } from "react"
|
||||||
|
import { LayoutContext } from '../layout/ResponsiveContainer'
|
||||||
|
|
||||||
|
const useGlobalContainer = () => {
|
||||||
|
const container = useContext(LayoutContext)
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useGlobalContainer
|
15
hooks/useHasMounted.js
Normal file
15
hooks/useHasMounted.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
|
||||||
|
const useHasMounted = () => {
|
||||||
|
const [hasMounted, setHasMounted] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setHasMounted(true)
|
||||||
|
// console.log('page is mounted')
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return hasMounted
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useHasMounted
|
9
hooks/useI18n.js
Normal file
9
hooks/useI18n.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { useContext } from 'react'
|
||||||
|
import { I18nContext } from '../plugins/i18nContext'
|
||||||
|
|
||||||
|
const useI18n = () => {
|
||||||
|
const i18n = useContext(I18nContext)
|
||||||
|
return i18n
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useI18n
|
9
hooks/useLoading.js
Normal file
9
hooks/useLoading.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { useContext } from "react"
|
||||||
|
import { LoadingContext } from "../plugins/LoadingContext"
|
||||||
|
|
||||||
|
const useLoading = () => {
|
||||||
|
const loading = useContext(LoadingContext)
|
||||||
|
return loading
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useLoading
|
192
layout/ResponsiveContainer.jsx
Normal file
192
layout/ResponsiveContainer.jsx
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import { useEffect, useState, createContext } from 'react'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import { execute } from "../helper/clientApi"
|
||||||
|
import environment from '../utils/environment'
|
||||||
|
import presets from '../utils/globalPresets'
|
||||||
|
import dynamic from 'next/dynamic'
|
||||||
|
import useLoading from '../hooks/useLoading'
|
||||||
|
import useHasMounted from '../hooks/useHasMounted'
|
||||||
|
import useI18n from '../hooks/useI18n'
|
||||||
|
|
||||||
|
export const LayoutContext = createContext()
|
||||||
|
|
||||||
|
const Footer = dynamic(() => { return import("vComponents/dist/Footer") }, { ssr: false })
|
||||||
|
const Navbar = dynamic(() => { return import("vComponents/dist/Navbar") }, { ssr: false })
|
||||||
|
const Sidebar = dynamic(() => { return import("vComponents/dist/Sidebar") }, { ssr: false })
|
||||||
|
|
||||||
|
const ResponsiveContainer = ({ children }) => {
|
||||||
|
const router = useRouter()
|
||||||
|
const loading = useLoading()
|
||||||
|
const i18n = useI18n()
|
||||||
|
const hasMounted = useHasMounted()
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(true)
|
||||||
|
const [menu, setMenu] = useState([])
|
||||||
|
const [title, setTitle] = useState('')
|
||||||
|
const [userObj, setUserObj] = useState()
|
||||||
|
const [token, setToken] = useState('')
|
||||||
|
|
||||||
|
const doLogout = async () => {
|
||||||
|
const redirectPath = await environment.logout()
|
||||||
|
setUserObj(null)
|
||||||
|
router.push(redirectPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBackKeyDown = () =>{
|
||||||
|
if (router.asPath === '/') {
|
||||||
|
// cuando esta en la pagina principal cierra la app
|
||||||
|
if (navigator.app) {
|
||||||
|
navigator.app.exitApp()
|
||||||
|
} else if (navigator.device) {
|
||||||
|
navigator.device.exitApp()
|
||||||
|
} else {
|
||||||
|
window.close()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.history.back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const validaPermisosRuta = async (token) => {
|
||||||
|
if (router.pathname.includes('/admin')) {
|
||||||
|
loading.start()
|
||||||
|
const tienePermiso = await environment.validaPermisos(token, 'S', 'N', 'N', 'N')
|
||||||
|
loading.stop()
|
||||||
|
if (tienePermiso === false) {
|
||||||
|
router.push(presets.locations.welcome)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (router.pathname.includes('/mantenimientos')) {
|
||||||
|
loading.start()
|
||||||
|
const tienePermiso = await environment.validaPermisos(token, 'N', 'S', 'N', 'N')
|
||||||
|
loading.stop()
|
||||||
|
if (tienePermiso === false) {
|
||||||
|
router.push(presets.locations.welcome)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getMenu = async (token) => {
|
||||||
|
loading.start()
|
||||||
|
setMenu([])
|
||||||
|
if (token && token !== null) {
|
||||||
|
console.log('Responsive Container - getMenu - token', token)
|
||||||
|
let options = await execute('SPR_MENU_S', [token, 'SC', null])
|
||||||
|
setMenu(options)
|
||||||
|
console.log('Responsive Container - getMenu - options', options)
|
||||||
|
if (environment.validaResultadoDB(options) === false) {
|
||||||
|
options = await execute('SPR_MENU_S', [token, 'SC', null])
|
||||||
|
setMenu(options)
|
||||||
|
console.log('Responsive Container - getMenu - reoptions', options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loading.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
const getEnv = async () => {
|
||||||
|
try {
|
||||||
|
const env = await environment.getEnvUser()
|
||||||
|
if (!env || !env.token) {
|
||||||
|
toast.error(i18n.t('common.inactiveSession'), presets.toaster)
|
||||||
|
router.push(presets.locations.login)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setUserObj(env.user)
|
||||||
|
setToken(env.token)
|
||||||
|
validaPermisosRuta(env.token)
|
||||||
|
getMenu(token)
|
||||||
|
} catch (error) {
|
||||||
|
router.push(presets.locations.login)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const containerWrapper = {
|
||||||
|
userObj: userObj,
|
||||||
|
setUserObj: setUserObj,
|
||||||
|
token: token,
|
||||||
|
setToken: setToken
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('Responsive Container - getMenu - useEffect token', token)
|
||||||
|
getMenu(token)
|
||||||
|
}, [token])
|
||||||
|
|
||||||
|
|
||||||
|
// when page is mounted
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasMounted) {
|
||||||
|
getEnv()
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [hasMounted])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (process.browser && window.cordova) {
|
||||||
|
document.addEventListener("backbutton", onBackKeyDown, false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LayoutContext.Provider value={containerWrapper}>
|
||||||
|
<div className="flex h-screen overflow-hidden">
|
||||||
|
|
||||||
|
{/* Sidebar */}
|
||||||
|
{
|
||||||
|
userObj && userObj.nombre_usuario &&
|
||||||
|
|
||||||
|
<Sidebar
|
||||||
|
sidebarOpen={sidebarOpen}
|
||||||
|
setSidebarOpen={setSidebarOpen}
|
||||||
|
menu={menu}
|
||||||
|
sidebarStyles={'via-bg-sidebar'}
|
||||||
|
optionStyles={'text-base font-normal via-options-sidebar'}
|
||||||
|
suboptionStyles={'text-sm font-normal via-suboptions-sidebar'}
|
||||||
|
onClickLogout={() => doLogout()}
|
||||||
|
setTitle={setTitle}
|
||||||
|
userObj={userObj}
|
||||||
|
environment={environment}
|
||||||
|
presets={presets}
|
||||||
|
router={router}
|
||||||
|
i18n={i18n}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
|
{/* Content area */}
|
||||||
|
<div className={`${sidebarOpen ? 'relative' : 'absolute'} flex flex-col flex-1 overflow-y-auto overflow-x-hidden w-full`}>
|
||||||
|
|
||||||
|
{/* Site header */}
|
||||||
|
{userObj && userObj.nombre_usuario &&
|
||||||
|
|
||||||
|
<Navbar
|
||||||
|
sidebarOpen={sidebarOpen}
|
||||||
|
setSidebarOpen={setSidebarOpen}
|
||||||
|
navbarStyles="border-b via-navbar"
|
||||||
|
menuButtonStyles="via-menu-btn-navbar"
|
||||||
|
userMenuButtonStyles="via-usermenu-btn-navbar"
|
||||||
|
userOptionStyles="via-useroptions-navbar"
|
||||||
|
userOptionSelectedStyles="via-useroptions-selected-navbar"
|
||||||
|
onClickLogout={() => doLogout()}
|
||||||
|
onClickProfile={() => router.push(`${presets.locations.profile}`)}
|
||||||
|
title={title}
|
||||||
|
userObj={userObj}
|
||||||
|
router={router}
|
||||||
|
presets={presets}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div className={userObj && userObj.nombre_usuario ? "px-4 sm:px-6 lg:px-8 py-2 w-full max-w-9xl mx-auto bg-gray-100 mb-10" : ''}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<Footer />
|
||||||
|
</LayoutContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ResponsiveContainer
|
35
models/CreditCardModel.js
Normal file
35
models/CreditCardModel.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
const CreditCardModel = () => {
|
||||||
|
return {
|
||||||
|
name: "",
|
||||||
|
card_number: "",
|
||||||
|
expiration_date: "",
|
||||||
|
security_code: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreditCardScreen = () => {
|
||||||
|
return {
|
||||||
|
main_spr: "SPR_GRUPOS_S",
|
||||||
|
parameters: [{"name":"token","value":null}],
|
||||||
|
insert_allowed: "N",
|
||||||
|
insert_spr: null,
|
||||||
|
parametersInsert: [],
|
||||||
|
update_allowed: "N",
|
||||||
|
update_spr: null,
|
||||||
|
parametersUpdate: [],
|
||||||
|
delete_allowed: "N",
|
||||||
|
delete_spr: null,
|
||||||
|
parametersDelete: [],
|
||||||
|
list_spr: null,
|
||||||
|
list_params_spr: null,
|
||||||
|
i18n_spr: null,
|
||||||
|
use_vista_consulta: "N"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const generalParams = [
|
||||||
|
{"name":"token","value":null}
|
||||||
|
]
|
||||||
|
|
||||||
|
export default CreditCardModel
|
||||||
|
export { CreditCardModel, CreditCardScreen }
|
372
models/CreditCardProps.js
Normal file
372
models/CreditCardProps.js
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
const CreditCardProps = () => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: "Name",
|
||||||
|
i18n: "",
|
||||||
|
value: "name",
|
||||||
|
listName: "",
|
||||||
|
listNameParams: "",
|
||||||
|
class: " ",
|
||||||
|
headerClass: "w-36",
|
||||||
|
disableOnEdit: false,
|
||||||
|
disableOnNew: false,
|
||||||
|
isKey: null,
|
||||||
|
defaultValue: "",
|
||||||
|
showInForm: true,
|
||||||
|
showInTable: false,
|
||||||
|
showAsBadge: false,
|
||||||
|
icon: "",
|
||||||
|
iconClass: "via-detalle-datatable",
|
||||||
|
badgeClass: "via-badge-datatable",
|
||||||
|
toLocation: "",
|
||||||
|
fromLocation: "",
|
||||||
|
fromTitle: "",
|
||||||
|
isFilter: false,
|
||||||
|
type: "string",
|
||||||
|
label: "Name",
|
||||||
|
filterOrder: 0,
|
||||||
|
filterType: "list",
|
||||||
|
filterSort: "ascending",
|
||||||
|
isSearchable: true,
|
||||||
|
isClearable: true,
|
||||||
|
isGroup: false,
|
||||||
|
isMulti: false,
|
||||||
|
useSpeechToText: false,
|
||||||
|
id: "field_name",
|
||||||
|
fieldId: 1,
|
||||||
|
fieldOrder: 1,
|
||||||
|
docType: "img",
|
||||||
|
formClass: "col-span-2",
|
||||||
|
countFormatDef: 1,
|
||||||
|
countInputProps: 1,
|
||||||
|
countChangeDef: 0,
|
||||||
|
countPristineMsg: 1,
|
||||||
|
formatDefinition: {"action":"format","value":"uppercase"},
|
||||||
|
onChangeDefinition: {},
|
||||||
|
pristineMessages: {"required":"common.ruleRequired","pattern":null,"minlength":null,"maxlength":null},
|
||||||
|
inputProps: {"type":"text","autoComplete":"off"},
|
||||||
|
fixedListParams: [],
|
||||||
|
mappingRules: [],
|
||||||
|
fileNameParts: [],
|
||||||
|
fileExtensionParts: [],
|
||||||
|
valor: "name",
|
||||||
|
texto: "Name",
|
||||||
|
classItem: null,
|
||||||
|
substituteVal: null,
|
||||||
|
format: null,
|
||||||
|
chosen: false,
|
||||||
|
selected: false,
|
||||||
|
onChange: null
|
||||||
|
}, {
|
||||||
|
text: "Card Number",
|
||||||
|
i18n: "",
|
||||||
|
value: "card_number",
|
||||||
|
listName: "",
|
||||||
|
listNameParams: "",
|
||||||
|
class: " text-right ",
|
||||||
|
headerClass: "w-36",
|
||||||
|
disableOnEdit: false,
|
||||||
|
disableOnNew: false,
|
||||||
|
isKey: null,
|
||||||
|
defaultValue: "",
|
||||||
|
showInForm: true,
|
||||||
|
showInTable: false,
|
||||||
|
showAsBadge: false,
|
||||||
|
icon: "",
|
||||||
|
iconClass: "via-detalle-datatable",
|
||||||
|
badgeClass: "via-badge-datatable",
|
||||||
|
toLocation: "",
|
||||||
|
fromLocation: "",
|
||||||
|
fromTitle: "",
|
||||||
|
isFilter: false,
|
||||||
|
type: "number",
|
||||||
|
label: "Card Number",
|
||||||
|
filterOrder: 0,
|
||||||
|
filterType: "list",
|
||||||
|
filterSort: "ascending",
|
||||||
|
isSearchable: true,
|
||||||
|
isClearable: true,
|
||||||
|
isGroup: false,
|
||||||
|
isMulti: false,
|
||||||
|
useSpeechToText: false,
|
||||||
|
id: "field_card_number",
|
||||||
|
fieldId: 2,
|
||||||
|
fieldOrder: 2,
|
||||||
|
docType: "img",
|
||||||
|
formClass: "col-span-2",
|
||||||
|
countFormatDef: 0,
|
||||||
|
countInputProps: 1,
|
||||||
|
countChangeDef: 0,
|
||||||
|
countPristineMsg: 1,
|
||||||
|
formatDefinition: {},
|
||||||
|
onChangeDefinition: {},
|
||||||
|
pristineMessages: {"required":"common.ruleRequired","pattern":null,"minlength":null,"maxlength":null},
|
||||||
|
inputProps: {"type":"number","autoComplete":"off", required: true},
|
||||||
|
fixedListParams: [],
|
||||||
|
mappingRules: [],
|
||||||
|
fileNameParts: [],
|
||||||
|
fileExtensionParts: [],
|
||||||
|
valor: "card_number",
|
||||||
|
texto: "Card Number",
|
||||||
|
classItem: null,
|
||||||
|
substituteVal: null,
|
||||||
|
format: null,
|
||||||
|
chosen: false,
|
||||||
|
selected: false,
|
||||||
|
onChange: null,
|
||||||
|
imask: {
|
||||||
|
mask: [
|
||||||
|
{
|
||||||
|
mask: '0000 000000 00000',
|
||||||
|
regex: '^3[47]\\d{0,13}',
|
||||||
|
cardtype: 'american express'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mask: '0000 0000 0000 0000',
|
||||||
|
regex: '^(?:6011|65\\d{0,2}|64[4-9]\\d?)\\d{0,12}',
|
||||||
|
cardtype: 'discover'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mask: '0000 000000 0000',
|
||||||
|
regex: '^3(?:0([0-5]|9)|[689]\\d?)\\d{0,11}',
|
||||||
|
cardtype: 'diners'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mask: '0000 0000 0000 0000',
|
||||||
|
regex: '^(5[1-5]\\d{0,2}|22[2-9]\\d{0,1}|2[3-7]\\d{0,2})\\d{0,12}',
|
||||||
|
cardtype: 'mastercard'
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// mask: '0000-0000-0000-0000',
|
||||||
|
// regex: '^(5019|4175|4571)\\d{0,12}',
|
||||||
|
// cardtype: 'dankort'
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// mask: '0000-0000-0000-0000',
|
||||||
|
// regex: '^63[7-9]\\d{0,13}',
|
||||||
|
// cardtype: 'instapayment'
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
mask: '0000 000000 00000',
|
||||||
|
regex: '^(?:2131|1800)\\d{0,11}',
|
||||||
|
cardtype: 'jcb15'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mask: '0000 0000 0000 0000',
|
||||||
|
regex: '^(?:35\\d{0,2})\\d{0,12}',
|
||||||
|
cardtype: 'jcb'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mask: '0000 0000 0000 0000',
|
||||||
|
regex: '^(?:5[0678]\\d{0,2}|6304|67\\d{0,2})\\d{0,12}',
|
||||||
|
cardtype: 'maestro'
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// mask: '0000-0000-0000-0000',
|
||||||
|
// regex: '^220[0-4]\\d{0,12}',
|
||||||
|
// cardtype: 'mir'
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
mask: '0000 0000 0000 0000',
|
||||||
|
regex: '^4\\d{0,15}',
|
||||||
|
cardtype: 'visa'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mask: '0000 0000 0000 0000',
|
||||||
|
regex: '^62\\d{0,14}',
|
||||||
|
cardtype: 'unionpay'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mask: '0000 0000 0000 0000',
|
||||||
|
cardtype: 'Unknown'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
dispatch: function (appended, dynamicMasked) {
|
||||||
|
var number = (dynamicMasked.value + appended).replace(/\D/g, '');
|
||||||
|
for (var i = 0; i < dynamicMasked.compiledMasks.length; i++) {
|
||||||
|
let re = new RegExp(dynamicMasked.compiledMasks[i].regex);
|
||||||
|
if (number.match(re) != null) {
|
||||||
|
return dynamicMasked.compiledMasks[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
text: "Expiration (mm/yy)",
|
||||||
|
i18n: "",
|
||||||
|
value: "expiration_date",
|
||||||
|
listName: "",
|
||||||
|
listNameParams: "",
|
||||||
|
class: " text-right ",
|
||||||
|
headerClass: "w-36",
|
||||||
|
disableOnEdit: false,
|
||||||
|
disableOnNew: false,
|
||||||
|
isKey: null,
|
||||||
|
defaultValue: "",
|
||||||
|
showInForm: true,
|
||||||
|
showInTable: false,
|
||||||
|
showAsBadge: false,
|
||||||
|
icon: "",
|
||||||
|
iconClass: "via-detalle-datatable",
|
||||||
|
badgeClass: "via-badge-datatable",
|
||||||
|
toLocation: "",
|
||||||
|
fromLocation: "",
|
||||||
|
fromTitle: "",
|
||||||
|
isFilter: false,
|
||||||
|
type: "number",
|
||||||
|
label: "Expiration (mm/yy)",
|
||||||
|
filterOrder: 0,
|
||||||
|
filterType: "list",
|
||||||
|
filterSort: "ascending",
|
||||||
|
isSearchable: true,
|
||||||
|
isClearable: true,
|
||||||
|
isGroup: false,
|
||||||
|
isMulti: false,
|
||||||
|
useSpeechToText: false,
|
||||||
|
id: "field_expiration_date",
|
||||||
|
fieldId: 3,
|
||||||
|
fieldOrder: 3,
|
||||||
|
docType: "img",
|
||||||
|
formClass: null,
|
||||||
|
countFormatDef: 0,
|
||||||
|
countInputProps: 1,
|
||||||
|
countChangeDef: 0,
|
||||||
|
countPristineMsg: 1,
|
||||||
|
formatDefinition: {},
|
||||||
|
onChangeDefinition: {},
|
||||||
|
pristineMessages: {"required":"common.ruleRequired","pattern":null,"minlength":null,"maxlength":null},
|
||||||
|
inputProps: {"type":"number","autoComplete":"off", required: true},
|
||||||
|
fixedListParams: [],
|
||||||
|
mappingRules: [],
|
||||||
|
fileNameParts: [],
|
||||||
|
fileExtensionParts: [],
|
||||||
|
valor: "expiration_date",
|
||||||
|
texto: "Expiration (mm/yy)",
|
||||||
|
classItem: null,
|
||||||
|
substituteVal: null,
|
||||||
|
format: null,
|
||||||
|
chosen: false,
|
||||||
|
selected: false,
|
||||||
|
onChange: null,
|
||||||
|
imask: {
|
||||||
|
mask: [
|
||||||
|
{
|
||||||
|
mask: 'MY{/}YY',
|
||||||
|
startsWith: '0',
|
||||||
|
definitions: {
|
||||||
|
'Y': /[1-9]/,
|
||||||
|
'M': /[0-1]/,
|
||||||
|
'N': /[0-2]/
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mask: 'MN{/}YY',
|
||||||
|
startsWith: '1',
|
||||||
|
definitions: {
|
||||||
|
'Y': /[1-9]/,
|
||||||
|
'M': /[0-1]/,
|
||||||
|
'N': /[0-2]/
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mask: 'MY{/}YY',
|
||||||
|
startsWith: '',
|
||||||
|
definitions: {
|
||||||
|
'Y': /[1-9]/,
|
||||||
|
'M': /[0-1]/,
|
||||||
|
'N': /[0-2]/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
dispatch: (appended, dynamicMasked) => {
|
||||||
|
const number = (dynamicMasked.value + appended).replace(/\D/g,'');
|
||||||
|
return dynamicMasked.compiledMasks.find(m => number.indexOf(m.startsWith) === 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// IMask(element, {
|
||||||
|
// mask: 'Ple\\ase fill ye\\ar 19YY, month MM \\and v\\alue VL',
|
||||||
|
// lazy: false, // make placeholder always visible
|
||||||
|
|
||||||
|
// blocks: {
|
||||||
|
// YY: {
|
||||||
|
// mask: '00',
|
||||||
|
// },
|
||||||
|
|
||||||
|
// MM: {
|
||||||
|
// mask: IMask.MaskedRange,
|
||||||
|
// from: 1,
|
||||||
|
// to: 12
|
||||||
|
// },
|
||||||
|
|
||||||
|
// VL: {
|
||||||
|
// mask: IMask.MaskedEnum,
|
||||||
|
// enum: ['TV', 'HD', 'VR']
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}, {
|
||||||
|
text: "Security Code",
|
||||||
|
i18n: "",
|
||||||
|
value: "security_code",
|
||||||
|
listName: "",
|
||||||
|
listNameParams: "",
|
||||||
|
class: " text-right ",
|
||||||
|
headerClass: "w-36",
|
||||||
|
disableOnEdit: false,
|
||||||
|
disableOnNew: false,
|
||||||
|
isKey: null,
|
||||||
|
defaultValue: "",
|
||||||
|
showInForm: true,
|
||||||
|
showInTable: false,
|
||||||
|
showAsBadge: false,
|
||||||
|
icon: "",
|
||||||
|
iconClass: "via-detalle-datatable",
|
||||||
|
badgeClass: "via-badge-datatable",
|
||||||
|
toLocation: "",
|
||||||
|
fromLocation: "",
|
||||||
|
fromTitle: "",
|
||||||
|
isFilter: false,
|
||||||
|
type: "number",
|
||||||
|
label: "Security Code",
|
||||||
|
filterOrder: 0,
|
||||||
|
filterType: "list",
|
||||||
|
filterSort: "ascending",
|
||||||
|
isSearchable: true,
|
||||||
|
isClearable: true,
|
||||||
|
isGroup: false,
|
||||||
|
isMulti: false,
|
||||||
|
useSpeechToText: false,
|
||||||
|
id: "field_security_code",
|
||||||
|
fieldId: 4,
|
||||||
|
fieldOrder: 4,
|
||||||
|
docType: "img",
|
||||||
|
formClass: null,
|
||||||
|
countFormatDef: 0,
|
||||||
|
countInputProps: 1,
|
||||||
|
countChangeDef: 0,
|
||||||
|
countPristineMsg: 1,
|
||||||
|
formatDefinition: {},
|
||||||
|
onChangeDefinition: {},
|
||||||
|
pristineMessages: {"required":"common.ruleRequired","pattern":null,"minlength":null,"maxlength":null},
|
||||||
|
inputProps: {"type":"number","autoComplete":"off", required: true},
|
||||||
|
fixedListParams: [],
|
||||||
|
mappingRules: [],
|
||||||
|
fileNameParts: [],
|
||||||
|
fileExtensionParts: [],
|
||||||
|
valor: "security_code",
|
||||||
|
texto: "Security Code",
|
||||||
|
classItem: null,
|
||||||
|
substituteVal: null,
|
||||||
|
format: null,
|
||||||
|
chosen: false,
|
||||||
|
selected: false,
|
||||||
|
onChange: null,
|
||||||
|
imask: {
|
||||||
|
mask: '0000',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CreditCardProps
|
||||||
|
|
45
next.config.js
Normal file
45
next.config.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
const config = require('config')
|
||||||
|
const constants = config.get('constants')
|
||||||
|
|
||||||
|
/** @type {import('next').NextConfig} */
|
||||||
|
|
||||||
|
const rewrites = async () => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/orbisapi/:path*',
|
||||||
|
destination: 'http://localhost:9000/:path*' // Proxy to Backend
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const redirects = async () => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/mantenimientos',
|
||||||
|
destination: constants.publicPath,
|
||||||
|
basePath: true,
|
||||||
|
permanent: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextConfig = {
|
||||||
|
env: {
|
||||||
|
...constants
|
||||||
|
},
|
||||||
|
images: {
|
||||||
|
domains: ['www.via-asesores.com', 'gt.via-asesores.com'],
|
||||||
|
unoptimized: true, // solo para generar sitio estatico
|
||||||
|
},
|
||||||
|
assetPrefix: constants.publicPath,
|
||||||
|
basePath: constants.publicPath,
|
||||||
|
// redirects,
|
||||||
|
compiler: {
|
||||||
|
styledComponents: true,
|
||||||
|
},
|
||||||
|
rewrites,
|
||||||
|
reactStrictMode: true,
|
||||||
|
swcMinify: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = nextConfig
|
66
package.json
Normal file
66
package.json
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"name": "credit-card-example",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"description": "Ejercicio formulario Tarjeta de crédito, uso de imask",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.via-asesores.com/dehernandezm/CreditCardExample.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"operations",
|
||||||
|
"orbis",
|
||||||
|
"smart",
|
||||||
|
"route",
|
||||||
|
"sales",
|
||||||
|
"delivery"
|
||||||
|
],
|
||||||
|
"author": "guatemala@via-asesores.com",
|
||||||
|
"license": "ISC",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev",
|
||||||
|
"build": "next build",
|
||||||
|
"generate": "next build && next export",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "next lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@headlessui/react": "^1.7.3",
|
||||||
|
"@heroicons/react": "^2.0.12",
|
||||||
|
"@react-pdf-viewer/core": "^3.8.0",
|
||||||
|
"@tailwindcss/line-clamp": "^0.4.2",
|
||||||
|
"alasql": "^2.5.1",
|
||||||
|
"base64-to-uint8array": "^1.0.0",
|
||||||
|
"config": "^3.3.8",
|
||||||
|
"js-cookie": "^3.0.1",
|
||||||
|
"js-md5": "^0.7.3",
|
||||||
|
"jspdf": "^2.5.1",
|
||||||
|
"jspdf-autotable": "^3.5.25",
|
||||||
|
"nanoid": "^4.0.0",
|
||||||
|
"next": "13.0.0",
|
||||||
|
"pdfjs-dist": "2.8.335",
|
||||||
|
"pristinejs": "^0.1.9",
|
||||||
|
"react": "18.2.0",
|
||||||
|
"react-card-flip": "^1.2.0",
|
||||||
|
"react-dom": "18.2.0",
|
||||||
|
"react-dropzone-component": "^3.2.0",
|
||||||
|
"react-multi-email": "^0.5.3",
|
||||||
|
"react-pivottable": "^0.11.0",
|
||||||
|
"react-select": "^5.5.7",
|
||||||
|
"react-toastify": "^9.0.8",
|
||||||
|
"rosetta": "^1.1.0",
|
||||||
|
"underscore": "^1.13.6",
|
||||||
|
"v-functions": "git+https://2bdcc0300e0ed5ac01f9dcd51368f7ac74fdb85a@git.via-asesores.com/libraries/v-functions.git",
|
||||||
|
"vComponents": "git+https://2bdcc0300e0ed5ac01f9dcd51368f7ac74fdb85a@git.via-asesores.com/libraries/v-components.git",
|
||||||
|
"viewerjs": "^1.11.1",
|
||||||
|
"xlsx": "^0.18.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/forms": "^0.5.3",
|
||||||
|
"autoprefixer": "^10.4.12",
|
||||||
|
"eslint": "8.26.0",
|
||||||
|
"eslint-config-next": "13.0.0",
|
||||||
|
"postcss": "^8.4.18",
|
||||||
|
"tailwindcss": "^3.2.1"
|
||||||
|
}
|
||||||
|
}
|
24
pages/_app.jsx
Normal file
24
pages/_app.jsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import '../styles/globals.css'
|
||||||
|
import LoadingProvider from '../plugins/LoadingContext'
|
||||||
|
import I18nProvider from '../plugins/i18nContext'
|
||||||
|
import { ToastContainer } from 'react-toastify'
|
||||||
|
import ResponsiveContainer from '../layout/ResponsiveContainer'
|
||||||
|
import 'vComponents/styles/generated/output.css'
|
||||||
|
import 'vComponents/styles/generated/bgColors.min.css'
|
||||||
|
import 'vComponents/styles/generated/grid.min.css'
|
||||||
|
|
||||||
|
function MyApp({ Component, pageProps }) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<I18nProvider locale={'es'}>
|
||||||
|
<LoadingProvider>
|
||||||
|
<ToastContainer />
|
||||||
|
<ResponsiveContainer>
|
||||||
|
<Component {...pageProps} />
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</LoadingProvider>
|
||||||
|
</I18nProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MyApp
|
107
pages/index.jsx
Normal file
107
pages/index.jsx
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import React, { useEffect, useState, useRef } from 'react'
|
||||||
|
import { CreditCardModel, CreditCardScreen } from './../models/CreditCardModel'
|
||||||
|
import CreditCardProps from './../models/CreditCardProps'
|
||||||
|
import environment from './../utils/environment'
|
||||||
|
import DataForm from 'vComponents/dist/DataForm'
|
||||||
|
import { useIMask } from 'react-imask'
|
||||||
|
|
||||||
|
import ReactCardFlip from 'react-card-flip'
|
||||||
|
|
||||||
|
const LoginPage = () => {
|
||||||
|
const maskFieldOptions = {
|
||||||
|
mask: '+{7}(000)000-00-00'
|
||||||
|
}
|
||||||
|
const modelInitial = CreditCardModel()
|
||||||
|
const [model, setModel] = useState(modelInitial)
|
||||||
|
const [headers, setHeaders] = useState(CreditCardProps())
|
||||||
|
const [isReadyHeaders, setIsReadyHeaders] = useState(false)
|
||||||
|
const [testInput, setTestInput] = useState(null)
|
||||||
|
const [isFlipped, setIsFlipped] = useState(false)
|
||||||
|
|
||||||
|
const [opts, setOpts] = useState(maskFieldOptions)
|
||||||
|
const {
|
||||||
|
ref,
|
||||||
|
maskRef,
|
||||||
|
value,
|
||||||
|
setValue,
|
||||||
|
unmaskedValue,
|
||||||
|
setUnmaskedValue,
|
||||||
|
typedValue,
|
||||||
|
setTypedValue,
|
||||||
|
} = useIMask(opts, /* { onAccept, onComplete } */);
|
||||||
|
// Declare a new state variable, which we'll call 'count'
|
||||||
|
const completeHeaders = () => {
|
||||||
|
let _newHeaders = []
|
||||||
|
_newHeaders = environment.buildFunctiontsHeaders(headers)
|
||||||
|
setHeaders(_newHeaders)
|
||||||
|
setIsReadyHeaders(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const formComponent = useRef(null)
|
||||||
|
|
||||||
|
// when page is mounted
|
||||||
|
useEffect(() => {
|
||||||
|
completeHeaders()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className=' flex w-screen h-screen items-center justify-center'>
|
||||||
|
<div className='w-[34] bg-emerald-50 flex flex-col p-8 space-y-4'>
|
||||||
|
{/* <span className=' font-semibold '>-{value}-</span>
|
||||||
|
<input
|
||||||
|
id='testInput'
|
||||||
|
ref={ref}
|
||||||
|
value={value}
|
||||||
|
className='block py-0.5 px-1.5 w-full text-sm text-gray-900 bg-gray-50 rounded-md border-l-gray-50 border-l-2 border border-gray-300 appearance-none focus:border-blue-500 focus:outline-none focus:shadow-outline focus:ring-1 focus:ring-gray-100 dark:bg-gray-700 dark:placeholder-gray-400 dark:text-white'
|
||||||
|
placeholder=' '
|
||||||
|
/> */}
|
||||||
|
<DataForm
|
||||||
|
ref={formComponent}
|
||||||
|
headers={headers}
|
||||||
|
model={model}
|
||||||
|
name='testCreditCard'
|
||||||
|
className='grid cols-2 gap-4'
|
||||||
|
onSave={(newMod) => { console.log('new model result ', newMod) }}
|
||||||
|
onCancel={() => { formComponent.current.reset(); setModel({}) }}
|
||||||
|
onAnyChange={() => { setModel(formComponent.current.getValues()) }}
|
||||||
|
/>
|
||||||
|
<ReactCardFlip isFlipped={isFlipped}>
|
||||||
|
<div className=' bg-gradient-to-r from-sky-500 to-indigo-500 w-full h-60 rounded-lg shadow-xl grid cols-12 grid-rows-3 auto-cols-fr' onClick={() => { setIsFlipped(!isFlipped) }}>
|
||||||
|
<div className=' col-start-2 col-span-2 row-start-1 flex h-full justify-center items-center p-3' >
|
||||||
|
<div className='w-full h-full bg-amber-400 rounded-md' />
|
||||||
|
</div>
|
||||||
|
<div className=' col-start-9 col-span-2 row-start-1 flex h-full w-20 rounded-full justify-center items-center p-3' >
|
||||||
|
<div className='w-full h-full bg-red-600 rounded-full' />
|
||||||
|
</div>
|
||||||
|
<div className=' col-start-10 col-span-2 row-start-1 flex h-full w-20 rounded-full justify-center items-center p-3' >
|
||||||
|
<div className='w-full h-full bg-yellow-600 rounded-full' />
|
||||||
|
</div>
|
||||||
|
<div className=' col-start-1 col-span-12 row-start-2 px-4 text-white flex flex-col '>
|
||||||
|
<span className=' text-sm '>Card Number</span>
|
||||||
|
<span className=' text-xl tabular-nums tracking-widest'>{model.card_number}</span>
|
||||||
|
</div>
|
||||||
|
<div className='w-full col-start-1 col-span-8 row-start-3 px-4 text-white flex flex-col '>
|
||||||
|
<span className=' text-sm '>Name</span>
|
||||||
|
<span className=' text-xl '>{model.name}</span>
|
||||||
|
</div>
|
||||||
|
<div className='w-full col-start-9 col-span-4 row-start-3 px-4 text-white flex flex-col '>
|
||||||
|
<span className=' text-sm '>Expiration Date</span>
|
||||||
|
<span className=' text-xl '>{model.expiration_date}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className=' bg-gradient-to-r from-sky-500 to-indigo-500 w-full h-60 rounded-lg shadow-xl grid cols-12 grid-rows-6' onClick={() => { setIsFlipped(!isFlipped) }}>
|
||||||
|
<div className='w-full col-start-1 col-span-12 bg-black row-start-2' />
|
||||||
|
<div className='w-full col-start-13 col-span-12 bg-black row-start-2' />
|
||||||
|
<div className='w-full col-start-2 col-span-12 bg-gray-100 row-start-3' />
|
||||||
|
<div className='w-full col-start-14 col-span-7 bg-gray-100 row-start-3' />
|
||||||
|
<div className='w-full col-start-19 col-span-3 row-start-3 bg-white flex items-center justify-center w-full h-full '>
|
||||||
|
<span>{model.security_code}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ReactCardFlip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LoginPage
|
16
pages/welcome.jsx
Normal file
16
pages/welcome.jsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import presets from "../utils/globalPresets"
|
||||||
|
|
||||||
|
const Welcome = () => {
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
className="pt-5 lg:pt-[120px] pb-10 lg:pb-20 lg:pl-2 bg-gray-100 w-screen h-screen bg-no-repeat bg-right-bottom bg-blend-overlay"
|
||||||
|
style={{ backgroundImage: `url(${presets.images.welcomeFondo})`}}
|
||||||
|
>
|
||||||
|
<div className="container">
|
||||||
|
<div className="flex flex-wrap -mx-4" />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Welcome
|
27
plugins/LoadingContext.jsx
Normal file
27
plugins/LoadingContext.jsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { createContext, useContext, useState } from "react"
|
||||||
|
import dynamic from 'next/dynamic'
|
||||||
|
import presets from "../utils/globalPresets"
|
||||||
|
|
||||||
|
const LoadingSpinner = dynamic(() => { return import("vComponents/dist/Loading") }, { ssr: false })
|
||||||
|
|
||||||
|
export const LoadingContext = createContext()
|
||||||
|
|
||||||
|
const LoadingProvider = ({ children }) => {
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
|
||||||
|
const loadingWrapper = {
|
||||||
|
loading: loading,
|
||||||
|
setLoading: setLoading,
|
||||||
|
start: () => { setLoading(true) },
|
||||||
|
stop: () => { setLoading(false) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LoadingContext.Provider value={ loadingWrapper }>
|
||||||
|
{ children }
|
||||||
|
<LoadingSpinner loading={loading} image={presets.images.imageLoader} background={'backgroundLoader'} color={'colorLoader'} />
|
||||||
|
</LoadingContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LoadingProvider
|
81
plugins/i18nContext.jsx
Normal file
81
plugins/i18nContext.jsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import { createContext, useState, useRef, useEffect } from 'react'
|
||||||
|
import rosetta from 'rosetta'
|
||||||
|
// import rosetta from 'rosetta/debug'
|
||||||
|
import { execute } from '../helper/clientApi'
|
||||||
|
import useHasMounted from '../hooks/useHasMounted'
|
||||||
|
|
||||||
|
const i18n = rosetta()
|
||||||
|
|
||||||
|
export const defaultLanguage = 'es'
|
||||||
|
export const languages = ['es', 'en']
|
||||||
|
export const contentLanguageMap = { es: 'es-GT', en: 'en-US' }
|
||||||
|
|
||||||
|
export const I18nContext = createContext()
|
||||||
|
|
||||||
|
// default language
|
||||||
|
i18n.locale(defaultLanguage)
|
||||||
|
|
||||||
|
const I18nProvider = ({ children, locale, dict }) => {
|
||||||
|
const activeLocaleRef = useRef(locale || defaultLanguage)
|
||||||
|
const [, setTick] = useState(0)
|
||||||
|
const firstRender = useRef(true)
|
||||||
|
const [langIsLoaded, setLangIsLoaded] = useState(false)
|
||||||
|
const hasMounted = useHasMounted()
|
||||||
|
|
||||||
|
const i18nWrapper = {
|
||||||
|
activeLocale: activeLocaleRef.current,
|
||||||
|
langIsLoaded: 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 = {}
|
||||||
|
// si la app ya esta renderizada se cargan los textos
|
||||||
|
if (hasMounted) {
|
||||||
|
const i18nDb = await execute('SPR_I18N_S', [locale])
|
||||||
|
msgs = i18nDb.reduce((obj, elm) => {
|
||||||
|
obj[elm.id_mensaje_padre] = { ...obj[elm.id_mensaje_padre], [elm.id_mensaje]: elm.mensaje }
|
||||||
|
return obj
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
i18nWrapper.locale(locale, msgs)
|
||||||
|
setLangIsLoaded(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// for initial SSR render
|
||||||
|
if (locale && firstRender.current === true) {
|
||||||
|
firstRender.current = false
|
||||||
|
setLanguage()
|
||||||
|
}
|
||||||
|
|
||||||
|
// when locale is updated
|
||||||
|
useEffect(() => {
|
||||||
|
if (locale) {
|
||||||
|
setLanguage()
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [locale])
|
||||||
|
|
||||||
|
// when page is mounted
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasMounted) {
|
||||||
|
setLanguage()
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [hasMounted])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<I18nContext.Provider value={i18nWrapper}>{children}</I18nContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default I18nProvider
|
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
4
public/vercel.svg
Normal file
4
public/vercel.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
7
styles/additional-styles/toastify.css
Normal file
7
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%);
|
||||||
|
}
|
15
styles/component-styles/datatable.css
Normal file
15
styles/component-styles/datatable.css
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
.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 bg-red-500 border-white dark:border-gray-900;
|
||||||
|
}
|
102
styles/component-styles/loading.css
Normal file
102
styles/component-styles/loading.css
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
.backgroungLoader {
|
||||||
|
@apply bg-gradient-to-r from-slate-300 backdrop-blur-md;
|
||||||
|
}
|
||||||
|
.colorLoader {
|
||||||
|
@apply bg-teal-700 shadow-md drop-shadow shadow-white;
|
||||||
|
}
|
||||||
|
.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 {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.spinner div {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation-timing-function: cubic-bezier(0, 1, 1, 0) !important;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(1) {
|
||||||
|
left: 10%;
|
||||||
|
animation: spinner1 0.6s infinite;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(2) {
|
||||||
|
left: 10%;
|
||||||
|
animation: spinner2 0.6s infinite;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(3) {
|
||||||
|
left: 40%;
|
||||||
|
animation: spinner2 0.6s infinite;
|
||||||
|
}
|
||||||
|
.spinner div:nth-child(4) {
|
||||||
|
left: 70%;
|
||||||
|
animation: spinner3 0.6s infinite;
|
||||||
|
}
|
||||||
|
@keyframes spinner1 {
|
||||||
|
0% {
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes spinner3 {
|
||||||
|
0% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes spinner2 {
|
||||||
|
0% {
|
||||||
|
transform: translate(0, 0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translate(184.61%, 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;
|
||||||
|
}
|
||||||
|
}
|
18
styles/component-styles/navbar.css
Normal file
18
styles/component-styles/navbar.css
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
.via-navbar {
|
||||||
|
@apply bg-white border-slate-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-menu-btn-navbar {
|
||||||
|
@apply text-slate-500 hover:text-slate-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-usermenu-btn-navbar {
|
||||||
|
@apply bg-oper-600 text-white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-useroptions-navbar {
|
||||||
|
@apply text-black hover:bg-oper-600 hover:text-white !important;
|
||||||
|
}
|
||||||
|
.via-useroptions-selected-navbar {
|
||||||
|
@apply bg-oper-600 text-white;
|
||||||
|
}
|
11
styles/component-styles/sidebar.css
Normal file
11
styles/component-styles/sidebar.css
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.via-bg-sidebar {
|
||||||
|
@apply bg-teal-700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-options-sidebar {
|
||||||
|
@apply text-gray-50 hover:bg-gray-200 hover:text-gray-600 dark:text-white dark:hover:bg-gray-700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-suboptions-sidebar {
|
||||||
|
@apply text-gray-50 hover:bg-gray-100 hover:text-gray-600 dark:text-white dark:hover:bg-gray-700;
|
||||||
|
}
|
36
styles/globals.css
Normal file
36
styles/globals.css
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=fallback');
|
||||||
|
/* <link rel="stylesheet" href="https://rsms.me/inter/inter.css"> */
|
||||||
|
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
/* width */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
background-color: #F5F5F5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Track */
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
-webkit-box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: #F5F5F5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle */
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: 6px;
|
||||||
|
-webkit-box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.3);
|
||||||
|
background-color: rgba(221, 233, 233, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Additional Styles */
|
||||||
|
@import 'additional-styles/toastify.css';
|
||||||
|
@import 'component-styles/loading.css';
|
||||||
|
@import 'component-styles/sidebar.css';
|
||||||
|
@import 'component-styles/navbar.css';
|
||||||
|
@import 'component-styles/datatable.css';
|
||||||
|
@import 'page-styles/common.css';
|
||||||
|
@import 'page-styles/login.css';
|
||||||
|
@import 'page-styles/eventos_colores.css';
|
38
styles/page-styles/common.css
Normal file
38
styles/page-styles/common.css
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
.via-card {
|
||||||
|
@apply block rounded-md shadow-md w-full border-gray-300 border;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-label {
|
||||||
|
@apply block text-gray-500 font-medium mb-2 pl-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-input {
|
||||||
|
@apply block p-1 w-full z-20 text-sm text-gray-900 rounded-lg border-l-gray-100 border border-gray-300 focus:ring-stone-500 focus:border-stone-500 dark:bg-stone-50 dark:border-stone-600 dark:placeholder-gray-400 dark:text-neutral-900 dark:focus:border-stone-500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-append-input {
|
||||||
|
@apply absolute top-0 right-0 p-1 text-sm font-medium text-white bg-blue-700 rounded-r-lg border border-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-append-input-extra {
|
||||||
|
@apply absolute top-0 right-0 p-1 mr-6 text-sm font-medium text-white bg-blue-700 rounded-r-lg border border-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-button {
|
||||||
|
@apply cursor-pointer inline-flex items-center h-10 px-5 m-2 text-white ease-linear transition-colors duration-150 rounded-lg;
|
||||||
|
}
|
||||||
|
.via-div-actions {
|
||||||
|
@apply flex w-full justify-center flex-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-no {
|
||||||
|
@apply text-red-700 dark:text-red-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-yes {
|
||||||
|
@apply text-green-700 dark:text-green-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-yellow {
|
||||||
|
@apply text-yellow-700 dark:text-yellow-300;
|
||||||
|
}
|
28
styles/page-styles/eventos_colores.css
Normal file
28
styles/page-styles/eventos_colores.css
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
.via-semaforo-verde {
|
||||||
|
@apply border-l-8 border-green-500;
|
||||||
|
}
|
||||||
|
.via-semaforo-amarillo {
|
||||||
|
@apply border-l-8 border-yellow-500;
|
||||||
|
}
|
||||||
|
.via-semaforo-rojo {
|
||||||
|
@apply border-l-8 border-red-500;
|
||||||
|
}
|
||||||
|
.via-bg-verde {
|
||||||
|
@apply bg-green-100 text-green-800 dark:bg-green-700 dark:text-green-300;
|
||||||
|
}
|
||||||
|
.via-bg-amarillo {
|
||||||
|
@apply bg-yellow-100 text-yellow-800 dark:bg-yellow-700 dark:text-yellow-300;
|
||||||
|
}
|
||||||
|
.via-bg-rojo {
|
||||||
|
@apply bg-red-100 text-red-800 dark:bg-red-700 dark:text-red-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.via-verde {
|
||||||
|
@apply text-green-700;
|
||||||
|
}
|
||||||
|
.via-amarillo {
|
||||||
|
@apply text-yellow-700;
|
||||||
|
}
|
||||||
|
.via-rojo {
|
||||||
|
@apply text-red-700;
|
||||||
|
}
|
23
styles/page-styles/login.css
Normal file
23
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-fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
79
tailwind.config.js
Normal file
79
tailwind.config.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
const defaultTheme = require('tailwindcss/defaultTheme')
|
||||||
|
const plugin = require('tailwindcss/plugin')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mode: 'jit',
|
||||||
|
content: [
|
||||||
|
"./pages/**/*.{js,ts,jsx,tsx}",
|
||||||
|
"./components/**/*.{js,ts,jsx,tsx}",
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
fontFamily: {
|
||||||
|
sans: ['Inter', ...defaultTheme.fontFamily.sans],
|
||||||
|
inter: ['Inter', 'sans-serif', ...defaultTheme.fontFamily.sans],
|
||||||
|
},
|
||||||
|
fontSize: {
|
||||||
|
xs: ['0.75rem', { lineHeight: '1.25' }],
|
||||||
|
sm: ['0.875rem', { lineHeight: '1.25' }],
|
||||||
|
base: ['1rem', { lineHeight: '1.25', letterSpacing: '-0.01em' }],
|
||||||
|
lg: ['1.125rem', { lineHeight: '1.25', letterSpacing: '-0.01em' }],
|
||||||
|
xl: ['1.25rem', { lineHeight: '1.25', letterSpacing: '-0.01em' }],
|
||||||
|
'2xl': ['1.5rem', { lineHeight: '1.33', letterSpacing: '-0.01em' }],
|
||||||
|
'3xl': ['1.88rem', { lineHeight: '1.33', letterSpacing: '-0.01em' }],
|
||||||
|
'4xl': ['2.25rem', { lineHeight: '1.25', letterSpacing: '-0.02em' }],
|
||||||
|
'5xl': ['3rem', { lineHeight: '1.25', letterSpacing: '-0.02em' }],
|
||||||
|
'6xl': ['3.75rem', { lineHeight: '1.2', letterSpacing: '-0.02em' }],
|
||||||
|
},
|
||||||
|
screens: {
|
||||||
|
xs: '480px',
|
||||||
|
},
|
||||||
|
borderWidth: {
|
||||||
|
3: '3px',
|
||||||
|
},
|
||||||
|
minWidth: {
|
||||||
|
36: '9rem',
|
||||||
|
44: '11rem',
|
||||||
|
56: '14rem',
|
||||||
|
60: '15rem',
|
||||||
|
72: '18rem',
|
||||||
|
80: '20rem',
|
||||||
|
},
|
||||||
|
maxWidth: {
|
||||||
|
'8xl': '88rem',
|
||||||
|
'9xl': '96rem',
|
||||||
|
},
|
||||||
|
zIndex: {
|
||||||
|
60: '60',
|
||||||
|
},
|
||||||
|
boxShadow: {
|
||||||
|
DEFAULT: '0 1px 3px 0 rgba(0, 0, 0, 0.08), 0 1px 2px 0 rgba(0, 0, 0, 0.02)',
|
||||||
|
md: '0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 2px 4px -1px rgba(0, 0, 0, 0.02)',
|
||||||
|
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.08), 0 4px 6px -2px rgba(0, 0, 0, 0.01)',
|
||||||
|
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.01)',
|
||||||
|
},
|
||||||
|
outline: {
|
||||||
|
blue: '2px solid rgba(0, 112, 244, 0.5)',
|
||||||
|
},
|
||||||
|
colors: {
|
||||||
|
oper: {
|
||||||
|
50: '#f7e8e7',
|
||||||
|
100: '#cc756d',
|
||||||
|
200: '#c45e55',
|
||||||
|
300: '#bb473d',
|
||||||
|
400: '#b33024',
|
||||||
|
500: '#aa190c',
|
||||||
|
600: '#99170b',
|
||||||
|
700: '#88140a',
|
||||||
|
800: '#771208',
|
||||||
|
900: '#660f07'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
require('@tailwindcss/forms'),
|
||||||
|
require('@tailwindcss/line-clamp')
|
||||||
|
]
|
||||||
|
}
|
160
utils/environment.js
Normal file
160
utils/environment.js
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
import functions from 'v-functions'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Objeto con funciones comunes de ambiente
|
||||||
|
*/
|
||||||
|
const environment = {
|
||||||
|
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) {
|
||||||
|
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 = 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 = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default environment
|
81
utils/globalPresets.js
Normal file
81
utils/globalPresets.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
const theme = 'blue'
|
||||||
|
|
||||||
|
const presets = {
|
||||||
|
ENV_URL_API_QUERY: 'https://gt.via-asesores.com/smartdeveloper/orbisapi/api',
|
||||||
|
theme: `${theme}`,
|
||||||
|
appTitle: 'SmartDeveloper',
|
||||||
|
svgIconUrl: 'https://www.via-asesores.com/svgicons//',
|
||||||
|
images: {
|
||||||
|
loginFondo: 'https://www.via-asesores.com/backgrounds/smartcollector/SmartCollector_bg001.jpg',
|
||||||
|
welcomeFondo: 'https://www.via-asesores.com/backgrounds/smartcollector/SmartCollector_bg001.jpg',
|
||||||
|
icon: 'https://www.via-asesores.com/icons/smartcollector/SmartCollector_icon_light.svg',
|
||||||
|
logo: 'https://www.via-asesores.com/logos/smartcollector/SmartCollector_logo_vertical.jpg',
|
||||||
|
imageLoader: 'https://www.via-asesores.com/logos/smartcollector/SmartCollector_loader.jpg',
|
||||||
|
},
|
||||||
|
locations: {
|
||||||
|
login: `/`,
|
||||||
|
welcome: `/welcome`,
|
||||||
|
profile: `/seguridad/profile`,
|
||||||
|
},
|
||||||
|
toaster: {
|
||||||
|
position: 'top-center',
|
||||||
|
autoClose: 5000,
|
||||||
|
hideProgressBar: false,
|
||||||
|
closeOnClick: true,
|
||||||
|
pauseOnHover: true,
|
||||||
|
draggable: true,
|
||||||
|
theme: 'light'
|
||||||
|
},
|
||||||
|
pristine: {
|
||||||
|
// class of the parent element where the error/success class is added
|
||||||
|
classTo: 'form-group',
|
||||||
|
errorClass: 'ring-red-400',
|
||||||
|
successClass: 'has-success',
|
||||||
|
// class of the parent element where error text element is appended
|
||||||
|
errorTextParent: 'form-group',
|
||||||
|
// type of element to create for the error text
|
||||||
|
errorTextTag: 'div',
|
||||||
|
// class of the error text element
|
||||||
|
errorTextClass: 'text-help text-red-500 text-sm py-1'
|
||||||
|
},
|
||||||
|
graphOptions: {
|
||||||
|
interaction: {
|
||||||
|
dragNodes: false,
|
||||||
|
dragView: true,
|
||||||
|
hover: true
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
hierarchical: {
|
||||||
|
enabled: true,
|
||||||
|
levelSeparation: 200,
|
||||||
|
nodeSpacing: 200,
|
||||||
|
treeSpacing: 200,
|
||||||
|
blockShifting: true,
|
||||||
|
edgeMinimization: true,
|
||||||
|
parentCentralization: true,
|
||||||
|
direction: "LR", // UD, DU, LR, RL
|
||||||
|
sortMethod: "hubsize", // hubsize, directed
|
||||||
|
shakeTowards: "leaves" // roots, leaves
|
||||||
|
}
|
||||||
|
},
|
||||||
|
edges: {
|
||||||
|
color: "#000000"
|
||||||
|
},
|
||||||
|
height: "700px",
|
||||||
|
physics: {
|
||||||
|
enabled: false,
|
||||||
|
// maxVelocity: 50,
|
||||||
|
// minVelocity: 0.1,
|
||||||
|
// solver: "barnesHut",
|
||||||
|
stabilization: {
|
||||||
|
enabled: true,
|
||||||
|
iterations: 1000,
|
||||||
|
updateInterval: 100,
|
||||||
|
onlyDynamicEdges: false,
|
||||||
|
fit: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default presets
|
Loading…
Reference in New Issue
Block a user