set translations en and es

This commit is contained in:
Alexandro Uc Santos
2024-05-18 17:30:39 -06:00
parent 1027f38eb0
commit c08567beda
11 changed files with 737 additions and 82 deletions

398
package-lock.json generated
View File

@@ -18,19 +18,21 @@
"sweetalert2": "^11.10.1", "sweetalert2": "^11.10.1",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-chartjs": "^5.3.0", "vue-chartjs": "^5.3.0",
"vue-i18n": "^9.13.1",
"vue-multiselect": "^3.0.0-beta.3", "vue-multiselect": "^3.0.0-beta.3",
"vue-router": "^4.2.5", "vue-router": "^4.2.5",
"vue3-google-map": "^0.18.0" "vue3-google-map": "^0.18.0"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^4.4.0", "@vitejs/plugin-vue": "^4.4.0",
"vite": "^4.4.11" "vite": "^4.4.11",
"vue-cli-plugin-i18n": "~2.3.2"
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.23.3", "version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz",
"integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==",
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
}, },
@@ -472,6 +474,47 @@
"supercluster": "^8.0.1" "supercluster": "^8.0.1"
} }
}, },
"node_modules/@intlify/core-base": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.13.1.tgz",
"integrity": "sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w==",
"dependencies": {
"@intlify/message-compiler": "9.13.1",
"@intlify/shared": "9.13.1"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@intlify/message-compiler": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.13.1.tgz",
"integrity": "sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w==",
"dependencies": {
"@intlify/shared": "9.13.1",
"source-map-js": "^1.0.2"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@intlify/shared": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.13.1.tgz",
"integrity": "sha512-u3b6BKGhE6j/JeRU6C/RL2FgyJfy6LakbtfeVF8fJXURpZZTzfh3e05J0bu0XPw447Q6/WUp3C4ajv4TMS4YsQ==",
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15", "version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
@@ -620,6 +663,15 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/asynckit": { "node_modules/asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -646,6 +698,12 @@
"proxy-from-env": "^1.1.0" "proxy-from-env": "^1.1.0"
} }
}, },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/base64-arraybuffer": { "node_modules/base64-arraybuffer": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
@@ -662,6 +720,16 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/braces": { "node_modules/braces": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
@@ -757,6 +825,21 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/commander": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
"integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
"dev": true,
"engines": {
"node": ">= 6"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
"node_modules/core-js": { "node_modules/core-js": {
"version": "3.35.1", "version": "3.35.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.35.1.tgz", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.35.1.tgz",
@@ -781,6 +864,32 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
}, },
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/delayed-stream": { "node_modules/delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -795,6 +904,28 @@
"integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ==", "integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ==",
"optional": true "optional": true
}, },
"node_modules/dot-object": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/dot-object/-/dot-object-2.1.5.tgz",
"integrity": "sha512-xHF8EP4XH/Ba9fvAF2LDd5O3IITVolerVV6xvkxoM8zlGEiCUrggpAnHyOoKJKCrhvPcGATFAUwIujj7bRG5UA==",
"dev": true,
"dependencies": {
"commander": "^6.1.0",
"glob": "^7.1.6"
},
"bin": {
"dot-object": "bin/dot-object"
}
},
"node_modules/dotenv": {
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz",
"integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/es6-promise": { "node_modules/es6-promise": {
"version": "4.2.8", "version": "4.2.8",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
@@ -837,6 +968,19 @@
"@esbuild/win32-x64": "0.18.20" "@esbuild/win32-x64": "0.18.20"
} }
}, },
"node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true,
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/estree-walker": { "node_modules/estree-walker": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
@@ -863,6 +1007,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/flat": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
"dev": true,
"bin": {
"flat": "cli.js"
}
},
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.15.3", "version": "1.15.3",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
@@ -895,6 +1048,12 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -908,6 +1067,26 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0" "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
} }
}, },
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/glob-parent": { "node_modules/glob-parent": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
@@ -946,6 +1125,22 @@
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz",
"integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA=="
}, },
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true,
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"node_modules/is-binary-path": { "node_modules/is-binary-path": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -984,6 +1179,28 @@
"node": ">=0.12.0" "node": ">=0.12.0"
} }
}, },
"node_modules/is-valid-glob": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz",
"integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"dev": true,
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/jspdf": { "node_modules/jspdf": {
"version": "2.5.1", "version": "2.5.1",
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz", "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz",
@@ -1036,6 +1253,24 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.3.7", "version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
@@ -1061,6 +1296,24 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"dependencies": {
"wrappy": "1"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/perfect-scrollbar": { "node_modules/perfect-scrollbar": {
"version": "1.5.5", "version": "1.5.5",
"resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.5.tgz", "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.5.tgz",
@@ -1174,6 +1427,22 @@
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/prettier": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"dev": true,
"optional": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/proxy-from-env": { "node_modules/proxy-from-env": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -1228,6 +1497,21 @@
"node": ">= 0.8.15" "node": ">= 0.8.15"
} }
}, },
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"dev": true,
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/rollup": { "node_modules/rollup": {
"version": "3.29.4", "version": "3.29.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
@@ -1260,6 +1544,15 @@
"node": ">=14.0.0" "node": ">=14.0.0"
} }
}, },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
@@ -1268,6 +1561,12 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"dev": true
},
"node_modules/stackblur-canvas": { "node_modules/stackblur-canvas": {
"version": "2.6.0", "version": "2.6.0",
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.6.0.tgz", "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.6.0.tgz",
@@ -1414,6 +1713,91 @@
"vue": "^3.0.0-0 || ^2.7.0" "vue": "^3.0.0-0 || ^2.7.0"
} }
}, },
"node_modules/vue-cli-plugin-i18n": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/vue-cli-plugin-i18n/-/vue-cli-plugin-i18n-2.3.2.tgz",
"integrity": "sha512-FM2soNhewEt1ebdwRQ4JrX9upSzA+5QJLOHBUcSlMqzfRkVCGVYva28QZ/DeObB+ODklpA/1Dwr+1x3e4xrLew==",
"dev": true,
"dependencies": {
"debug": "^4.3.0",
"deepmerge": "^4.2.0",
"dotenv": "^8.2.0",
"flat": "^5.0.0",
"rimraf": "^3.0.0",
"vue": "^2.6.11",
"vue-i18n": "^8.17.0",
"vue-i18n-extract": "^1.0.2"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/vue-cli-plugin-i18n/node_modules/@vue/compiler-sfc": {
"version": "2.7.16",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz",
"integrity": "sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==",
"dev": true,
"dependencies": {
"@babel/parser": "^7.23.5",
"postcss": "^8.4.14",
"source-map": "^0.6.1"
},
"optionalDependencies": {
"prettier": "^1.18.2 || ^2.0.0"
}
},
"node_modules/vue-cli-plugin-i18n/node_modules/vue": {
"version": "2.7.16",
"resolved": "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz",
"integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==",
"deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.",
"dev": true,
"dependencies": {
"@vue/compiler-sfc": "2.7.16",
"csstype": "^3.1.0"
}
},
"node_modules/vue-cli-plugin-i18n/node_modules/vue-i18n": {
"version": "8.28.2",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.28.2.tgz",
"integrity": "sha512-C5GZjs1tYlAqjwymaaCPDjCyGo10ajUphiwA922jKt9n7KPpqR7oM1PCwYzhB/E7+nT3wfdG3oRre5raIT1rKA==",
"dev": true
},
"node_modules/vue-i18n": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.13.1.tgz",
"integrity": "sha512-mh0GIxx0wPtPlcB1q4k277y0iKgo25xmDPWioVVYanjPufDBpvu5ySTjP5wOrSvlYQ2m1xI+CFhGdauv/61uQg==",
"dependencies": {
"@intlify/core-base": "9.13.1",
"@intlify/shared": "9.13.1",
"@vue/devtools-api": "^6.5.0"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
},
"peerDependencies": {
"vue": "^3.0.0"
}
},
"node_modules/vue-i18n-extract": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/vue-i18n-extract/-/vue-i18n-extract-1.2.3.tgz",
"integrity": "sha512-ZLtF6wp732KHKawHx5ZSmjyydkli9g26z0NfGLP89DkiGx4nKFYZ2oIH35HtImdhcfq1zqkeSwxs7kRzarLoVw==",
"dev": true,
"dependencies": {
"commander": "^6.1.0",
"dot-object": "^2.1.4",
"glob": "^7.1.6",
"is-valid-glob": "^1.0.0",
"js-yaml": "^3.14.0"
},
"bin": {
"vue-i18n-extract": "bin/vue-i18n-extract.js"
}
},
"node_modules/vue-multiselect": { "node_modules/vue-multiselect": {
"version": "3.0.0-beta.3", "version": "3.0.0-beta.3",
"resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-3.0.0-beta.3.tgz", "resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-3.0.0-beta.3.tgz",
@@ -1452,6 +1836,12 @@
"peerDependencies": { "peerDependencies": {
"vue": "^3" "vue": "^3"
} }
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
} }
} }
} }

View File

@@ -18,12 +18,14 @@
"sweetalert2": "^11.10.1", "sweetalert2": "^11.10.1",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-chartjs": "^5.3.0", "vue-chartjs": "^5.3.0",
"vue-i18n": "^9.13.1",
"vue-multiselect": "^3.0.0-beta.3", "vue-multiselect": "^3.0.0-beta.3",
"vue-router": "^4.2.5", "vue-router": "^4.2.5",
"vue3-google-map": "^0.18.0" "vue3-google-map": "^0.18.0"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^4.4.0", "@vitejs/plugin-vue": "^4.4.0",
"vite": "^4.4.11" "vite": "^4.4.11",
"vue-cli-plugin-i18n": "~2.3.2"
} }
} }

View File

@@ -1,8 +1,73 @@
<script setup> <script setup>
import { useI18n } from 'vue-i18n';
import CustomPopup from './CustomPopup.vue';
import { ref } from 'vue';
import { onMounted } from 'vue';
import { watch } from 'vue';
const { t, locale } = useI18n();
const openPopup = ref(false);
const options = ref([]);
const lang = ref(null);
onMounted(() => {
const langInit = localStorage.getItem('lang') ?? locale.value;
locale.value = langInit
lang.value = {value: langInit, label: langInit == 'en' ? t('global.en') : t('global.es')}
options.value = [
{value: 'es',label: t('global.es')},
{value: 'en',label: t('global.en')},
]
});
const changeLang = () => {
if(locale.value == 'es') {
locale.value = 'en'
lang.value = {
value: 'en',
label: ''
}
} else {
locale.value = 'es'
lang.value = {
value: 'es',
label: ''
}
}
localStorage.setItem('lang', locale.value);
openPopup.value = false
}
watch(lang, () => {
options.value = [
{value: 'es',label: t('global.es')},
{value: 'en',label: t('global.en')},
]
})
const closePopup = () => {
openPopup.value = false
}
</script> </script>
<template> <template>
<div
v-if="openPopup"
>
<CustomPopup
:options="options"
:value="lang"
@change-value="changeLang"
@close-popup="closePopup"
selected-color="#e3a11e"
:style="{
right: '30px',
top: '70px',
}"
/>
</div>
<div class="header-content"> <div class="header-content">
<div class="box-content"> <div class="box-content">
<RouterLink <RouterLink
@@ -14,6 +79,9 @@
<p class="title-header">Tablero de <span class="title-main">Embarques</span> y <span class="title-main">Transportes</span></p> <p class="title-header">Tablero de <span class="title-main">Embarques</span> y <span class="title-main">Transportes</span></p>
</div> </div>
</div> </div>
<a
@click="openPopup = true"
class="lang"><i class="fa-solid fa-globe"></i> {{ locale }}</a>
</div> </div>
</template> </template>
@@ -48,6 +116,15 @@
color: #FFF; color: #FFF;
} }
.lang {
color: #FFF;
text-decoration: none;
align-items: center;
align-self: center;
align-content: center;
cursor: pointer;
}
.app-btn{ .app-btn{
background-color: #FBBA33; background-color: #FBBA33;
/* background-color: #000; */ /* background-color: #000; */

28
src/helpers/messages.js Normal file
View File

@@ -0,0 +1,28 @@
export const messages = {
en: {
labels: {
email: 'Email',
password: 'Password',
},
global: {
signIn: "Sign In"
},
login: {
title: 'Sign in',
greeting: 'Welcome! Enter your email and password'
}
},
es: {
labels: {
email: 'Correo electrónico',
password: 'Contraseña',
},
global: {
signIn: "Ingresar"
},
login: {
title: 'Iniciar sesión',
greeting: 'Bienvenido! Ingresa tu email y contraseña'
}
}
}

147
src/i18n/i18n.js Normal file
View File

@@ -0,0 +1,147 @@
import { createI18n } from 'vue-i18n';
const messages = {
en: {
labels: {
email: 'Email',
password: 'Password',
password2: 'New password',
password3: 'Confirm Password',
code: 'Enter the code',
},
buttons: {
enter: "Enter here",
signup: "Sign up here",
continue: "Continue",
back: "Go back",
resendCode: "Resend code",
terms: 'Terms and Conditions',
noticePrivacity: 'Privacy notice',
},
errors: {
requireds: "All fields required",
email: "Email is not valid",
weakPassword: "Weak password",
matchPassword: "Passwords do not match",
code: 'Enter valid code',
company: 'Enter valid company name',
rfc: 'Enter valid RFC',
segments: 'Select at least one segment',
states: 'Select at least one state',
cities: 'Select at least one city',
trucks: 'Select at least one type of transport',
name: 'Enter valid name(s)',
lastname: 'Enter valid last name(s)',
phone: 'Enter valid phone number'
},
messages: {
sendCode: 'We send you a code to the email, entered!',
changePassword: 'Password has been changed successfully!',
register: "Successful registration, Complete your registration!"
},
global: {
signIn: "Sign In",
and: "and",
es: "Spanish",
en: "English",
shipper: 'Shipper',
carrier: 'Carrier',
brokerShipper: 'Broker (Shipper)',
brokerCarrier: 'Broker (Carrier)',
fisica: 'Persona fisica',
moral: 'Persona moral',
},
login: {
title: 'Sign in',
recovery: 'Recover password',
register: 'Registration of new users',
completeRegister: 'Complete your registration',
questionTypeCompany: 'How do you want to register?',
questionFiscal: 'How do you work?',
companyData: 'Company data',
helptext: "The Password must be at least 8 characters, at least one uppercase letter, at least one lowercase letter, and one digit.",
helptextCode: "We send you a verification code to the email, enter it to confirm the password recovery. Don't forget to check the spam folder.",
greeting: 'Welcome! Enter your email and password',
notHaveAccount: "You do not have an account?",
forgotPassword: "Forgot your password?",
notice: 'By registering you accept our',
questionAccount: 'Do you already have an account?',
}
},
es: {
labels: {
email: 'Correo electrónico',
password: 'Contraseña',
password2: 'Nueva contraseña',
password3: 'Confirmar contraseña',
code: 'Ingresa el código',
},
buttons: {
enter: "Ingresa aqui",
signup: "Registrate aqui",
continue: "Continuar",
back: "Volver",
resendCode: "Reenviar código",
terms: 'Términos y condiciones',
noticePrivacity: 'Aviso de privaciadad',
},
errors: {
requireds: 'Todos los campos con obligatorios',
email: 'Correo electrónico no es valido',
weakPassword: 'Contraseña poco segura',
matchPassword: 'Las contraseñas no coinciden',
code: 'Ingresa código valido',
company: 'Ingresa nombre de empresa valido',
rfc: 'Ingresa RFC valido',
segments: 'Selecciona al menos un segmento',
states: 'Selecciona al menos un estado',
cities: 'Selecciona al menos un municipio',
trucks: 'Selecciona al menos un tipo de transporte',
name: 'Ingresa nombre(s) valido',
lastname: 'Ingresa apellido(s) valido',
phone: 'Ingresa teléfono valido'
},
messages: {
sendCode: 'Te enviamos un código al correo, ingresado!',
changePassword: 'Contraseña se ha cambiando exitosamente!',
register: "Registro exitoso, Complete su registro!"
},
global: {
signIn: 'Ingresar',
and: "y",
es: 'Español',
en: 'Ingles',
shipper: 'Embarcador',
carrier: 'Transportista',
brokerShipper: 'Broker (Embarcador)',
brokerCarrier: 'Broker (Transportista)',
fisica: 'Persona fisica',
moral: 'Persona moral',
},
login: {
title: 'Iniciar sesión',
recovery: 'Recuperar contraseña',
register: 'Registro de nuevos usuarios',
completeRegister: 'Complete su registro',
questionTypeCompany: '¿Como te quieres registrar?',
questionFiscal: '¿Como trabajas?',
companyData: 'Datos de la empresa',
helptext: 'La Contraseña debe ser mínimo 8 caracteres, al menos una mayúscula, al menos una minúscula, y un digito.',
helptextCode: "Te enviamos un código de verificación al correo electrónico, ingresalo para confirmar la recuperacion de contraseña. No olvides revisar en la carpeta spam.",
greeting: 'Bienvenido! Ingresa tu email y contraseña',
forgotPassword: '¿Olvidaste tu contreseña?',
notHaveAccount: '¿No tienes una cuenta?',
notice: 'Al registrarte aceptas nuestros',
questionAccount: '¿Ya tienes una cuenta?',
}
}
}
const i18n = createI18n({
legacy: false,
locale: 'es', // default locale
fallbackLocale: 'es',
messages,
});
export default i18n;

View File

@@ -4,10 +4,12 @@ import { createPinia } from 'pinia'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
import i18n from './i18n/i18n'
const app = createApp(App) const app = createApp(App)
app.use(createPinia()) app.use(createPinia())
app.use(router) app.use(router)
app.use(i18n)
app.mount('#app') app.mount('#app')

View File

@@ -14,6 +14,7 @@
import { complete_registry } from "../services/auth"; import { complete_registry } from "../services/auth";
import { updateMyUserProfile } from "../services/company" import { updateMyUserProfile } from "../services/company"
import Spiner from '../components/ui/Spiner.vue'; import Spiner from '../components/ui/Spiner.vue';
import { useI18n } from 'vue-i18n';
const notifications = useNotificationsStore(); const notifications = useNotificationsStore();
const auth = useAuthStore(); const auth = useAuthStore();
@@ -23,6 +24,8 @@
const msgError = ref(''); const msgError = ref('');
const msgSuccess = ref(''); const msgSuccess = ref('');
const { t } = useI18n()
const typeCompany = reactive({ const typeCompany = reactive({
typeCompany: 'shipper', typeCompany: 'shipper',
typeRFC: 'fisica' typeRFC: 'fisica'
@@ -47,7 +50,7 @@
const handleSelectedTypeCompany = () => { const handleSelectedTypeCompany = () => {
if(typeCompany.typeCompany === null || typeCompany.typeRFC === null) { if(typeCompany.typeCompany === null || typeCompany.typeRFC === null) {
msgError.value = 'Todos los campos con obligatorios'; msgError.value = t('errors.requireds');
clearMessages(); clearMessages();
return; return;
} }
@@ -63,7 +66,7 @@
return; return;
} }
step.value = 3; step.value = 3;
console.log(company); // console.log(company);
} }
const handleSendRegister = async () => { const handleSendRegister = async () => {
@@ -95,7 +98,7 @@
return; return;
} }
console.log(result); // console.log(result);
localStorage.setItem('id', result.data._id); localStorage.setItem('id', result.data._id);
localStorage.setItem('session', auth.sesion); localStorage.setItem('session', auth.sesion);
// localStorage.setItem('access', auth.token); // localStorage.setItem('access', auth.token);
@@ -137,17 +140,17 @@
const validatiosCompany = () => { const validatiosCompany = () => {
if(company.name.trim().length <= 2) { if(company.name.trim().length <= 2) {
return 'Ingresa nombre de empresa valido'; return t('errors.company');
} else if(!validRFC(company.rfc, typeCompany.typeRFC)) { } else if(!validRFC(company.rfc, typeCompany.typeRFC)) {
return 'Ingresa RFC valido'; return t('errors.rfc')
} else if(company.segments.length === 0) { } else if(company.segments.length === 0) {
return 'Selecciona al menos un segmento'; return t('errors.segments')
} else if(company.states.length === 0) { } else if(company.states.length === 0) {
return 'Selecciona al menos un estado'; return t('errors.states');
} else if(company.cities.length === 0) { } else if(company.cities.length === 0) {
return 'Selecciona al menos un municipio'; return t('errors.cities');
} else if(company.truckTypes.length === 0) { } else if(company.truckTypes.length === 0) {
return 'Selecciona al menos un tipo de transporte'; return t('errors.trucks');
} }
else { else {
return ''; return '';
@@ -169,38 +172,38 @@
</script> </script>
<template> <template>
<h2 class="title my-5">Complete su registro</h2> <h2 class="title my-5">{{ t('login.completeRegister') }}</h2>
<div class="card-info flex-column justify-content-center align-items-center mb-5"> <div class="card-info flex-column justify-content-center align-items-center mb-5">
<form @submit.prevent="handleSelectedTypeCompany" v-if="step === 1" class="form-view"> <form @submit.prevent="handleSelectedTypeCompany" v-if="step === 1" class="form-view">
<NotificationBadge :msg="msgError" v-if="msgError != ''"/> <NotificationBadge :msg="msgError" v-if="msgError != ''"/>
<h2 class="mt-4">¿Como te quieres registrar?*</h2> <h2 class="mt-4">{{ t('login.questionTypeCompany') }}*</h2>
<CustomRadioInput <CustomRadioInput
value="shipper" value="shipper"
label="Embarcador" :label="t('global.shipper')"
name="type-company" name="type-company"
v-model:typeselected="typeCompany.typeCompany" v-model:typeselected="typeCompany.typeCompany"
/> />
<CustomRadioInput <CustomRadioInput
value="carrier" value="carrier"
label="Transportista" :label="t('global.carrier')"
name="type-company" name="type-company"
v-model:typeselected="typeCompany.typeCompany" v-model:typeselected="typeCompany.typeCompany"
/> />
<CustomRadioInput <CustomRadioInput
value="b-shipper" value="b-shipper"
label="Broker (Embarcador)" :label="t('global.brokerShipper')"
name="type-company" name="type-company"
v-model:typeselected="typeCompany.typeCompany" v-model:typeselected="typeCompany.typeCompany"
/> />
<CustomRadioInput <CustomRadioInput
value="b-carrier" value="b-carrier"
label="Broker (Transportista)" :label="t('global.brokerCarrier')"
name="type-company" name="type-company"
v-model:typeselected="typeCompany.typeCompany" v-model:typeselected="typeCompany.typeCompany"
/> />
<h2 class="mt-5">¿Como trabajas?*</h2> <h2 class="mt-5">{{ t('login.questionFiscal') }}*</h2>
<CustomRadioInput <CustomRadioInput
value="fisica" value="fisica"
label="Persona fisica" label="Persona fisica"
@@ -214,16 +217,16 @@
v-model:typeselected="typeCompany.typeRFC" v-model:typeselected="typeCompany.typeRFC"
/> />
<input type="submit" value="Continuar" class="btn-primary-lg btn-lg-block my-4"> <input type="submit" :value="t('buttons.continue')" class="btn-primary-lg btn-lg-block my-4">
</form> </form>
<form @submit.prevent="handleDataCompany" v-if="step === 2"> <form @submit.prevent="handleDataCompany" v-if="step === 2">
<div class="d-flex justify-content-center align-items-center my-4"> <div class="d-flex justify-content-center align-items-center my-4">
<a <a
@click="handleBack(1)" @click="handleBack(1)"
class="btn-text ms-2"><i class="fa-solid fa-arrow-left"></i> Volver</a> class="btn-text ms-2"><i class="fa-solid fa-arrow-left"></i> {{ t('buttons.back') }}</a>
</div> </div>
<NotificationBadge :msg="msgError" v-if="msgError != ''"/> <NotificationBadge :msg="msgError" v-if="msgError != ''"/>
<h2>Datos de la empresa</h2> <h2>{{ t('login.companyData') }}</h2>
<div class="divider mt-2 mb-4"></div> <div class="divider mt-2 mb-4"></div>
<Custominput <Custominput
label="¿Cuál es el nombre de la empresa? *" label="¿Cuál es el nombre de la empresa? *"
@@ -275,13 +278,13 @@
v-model:field="company.description" v-model:field="company.description"
/> />
<input type="submit" value="Continuar" class="btn-primary-lg btn-lg-block my-4"> <input type="submit" :value="t('buttons.continue')" class="btn-primary-lg btn-lg-block my-4">
</form> </form>
<form @submit.prevent="handleSendRegister" v-if="step === 3" class="form-view"> <form @submit.prevent="handleSendRegister" v-if="step === 3" class="form-view">
<div class="d-flex justify-content-center align-items-center mb-4"> <div class="d-flex justify-content-center align-items-center mb-4">
<a <a
@click="handleBack(2)" @click="handleBack(2)"
class="btn-text ms-2"><i class="fa-solid fa-arrow-left"></i> Volver</a> class="btn-text ms-2"><i class="fa-solid fa-arrow-left"></i> {{ t('buttons.back') }}</a>
</div> </div>
<NotificationBadge :msg="msgError" v-if="msgError != ''"/> <NotificationBadge :msg="msgError" v-if="msgError != ''"/>
<h2>Información personal</h2> <h2>Información personal</h2>

View File

@@ -7,6 +7,7 @@
import { login } from '../services/auth'; import { login } from '../services/auth';
import { RouterLink, useRouter } from 'vue-router'; import { RouterLink, useRouter } from 'vue-router';
import { useAuthStore } from '../stores/auth'; import { useAuthStore } from '../stores/auth';
import { useI18n } from 'vue-i18n';
const form = reactive({ const form = reactive({
email: '', email: '',
@@ -19,6 +20,7 @@
const loading = ref(false); const loading = ref(false);
const msgError = ref(''); const msgError = ref('');
const msgSuccess = ref(''); const msgSuccess = ref('');
const {t} = useI18n();
const handleLogin = async() => { const handleLogin = async() => {
msgError.value = ''; msgError.value = '';
@@ -67,9 +69,9 @@
const validations = () => { const validations = () => {
if(form.email.trim() == '' || form.password.trim() == '') { if(form.email.trim() == '' || form.password.trim() == '') {
return 'Todos los campos con obligatorios'; return t('errors.requireds')
} else if (!validateEmail(form.email)) { } else if (!validateEmail(form.email)) {
return 'Correo electrónico no es valido' return t('errors.email')
} else { } else {
return ''; return '';
} }
@@ -86,19 +88,19 @@
<template> <template>
<div class="d-flex flex-column my-5 justify-content-center align-items-center"> <div class="d-flex flex-column my-5 justify-content-center align-items-center">
<h2 class="title">Iniciar sesión</h2> <h2 class="title">{{ $t("login.title") }}</h2>
<p class="subtitle mt-4 mb-5 text-center">Bienvenido de vuelta! Ingresa tu email y contraseña</p> <p class="subtitle mt-4 mb-5 text-center">{{ $t("login.greeting") }}</p>
<form @submit.prevent="handleLogin" class="form-content"> <form @submit.prevent="handleLogin" class="form-content">
<NotificationBadge :msg="msgError" v-if="msgError != ''"/> <NotificationBadge :msg="msgError" v-if="msgError != ''"/>
<NotificationBadge :msg="msgSuccess" :is-error="false" v-if="msgSuccess != ''"/> <NotificationBadge :msg="msgSuccess" :is-error="false" v-if="msgSuccess != ''"/>
<CustomInput <CustomInput
label="Ingresa tu correo electrónico" :label="$t('labels.email')"
name="email" name="email"
type="email" type="email"
v-model:field="form.email" v-model:field="form.email"
/> />
<CustomInput <CustomInput
label="Contraseña" :label="$t('labels.password')"
name="password" name="password"
type="password" type="password"
v-model:field="form.password" v-model:field="form.password"
@@ -107,10 +109,10 @@
<input <input
v-else v-else
type="submit" type="submit"
class="btn-primary-lg btn-lg-block radius-1 mt-5" value="Ingresar"> class="btn-primary-lg btn-lg-block radius-1 mt-5" :value="$t('global.signIn')">
</form> </form>
<p class="mt-3 fs-6">¿Olvidaste tu contreseña? <RouterLink class="btn-text" :to="{name: 'recovery'}">Ingresa aqui</RouterLink></p> <p class="mt-3 fs-6">{{ $t("login.forgotPassword") }} <RouterLink class="btn-text" :to="{name: 'recovery'}">{{ $t("buttons.enter") }}</RouterLink></p>
<p class="mt-5 fs-6">¿No tienes una cuenta? <RouterLink class="btn-text" :to="{name: 'register'}">Registrate aqui</RouterLink></p> <p class="mt-5 fs-6">{{ $t("login.notHaveAccount") }} <RouterLink class="btn-text" :to="{name: 'register'}">{{ $t("buttons.signup") }}</RouterLink></p>
</div> </div>
</template> </template>

View File

@@ -7,6 +7,7 @@
import Spiner from '../components/ui/Spiner.vue'; import Spiner from '../components/ui/Spiner.vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useNotificationsStore } from '../stores/notifications'; import { useNotificationsStore } from '../stores/notifications';
import { useI18n } from 'vue-i18n';
const router = useRouter(); const router = useRouter();
const notifications = useNotificationsStore() const notifications = useNotificationsStore()
@@ -23,6 +24,7 @@
const checksum = ref(''); const checksum = ref('');
const msgError = ref(''); const msgError = ref('');
const msgSuccess = ref(''); const msgSuccess = ref('');
const { t } = useI18n()
const handleRegister = async() => { const handleRegister = async() => {
msgError.value = ''; msgError.value = '';
@@ -41,7 +43,7 @@
} }
const result = await recoveryPassword(data); const result = await recoveryPassword(data);
if(result.msg === 'success' && result.data !== null) { if(result.msg === 'success' && result.data !== null) {
msgSuccess.value = 'Te enviamos un código al correo, ingresado!'; msgSuccess.value = t('messages.sendCode');
checksum.value = result.data.checksum; checksum.value = result.data.checksum;
step.value = 2; step.value = 2;
clearMessages(); clearMessages();
@@ -58,7 +60,7 @@
msgError.value = ''; msgError.value = '';
msgSuccess.value = ''; msgSuccess.value = '';
if(form.code.length < 6) { if(form.code.length < 6) {
msgError.value = 'Ingresa código valido'; msgError.value = t('errors.code');
clearMessages(); clearMessages();
return; return;
} else { } else {
@@ -73,7 +75,7 @@
const result = await recoveryPasswordConfirm(data); const result = await recoveryPasswordConfirm(data);
// console.log(result); // console.log(result);
if(result.msg === 'success' && result.data !== null){ if(result.msg === 'success' && result.data !== null){
msgSuccess.value = 'Contraseña se ha cambiando exitosamente!'; msgSuccess.value = t('messages.changePassword');
step.value = 3; step.value = 3;
checksum.value = ''; checksum.value = '';
Object.assign(form, { Object.assign(form, {
@@ -84,7 +86,7 @@
}); });
clearMessages(); clearMessages();
notifications.$patch({ notifications.$patch({
text : 'Contraseña se ha cambiando exitosamente!', text : t('messages.changePassword'),
show : true, show : true,
error: false error: false
}); });
@@ -100,13 +102,13 @@
const validations = () => { const validations = () => {
const pass = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/; const pass = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/;
if(form.email.trim() == '' || form.pwd.trim() == '' || form.retryPwd.trim() == '') { if(form.email.trim() == '' || form.pwd.trim() == '' || form.retryPwd.trim() == '') {
return 'Todos los campos con obligatorios'; return t('errors.requireds');
} else if (!validateEmail(form.email)) { } else if (!validateEmail(form.email)) {
return 'Correo electrónico no es valido' return t('errors.email')
} else if(!pass.test(form.pwd)) { } else if(!pass.test(form.pwd)) {
return 'Contraseña poco segura'; return t('errors.weakPassword');
} else if (form.pwd != form.retryPwd) { } else if (form.pwd != form.retryPwd) {
return 'Las contraseñas no coinciden'; return t('errors.matchPassword');
} else { } else {
return ''; return '';
} }
@@ -144,26 +146,26 @@
<template> <template>
<div class="d-flex flex-column my-5 justify-content-center align-items-center"> <div class="d-flex flex-column my-5 justify-content-center align-items-center">
<h2 class="title">Recuperar contraseña</h2> <h2 class="title">{{ t('login.recovery') }}</h2>
<div class="form-content"> <div class="form-content">
<form v-if="step === 1" @submit.prevent="handleRegister"> <form v-if="step === 1" @submit.prevent="handleRegister">
<NotificationBadge :msg="msgError" v-if="msgError != ''"/> <NotificationBadge :msg="msgError" v-if="msgError != ''"/>
<NotificationBadge :msg="msgSuccess" :is-error="false" v-if="msgSuccess != ''"/> <NotificationBadge :msg="msgSuccess" :is-error="false" v-if="msgSuccess != ''"/>
<CustomInput <CustomInput
label="Ingresa tu correo electrónico" :label="t('labels.email')"
name="email" name="email"
type="email" type="email"
v-model:field="form.email" v-model:field="form.email"
/> />
<CustomInput <CustomInput
label="Nueva contraseña" :label="t('labels.password2')"
name="password" name="password"
type="password" type="password"
v-model:field="form.pwd" v-model:field="form.pwd"
help-text="La Contraseña debe ser mínimo 8 caracteres, al menos una mayúscula, al menos una minúscula, y un digito." :help-text="t('login.helptext')"
/> />
<CustomInput <CustomInput
label="Confirmar Contraseña" :label="t('labels.password3')"
name="retryPassword" name="retryPassword"
type="password" type="password"
v-model:field="form.retryPwd" v-model:field="form.retryPwd"
@@ -172,22 +174,22 @@
<input <input
v-else v-else
type="submit" type="submit"
class="btn-primary-lg btn-lg-block radius-1 mt-5" value="Continuar"> class="btn-primary-lg btn-lg-block radius-1 mt-5" :value="t('buttons.continue')">
<p class="mt-5 fs-6 text-center"><RouterLink class="btn-text" :to="{name: 'login'}">Iniciar sesión</RouterLink></p> <p class="mt-5 fs-6 text-center"><RouterLink class="btn-text" :to="{name: 'login'}">{{ t('login.title') }}</RouterLink></p>
</form> </form>
<form v-if="step === 2" @submit.prevent="handleConfirmRegister" class="mx-5"> <form v-if="step === 2" @submit.prevent="handleConfirmRegister" class="mx-5">
<div class="d-flex justify-content-center align-items-center mb-4"> <div class="d-flex justify-content-center align-items-center mb-4">
<a <a
@click="handleBack(1)" @click="handleBack(1)"
class="btn-text ms-2"><i class="fa-solid fa-arrow-left"></i> Volver</a> class="btn-text ms-2"><i class="fa-solid fa-arrow-left"></i> {{ t('buttons.back') }}</a>
</div> </div>
<NotificationBadge :msg="msgError" v-if="msgError != ''"/> <NotificationBadge :msg="msgError" v-if="msgError != ''"/>
<NotificationBadge :msg="msgSuccess" :is-error="false" v-if="msgSuccess != ''"/> <NotificationBadge :msg="msgSuccess" :is-error="false" v-if="msgSuccess != ''"/>
<p class="help-info">Te enviamos un código de verificación al correo electrónico, ingresalo para confirmar la recuperacion de contraseña. No olvides revisar en la carpeta spam</p> <p class="help-info">{{ t('login.helptextCode') }}</p>
<CustomInput <CustomInput
label="Ingresa el código" :label="t('labels.code')"
name="code" name="code"
type="text" type="text"
v-model:field="form.code" v-model:field="form.code"
@@ -201,7 +203,7 @@
<input <input
v-else v-else
type="submit" type="submit"
class="btn-primary-lg btn-lg-block radius-1 mt-5" value="Continuar"> class="btn-primary-lg btn-lg-block radius-1 mt-5" :value="t('buttons.continue')">
</form> </form>
</div> </div>
</div> </div>

View File

@@ -8,10 +8,12 @@
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useNotificationsStore } from '../stores/notifications'; import { useNotificationsStore } from '../stores/notifications';
import { useAuthStore } from '../stores/auth'; import { useAuthStore } from '../stores/auth';
import { useI18n } from 'vue-i18n';
const router = useRouter(); const router = useRouter();
const notifications = useNotificationsStore() const notifications = useNotificationsStore()
const auth = useAuthStore(); const auth = useAuthStore();
const { t } = useI18n()
const form = reactive({ const form = reactive({
email: '', email: '',
@@ -43,7 +45,7 @@ import { useAuthStore } from '../stores/auth';
} }
const result = await regiter(data); const result = await regiter(data);
if(result.msg === 'success' && result.data !== null) { if(result.msg === 'success' && result.data !== null) {
msgSuccess.value = 'Te enviamos un código al correo, ingresado!'; msgSuccess.value = t('messages.sendCode');
checksum.value = result.data.checksum; checksum.value = result.data.checksum;
step.value = 2; step.value = 2;
clearMessages(); clearMessages();
@@ -60,7 +62,7 @@ import { useAuthStore } from '../stores/auth';
msgError.value = ''; msgError.value = '';
msgSuccess.value = ''; msgSuccess.value = '';
if(form.code.length < 6) { if(form.code.length < 6) {
msgError.value = 'Ingresa código valido'; msgError.value = t('errors.code');
clearMessages(); clearMessages();
return; return;
} else { } else {
@@ -75,7 +77,7 @@ import { useAuthStore } from '../stores/auth';
const result = await regiterConfirm(data); const result = await regiterConfirm(data);
// console.log(result); // console.log(result);
if(result.msg === 'success' && result.data !== null){ if(result.msg === 'success' && result.data !== null){
msgSuccess.value = 'Registro exitoso!'; // msgSuccess.value = 'Registro exitoso!';
step.value = 3; step.value = 3;
checksum.value = ''; checksum.value = '';
Object.assign(form, { Object.assign(form, {
@@ -86,7 +88,7 @@ import { useAuthStore } from '../stores/auth';
}); });
clearMessages(); clearMessages();
notifications.$patch({ notifications.$patch({
text : 'Registro exitoso, Complete su registro!', text : t('messages.register'),
show : true, show : true,
error: false error: false
}); });
@@ -107,13 +109,13 @@ import { useAuthStore } from '../stores/auth';
const validations = () => { const validations = () => {
const pass = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/; const pass = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/;
if(form.email.trim() == '' || form.pwd.trim() == '' || form.retryPwd.trim() == '') { if(form.email.trim() == '' || form.pwd.trim() == '' || form.retryPwd.trim() == '') {
return 'Todos los campos con obligatorios'; return t('errors.requireds');
} else if (!validateEmail(form.email)) { } else if (!validateEmail(form.email)) {
return 'Correo electrónico no es valido' return t('errors.email')
} else if(!pass.test(form.pwd)) { } else if(!pass.test(form.pwd)) {
return 'Contraseña poco segura'; return t('errors.weakPassword');
} else if (form.pwd != form.retryPwd) { } else if (form.pwd != form.retryPwd) {
return 'Las contraseñas no coinciden'; return t('errors.matchPassword');
} else { } else {
return ''; return '';
} }
@@ -134,7 +136,7 @@ import { useAuthStore } from '../stores/auth';
} }
const result = await regiter(data); const result = await regiter(data);
if(result.msg === 'success' && result.data !== null) { if(result.msg === 'success' && result.data !== null) {
msgSuccess.value = 'Te enviamos un código al correo, ingresado!'; msgSuccess.value = t('messages.sendCode');
checksum.value = result.data.checksum; checksum.value = result.data.checksum;
clearMessages(); clearMessages();
} else { } else {
@@ -151,26 +153,26 @@ import { useAuthStore } from '../stores/auth';
<template> <template>
<div class="d-flex flex-column my-5 justify-content-center align-items-center"> <div class="d-flex flex-column my-5 justify-content-center align-items-center">
<h2 class="title">Registro de nuevos usuarios</h2> <h2 class="title">{{ t('login.register') }}</h2>
<div class="form-content"> <div class="form-content">
<form v-if="step === 1" @submit.prevent="handleRegister"> <form v-if="step === 1" @submit.prevent="handleRegister">
<NotificationBadge :msg="msgError" v-if="msgError != ''"/> <NotificationBadge :msg="msgError" v-if="msgError != ''"/>
<NotificationBadge :msg="msgSuccess" :is-error="false" v-if="msgSuccess != ''"/> <NotificationBadge :msg="msgSuccess" :is-error="false" v-if="msgSuccess != ''"/>
<CustomInput <CustomInput
label="Ingresa tu correo electrónico" :label="t('labels.email')"
name="email" name="email"
type="email" type="email"
v-model:field="form.email" v-model:field="form.email"
/> />
<CustomInput <CustomInput
label="Contraseña" :label="t('labels.password')"
name="password" name="password"
type="password" type="password"
v-model:field="form.pwd" v-model:field="form.pwd"
help-text="La Contraseña debe ser mínimo 8 caracteres, al menos una mayúscula, al menos una minúscula, y un digito." :help-text="t('login.helptext')"
/> />
<CustomInput <CustomInput
label="Confirma Contraseña" :label="t('labels.password3')"
name="retryPassword" name="retryPassword"
type="password" type="password"
v-model:field="form.retryPwd" v-model:field="form.retryPwd"
@@ -179,34 +181,34 @@ import { useAuthStore } from '../stores/auth';
<input <input
v-else v-else
type="submit" type="submit"
class="btn-primary-lg btn-lg-block radius-1 mt-5" value="Continuar"> class="btn-primary-lg btn-lg-block radius-1 mt-5" :value="t('buttons.continue')">
<p class="mt-5 fs-6 text-center"> <p class="mt-5 fs-6 text-center">
Al registrarte aceptas nuestros {{ t('login.notice') }}
<RouterLink <RouterLink
class="btn-text me-1" class="btn-text me-1"
:to="{name: 'terms-conditions'}" :to="{name: 'terms-conditions'}"
target="_blank">términos y condiciones</RouterLink> target="_blank">{{t('buttons.terms')}}</RouterLink>
y {{ t('global.and') }}
<RouterLink <RouterLink
class="btn-text ms-1" class="btn-text ms-1"
:to="{name: 'notice-privacy'}" :to="{name: 'notice-privacy'}"
target="_blank"> Aviso de privaciadad</RouterLink> target="_blank"> {{ t('buttons.noticePrivacity') }}</RouterLink>
</p> </p>
<p class="mt-5 fs-6 text-center">¿Ya tienes una cuenta? <RouterLink class="btn-text" :to="{name: 'login'}">Ingresa aqui</RouterLink></p> <p class="mt-5 fs-6 text-center"> {{t('login.questionAccount')}} <RouterLink class="btn-text" :to="{name: 'login'}">{{ t('buttons.enter') }}</RouterLink></p>
</form> </form>
<form v-if="step === 2" @submit.prevent="handleConfirmRegister" class="mx-5"> <form v-if="step === 2" @submit.prevent="handleConfirmRegister" class="mx-5">
<div class="d-flex justify-content-center align-items-center mb-4"> <div class="d-flex justify-content-center align-items-center mb-4">
<a <a
@click="handleBack(1)" @click="handleBack(1)"
class="btn-text ms-2"><i class="fa-solid fa-arrow-left"></i> Volver</a> class="btn-text ms-2"><i class="fa-solid fa-arrow-left"></i> {{t('buttons.back')}}</a>
</div> </div>
<NotificationBadge :msg="msgError" v-if="msgError != ''"/> <NotificationBadge :msg="msgError" v-if="msgError != ''"/>
<NotificationBadge :msg="msgSuccess" :is-error="false" v-if="msgSuccess != ''"/> <NotificationBadge :msg="msgSuccess" :is-error="false" v-if="msgSuccess != ''"/>
<p class="help-info">Te enviamos un código de verificación al correo electrónico, ingresalo para confirmar registro. No olvides revisar en la carpeta spam</p> <p class="help-info">{{ t('login.helptextCode') }}</p>
<CustomInput <CustomInput
label="Ingresa el código" :label="t('labels.code')"
name="code" name="code"
type="text" type="text"
v-model:field="form.code" v-model:field="form.code"
@@ -214,13 +216,13 @@ import { useAuthStore } from '../stores/auth';
<div v-if="!loading" class="d-flex justify-content-center align-items-center mt-4"> <div v-if="!loading" class="d-flex justify-content-center align-items-center mt-4">
<a <a
@click="resendCode()" @click="resendCode()"
class="btn-text ms-2"><i class="fa-solid fa-rotate-right"></i> Reenviar código</a> class="btn-text ms-2"><i class="fa-solid fa-rotate-right"></i> {{ t('buttons.resendCode') }}</a>
</div> </div>
<Spiner v-if="loading" class="mt-5"/> <Spiner v-if="loading" class="mt-5"/>
<input <input
v-else v-else
type="submit" type="submit"
class="btn-primary-lg btn-lg-block radius-1 mt-5" value="Continuar"> class="btn-primary-lg btn-lg-block radius-1 mt-5" :value="t('buttons.continue')">
</form> </form>
</div> </div>
</div> </div>