add: register & recovery password

This commit is contained in:
Alexandro Uc Santos
2023-11-18 19:58:42 -06:00
commit afa8e1983b
37 changed files with 2730 additions and 0 deletions

28
.gitignore vendored Normal file
View File

@@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

3
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
}

29
README.md Normal file
View File

@@ -0,0 +1,29 @@
# eta_main
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Compile and Minify for Production
```sh
npm run build
```

19
index.html Normal file
View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<title>Eta viaporte</title>
</head>
<body class="bg-body">
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
<script src="https://kit.fontawesome.com/3675730ed5.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</html>

894
package-lock.json generated Normal file
View File

@@ -0,0 +1,894 @@
{
"name": "eta_main",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "eta_main",
"version": "0.0.0",
"dependencies": {
"axios": "^1.6.2",
"pinia": "^2.1.7",
"vue": "^3.3.4",
"vue-multiselect": "^3.0.0-beta.3",
"vue-router": "^4.2.5"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.4.0",
"vite": "^4.4.11"
}
},
"node_modules/@babel/parser": {
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz",
"integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==",
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
"integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
"integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
"integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
"integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
"integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
"integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
"integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
"integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
"integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
"integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
"integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
"integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
"integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
"integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
"integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
"integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
"integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
"integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
"integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
"integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
"integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
"integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"node_modules/@vitejs/plugin-vue": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.4.1.tgz",
"integrity": "sha512-HCQG8VDFDM7YDAdcj5QI5DvUi+r6xvo9LgvYdk7LSkUNwdpempdB5horkMSZsbdey9Ywsf5aaU8kEPw9M5kREA==",
"dev": true,
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"peerDependencies": {
"vite": "^4.0.0",
"vue": "^3.2.25"
}
},
"node_modules/@vue/compiler-core": {
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.8.tgz",
"integrity": "sha512-hN/NNBUECw8SusQvDSqqcVv6gWq8L6iAktUR0UF3vGu2OhzRqcOiAno0FmBJWwxhYEXRlQJT5XnoKsVq1WZx4g==",
"dependencies": {
"@babel/parser": "^7.23.0",
"@vue/shared": "3.3.8",
"estree-walker": "^2.0.2",
"source-map-js": "^1.0.2"
}
},
"node_modules/@vue/compiler-dom": {
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.8.tgz",
"integrity": "sha512-+PPtv+p/nWDd0AvJu3w8HS0RIm/C6VGBIRe24b9hSyNWOAPEUosFZ5diwawwP8ip5sJ8n0Pe87TNNNHnvjs0FQ==",
"dependencies": {
"@vue/compiler-core": "3.3.8",
"@vue/shared": "3.3.8"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.8.tgz",
"integrity": "sha512-WMzbUrlTjfYF8joyT84HfwwXo+8WPALuPxhy+BZ6R4Aafls+jDBnSz8PDz60uFhuqFbl3HxRfxvDzrUf3THwpA==",
"dependencies": {
"@babel/parser": "^7.23.0",
"@vue/compiler-core": "3.3.8",
"@vue/compiler-dom": "3.3.8",
"@vue/compiler-ssr": "3.3.8",
"@vue/reactivity-transform": "3.3.8",
"@vue/shared": "3.3.8",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.5",
"postcss": "^8.4.31",
"source-map-js": "^1.0.2"
}
},
"node_modules/@vue/compiler-ssr": {
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.8.tgz",
"integrity": "sha512-hXCqQL/15kMVDBuoBYpUnSYT8doDNwsjvm3jTefnXr+ytn294ySnT8NlsFHmTgKNjwpuFy7XVV8yTeLtNl/P6w==",
"dependencies": {
"@vue/compiler-dom": "3.3.8",
"@vue/shared": "3.3.8"
}
},
"node_modules/@vue/devtools-api": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.1.tgz",
"integrity": "sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA=="
},
"node_modules/@vue/reactivity": {
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.8.tgz",
"integrity": "sha512-ctLWitmFBu6mtddPyOKpHg8+5ahouoTCRtmAHZAXmolDtuZXfjL2T3OJ6DL6ezBPQB1SmMnpzjiWjCiMYmpIuw==",
"dependencies": {
"@vue/shared": "3.3.8"
}
},
"node_modules/@vue/reactivity-transform": {
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.8.tgz",
"integrity": "sha512-49CvBzmZNtcHua0XJ7GdGifM8GOXoUMOX4dD40Y5DxI3R8OUhMlvf2nvgUAcPxaXiV5MQQ1Nwy09ADpnLQUqRw==",
"dependencies": {
"@babel/parser": "^7.23.0",
"@vue/compiler-core": "3.3.8",
"@vue/shared": "3.3.8",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.5"
}
},
"node_modules/@vue/runtime-core": {
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.8.tgz",
"integrity": "sha512-qurzOlb6q26KWQ/8IShHkMDOuJkQnQcTIp1sdP4I9MbCf9FJeGVRXJFr2mF+6bXh/3Zjr9TDgURXrsCr9bfjUw==",
"dependencies": {
"@vue/reactivity": "3.3.8",
"@vue/shared": "3.3.8"
}
},
"node_modules/@vue/runtime-dom": {
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.8.tgz",
"integrity": "sha512-Noy5yM5UIf9UeFoowBVgghyGGPIDPy1Qlqt0yVsUdAVbqI8eeMSsTqBtauaEoT2UFXUk5S64aWVNJN4MJ2vRdA==",
"dependencies": {
"@vue/runtime-core": "3.3.8",
"@vue/shared": "3.3.8",
"csstype": "^3.1.2"
}
},
"node_modules/@vue/server-renderer": {
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.8.tgz",
"integrity": "sha512-zVCUw7RFskvPuNlPn/8xISbrf0zTWsTSdYTsUTN1ERGGZGVnRxM2QZ3x1OR32+vwkkCm0IW6HmJ49IsPm7ilLg==",
"dependencies": {
"@vue/compiler-ssr": "3.3.8",
"@vue/shared": "3.3.8"
},
"peerDependencies": {
"vue": "3.3.8"
}
},
"node_modules/@vue/shared": {
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz",
"integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw=="
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
"integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/csstype": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/esbuild": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
"integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
"dev": true,
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/android-arm": "0.18.20",
"@esbuild/android-arm64": "0.18.20",
"@esbuild/android-x64": "0.18.20",
"@esbuild/darwin-arm64": "0.18.20",
"@esbuild/darwin-x64": "0.18.20",
"@esbuild/freebsd-arm64": "0.18.20",
"@esbuild/freebsd-x64": "0.18.20",
"@esbuild/linux-arm": "0.18.20",
"@esbuild/linux-arm64": "0.18.20",
"@esbuild/linux-ia32": "0.18.20",
"@esbuild/linux-loong64": "0.18.20",
"@esbuild/linux-mips64el": "0.18.20",
"@esbuild/linux-ppc64": "0.18.20",
"@esbuild/linux-riscv64": "0.18.20",
"@esbuild/linux-s390x": "0.18.20",
"@esbuild/linux-x64": "0.18.20",
"@esbuild/netbsd-x64": "0.18.20",
"@esbuild/openbsd-x64": "0.18.20",
"@esbuild/sunos-x64": "0.18.20",
"@esbuild/win32-arm64": "0.18.20",
"@esbuild/win32-ia32": "0.18.20",
"@esbuild/win32-x64": "0.18.20"
}
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
},
"node_modules/follow-redirects": {
"version": "1.15.3",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
"integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/magic-string": {
"version": "0.30.5",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz",
"integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
},
"engines": {
"node": ">=12"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"node_modules/pinia": {
"version": "2.1.7",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.7.tgz",
"integrity": "sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==",
"dependencies": {
"@vue/devtools-api": "^6.5.0",
"vue-demi": ">=0.14.5"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"@vue/composition-api": "^1.4.0",
"typescript": ">=4.4.4",
"vue": "^2.6.14 || ^3.3.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
},
"typescript": {
"optional": true
}
}
},
"node_modules/pinia/node_modules/vue-demi": {
"version": "0.14.6",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz",
"integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/rollup": {
"version": "3.29.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
"integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=14.18.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/vite": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz",
"integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==",
"dev": true,
"dependencies": {
"esbuild": "^0.18.10",
"postcss": "^8.4.27",
"rollup": "^3.27.1"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
},
"peerDependencies": {
"@types/node": ">= 14",
"less": "*",
"lightningcss": "^1.21.0",
"sass": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
"less": {
"optional": true
},
"lightningcss": {
"optional": true
},
"sass": {
"optional": true
},
"stylus": {
"optional": true
},
"sugarss": {
"optional": true
},
"terser": {
"optional": true
}
}
},
"node_modules/vue": {
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.8.tgz",
"integrity": "sha512-5VSX/3DabBikOXMsxzlW8JyfeLKlG9mzqnWgLQLty88vdZL7ZJgrdgBOmrArwxiLtmS+lNNpPcBYqrhE6TQW5w==",
"dependencies": {
"@vue/compiler-dom": "3.3.8",
"@vue/compiler-sfc": "3.3.8",
"@vue/runtime-dom": "3.3.8",
"@vue/server-renderer": "3.3.8",
"@vue/shared": "3.3.8"
},
"peerDependencies": {
"typescript": "*"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/vue-multiselect": {
"version": "3.0.0-beta.3",
"resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-3.0.0-beta.3.tgz",
"integrity": "sha512-P7Fx+ovVF7WMERSZ0lw6N3p4H4bnQ3NcaY3ORjzFPv0r/6lpIqvFWmK9Xnwze9mgAvmNV1foI1VWrBmjnfBTLQ==",
"engines": {
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
}
},
"node_modules/vue-router": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz",
"integrity": "sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==",
"dependencies": {
"@vue/devtools-api": "^6.5.0"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"vue": "^3.2.0"
}
}
}
}

21
package.json Normal file
View File

@@ -0,0 +1,21 @@
{
"name": "eta_main",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.6.2",
"pinia": "^2.1.7",
"vue": "^3.3.4",
"vue-multiselect": "^3.0.0-beta.3",
"vue-router": "^4.2.5"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.4.0",
"vite": "^4.4.11"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
public/images/._auth.png Normal file

Binary file not shown.

Binary file not shown.

BIN
public/images/auth.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
public/images/fondo1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
public/images/logo-eta.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
public/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

16
src/App.vue Normal file
View File

@@ -0,0 +1,16 @@
<template>
<main>
<RouterView />
</main>
<Notification/>
</template>
<script setup>
import Notification from './components/ui/Notification.vue';
</script>
<style scoped>
</style>

220
src/assets/main.css Normal file
View File

@@ -0,0 +1,220 @@
body {
margin: 0px 0px;
padding: 0px;
}
.bg-body{
background-color: red;
}
.w-lg-45{
width: 45%;
}
.radius-1 {
border-radius: 1rem !important;
}
.radius-2 {
border-radius: 2rem !important;
}
.radius-3 {
border-radius: 3rem !important;
}
.divider {
display: block;
height: 2px;
width: 100%;
background-color: rgb(243, 226, 226);
}
.btn-text{
font-size: 1.2rem;
font-weight: 700;
color: #FBBA33;
text-decoration: none;
cursor: pointer;
}
.btn-lg-block{
width: 100%;
}
.btn-primary-lg {
background-color: #FBBA33;
color: #FFF;
padding: 12px 30px;
border: none;
border-radius: 25px;
font-size: 18px;
text-decoration: none;
font-weight: 900;
}
.btn-primary-lg:hover {
background-color: #e3a11e;
transition: background-color 300ms ease;
}
.btn-primary-sm {
background-color: #FBBA33;
padding: 8px 16px;
color: #FFF;
font-size: 16px;
border: none;
text-decoration: none;
text-align: center;
border-radius: 13px;
font-weight: 700;
}
.btn-primary-sm:hover {
background-color: #e3a11e;
transition: background-color 300ms ease;
}
.title{
font-size: 1.6rem;
font-weight: 900;
color: #323030;
}
.text-content {
font-size: 1.2rem;
font-weight: normal;
color: #323030;
}
.title-main{
color: #FBBA33;
}
.card-info,
.card-fixed {
width: 100%;
background-color: #FFF;
padding: 24px 32px;
border: none;
border-radius: 13px;
display: flex;
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.10));
margin-bottom: 12px;
}
.card-info h2{
font-size: 1.5rem;
font-weight: 800;
color: #323030;
}
.card-info p{
font-size: 1rem;
font-weight: 400;
color: #323030;
}
.loads-table {
overflow: scroll;
}
th {
font-size: 16px;
font-weight: 600;
align-items: center;
justify-content: center;
color: #323030;
}
td {
font-size: 14px;
font-weight: 400;
color: #323030;
}
.custom-label {
font-size: 1.2rem;
font-weight: 600;
color: #645555;
}
.custom-input {
background-color: rgb(233, 233, 241);
border-radius: 13px;
border: none;
padding: 10px 12px;
font-size: 1rem;
}
.custom-input:enabled{
border: none;
}
.custom-input:active{
border: none;
}
.custom-input:focus{
border: none;
}
@media (max-width: 1024px) {
th {
font-size: 13px;
font-weight: 500;
}
td {
font-size: 12px;
font-weight: 300;
}
}
@media (max-width: 768px) {
.card-info {
padding: 16px 16px;
}
.card-info h2{
font-size: 1.2rem;
font-weight: 700;
}
.card-info p{
font-size: 0.8rem;
font-weight: 400;
}
.w-lg-45 {
width: 100%;
}
.btn-primary-lg {
padding: 8px 15px;
border: none;
border-radius: 25px;
font-size: 16px;
font-weight: 700;
}
.btn-primary-sm {
padding: 8px 12px;
font-size: 14px;
border: none;
border-radius: 13px;
font-weight: 700;
}
}
@media (max-width: 568px) {
.card-info {
width: 100%;
background-color: transparent;
padding: 16px 8px;
flex-direction: column;
}
th {
font-size: 13px;
font-weight: 400;
}
td {
font-size: 12px;
font-weight: 300;
}
}

99
src/components/Footer.vue Normal file
View File

@@ -0,0 +1,99 @@
<template>
<div class="footer">
<div class="d-flex justify-content-between">
<div class="social-media">
<div class="circle-btn">
<i class="fa-brands fa-facebook"></i>
</div>
<div class="circle-btn">
<i class="fa-brands fa-instagram"></i>
</div>
<div class="circle-btn">
<i class="fa-brands fa-x-twitter"></i>
</div>
<div class="circle-btn">
<i class="fa-brands fa-tiktok"></i>
</div>
<div class="circle-btn">
<i class="fa-brands fa-linkedin"></i>
</div>
</div>
<div class="d-flex flex-column">
<a class="btn-links mb-1" href="">Aviso de privacidad</a>
<a class="btn-links" href="">Terminos y condiciones</a>
</div>
</div>
<h4 class="copy"><i class="fa fa-copyright" aria-hidden="true"></i> 2023 ETA VIAPORTE | TODOS LOS DERECHOS RESERVADOS</h4>
</div>
</template>
<style scoped>
.footer {
width: 100%;
padding: 36px 100px;
background-color: #303030;
display: flex;
flex-direction: column;
}
.social-media{
display: flex;
}
.copy{
padding-top: 32px;
color: #FFF;
opacity: 0.2;
justify-content: center;
margin: 0 auto;
font-size: 22px;
font-weight: 400;
}
.circle-btn{
cursor: pointer;
margin: 0px 5px;
display: flex;
border-radius: 13px;
border: none;
background-color: #000;
color: #FFF;
padding: 15px;
justify-content: center;
align-items: center;
}
.btn-links {
font-size: 16px;
font-weight: 500;
color: rgb(85, 85, 223);
text-decoration: none;
}
.circle-btn i{
font-size: 30px;
}
@media (max-width: 768px) {
.footer {
width: 100%;
padding: 32px 24px;
background-color: #303030;
display: flex;
flex-direction: column;
}
.circle-btn {
padding: 8px;
margin: 0px 2px;
}
.circle-btn i{
font-size: 18px;
}
.btn-links {
font-size: 12px;
font-weight: 400;
}
.copy{
font-size: 16px;
font-weight: 400;
text-align: center;
}
}
</style>

110
src/components/Header.vue Normal file
View File

@@ -0,0 +1,110 @@
<script setup>
</script>
<template>
<div class="header-content">
<div class="box-content">
<img src="/images/logo-eta.png" class="logo" alt="Eta Viaporte" >
<div class="box-register">
<p class="title-header">Tablero de <span class="title-main">Embarques</span> y <span class="title-main">Transportes</span></p>
</div>
</div>
</div>
</template>
<style scoped>
.header-content {
position: relative;
width: 100%;
background-color: #323030;
display: flex;
flex-direction: row;
margin: 0 auto;
padding: 20px 24px;
align-items: center;
justify-content: space-between;
}
.logo{
height: 70px;
margin-right: 10px;
}
.box-content {
display: flex;
align-items: center;
align-content: center;
/* width: 65%; */
}
.box-register{
margin-left: 24px;
}
.title-header{
font-size: 1.8rem;
font-weight: 900;
color: #FFF;
}
.app-btn{
background-color: #FBBA33;
/* background-color: #000; */
border: none;
color: #FFF;
border-radius: 25px;
padding: 12px 32px;
}
.app-btn:hover{
background-color: #e3a11e;
transition: background-color 300ms ease;
}
.app-btn i{
font-size: 1.4rem;
}
.app-btn span{
margin-left: 8px;
font-size: 1.4rem;
}
@media (max-width: 1024px) {
.header-content {
padding: 16px 36px;
}
.box-register{
margin-left: 10px;
}
.app-btn{
padding: 10px 24px;
}
.app-btn i{
font-size: 1rem;
}
.app-btn span{
margin-left: 8px;
font-size: 1rem;
}
}
@media (max-width: 768px) {
.header-content {
padding: 16px 16px;
}
.box-buttons{
display: none !important;
}
}
@media (max-width: 568px) {
.logo{
height: 80px;
}
.title-header{
font-size: 1rem;
font-weight: 700;
color: #FFF;
}
.title-main{
color: #FBBA33;
}
}
</style>

View File

@@ -0,0 +1,47 @@
<script setup>
defineProps({
field: {
type: String
},
label: {
type: String,
required: false,
},
name: {
type: String,
required: true,
},
type: {
type: String,
default: 'text',
},
helpText: {
type: String,
default: '',
}
})
defineEmits(['update:field'])
</script>
<template>
<div class="d-flex flex-column gap-2 mb-4">
<label class="custom-label" :for="name">{{ label }}</label>
<input
class="custom-input"
:type="type"
:id="name"
:name="name"
:value="field"
@input="$event => $emit('update:field', $event.target.value)">
<span class="help" v-if="helpText.length > 0">{{ helpText }}</span>
</div>
</template>
<style scoped>
.help {
font-size: 12px;
font-weight: 300;
color: rgb(108, 92, 92);
}
</style>

View File

@@ -0,0 +1,85 @@
<script setup>
import { useNotificationsStore } from '../../stores/notifications';
const notifications = useNotificationsStore();
</script>
<template>
<div class="noty-fixed">
<div class="content-noty" v-if="notifications.show">
<div class="body">
<i v-if="notifications.error === false" class="fa-regular fa-circle-check text-success icon-category"></i>
<i v-else class="fa-solid fa-circle-exclamation text-danger"></i>
<div>
<h4 class="noty-title">Notificación</h4>
<p class="noty-body">{{ notifications.text }}</p>
</div>
<i class="fa-solid fa-xmark close-icon" @click="notifications.show = false"></i>
</div>
</div>
</div>
</template>
<style scoped>
.noty-fixed {
position: fixed;
right: 100px;
top: 50px;
}
.content-noty {
width: 100%;
max-width: 500px;
padding: 14px 20px;
background-color: white;
border-radius: 8px;
box-shadow: -5px 5px 9px -1px rgba(0,0,0,0.20);
-webkit-box-shadow: -5px 5px 9px -1px rgba(0,0,0,0.20);
-moz-box-shadow: -5px 5px 9px -1px rgba(0,0,0,0.20);
}
.body {
display: flex;
flex-direction: row;
align-items: center;
gap: 1rem;
/* align-content: center; */
justify-content: space-between;
}
.noty-title {
font-size: 1.2rem;
color: black;
margin: 0px;
margin-bottom: 4px;
}
.noty-body {
font-size: 1rem;
color: black;
margin: 0px;
}
.icon-category {
font-size: 24px;
}
.close-icon {
position: absolute;
right: 12px;
top: 10px;
font-size: 20px;
cursor: pointer;
}
@media (max-width: 768px) {
.noty-fixed {
right: 20px;
top: 30px;
}
.content-noty {
width: 100%;
max-width: 320px;
padding: 14px 16px;
background-color: white;
border-radius: 8px;
}
}
</style>

View File

@@ -0,0 +1,56 @@
<script setup>
defineProps({
msg: {
type: String,
required: true,
},
isError: {
type: Boolean,
default: true,
},
showIcon: {
type: Boolean,
default: true,
}
})
</script>
<template>
<div class="badge" :class="[isError ? 'badge-error' : 'badge-success']">
<span>
<i v-if="showIcon && isError" class="fa-solid fa-circle-exclamation me-2"></i>
<i v-if="showIcon && !isError" class="fa-solid fa-circle-check"></i>
{{ msg }}
</span>
</div>
</template>
<style scoped>
.badge {
display: flex;
width: 100%;
color: #FFF;
font-size: 1rem;
font-weight: 700;
border-radius: 8px;
justify-content: center;
padding: 10px 16px;
margin-bottom: 12px;
}
.badge-error {
background-color: rgb(238, 101, 101);
}
.badge-success {
background-color: rgb(29, 162, 113);
}
@media (max-width: 768px) {
.badge {
font-size: 0.8rem;
font-weight: 400;
border-radius: 8px;
padding: 10px 12px;
}
}
</style>

View File

@@ -0,0 +1,50 @@
<template>
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
</template>
<style scoped>
.spinner {
margin: 20px auto 0;
width: 70px;
text-align: center;
}
.spinner > div {
width: 18px;
height: 18px;
background-color: #FBBA33;
border-radius: 100%;
display: inline-block;
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
}
.spinner .bounce1 {
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}
.spinner .bounce2 {
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}
@-webkit-keyframes sk-bouncedelay {
0%, 80%, 100% { -webkit-transform: scale(0) }
40% { -webkit-transform: scale(1.0) }
}
@keyframes sk-bouncedelay {
0%, 80%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
} 40% {
-webkit-transform: scale(1.0);
transform: scale(1.0);
}
}
</style>

View File

@@ -0,0 +1,12 @@
export const getDateMonthDay = (value) => {
const date = new Date(value)
return date.toLocaleString(['en-US'], {
month: 'short',
day: '2-digit',
year: 'numeric',
})
}

View File

@@ -0,0 +1,18 @@
export const validateEmail = (email) => {
return String(email)
.toLowerCase()
.match(
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
);
};
export const messagesError = (msg) => {
switch (msg) {
case 'Email is not registered!':
return 'No se encontro una cuenta con este email';
case 'Wrong OTP':
return 'Código ingresado incorrecto';
default:
return msg;
}
};

View File

@@ -0,0 +1,11 @@
<template>
<RouterView />
</template>
<script setup>
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,68 @@
<script setup>
import Header from '../components/Header.vue';
import Footer from '../components/Footer.vue';
</script>
<template>
<Header/>
<div class="auth-layout">
<!-- <div class="img-auth">
<img src="/images/auth.png" class="img" alt="fondo">
</div> -->
<!-- <div class="auth-view"> -->
<!-- <img src="/images/logo.png" width="150"/> -->
<RouterView/>
<!-- </div> -->
</div>
<Footer/>
</template>
<style scoped>
/* .auth-layout {
display: flex;
flex-direction: row;
width: 100%;
margin: 0px 0px !important;
padding: 0px 0px !important;
overflow: hidden;
} */
.auth-layout {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
align-content: center;
width: 50%;
margin: 0px auto !important;
padding: 0px 0px !important;
overflow: hidden;
min-height: 700px;
}
.img-auth {
width: 50%;
/* object-fit: cover; */
margin: 24px 50px;
/* padding: 24p */
}
.img {
width: 100%;
/* max-height: 80vh; */
border-radius: 13px;
/* object-fit: cover; */
/* padding: 24px; */
}
.auth-view {
display: flex;
width: 50%;
margin: 0px 0px;
padding: 0px 0px;
/* background-color: red; */
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>

9
src/lib/axios.js Normal file
View File

@@ -0,0 +1,9 @@
import axios from "axios";
const baseUrl = import.meta.env.VITE_API_URL;
const api = axios.create({
baseURL: baseUrl
});
export default api;

14
src/main.js Normal file
View File

@@ -0,0 +1,14 @@
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')

45
src/router/index.js Normal file
View File

@@ -0,0 +1,45 @@
import { createRouter, createWebHistory } from 'vue-router'
import AuthLayout from '../layouts/AuthLayout.vue'
import LoginView from '../views/LoginView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'auth',
component: AuthLayout,
children: [
{
path: '',
name: 'login',
component: () => import('../views/LoginView.vue'),
},
{
path: 'registro',
name: 'register',
component: () => import('../views/RegisterView.vue'),
},
{
path: 'recuperar-cuenta',
name: 'recovery',
component: () => import('../views/RecoveryPasswordView.vue'),
},
]
},
{
path: '/dashboard',
name: 'dashboard',
component: () => import('../layouts/AdminLayout.vue'),
children: [
{
path: 'inicio',
name: 'inicio',
component: () => import('../views/HomeView.vue'),
},
]
}
]
})
export default router

83
src/services/auth.js Normal file
View File

@@ -0,0 +1,83 @@
import api from "../lib/axios";
import {messagesError} from '../helpers/validations';
export const regiter = async(body) => {
try {
const endpoint = "/account/signup";
const {data} = await api.post(endpoint, body);
return {
msg: 'success',
data
};
} catch (error) {
return {
msg: error.response.data.error ?? 'Algo salio mal, intente más tarde',
data: null
};
}
}
export const regiterConfirm = async(body) => {
try {
const endpoint = "/account/signup";
const {data} = await api.patch(endpoint, body);
return {
msg: 'success',
data
};
} catch (error) {
let msg = 'Algo salio mal, intente más tarde';
if(error.response.data.error) {
if(error.response.data.error === 'Wrong OTP'){
msg = 'Codigo ingresado incorrecto';
} else {
msg = error.response.data.error;
}
}
return {
msg,
data: null
};
}
}
export const recoveryPassword = async(body) => {
try {
const endpoint = "/account/recover";
const {data} = await api.post(endpoint, body);
return {
msg: 'success',
data
};
} catch (error) {
const errStr = error.response.data.error ?? 'Algo salio mal, intente más tarde';
return {
msg: messagesError(errStr),
data: null
};
}
}
export const recoveryPasswordConfirm = async(body) => {
try {
const endpoint = "/account/recover";
const {data} = await api.patch(endpoint, body);
return {
msg: 'success',
data
};
} catch (error) {
let msg = 'Algo salio mal, intente más tarde';
if(error.response.data.error) {
if(error.response.data.error === 'Wrong OTP'){
msg = 'Codigo ingresado incorrecto';
} else {
msg = error.response.data.error;
}
}
return {
msg,
data: null
};
}
}

117
src/services/public.js Normal file
View File

@@ -0,0 +1,117 @@
export const getLoadDirectories = async(filterStr) => {
try {
const endpoint = `/public-loads${filterStr}`;
const {data} = await api.get(endpoint);
return data.data;
} catch (error) {
console.log(error);
return [];
}
}
export const getVehicleDirectories = async(filter) => {
try {
const endpoint = `/public-vehicles/published${filter}`;
const {data} = await api.get(endpoint);
return data.data;
} catch (error) {
console.log(error);
return [];
}
}
export const getFreeVehicles = async() => {
try {
// console.log(process.env.API_URL + "/vehicles/?status=Free&updatedAt[$gt]=" + moment.utc(lasthour).valueOf());
const endpoint = `/public-vehicles/location`;
console.log({endpoint});
const {data} = await api.get(endpoint);
return data.data;
} catch (error) {
console.log(error);
return [];
}
}
export const getNews = async() => {
try {
const endpoint = `/news`;
console.log({endpoint});
const {data} = await api.get(endpoint);
console.log(data);
return data.data;
} catch (error) {
console.log(error);
return [];
}
}
export const getCompanies = async(filter) => {
try {
const endpoint = `/public-companies/${filter}`;
console.log(endpoint);
const {data} = await api.get(endpoint);
return data.data;
} catch (error) {
console.log(error);
return [];
}
}
export const getUsersCompany = async(filter) => {
try {
const endpoint = `/users?${filter}`;
// console.log({endpoint});
const {data} = await api.get(endpoint);
// console.log(data);
return data.data;
} catch (error) {
console.log(error);
return [];
}
}
export const getSettingsQuery = async(filter) => {
try {
const endpoint = "/meta-data/find?regex=" + filter.query;
const {data} = await api.get(endpoint);
return data.data;
} catch (error) {
console.log(error);
return [];
}
}
export const searchcategories = async(query) => {
try {
const endpoint = "/product-categories/find?regex=" + query;
const {data} = await api.get(endpoint);
return data.data;
} catch (error) {
console.log(error);
return [];
}
}
export const searchstates = async(query) => {
try {
const endpoint = "/states/find?regex=" + query;
const {data} = await api.get(endpoint);
return data.data;
} catch (error) {
console.log(error);
return [];
}
}
export const searchcities = async(query) => {
try {
// const endpoint = "/cities/?city_name[$regex]=" + query + "&city_name[$options]=i";
const endpoint = "/cities/find?regex=" + query;
const {data} = await api.get(endpoint);
return data.data;
} catch (error) {
console.log(error);
return [];
}
}

12
src/stores/counter.js Normal file
View File

@@ -0,0 +1,12 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})

View File

@@ -0,0 +1,27 @@
import { defineStore } from "pinia";
import { ref, watch } from "vue";
export const useNotificationsStore = defineStore('notifications', () => {
const text = ref('')
const error = ref(false)
const show = ref(false)
watch(show, () => {
if(show) {
setTimeout(() => {
text.value = '';
error.value = false;
show.value = false;
}, 4000);
}
});
return {
text,
error,
show,
}
});

6
src/views/HomeView.vue Normal file
View File

@@ -0,0 +1,6 @@
<script setup>
</script>
<template>
<h1>HomeView</h1>
</template>

133
src/views/LoginView.vue Normal file
View File

@@ -0,0 +1,133 @@
<script setup>
import { reactive, ref } from 'vue';
import CustomInput from '../components/ui/custominput.vue';
import NotificationBadge from '../components/ui/NotificationBadge.vue';
import {validateEmail} from '../helpers/validations';
import Spiner from '../components/ui/Spiner.vue';
import { RouterLink } from 'vue-router';
const form = reactive({
email: '',
password: '',
});
const loading = ref(false);
const msgError = ref('');
const msgSuccess = ref('');
const handleLogin = async() => {
msgError.value = '';
msgSuccess.value = '';
let resp = validations();
if(resp !== '') {
msgError.value = resp;
clearMessages();
return;
} else {
loading.value = true;
msgError.value = '';
const data = {
email: form.email,
password: form.password
}
console.log(data);
loading.value = false;
}
}
const validations = () => {
if(form.email.trim() == '' || form.password.trim() == '') {
return 'Todos los campos con obligatorios';
} else if (!validateEmail(form.email)) {
return 'Correo electrónico no es valido'
} else {
return '';
}
}
const clearMessages = () => {
setTimeout(() => {
msgError.value = '';
msgSuccess.value = '';
}, 3000);
}
</script>
<template>
<div class="d-flex flex-column my-5 justify-content-center align-items-center">
<h2 class="title">Iniciar sesión</h2>
<p class="subtitle mt-4 mb-5">Bienvenido de vuelta! Ingresa tu email y contraseña</p>
<form @submit.prevent="handleLogin" class="form-content">
<NotificationBadge :msg="msgError" v-if="msgError != ''"/>
<NotificationBadge :msg="msgSuccess" :is-error="false" v-if="msgSuccess != ''"/>
<CustomInput
label="Ingresa tu correo electrónico"
name="email"
type="email"
v-model:field="form.email"
/>
<CustomInput
label="Contraseña"
name="password"
type="password"
v-model:field="form.password"
/>
<Spiner v-if="loading" class="mt-5"/>
<input
v-else
type="submit"
class="btn-primary-lg btn-lg-block radius-1 mt-5" value="Ingresar">
</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-5 fs-6">¿No tienes una cuenta? <RouterLink class="btn-text" :to="{name: 'register'}">Registrate aqui</RouterLink></p>
</div>
</template>
<style scoped>
.subtitle {
font-size: 1.4rem;
font-weight: 500;
color: grey;
}
.form-content {
display: flex;
flex-direction: column;
width: 100%;
/* min-width: 420px; */
/* padding: 2rem 3rem; */
}
.icon-success{
font-size: 5rem;
color: green;
}
.help-info {
margin-bottom: 2rem;
font-size: 1.2rem;
font-weight: 400;
color: #5a4b4b;
}
.msg-success {
margin-bottom: 2rem;
font-size: 1.4rem;
font-weight: 500;
color: #5a4b4b;
}
@media (max-width: 1224px) {
.form-content {
width: 80%;
}
}
@media (max-width: 768px) {
.form-content {
width: 100%;
padding: 2rem 1rem;
}
}
</style>

View File

@@ -0,0 +1,235 @@
<script setup>
import { reactive, ref } from 'vue';
import CustomInput from '../components/ui/custominput.vue';
import NotificationBadge from '../components/ui/NotificationBadge.vue';
import {validateEmail} from '../helpers/validations';
import {recoveryPassword, recoveryPasswordConfirm} from "../services/auth";
import Spiner from '../components/ui/Spiner.vue';
import { useRouter } from 'vue-router';
import { useNotificationsStore } from '../stores/notifications';
const router = useRouter();
const notifications = useNotificationsStore()
const form = reactive({
email: '',
pwd: '',
retryPwd: '',
code: ''
});
const step = ref(1);
const loading = ref(false);
const checksum = ref('');
const msgError = ref('');
const msgSuccess = ref('');
const handleRegister = async() => {
msgError.value = '';
msgSuccess.value = '';
let resp = validations();
if(resp !== '') {
msgError.value = resp;
clearMessages();
return;
} else {
loading.value = true;
msgError.value = '';
const data = {
email: form.email,
password: form.pwd
}
const result = await recoveryPassword(data);
if(result.msg === 'success' && result.data !== null) {
msgSuccess.value = 'Te enviamos un código al correo, ingresado!';
checksum.value = result.data.checksum;
step.value = 2;
clearMessages();
} else {
msgError.value = result.msg;
clearMessages();
}
loading.value = false;
}
}
const handleConfirmRegister = async() => {
msgError.value = '';
msgSuccess.value = '';
if(form.code.length < 6) {
msgError.value = 'Ingresa código valido';
clearMessages();
return;
} else {
loading.value = true;
msgError.value = '';
const data = {
email: form.email,
password: form.pwd,
otp: form.code,
checksum: checksum.value
}
const result = await recoveryPasswordConfirm(data);
// console.log(result);
if(result.msg === 'success' && result.data !== null){
msgSuccess.value = 'Contraseña se ha cambiando exitosamente!';
step.value = 3;
checksum.value = '';
Object.assign(form, {
email: '',
pwd: '',
retryPwd: '',
code: ''
});
clearMessages();
notifications.$patch({
text : 'Contraseña se ha cambiando exitosamente!',
show : true,
error: false
});
router.push({name: 'login'});
} else {
msgError.value = result.msg;
clearMessages()
}
loading.value = false;
}
}
const validations = () => {
const pass = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/;
if(form.email.trim() == '' || form.pwd.trim() == '' || form.retryPwd.trim() == '') {
return 'Todos los campos con obligatorios';
} else if (!validateEmail(form.email)) {
return 'Correo electrónico no es valido'
} else if(!pass.test(form.pwd)) {
return 'Contraseña poco segura';
} else if (form.pwd != form.retryPwd) {
return 'Las contraseñas no coinciden';
} else {
return '';
}
}
const clearMessages = () => {
setTimeout(() => {
msgError.value = '';
msgSuccess.value = '';
}, 3000);
}
const resendCode = async() => {
loading.value = true;
const data = {
email: form.email,
password: form.pwd
}
const result = await regiter(data);
if(result.msg === 'success' && result.data !== null) {
msgSuccess.value = 'Te enviamos un código al correo, ingresado!';
checksum.value = result.data.checksum;
clearMessages();
} else {
msgError.value = result.msg;
clearMessages();
}
loading.value = false;
}
const handleBack = (val) => {
step.value = val;
}
</script>
<template>
<div class="d-flex flex-column my-5 justify-content-center align-items-center">
<h2 class="title">Recuperar contraseña</h2>
<div class="form-content">
<form v-if="step === 1" @submit.prevent="handleRegister">
<NotificationBadge :msg="msgError" v-if="msgError != ''"/>
<NotificationBadge :msg="msgSuccess" :is-error="false" v-if="msgSuccess != ''"/>
<CustomInput
label="Ingresa tu correo electrónico"
name="email"
type="email"
v-model:field="form.email"
/>
<CustomInput
label="Nueva contraseña"
name="password"
type="password"
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."
/>
<CustomInput
label="Confirmar Contraseña"
name="retryPassword"
type="password"
v-model:field="form.retryPwd"
/>
<Spiner v-if="loading" class="mt-5"/>
<input
v-else
type="submit"
class="btn-primary-lg btn-lg-block radius-1 mt-5" value="Continuar">
<p class="mt-5 fs-6 text-center"><RouterLink class="btn-text" :to="{name: 'login'}">Iniciar sesión</RouterLink></p>
</form>
<form v-if="step === 2" @submit.prevent="handleConfirmRegister" class="mx-5">
<div class="d-flex justify-content-center align-items-center mb-4">
<a
@click="handleBack(1)"
class="btn-text ms-2"><i class="fa-solid fa-arrow-left"></i> Volver</a>
</div>
<NotificationBadge :msg="msgError" v-if="msgError != ''"/>
<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>
<CustomInput
label="Ingresa el código"
name="code"
type="text"
v-model:field="form.code"
/>
<div v-if="!loading" class="d-flex justify-content-center align-items-center mt-4">
<a
@click="resendCode()"
class="btn-text ms-2"><i class="fa-solid fa-rotate-right"></i> Reenviar código</a>
</div>
<Spiner v-if="loading" class="mt-5"/>
<input
v-else
type="submit"
class="btn-primary-lg btn-lg-block radius-1 mt-5" value="Continuar">
</form>
</div>
</div>
</template>
<style scoped>
.form-content {
width: 100%;
padding: 2rem 3rem;
}
.help-info {
margin-bottom: 2rem;
font-size: 1.2rem;
font-weight: 400;
color: #5a4b4b;
}
@media (max-width: 1224px) {
.form-content {
width: 80%;
}
}
@media (max-width: 768px) {
.form-content {
width: 100%;
padding: 2rem 1rem;
}
}
</style>

247
src/views/RegisterView.vue Normal file
View File

@@ -0,0 +1,247 @@
<script setup>
import { reactive, ref } from 'vue';
import CustomInput from '../components/ui/custominput.vue';
import NotificationBadge from '../components/ui/NotificationBadge.vue';
import {validateEmail} from '../helpers/validations';
import {regiter, regiterConfirm} from "../services/auth";
import Spiner from '../components/ui/Spiner.vue';
import { useRouter } from 'vue-router';
import { useNotificationsStore } from '../stores/notifications';
const router = useRouter();
const notifications = useNotificationsStore()
const form = reactive({
email: '',
pwd: '',
retryPwd: '',
code: ''
});
const step = ref(1);
const loading = ref(false);
const checksum = ref('');
const msgError = ref('');
const msgSuccess = ref('');
const handleRegister = async() => {
msgError.value = '';
msgSuccess.value = '';
let resp = validations();
if(resp !== '') {
msgError.value = resp;
clearMessages();
return;
} else {
loading.value = true;
msgError.value = '';
const data = {
email: form.email,
password: form.pwd
}
const result = await regiter(data);
if(result.msg === 'success' && result.data !== null) {
msgSuccess.value = 'Te enviamos un código al correo, ingresado!';
checksum.value = result.data.checksum;
step.value = 2;
clearMessages();
} else {
msgError.value = result.msg;
clearMessages();
}
loading.value = false;
}
}
const handleConfirmRegister = async() => {
msgError.value = '';
msgSuccess.value = '';
if(form.code.length < 6) {
msgError.value = 'Ingresa código valido';
clearMessages();
return;
} else {
loading.value = true;
msgError.value = '';
const data = {
email: form.email,
password: form.pwd,
otp: form.code,
checksum: checksum.value
}
const result = await regiterConfirm(data);
// console.log(result);
if(result.msg === 'success' && result.data !== null){
msgSuccess.value = 'Registro exitoso!';
step.value = 3;
checksum.value = '';
Object.assign(form, {
email: '',
pwd: '',
retryPwd: '',
code: ''
});
clearMessages();
notifications.$patch({
text : 'Registro exitoso, Inicie sesión!',
show : true,
error: false
});
router.push({name: 'login'});
} else {
msgError.value = result.msg;
clearMessages()
}
loading.value = false;
}
}
const validations = () => {
const pass = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/;
if(form.email.trim() == '' || form.pwd.trim() == '' || form.retryPwd.trim() == '') {
return 'Todos los campos con obligatorios';
} else if (!validateEmail(form.email)) {
return 'Correo electrónico no es valido'
} else if(!pass.test(form.pwd)) {
return 'Contraseña poco segura';
} else if (form.pwd != form.retryPwd) {
return 'Las contraseñas no coinciden';
} else {
return '';
}
}
const clearMessages = () => {
setTimeout(() => {
msgError.value = '';
msgSuccess.value = '';
}, 3000);
}
const resendCode = async() => {
loading.value = true;
const data = {
email: form.email,
password: form.pwd
}
const result = await regiter(data);
if(result.msg === 'success' && result.data !== null) {
msgSuccess.value = 'Te enviamos un código al correo, ingresado!';
checksum.value = result.data.checksum;
clearMessages();
} else {
msgError.value = result.msg;
clearMessages();
}
loading.value = false;
}
const handleBack = (val) => {
step.value = val;
}
</script>
<template>
<div class="d-flex flex-column my-5 justify-content-center align-items-center">
<h2 class="title">Registro de nuevos usuarios</h2>
<div class="form-content">
<form v-if="step === 1" @submit.prevent="handleRegister">
<NotificationBadge :msg="msgError" v-if="msgError != ''"/>
<NotificationBadge :msg="msgSuccess" :is-error="false" v-if="msgSuccess != ''"/>
<CustomInput
label="Ingresa tu correo electrónico"
name="email"
type="email"
v-model:field="form.email"
/>
<CustomInput
label="Contraseña"
name="password"
type="password"
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."
/>
<CustomInput
label="Confirma Contraseña"
name="retryPassword"
type="password"
v-model:field="form.retryPwd"
/>
<Spiner v-if="loading" class="mt-5"/>
<input
v-else
type="submit"
class="btn-primary-lg btn-lg-block radius-1 mt-5" value="Continuar">
<p class="mt-5 fs-6 text-center">Al registrarte aceptas nuestros <RouterLink class="btn-text" :to="{name: 'login'}">términos y cóndiciones</RouterLink></p>
<p class="mt-5 fs-6 text-center">¿Ya tienes una cuenta? <RouterLink class="btn-text" :to="{name: 'login'}">Ingresa aqui</RouterLink></p>
</form>
<form v-if="step === 2" @submit.prevent="handleConfirmRegister" class="mx-5">
<div class="d-flex justify-content-center align-items-center mb-4">
<a
@click="handleBack(1)"
class="btn-text ms-2"><i class="fa-solid fa-arrow-left"></i> Volver</a>
</div>
<NotificationBadge :msg="msgError" v-if="msgError != ''"/>
<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>
<CustomInput
label="Ingresa el código"
name="code"
type="text"
v-model:field="form.code"
/>
<div v-if="!loading" class="d-flex justify-content-center align-items-center mt-4">
<a
@click="resendCode()"
class="btn-text ms-2"><i class="fa-solid fa-rotate-right"></i> Reenviar código</a>
</div>
<Spiner v-if="loading" class="mt-5"/>
<input
v-else
type="submit"
class="btn-primary-lg btn-lg-block radius-1 mt-5" value="Continuar">
</form>
</div>
</div>
</template>
<style scoped>
.form-content {
width: 100%;
padding: 2rem 3rem;
}
.icon-success{
font-size: 5rem;
color: green;
}
.help-info {
margin-bottom: 2rem;
font-size: 1.2rem;
font-weight: 400;
color: #5a4b4b;
}
.msg-success {
margin-bottom: 2rem;
font-size: 1.4rem;
font-weight: 500;
color: #5a4b4b;
}
@media (max-width: 1224px) {
.form-content {
width: 80%;
}
}
@media (max-width: 768px) {
.form-content {
width: 100%;
padding: 2rem 1rem;
}
}
</style>

16
vite.config.js Normal file
View File

@@ -0,0 +1,16 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})