many fixes and improvements - rework for modules/ and common/
feat(emailer): add Postmark and Resend providers
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"parser": "vue-eslint-parser",
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
@@ -9,6 +10,7 @@
|
||||
"plugin:tailwindcss/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
|
||||
565
frontend/package-lock.json
generated
565
frontend/package-lock.json
generated
@@ -24,23 +24,27 @@
|
||||
"vue-advanced-cropper": "^2.8.9",
|
||||
"vue-i18n": "^10.0.7",
|
||||
"vue-router": "^4.2.5",
|
||||
"vue-toastification": "^2.0.0-rc.5",
|
||||
"vue3-google-login": "^2.0.26",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"vuetify": "^3.5.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/webpack-env": "^1.18.8",
|
||||
"@typescript-eslint/eslint-plugin": "^8.34.0",
|
||||
"@typescript-eslint/parser": "^8.34.0",
|
||||
"@vitejs/plugin-vue": "^5.0.3",
|
||||
"@vue/eslint-config-prettier": "^10.2.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-plugin-tailwindcss": "^3.18.0",
|
||||
"eslint-plugin-vue": "^9.22.0",
|
||||
"postcss": "^8.5.3",
|
||||
"prettier": "^3.5.3",
|
||||
"rollup-plugin-visualizer": "^6.0.1",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"vite": "^6.3.1"
|
||||
"vite": "^6.3.1",
|
||||
"vue-eslint-parser": "^10.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
@@ -552,14 +556,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/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==",
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
@@ -594,9 +606,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array/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==",
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -1060,9 +1072,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz",
|
||||
"integrity": "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.43.0.tgz",
|
||||
"integrity": "sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1073,9 +1085,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz",
|
||||
"integrity": "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.43.0.tgz",
|
||||
"integrity": "sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1086,9 +1098,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz",
|
||||
"integrity": "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.43.0.tgz",
|
||||
"integrity": "sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1099,9 +1111,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz",
|
||||
"integrity": "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.43.0.tgz",
|
||||
"integrity": "sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1112,9 +1124,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz",
|
||||
"integrity": "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.43.0.tgz",
|
||||
"integrity": "sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1125,9 +1137,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz",
|
||||
"integrity": "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.43.0.tgz",
|
||||
"integrity": "sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1138,9 +1150,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz",
|
||||
"integrity": "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.43.0.tgz",
|
||||
"integrity": "sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1151,9 +1163,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz",
|
||||
"integrity": "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.43.0.tgz",
|
||||
"integrity": "sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1164,9 +1176,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz",
|
||||
"integrity": "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.43.0.tgz",
|
||||
"integrity": "sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1177,9 +1189,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz",
|
||||
"integrity": "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.43.0.tgz",
|
||||
"integrity": "sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1190,9 +1202,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz",
|
||||
"integrity": "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.43.0.tgz",
|
||||
"integrity": "sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -1203,9 +1215,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz",
|
||||
"integrity": "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.43.0.tgz",
|
||||
"integrity": "sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -1216,9 +1228,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz",
|
||||
"integrity": "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.43.0.tgz",
|
||||
"integrity": "sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1229,9 +1241,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz",
|
||||
"integrity": "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.43.0.tgz",
|
||||
"integrity": "sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1242,9 +1254,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz",
|
||||
"integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.43.0.tgz",
|
||||
"integrity": "sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -1255,9 +1267,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz",
|
||||
"integrity": "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.43.0.tgz",
|
||||
"integrity": "sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1268,9 +1280,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz",
|
||||
"integrity": "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.43.0.tgz",
|
||||
"integrity": "sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1281,9 +1293,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz",
|
||||
"integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.43.0.tgz",
|
||||
"integrity": "sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1294,9 +1306,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz",
|
||||
"integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.43.0.tgz",
|
||||
"integrity": "sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -1307,9 +1319,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz",
|
||||
"integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.43.0.tgz",
|
||||
"integrity": "sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1339,9 +1351,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
|
||||
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.17.17",
|
||||
@@ -1359,13 +1371,66 @@
|
||||
"integrity": "sha512-G9eAoJRMLjcvN4I08wB5I7YofOb/kaJNd5uoCMX+LbKXTPCF+ZIHuqTnFaK9Jz1rgs035f9JUPUhNFtqgucy/A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.33.1.tgz",
|
||||
"integrity": "sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw==",
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.0.tgz",
|
||||
"integrity": "sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.33.1",
|
||||
"@typescript-eslint/types": "^8.33.1",
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
"@typescript-eslint/type-utils": "8.34.0",
|
||||
"@typescript-eslint/utils": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^7.0.0",
|
||||
"natural-compare": "^1.4.0",
|
||||
"ts-api-utils": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.34.0",
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.0.tgz",
|
||||
"integrity": "sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.0.tgz",
|
||||
"integrity": "sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.34.0",
|
||||
"@typescript-eslint/types": "^8.34.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1380,12 +1445,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.33.1.tgz",
|
||||
"integrity": "sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA==",
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.0.tgz",
|
||||
"integrity": "sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.33.1",
|
||||
"@typescript-eslint/visitor-keys": "8.33.1"
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1396,9 +1461,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.1.tgz",
|
||||
"integrity": "sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g==",
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.0.tgz",
|
||||
"integrity": "sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
@@ -1410,10 +1475,33 @@
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.0.tgz",
|
||||
"integrity": "sha512-n7zSmOcUVhcRYC75W2pnPpbO1iwhJY3NLoHEtbJwJSNlVAZuwqu05zY3f3s2SDWWDSo9FdN5szqc73DCtDObAg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.34.0",
|
||||
"@typescript-eslint/utils": "8.34.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.1.tgz",
|
||||
"integrity": "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg==",
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.0.tgz",
|
||||
"integrity": "sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
@@ -1423,14 +1511,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.1.tgz",
|
||||
"integrity": "sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA==",
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.0.tgz",
|
||||
"integrity": "sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.33.1",
|
||||
"@typescript-eslint/tsconfig-utils": "8.33.1",
|
||||
"@typescript-eslint/types": "8.33.1",
|
||||
"@typescript-eslint/visitor-keys": "8.33.1",
|
||||
"@typescript-eslint/project-service": "8.34.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.34.0",
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/visitor-keys": "8.34.0",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -1449,12 +1537,35 @@
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.1.tgz",
|
||||
"integrity": "sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ==",
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.0.tgz",
|
||||
"integrity": "sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.33.1",
|
||||
"@eslint-community/eslint-utils": "^4.7.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"@typescript-eslint/typescript-estree": "8.34.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.0.tgz",
|
||||
"integrity": "sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1466,9 +1577,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
|
||||
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
@@ -1547,11 +1658,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vee-validate/rules": {
|
||||
"version": "4.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@vee-validate/rules/-/rules-4.15.0.tgz",
|
||||
"integrity": "sha512-Cvll7r98O5tU6ew2AUifVpdhNnTkMTY7+D9N++J7apQXRXWfHMe4tNvjo4TJpKUPCtfLHbdTY/DCquDRc+uH4w==",
|
||||
"version": "4.15.1",
|
||||
"resolved": "https://registry.npmjs.org/@vee-validate/rules/-/rules-4.15.1.tgz",
|
||||
"integrity": "sha512-2TGXq2MYt21nT8ysuxyFY/LBVQDcMPKn1hY0w3uIDmG333vzBkOtXAylmvrS93AsJ7N5coHMJjcCGG4JxCO2hQ==",
|
||||
"dependencies": {
|
||||
"vee-validate": "4.15.0"
|
||||
"vee-validate": "4.15.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitejs/plugin-vue": {
|
||||
@@ -1784,9 +1895,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.14.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
||||
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -2006,9 +2117,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
@@ -2105,9 +2216,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001721",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz",
|
||||
"integrity": "sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==",
|
||||
"version": "1.0.30001722",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001722.tgz",
|
||||
"integrity": "sha512-DCQHBBZtiK6JVkAGw7drvAMK0Q0POD/xZvEmDp6baiMMP6QXXk9HpD6mNYBZWhOPG6LvIDb82ITqtWjhDckHCA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -2252,9 +2363,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "3.42.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.42.0.tgz",
|
||||
"integrity": "sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==",
|
||||
"version": "3.43.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.43.0.tgz",
|
||||
"integrity": "sha512-N6wEbTTZSYOY2rYAn85CuvWWkCK6QweMn7/4Nr3w+gDBeBhk/x4EJeY6FPo4QzDoJZxVTv8U7CMvgWk6pOHHqA==",
|
||||
"hasInstallScript": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -2386,9 +2497,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.165",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.165.tgz",
|
||||
"integrity": "sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw==",
|
||||
"version": "1.5.166",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.166.tgz",
|
||||
"integrity": "sha512-QPWqHL0BglzPYyJJ1zSSmwFFL6MFXhbACOCcsCdUMCkzPdS9/OIBVxg516X/Ado2qwAq8k0nJJ7phQPCqiaFAw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
@@ -2666,6 +2777,30 @@
|
||||
"eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-vue/node_modules/vue-eslint-parser": {
|
||||
"version": "9.4.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz",
|
||||
"integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
"eslint-scope": "^7.1.1",
|
||||
"eslint-visitor-keys": "^3.3.0",
|
||||
"espree": "^9.3.1",
|
||||
"esquery": "^1.4.0",
|
||||
"lodash": "^4.17.21",
|
||||
"semver": "^7.3.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mysticatea"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-scope": {
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
|
||||
@@ -2693,14 +2828,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/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==",
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
@@ -2870,9 +3013,9 @@
|
||||
"integrity": "sha512-66peeFF3epjeQR5l+aaB03aF8bEI+bQf+wMq3fjnUEyQ1d6qR+Z6rGHq9bSxuu2kzEtWG+0PfU5x2SiVEcYy0w=="
|
||||
},
|
||||
"node_modules/fdir": {
|
||||
"version": "6.4.5",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz",
|
||||
"integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==",
|
||||
"version": "6.4.6",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
|
||||
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
@@ -3129,9 +3272,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/glob/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==",
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -3342,9 +3485,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
|
||||
"integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
@@ -4191,9 +4335,9 @@
|
||||
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz",
|
||||
"integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==",
|
||||
"version": "8.5.5",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.5.tgz",
|
||||
"integrity": "sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -4516,9 +4660,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.41.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz",
|
||||
"integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==",
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.43.0.tgz",
|
||||
"integrity": "sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.7"
|
||||
@@ -4531,33 +4675,33 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.41.1",
|
||||
"@rollup/rollup-android-arm64": "4.41.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.41.1",
|
||||
"@rollup/rollup-darwin-x64": "4.41.1",
|
||||
"@rollup/rollup-freebsd-arm64": "4.41.1",
|
||||
"@rollup/rollup-freebsd-x64": "4.41.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.41.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.41.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.41.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.41.1",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.41.1",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.41.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.41.1",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.41.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.41.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.41.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.41.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.41.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.41.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.41.1",
|
||||
"@rollup/rollup-android-arm-eabi": "4.43.0",
|
||||
"@rollup/rollup-android-arm64": "4.43.0",
|
||||
"@rollup/rollup-darwin-arm64": "4.43.0",
|
||||
"@rollup/rollup-darwin-x64": "4.43.0",
|
||||
"@rollup/rollup-freebsd-arm64": "4.43.0",
|
||||
"@rollup/rollup-freebsd-x64": "4.43.0",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.43.0",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.43.0",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.43.0",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.43.0",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.43.0",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.43.0",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.43.0",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.43.0",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.43.0",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.43.0",
|
||||
"@rollup/rollup-linux-x64-musl": "4.43.0",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.43.0",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.43.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.43.0",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup-plugin-visualizer": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-6.0.1.tgz",
|
||||
"integrity": "sha512-NjlGElvLXCSZSAi3gNRZbfX3qlQbQcJ9TW97c5JpqfVwMhttj9YwEdPwcvbKj91RnMX2PWAjonvSEv6UEYtnRQ==",
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-6.0.3.tgz",
|
||||
"integrity": "sha512-ZU41GwrkDcCpVoffviuM9Clwjy5fcUxlz0oMoTXTYsK+tcIFzbdacnrr2n8TXcHxbGKKXtOdjxM2HUS4HjkwIw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"open": "^8.0.0",
|
||||
@@ -4572,7 +4716,7 @@
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rolldown": "1.x",
|
||||
"rolldown": "1.x || ^1.0.0-beta",
|
||||
"rollup": "2.x || 3.x || 4.x"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
@@ -4593,6 +4737,12 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup/node_modules/@types/estree": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
|
||||
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
@@ -5167,9 +5317,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vee-validate": {
|
||||
"version": "4.15.0",
|
||||
"resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-4.15.0.tgz",
|
||||
"integrity": "sha512-PGJh1QCFwCBjbHu5aN6vB8macYVWrajbDvgo1Y/8fz9n/RVIkLmZCJDpUgu7+mUmCOPMxeyq7vXUOhbwAqdXcA==",
|
||||
"version": "4.15.1",
|
||||
"resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-4.15.1.tgz",
|
||||
"integrity": "sha512-DkFsiTwEKau8VIxyZBGdO6tOudD+QoUBPuHj3e6QFqmbfCRj1ArmYWue9lEp6jLSWBIw4XPlDLjFIZNLdRAMSg==",
|
||||
"dependencies": {
|
||||
"@vue/devtools-api": "^7.5.2",
|
||||
"type-fest": "^4.8.3"
|
||||
@@ -5334,27 +5484,72 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue-eslint-parser": {
|
||||
"version": "9.4.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz",
|
||||
"integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==",
|
||||
"version": "10.1.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.1.3.tgz",
|
||||
"integrity": "sha512-dbCBnd2e02dYWsXoqX5yKUZlOt+ExIpq7hmHKPb5ZqKcjf++Eo0hMseFTZMLKThrUk61m+Uv6A2YSBve6ZvuDQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
"eslint-scope": "^7.1.1",
|
||||
"eslint-visitor-keys": "^3.3.0",
|
||||
"espree": "^9.3.1",
|
||||
"esquery": "^1.4.0",
|
||||
"debug": "^4.4.0",
|
||||
"eslint-scope": "^8.2.0",
|
||||
"eslint-visitor-keys": "^4.2.0",
|
||||
"espree": "^10.3.0",
|
||||
"esquery": "^1.6.0",
|
||||
"lodash": "^4.17.21",
|
||||
"semver": "^7.3.6"
|
||||
"semver": "^7.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.17.0 || >=16.0.0"
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mysticatea"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=6.0.0"
|
||||
"eslint": "^8.57.0 || ^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-eslint-parser/node_modules/eslint-scope": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
|
||||
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^5.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-eslint-parser/node_modules/espree": {
|
||||
"version": "10.4.0",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
|
||||
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"acorn": "^8.15.0",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-i18n": {
|
||||
@@ -5401,6 +5596,14 @@
|
||||
"vue": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-toastification": {
|
||||
"version": "2.0.0-rc.5",
|
||||
"resolved": "https://registry.npmjs.org/vue-toastification/-/vue-toastification-2.0.0-rc.5.tgz",
|
||||
"integrity": "sha512-q73e5jy6gucEO/U+P48hqX+/qyXDozAGmaGgLFm5tXX4wJBcVsnGp4e/iJqlm9xzHETYOilUuwOUje2Qg1JdwA==",
|
||||
"peerDependencies": {
|
||||
"vue": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/vue3-google-login": {
|
||||
"version": "2.0.33",
|
||||
"resolved": "https://registry.npmjs.org/vue3-google-login/-/vue3-google-login-2.0.33.tgz",
|
||||
@@ -5421,9 +5624,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vuetify": {
|
||||
"version": "3.8.8",
|
||||
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.8.8.tgz",
|
||||
"integrity": "sha512-EPFynvxh72PBgUVZnGpfYfGluz8dz/tXM1OzjszFOK7ywqS+bAm8K9jJq0MIlAG8HKE7gBFQwCJGkzIyuUDipA==",
|
||||
"version": "3.8.9",
|
||||
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.8.9.tgz",
|
||||
"integrity": "sha512-X9kCxeqf7w5sca2Mfn4NCVsDDimi81jxKyqsZHjW0XG/rTdtwRFKttxOcv0Mmi+67ulPjDZywA7pBFK0rxoafA==",
|
||||
"engines": {
|
||||
"node": "^12.20 || >=14.13"
|
||||
},
|
||||
|
||||
@@ -25,22 +25,26 @@
|
||||
"vue-advanced-cropper": "^2.8.9",
|
||||
"vue-i18n": "^10.0.7",
|
||||
"vue-router": "^4.2.5",
|
||||
"vue-toastification": "^2.0.0-rc.5",
|
||||
"vue3-google-login": "^2.0.26",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"vuetify": "^3.5.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/webpack-env": "^1.18.8",
|
||||
"@typescript-eslint/eslint-plugin": "^8.34.0",
|
||||
"@typescript-eslint/parser": "^8.34.0",
|
||||
"@vitejs/plugin-vue": "^5.0.3",
|
||||
"@vue/eslint-config-prettier": "^10.2.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-plugin-tailwindcss": "^3.18.0",
|
||||
"eslint-plugin-vue": "^9.22.0",
|
||||
"postcss": "^8.5.3",
|
||||
"prettier": "^3.5.3",
|
||||
"rollup-plugin-visualizer": "^6.0.1",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"vite": "^6.3.1"
|
||||
"vite": "^6.3.1",
|
||||
"vue-eslint-parser": "^10.1.3"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
frontend/src/assets/hutopy-icon-white-circle.png
Normal file
BIN
frontend/src/assets/hutopy-icon-white-circle.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
@@ -5,17 +5,19 @@ import { createPinia } from 'pinia';
|
||||
import 'vuetify/styles';
|
||||
import { createVuetify } from 'vuetify';
|
||||
import { aliases, mdi } from 'vuetify/iconsets/mdi-svg';
|
||||
import { VDialog, VApp, VBtn, VProgressLinear, VProgressCircular, VIcon, VTextField, VSnackbar, VForm, VTextarea } from 'vuetify/components';
|
||||
import { VDialog, VApp, VBtn, VProgressLinear, VProgressCircular, VIcon, VTextField, VSnackbar, VForm, VTextarea, VAlert } from 'vuetify/components';
|
||||
import { } from 'vuetify/directives';
|
||||
import vueGoogleOauth from 'vue3-google-login';
|
||||
import { useAuthStore } from "@/stores/authStore.js";
|
||||
import { useUserProfileStore } from "@/stores/userProfileStore.js";
|
||||
import { useCreatorProfileStore } from "@/stores/creatorProfileStore.js";
|
||||
import Toast, { POSITION } from 'vue-toastification';
|
||||
import 'vue-toastification/dist/index.css';
|
||||
import './assets/main.css';
|
||||
|
||||
const vuetify = createVuetify({
|
||||
components: {
|
||||
VDialog, VApp, VBtn, VProgressLinear, VProgressCircular, VIcon, VTextField, VSnackbar, VForm, VTextarea
|
||||
VDialog, VApp, VBtn, VProgressLinear, VProgressCircular, VIcon, VTextField, VSnackbar, VForm, VTextarea, VAlert
|
||||
},
|
||||
directives: {
|
||||
},
|
||||
@@ -50,7 +52,10 @@ const app = createApp(App)
|
||||
.use(i18n)
|
||||
.use(vueGoogleOauth, {
|
||||
clientId: import.meta.env.VITE_GOOGLE_CLIENT_ID,
|
||||
});
|
||||
})
|
||||
.use(Toast, {
|
||||
position: POSITION.TOP_CENTER,
|
||||
});
|
||||
|
||||
useAuthStore();
|
||||
useUserProfileStore();
|
||||
|
||||
@@ -1,147 +1,155 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<!-- Navigation Link at the top -->
|
||||
<div class="navigation-link">
|
||||
<button class="link-button" @click="goBack()">
|
||||
<v-icon :icon="mdiArrowLeft" />
|
||||
{{ t('returnToCreator') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<!-- Navigation Link at the top -->
|
||||
<div class="navigation-link">
|
||||
<button
|
||||
class="link-button"
|
||||
@click="goBack()"
|
||||
>
|
||||
<v-icon :icon="mdiArrowLeft" />
|
||||
{{ t('returnToCreator') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1>
|
||||
{{ t('title') }}
|
||||
</h1>
|
||||
<h1 v-html="titleWithCreatorName"></h1>
|
||||
|
||||
<p>
|
||||
<v-icon size="120" color="success" :icon="mdiCheckCircle" />
|
||||
</p>
|
||||
<p>
|
||||
<v-icon
|
||||
:icon="mdiCheckCircle"
|
||||
color="success"
|
||||
size="120"
|
||||
/>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{{ t('message') }}
|
||||
<p>
|
||||
{{ t('message') }}
|
||||
</p>
|
||||
|
||||
<span v-if="brandingStore.value?.name">
|
||||
{{ brandingStore.value.name }}
|
||||
</span>
|
||||
|
||||
<span v-else>
|
||||
{{ t('usernameDefault') }}
|
||||
</span>
|
||||
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{{ t('receipt') }}
|
||||
</p>
|
||||
<p>
|
||||
{{ t('receipt') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useBrandingStore } from '@/stores/brandingStore.js';
|
||||
import { mdiArrowLeft, mdiCheckCircle } from '@mdi/js';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useBrandingStore } from '@/stores/brandingStore.js';
|
||||
import { mdiArrowLeft, mdiCheckCircle } from '@mdi/js';
|
||||
import { computed } from 'vue';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const brandingStore = useBrandingStore();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const brandingStore = useBrandingStore();
|
||||
|
||||
function goBack() {
|
||||
// Navigate back to the creator's page
|
||||
const creatorName = route.params.creator?.split('/')[0] || '';
|
||||
router.push(`/@${creatorName}`);
|
||||
}
|
||||
const creatorName = computed(() => {
|
||||
return route.params.creator?.split('/')[0] || t('usernameDefault');
|
||||
});
|
||||
|
||||
const titleWithCreatorName = computed(() => {
|
||||
return t('title', { creatorName: creatorName.value });
|
||||
});
|
||||
|
||||
function goBack() {
|
||||
// Navigate back to the creator's page
|
||||
const creatorNameParam = route.params.creator?.split('/')[0] || '';
|
||||
router.push(`/@${creatorNameParam}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"title": "Payment Successful!",
|
||||
"message": "Your payment has been processed successfully.",
|
||||
"usernameDefault": "the creator",
|
||||
"receipt": "A receipt has been sent to your email.",
|
||||
"continue": "Continue to",
|
||||
"returnToCreator": "Return to creator page"
|
||||
},
|
||||
"fr": {
|
||||
"title": "Paiement réussi !",
|
||||
"message": "Votre paiement a été traité avec succès.",
|
||||
"usernameDefault": "le créateur",
|
||||
"receipt": "Un reçu a été envoyé à votre email.",
|
||||
"continue": "Continuer vers",
|
||||
"returnToCreator": "Retourner à la page du créateur"
|
||||
},
|
||||
"es": {
|
||||
"title": "¡Pago exitoso!",
|
||||
"message": "Su pago ha sido procesado con éxito.",
|
||||
"usernameDefault": "el creador",
|
||||
"receipt": "Se ha enviado un recibo a su correo electrónico.",
|
||||
"continue": "Continuar a",
|
||||
"returnToCreator": "Volver a la página del creador"
|
||||
}
|
||||
"en": {
|
||||
"title": "{creatorName} thanks you!",
|
||||
"message": "Your payment has been processed successfully.",
|
||||
"usernameDefault": "The creator",
|
||||
"receipt": "A receipt has been sent to your email.",
|
||||
"returnToCreator": "Return to creator page"
|
||||
},
|
||||
"fr": {
|
||||
"title": "{creatorName} vous remercie !",
|
||||
"message": "Votre paiement a été traité avec succès.",
|
||||
"usernameDefault": "Le créateur",
|
||||
"receipt": "Un reçu a été envoyé à votre email.",
|
||||
"returnToCreator": "Retourner à la page du créateur"
|
||||
},
|
||||
"es": {
|
||||
"title": "¡{creatorName} te agradece!",
|
||||
"message": "Su pago ha sido procesado con éxito.",
|
||||
"usernameDefault": "El creador",
|
||||
"receipt": "Se ha enviado un recibo a su correo electrónico.",
|
||||
"returnToCreator": "Volver a la página del creador"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
@apply flex items-center justify-center;
|
||||
@apply p-5;
|
||||
@apply w-full;
|
||||
@apply mx-auto;
|
||||
@apply max-w-[1024px];
|
||||
}
|
||||
.container {
|
||||
@apply flex items-center justify-center;
|
||||
@apply p-5;
|
||||
@apply w-full;
|
||||
@apply mx-auto;
|
||||
@apply max-w-[1024px];
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply bg-hSurface text-hOnSurface;
|
||||
@apply p-8;
|
||||
@apply font-sans;
|
||||
@apply rounded-2xl;
|
||||
@apply shadow-2xl;
|
||||
@apply relative;
|
||||
@apply w-full;
|
||||
@apply max-w-2xl;
|
||||
@apply mx-auto;
|
||||
}
|
||||
.card {
|
||||
@apply bg-hSurface text-hOnSurface;
|
||||
@apply p-8;
|
||||
@apply font-sans;
|
||||
@apply rounded-2xl;
|
||||
@apply shadow-2xl;
|
||||
@apply relative;
|
||||
@apply w-full;
|
||||
@apply max-w-2xl;
|
||||
@apply mx-auto;
|
||||
}
|
||||
|
||||
.card::before {
|
||||
@apply absolute inset-0;
|
||||
@apply rounded-2xl;
|
||||
@apply p-[1px];
|
||||
content: '';
|
||||
background: linear-gradient(135deg, rgba(64, 64, 64, 1) 0%, rgba(64, 64, 64, 0) 20%, rgba(64, 64, 64, 0.5) 100%);
|
||||
mask: linear-gradient(#fff 0 0) content-box,
|
||||
linear-gradient(#fff 0 0);
|
||||
mask-composite: exclude;
|
||||
pointer-events: none;
|
||||
}
|
||||
.card::before {
|
||||
@apply absolute inset-0;
|
||||
@apply rounded-2xl;
|
||||
@apply p-[1px];
|
||||
content: '';
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(64, 64, 64, 1) 0%,
|
||||
rgba(64, 64, 64, 0) 20%,
|
||||
rgba(64, 64, 64, 0.5) 100%
|
||||
);
|
||||
mask:
|
||||
linear-gradient(#fff 0 0) content-box,
|
||||
linear-gradient(#fff 0 0);
|
||||
mask-composite: exclude;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.navigation-link {
|
||||
@apply flex items-center;
|
||||
@apply mb-6;
|
||||
}
|
||||
.navigation-link {
|
||||
@apply flex items-center text-hutopyPrimary;
|
||||
@apply mb-6;
|
||||
}
|
||||
|
||||
.link-button {
|
||||
@apply flex items-center gap-2;
|
||||
@apply text-hutopyPrimary hover:text-hutopySecondary;
|
||||
@apply transition-colors;
|
||||
@apply duration-300;
|
||||
@apply font-medium;
|
||||
}
|
||||
.link-button {
|
||||
@apply flex items-center gap-2;
|
||||
@apply text-hutopyPrimary hover:text-hutopySecondary;
|
||||
@apply transition-colors;
|
||||
@apply duration-300;
|
||||
@apply text-xl;
|
||||
@apply font-semibold;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-6xl;
|
||||
@apply font-medium;
|
||||
@apply mb-8;
|
||||
@apply text-center;
|
||||
}
|
||||
h1 {
|
||||
@apply text-6xl;
|
||||
@apply font-medium;
|
||||
@apply mb-8;
|
||||
@apply text-center;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-lg;
|
||||
@apply font-medium;
|
||||
@apply mb-8;
|
||||
@apply text-center;
|
||||
}
|
||||
p {
|
||||
@apply text-lg;
|
||||
@apply font-medium;
|
||||
@apply mb-8;
|
||||
@apply text-center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,115 +1,125 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<!-- Navigation Link at the top -->
|
||||
<div class="navigation-link">
|
||||
<button class="link-button" @click="goBack()">
|
||||
<v-icon :icon="mdiArrowLeft" />
|
||||
{{ t('returnToCreator') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<!-- Navigation Link at the top -->
|
||||
<div class="navigation-link">
|
||||
<button
|
||||
class="link-button"
|
||||
@click="goBack()"
|
||||
>
|
||||
<v-icon :icon="mdiArrowLeft" />
|
||||
{{ t('returnToCreator') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1>{{ t('title') }}</h1>
|
||||
<p>{{ t('message') }}</p>
|
||||
<h1>{{ t('title') }}</h1>
|
||||
<p>{{ t('message') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { mdiArrowLeft } from '@mdi/js';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { mdiArrowLeft } from '@mdi/js';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
||||
function goBack() {
|
||||
const creatorName = route.params.creator?.split('/')[0] || '';
|
||||
router.push(`/@${creatorName}`);
|
||||
}
|
||||
function goBack() {
|
||||
const creatorName = route.params.creator?.split('/')[0] || '';
|
||||
router.push(`/@${creatorName}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"title": "Payment Failed",
|
||||
"message": "We couldn't process your payment.",
|
||||
"retry": "Try Again",
|
||||
"returnToCreator": "Return to creator page"
|
||||
},
|
||||
"fr": {
|
||||
"title": "Échec du paiement",
|
||||
"message": "Nous n'avons pas pu traiter votre paiement.",
|
||||
"retry": "Réessayer",
|
||||
"returnToCreator": "Retourner à la page du créateur"
|
||||
},
|
||||
"es": {
|
||||
"title": "Pago fallido",
|
||||
"message": "No pudimos procesar su pago.",
|
||||
"retry": "Intentar de nuevo",
|
||||
"returnToCreator": "Volver a la página del creador"
|
||||
}
|
||||
"en": {
|
||||
"title": "Payment Failed",
|
||||
"message": "We couldn't process your payment.",
|
||||
"retry": "Try Again",
|
||||
"returnToCreator": "Return to creator page"
|
||||
},
|
||||
"fr": {
|
||||
"title": "Échec du paiement",
|
||||
"message": "Nous n'avons pas pu traiter votre paiement.",
|
||||
"retry": "Réessayer",
|
||||
"returnToCreator": "Retourner à la page du créateur"
|
||||
},
|
||||
"es": {
|
||||
"title": "Pago fallido",
|
||||
"message": "No pudimos procesar su pago.",
|
||||
"retry": "Intentar de nuevo",
|
||||
"returnToCreator": "Volver a la página del creador"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
@apply flex items-center justify-center;
|
||||
@apply p-5;
|
||||
@apply w-full;
|
||||
@apply mx-auto;
|
||||
@apply max-w-[1024px];
|
||||
}
|
||||
.container {
|
||||
@apply flex items-center justify-center;
|
||||
@apply p-5;
|
||||
@apply w-full;
|
||||
@apply mx-auto;
|
||||
@apply max-w-[1024px];
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply bg-hSurface text-hOnSurface;
|
||||
@apply p-8;
|
||||
@apply font-sans;
|
||||
@apply rounded-2xl;
|
||||
@apply shadow-2xl;
|
||||
@apply relative;
|
||||
@apply w-full;
|
||||
@apply max-w-2xl;
|
||||
@apply mx-auto;
|
||||
}
|
||||
.card {
|
||||
@apply bg-hSurface text-hOnSurface;
|
||||
@apply p-8;
|
||||
@apply font-sans;
|
||||
@apply rounded-2xl;
|
||||
@apply shadow-2xl;
|
||||
@apply relative;
|
||||
@apply w-full;
|
||||
@apply max-w-2xl;
|
||||
@apply mx-auto;
|
||||
}
|
||||
|
||||
.card::before {
|
||||
content: '';
|
||||
@apply absolute inset-0;
|
||||
@apply rounded-2xl;
|
||||
@apply p-[1px];
|
||||
background: linear-gradient(135deg, rgba(64, 64, 64, 1) 0%, rgba(64, 64, 64, 0) 20%, rgba(64, 64, 64, 0.5) 100%);
|
||||
mask: linear-gradient(#fff 0 0) content-box,
|
||||
linear-gradient(#fff 0 0);
|
||||
mask-composite: exclude;
|
||||
pointer-events: none;
|
||||
}
|
||||
.card::before {
|
||||
content: '';
|
||||
@apply absolute inset-0;
|
||||
@apply rounded-2xl;
|
||||
@apply p-[1px];
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(64, 64, 64, 1) 0%,
|
||||
rgba(64, 64, 64, 0) 20%,
|
||||
rgba(64, 64, 64, 0.5) 100%
|
||||
);
|
||||
mask:
|
||||
linear-gradient(#fff 0 0) content-box,
|
||||
linear-gradient(#fff 0 0);
|
||||
mask-composite: exclude;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.navigation-link {
|
||||
@apply flex items-center;
|
||||
@apply mb-6;
|
||||
}
|
||||
.navigation-link {
|
||||
@apply flex items-center;
|
||||
@apply mb-6;
|
||||
}
|
||||
|
||||
.link-button {
|
||||
@apply flex items-center gap-2;
|
||||
@apply text-hutopyPrimary hover:text-hutopySecondary;
|
||||
@apply transition-colors;
|
||||
@apply duration-300;
|
||||
@apply font-medium;
|
||||
}
|
||||
.link-button {
|
||||
@apply flex items-center gap-2;
|
||||
@apply text-hutopyPrimary hover:text-hutopySecondary;
|
||||
@apply transition-colors;
|
||||
@apply duration-300;
|
||||
@apply text-xl;
|
||||
@apply font-semibold;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-6xl;
|
||||
@apply font-medium;
|
||||
@apply mb-8;
|
||||
@apply text-center;
|
||||
}
|
||||
h1 {
|
||||
@apply text-6xl;
|
||||
@apply font-medium;
|
||||
@apply mb-8;
|
||||
@apply text-center;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-lg;
|
||||
@apply font-medium;
|
||||
@apply mb-8;
|
||||
@apply text-center;
|
||||
}
|
||||
p {
|
||||
@apply text-lg;
|
||||
@apply font-medium;
|
||||
@apply mb-8;
|
||||
@apply text-center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,229 +1,277 @@
|
||||
<template>
|
||||
<div class="flex min-h-full w-full items-center justify-center p-4">
|
||||
<div class="flex w-full max-w-[512px] flex-col gap-10">
|
||||
<h1 class="text-center text-2xl font-bold">
|
||||
{{ t('title') }}
|
||||
</h1>
|
||||
<div class="flex min-h-full w-full items-center justify-center p-4">
|
||||
<div class="flex w-full max-w-[512px] flex-col gap-10">
|
||||
<h1 class="text-center text-2xl font-bold">
|
||||
{{ t('title') }}
|
||||
</h1>
|
||||
|
||||
<form @submit.prevent="handleResetPassword" class="card">
|
||||
<div class="card-content">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="form-field">
|
||||
<label for="password" class="form-label">{{ t('newPassword') }}</label>
|
||||
<div class="relative">
|
||||
<input id="password" v-model="password" :type="showPassword ? 'text' : 'password'" class="form-input"
|
||||
required />
|
||||
<button type="button" @click="showPassword = !showPassword" class="password-toggle">
|
||||
<v-icon size="small" :icon="showPassword ? mdiEyeOff : mdiEye" />
|
||||
</button>
|
||||
</div>
|
||||
<p class="mt-1 text-sm text-gray-500">{{ t('passwordRequirements') }}</p>
|
||||
<form
|
||||
class="card"
|
||||
@submit.prevent="handleResetPassword"
|
||||
>
|
||||
<div class="card-content">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="form-field">
|
||||
<label
|
||||
class="form-label"
|
||||
for="password"
|
||||
>
|
||||
{{ t('newPassword') }}
|
||||
</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
id="password"
|
||||
v-model="password"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
class="form-input"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
class="password-toggle"
|
||||
type="button"
|
||||
@click="showPassword = !showPassword"
|
||||
>
|
||||
<v-icon
|
||||
:icon="showPassword ? mdiEyeOff : mdiEye"
|
||||
size="small"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<p class="mt-1 text-sm text-gray-500">{{ t('passwordRequirements') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label
|
||||
class="form-label"
|
||||
for="confirmPassword"
|
||||
>
|
||||
{{ t('confirmPassword') }}
|
||||
</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
id="confirmPassword"
|
||||
v-model="confirmPassword"
|
||||
:type="showConfirmPassword ? 'text' : 'password'"
|
||||
class="form-input"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
class="password-toggle"
|
||||
type="button"
|
||||
@click="showConfirmPassword = !showConfirmPassword"
|
||||
>
|
||||
<v-icon
|
||||
:icon="showConfirmPassword ? mdiEyeOff : mdiEye"
|
||||
size="small"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="errorMessage"
|
||||
class="error-message"
|
||||
>
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
|
||||
<button
|
||||
:disabled="isLoading"
|
||||
class="primary w-full"
|
||||
type="submit"
|
||||
>
|
||||
<span
|
||||
v-if="isLoading"
|
||||
class="loading-spinner mr-2"
|
||||
></span>
|
||||
{{ t('resetPassword') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Success message -->
|
||||
<div
|
||||
v-if="success"
|
||||
class="success-message"
|
||||
>
|
||||
{{ t('passwordResetSuccess') }}
|
||||
<div class="mt-4">
|
||||
<router-link
|
||||
class="text-blue-500"
|
||||
to="/login"
|
||||
>
|
||||
{{ t('proceedToLogin') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="confirmPassword" class="form-label">{{ t('confirmPassword') }}</label>
|
||||
<div class="relative">
|
||||
<input id="confirmPassword" v-model="confirmPassword" :type="showConfirmPassword ? 'text' : 'password'"
|
||||
class="form-input" required />
|
||||
<button type="button" @click="showConfirmPassword = !showConfirmPassword" class="password-toggle">
|
||||
<v-icon size="small" :icon="showConfirmPassword ? mdiEyeOff : mdiEye" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="errorMessage" class="error-message">
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
|
||||
<button type="submit" class="primary w-full" :disabled="isLoading">
|
||||
<span v-if="isLoading" class="loading-spinner mr-2"></span>
|
||||
{{ t('resetPassword') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Success message -->
|
||||
<div v-if="success" class="success-message">
|
||||
{{ t('passwordResetSuccess') }}
|
||||
<div class="mt-4">
|
||||
<router-link to="/login" class="text-blue-500">
|
||||
{{ t('proceedToLogin') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useClient } from '@/plugins/api.js';
|
||||
import { mdiEye, mdiEyeOff } from '@mdi/js';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useClient } from '@/plugins/api.js';
|
||||
import { mdiEye, mdiEyeOff } from '@mdi/js';
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const clientApi = useClient();
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const clientApi = useClient();
|
||||
|
||||
const email = ref('');
|
||||
const token = ref('');
|
||||
const password = ref('');
|
||||
const confirmPassword = ref('');
|
||||
const showPassword = ref(false);
|
||||
const showConfirmPassword = ref(false);
|
||||
const isLoading = ref(false);
|
||||
const errorMessage = ref('');
|
||||
const success = ref(false);
|
||||
const email = ref('');
|
||||
const token = ref('');
|
||||
const password = ref('');
|
||||
const confirmPassword = ref('');
|
||||
const showPassword = ref(false);
|
||||
const showConfirmPassword = ref(false);
|
||||
const isLoading = ref(false);
|
||||
const errorMessage = ref('');
|
||||
const success = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
// Get email and token from URL query parameters
|
||||
email.value = route.query.email || '';
|
||||
token.value = route.query.token || '';
|
||||
onMounted(() => {
|
||||
// Get email and token from URL query parameters
|
||||
email.value = route.query.email || '';
|
||||
token.value = route.query.token || '';
|
||||
|
||||
// Validate that we have both email and token
|
||||
if (!email.value || !token.value) {
|
||||
errorMessage.value = t('invalidResetLink');
|
||||
}
|
||||
});
|
||||
|
||||
async function handleResetPassword() {
|
||||
// Reset error message
|
||||
errorMessage.value = '';
|
||||
|
||||
// Validate passwords match
|
||||
if (password.value !== confirmPassword.value) {
|
||||
errorMessage.value = t('passwordsDoNotMatch');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate password length
|
||||
if (password.value.length < 8) {
|
||||
errorMessage.value = t('passwordTooShort');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate that we have email and token
|
||||
if (!email.value || !token.value) {
|
||||
errorMessage.value = t('invalidResetLink');
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading.value = true;
|
||||
|
||||
try {
|
||||
// Call password reset API
|
||||
await clientApi.post('api/users/reset-password', {
|
||||
email: email.value,
|
||||
token: token.value,
|
||||
newPassword: password.value
|
||||
// Validate that we have both email and token
|
||||
if (!email.value || !token.value) {
|
||||
errorMessage.value = t('invalidResetLink');
|
||||
}
|
||||
});
|
||||
|
||||
// Show success message
|
||||
success.value = true;
|
||||
async function handleResetPassword() {
|
||||
// Reset error message
|
||||
errorMessage.value = '';
|
||||
|
||||
// Clear form fields
|
||||
password.value = '';
|
||||
confirmPassword.value = '';
|
||||
// Validate passwords match
|
||||
if (password.value !== confirmPassword.value) {
|
||||
errorMessage.value = t('passwordsDoNotMatch');
|
||||
return;
|
||||
}
|
||||
|
||||
// Redirect to login after a delay
|
||||
setTimeout(() => {
|
||||
router.push('/login');
|
||||
}, 5000);
|
||||
} catch (error) {
|
||||
console.error('Password reset failed:', error);
|
||||
errorMessage.value = error.response?.data || t('resetFailed');
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
// Validate password length
|
||||
if (password.value.length < 8) {
|
||||
errorMessage.value = t('passwordTooShort');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate that we have email and token
|
||||
if (!email.value || !token.value) {
|
||||
errorMessage.value = t('invalidResetLink');
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading.value = true;
|
||||
|
||||
try {
|
||||
// Call password reset API
|
||||
await clientApi.post('api/users/reset-password', {
|
||||
email: email.value,
|
||||
token: token.value,
|
||||
newPassword: password.value,
|
||||
});
|
||||
|
||||
// Show success message
|
||||
success.value = true;
|
||||
|
||||
// Clear form fields
|
||||
password.value = '';
|
||||
confirmPassword.value = '';
|
||||
|
||||
// Redirect to login after a delay
|
||||
setTimeout(() => {
|
||||
router.push('/login');
|
||||
}, 5000);
|
||||
} catch (error) {
|
||||
console.error('Password reset failed:', error);
|
||||
errorMessage.value = error.response?.data || t('resetFailed');
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.card {
|
||||
@apply bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden;
|
||||
}
|
||||
form {
|
||||
@apply bg-hSurface rounded-xl p-4;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
@apply p-6;
|
||||
}
|
||||
.form-field {
|
||||
@apply flex flex-col mb-4;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
@apply flex flex-col mb-4;
|
||||
}
|
||||
.form-label {
|
||||
@apply block mb-2 text-sm font-medium text-gray-700 dark:text-gray-300;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
@apply block mb-2 text-sm font-medium text-gray-700 dark:text-gray-300;
|
||||
}
|
||||
.form-input {
|
||||
@apply bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:text-white;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
@apply bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:text-white;
|
||||
}
|
||||
.primary {
|
||||
@apply bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg text-sm px-5 py-2.5 focus:outline-none focus:ring-4 focus:ring-blue-300 disabled:opacity-50 disabled:cursor-not-allowed;
|
||||
}
|
||||
|
||||
.primary {
|
||||
@apply bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg text-sm px-5 py-2.5 focus:outline-none focus:ring-4 focus:ring-blue-300 disabled:opacity-50 disabled:cursor-not-allowed;
|
||||
}
|
||||
.error-message {
|
||||
@apply p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-100 dark:bg-red-900 dark:text-red-300;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
@apply p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-100 dark:bg-red-900 dark:text-red-300;
|
||||
}
|
||||
.success-message {
|
||||
@apply p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-100 dark:bg-green-900 dark:text-green-300 text-center;
|
||||
}
|
||||
|
||||
.success-message {
|
||||
@apply p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-100 dark:bg-green-900 dark:text-green-300 text-center;
|
||||
}
|
||||
.password-toggle {
|
||||
@apply absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300;
|
||||
}
|
||||
|
||||
.password-toggle {
|
||||
@apply absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300;
|
||||
}
|
||||
|
||||
|
||||
.loading-spinner {
|
||||
@apply inline-block h-4 w-4 animate-spin rounded-full border-2 border-solid border-current border-r-transparent align-[-0.125em] motion-reduce:animate-[spin_1.5s_linear_infinite];
|
||||
}
|
||||
.loading-spinner {
|
||||
@apply inline-block h-4 w-4 animate-spin rounded-full border-2 border-solid border-current border-r-transparent align-[-0.125em] motion-reduce:animate-[spin_1.5s_linear_infinite];
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"title": "Reset Your Password",
|
||||
"newPassword": "New Password",
|
||||
"confirmPassword": "Confirm Password",
|
||||
"passwordRequirements": "Password must be at least 8 characters",
|
||||
"resetPassword": "Reset Password",
|
||||
"passwordResetSuccess": "Your password has been reset successfully!",
|
||||
"proceedToLogin": "Proceed to Login",
|
||||
"passwordsDoNotMatch": "Passwords do not match",
|
||||
"passwordTooShort": "Password must be at least 8 characters long",
|
||||
"resetFailed": "Password reset failed. Please try again or request a new reset link.",
|
||||
"invalidResetLink": "Invalid or expired reset link. Please request a new password reset."
|
||||
},
|
||||
"fr": {
|
||||
"title": "Réinitialiser Votre Mot de Passe",
|
||||
"newPassword": "Nouveau Mot de Passe",
|
||||
"confirmPassword": "Confirmer le Mot de Passe",
|
||||
"passwordRequirements": "Le mot de passe doit comporter au moins 8 caractères",
|
||||
"resetPassword": "Réinitialiser le Mot de Passe",
|
||||
"passwordResetSuccess": "Votre mot de passe a été réinitialisé avec succès!",
|
||||
"proceedToLogin": "Procéder à la Connexion",
|
||||
"passwordsDoNotMatch": "Les mots de passe ne correspondent pas",
|
||||
"passwordTooShort": "Le mot de passe doit comporter au moins 8 caractères",
|
||||
"resetFailed": "Échec de la réinitialisation du mot de passe. Veuillez réessayer ou demander un nouveau lien de réinitialisation.",
|
||||
"invalidResetLink": "Lien de réinitialisation invalide ou expiré. Veuillez demander une nouvelle réinitialisation de mot de passe."
|
||||
},
|
||||
"es": {
|
||||
"title": "Restablecer su Contraseña",
|
||||
"newPassword": "Nueva Contraseña",
|
||||
"confirmPassword": "Confirmar Contraseña",
|
||||
"passwordRequirements": "La contraseña debe tener al menos 8 caracteres",
|
||||
"resetPassword": "Restablecer Contraseña",
|
||||
"passwordResetSuccess": "¡Su contraseña ha sido restablecida con éxito!",
|
||||
"proceedToLogin": "Proceder al Inicio de Sesión",
|
||||
"passwordsDoNotMatch": "Las contraseñas no coinciden",
|
||||
"passwordTooShort": "La contraseña debe tener al menos 8 caracteres",
|
||||
"resetFailed": "Error al restablecer la contraseña. Inténtelo de nuevo o solicite un nuevo enlace de restablecimiento.",
|
||||
"invalidResetLink": "Enlace de restablecimiento inválido o caducado. Solicite un nuevo restablecimiento de contraseña."
|
||||
}
|
||||
"en": {
|
||||
"title": "Reset Your Password",
|
||||
"newPassword": "New Password",
|
||||
"confirmPassword": "Confirm Password",
|
||||
"passwordRequirements": "Password must be at least 8 characters",
|
||||
"resetPassword": "Reset Password",
|
||||
"passwordResetSuccess": "Your password has been reset successfully!",
|
||||
"proceedToLogin": "Proceed to Login",
|
||||
"passwordsDoNotMatch": "Passwords do not match",
|
||||
"passwordTooShort": "Password must be at least 8 characters long",
|
||||
"resetFailed": "Password reset failed. Please try again or request a new reset link.",
|
||||
"invalidResetLink": "Invalid or expired reset link. Please request a new password reset."
|
||||
},
|
||||
"fr": {
|
||||
"title": "Réinitialiser Votre Mot de Passe",
|
||||
"newPassword": "Nouveau Mot de Passe",
|
||||
"confirmPassword": "Confirmer le Mot de Passe",
|
||||
"passwordRequirements": "Le mot de passe doit comporter au moins 8 caractères",
|
||||
"resetPassword": "Réinitialiser le Mot de Passe",
|
||||
"passwordResetSuccess": "Votre mot de passe a été réinitialisé avec succès!",
|
||||
"proceedToLogin": "Procéder à la Connexion",
|
||||
"passwordsDoNotMatch": "Les mots de passe ne correspondent pas",
|
||||
"passwordTooShort": "Le mot de passe doit comporter au moins 8 caractères",
|
||||
"resetFailed": "Échec de la réinitialisation du mot de passe. Veuillez réessayer ou demander un nouveau lien de réinitialisation.",
|
||||
"invalidResetLink": "Lien de réinitialisation invalide ou expiré. Veuillez demander une nouvelle réinitialisation de mot de passe."
|
||||
},
|
||||
"es": {
|
||||
"title": "Restablecer su Contraseña",
|
||||
"newPassword": "Nueva Contraseña",
|
||||
"confirmPassword": "Confirmar Contraseña",
|
||||
"passwordRequirements": "La contraseña debe tener al menos 8 caracteres",
|
||||
"resetPassword": "Restablecer Contraseña",
|
||||
"passwordResetSuccess": "¡Su contraseña ha sido restablecida con éxito!",
|
||||
"proceedToLogin": "Proceder al Inicio de Sesión",
|
||||
"passwordsDoNotMatch": "Las contraseñas no coinciden",
|
||||
"passwordTooShort": "La contraseña debe tener al menos 8 caracteres",
|
||||
"resetFailed": "Error al restablecer la contraseña. Inténtelo de nuevo o solicite un nuevo enlace de restablecimiento.",
|
||||
"invalidResetLink": "Enlace de restablecimiento inválido o caducado. Solicite un nuevo restablecimiento de contraseña."
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
@@ -87,16 +87,21 @@
|
||||
|
||||
<!-- Contact Information Section -->
|
||||
<div v-if="phoneNumber || email" class="contact-info mt-6">
|
||||
|
||||
<!-- Phone Number -->
|
||||
<div v-if="phoneNumber" class="contact-item">
|
||||
{{ phoneNumber }}
|
||||
<div v-if="phoneNumber" class="contact-capsule" @click="callPhone">
|
||||
<v-icon :icon="mdiPhone" class="contact-icon" />
|
||||
<span class="contact-text">{{ phoneNumber }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Email -->
|
||||
<div v-if="email" class="contact-item">
|
||||
{{ email }}
|
||||
<div v-if="email" class="contact-capsule" @click="sendEmail">
|
||||
<v-icon :icon="mdiEmail" class="contact-icon" />
|
||||
<span class="contact-text">{{ email }}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -112,12 +117,14 @@ import { buildEmbedUrl, isValidYouTubeUrlOrId, extractVideoId } from '@/utils/yo
|
||||
import AlbumEditor from "@/views/creators/AlbumEditor.vue";
|
||||
import AlbumView from "@/views/creators/AlbumView.vue";
|
||||
import AlbumViewer from './AlbumViewer.vue';
|
||||
import { mdiPencil, mdiCheck, mdiClose } from '@mdi/js';
|
||||
import { useToast } from 'vue-toastification';
|
||||
import { mdiPencil, mdiCheck, mdiClose, mdiPhone, mdiEmail } from '@mdi/js';
|
||||
|
||||
const { t } = useI18n();
|
||||
const creatorProfileStore = useCreatorProfileStore();
|
||||
const brandingStore = useBrandingStore();
|
||||
const client = useClient();
|
||||
const toast = useToast();
|
||||
|
||||
const isLoading = ref(true);
|
||||
const isSaving = ref(false);
|
||||
@@ -143,6 +150,21 @@ const editableVideoUrl = ref("");
|
||||
const videoUrlError = ref("");
|
||||
const descriptionError = ref("");
|
||||
|
||||
function callPhone() {
|
||||
if (phoneNumber.value) {
|
||||
toast.info('Calling your contact');
|
||||
// Remove formatting and create tel: link
|
||||
const cleanPhone = phoneNumber.value.replace(/\D/g, '');
|
||||
window.location.href = `tel:+1${cleanPhone}`;
|
||||
}
|
||||
}
|
||||
|
||||
function sendEmail() {
|
||||
if (email.value) {
|
||||
window.location.href = `mailto:${email.value}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Computed property to check if we can save
|
||||
const canSave = computed(() => {
|
||||
if (isSaving.value == true) { return false; }
|
||||
@@ -400,11 +422,13 @@ function cancelEdit() {
|
||||
// Désactiver le mode édition
|
||||
isEditMode.value = false;
|
||||
}
|
||||
|
||||
// Add this function to handle photo clicks
|
||||
function handlePhotoClick(index) {
|
||||
selectedPhotoIndex.value = index;
|
||||
showAlbumViewer.value = true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -446,12 +470,27 @@ function handlePhotoClick(index) {
|
||||
}
|
||||
|
||||
.contact-info {
|
||||
@apply text-lg text-justify whitespace-pre-line;
|
||||
@apply flex flex-col items-center;
|
||||
@apply flex flex-col items-center gap-3;
|
||||
}
|
||||
|
||||
.contact-item {
|
||||
@apply text-lg text-center mb-2;
|
||||
.contact-capsule {
|
||||
@apply flex items-center gap-2 px-2 py-1 bg-hSurface ;
|
||||
@apply rounded-xl cursor-pointer transition-all duration-200;
|
||||
@apply hover:shadow-md min-w-fit;
|
||||
@apply border border-hutopyPrimary;
|
||||
}
|
||||
|
||||
.contact-capsule:hover {
|
||||
@apply transform scale-105;
|
||||
}
|
||||
|
||||
.contact-icon {
|
||||
@apply text-hutopyPrimary;
|
||||
@apply text-xl
|
||||
}
|
||||
|
||||
.contact-text {
|
||||
@apply text-hOnSurface font-medium text-base;
|
||||
}
|
||||
|
||||
/* Formatting styles for description */
|
||||
|
||||
@@ -119,7 +119,7 @@ async function createAccount() {
|
||||
"en": {
|
||||
"title": "Create your Hutopy",
|
||||
"cancel": "Cancel",
|
||||
"create": "Create Creator Page",
|
||||
"create": "Create my page",
|
||||
"errors": {
|
||||
"unexpected": "An unexpected error occurred"
|
||||
}
|
||||
@@ -127,7 +127,7 @@ async function createAccount() {
|
||||
"fr": {
|
||||
"title": "Créez votre Hutopy",
|
||||
"cancel": "Annuler",
|
||||
"create": "Créer la page créateur",
|
||||
"create": "Créer ma page",
|
||||
"errors": {
|
||||
"unexpected": "Une erreur inattendue s'est produite"
|
||||
}
|
||||
@@ -135,10 +135,10 @@ async function createAccount() {
|
||||
"es": {
|
||||
"title": "Crea tu Hutopy",
|
||||
"cancel": "Cancelar",
|
||||
"create": "Crear página de creador",
|
||||
"create": "Crear mi página",
|
||||
"errors": {
|
||||
"unexpected": "Se produjo un error inesperado"
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
</i18n>
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
<template>
|
||||
<v-dialog v-model="donationModal">
|
||||
<DonationForm
|
||||
:show-cancel-button="showCancelButton"
|
||||
:creator-id="creatorId"
|
||||
:creator-name="creatorName"
|
||||
:on-success-url="onSuccessUrl"
|
||||
:on-cancelled-url="onCancelledUrl"
|
||||
@cancel="closeDonationDialog"
|
||||
/>
|
||||
</v-dialog>
|
||||
<v-dialog v-model="donationModal">
|
||||
<DonationForm
|
||||
:show-cancel-button="showCancelButton"
|
||||
:creator-id="creatorId"
|
||||
:creator-name="creatorName"
|
||||
:on-success-url="onSuccessUrl"
|
||||
:on-cancelled-url="onCancelledUrl"
|
||||
@cancel="closeDonationDialog"
|
||||
/>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref} from 'vue';
|
||||
import DonationForm from './DonationForm.vue';
|
||||
import { ref } from 'vue';
|
||||
import DonationForm from './DonationForm.vue';
|
||||
|
||||
const props = defineProps({
|
||||
creatorId: {default: 'missing-creator-id', required: true},
|
||||
creatorName: {default: 'missing-creator-name', required: true},
|
||||
onSuccessUrl: {default: 'missing-on-success-u', required: true},
|
||||
onCancelledUrl: {default: 'missing-on-cancelled-url', required: true},
|
||||
showCancelButton: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
});
|
||||
const props = defineProps({
|
||||
creatorId: { default: 'missing-creator-id', required: true },
|
||||
creatorName: { default: 'missing-creator-name', required: true },
|
||||
onSuccessUrl: { default: 'missing-on-success-u', required: true },
|
||||
onCancelledUrl: { default: 'missing-on-cancelled-url', required: true },
|
||||
showCancelButton: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const donationModal = ref(false);
|
||||
const donationModal = ref(false);
|
||||
|
||||
function openDonationDialog() {
|
||||
donationModal.value = true;
|
||||
}
|
||||
function openDonationDialog() {
|
||||
donationModal.value = true;
|
||||
}
|
||||
|
||||
function closeDonationDialog() {
|
||||
donationModal.value = false;
|
||||
emit('close');
|
||||
}
|
||||
function closeDonationDialog() {
|
||||
donationModal.value = false;
|
||||
emit('close');
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
openDonationDialog
|
||||
});
|
||||
</script>
|
||||
defineExpose({
|
||||
openDonationDialog,
|
||||
});
|
||||
</script>
|
||||
@@ -1,207 +1,206 @@
|
||||
<template>
|
||||
<div class="card bg-hSurface text-hOnSurface">
|
||||
<div class="card-title">
|
||||
{{ t('creator.donation.isupport') }}
|
||||
<div class="card dialog bg-hSurface text-hOnSurface">
|
||||
<div class="card-title">
|
||||
{{ t('creator.donation.isupport') }}
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<v-text-field
|
||||
v-model="tipAmountInDollars"
|
||||
:label="t('creator.donation.amount')"
|
||||
:min="0"
|
||||
autofocus
|
||||
class="p-2"
|
||||
clearable
|
||||
density="comfortable"
|
||||
hide-details
|
||||
inputmode="numeric"
|
||||
placeholder="0"
|
||||
prepend-inner-icon="mdi-currency-usd"
|
||||
type="number"
|
||||
variant="outlined"
|
||||
@keydown="preventNonNumeric"
|
||||
></v-text-field>
|
||||
|
||||
<v-textarea
|
||||
v-model="tipMessage"
|
||||
:label="t('creator.donation.message')"
|
||||
auto-grow
|
||||
class="p-2"
|
||||
clearable
|
||||
density="compact"
|
||||
hide-details
|
||||
rows="2"
|
||||
variant="outlined"
|
||||
></v-textarea>
|
||||
</div>
|
||||
|
||||
<div class="card-actions">
|
||||
<button
|
||||
v-if="showCancelButton"
|
||||
class="secondary"
|
||||
@click="$emit('cancel')"
|
||||
>
|
||||
{{ t('common.cancel') }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
:disabled="isProcessing"
|
||||
class="primary"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
<span
|
||||
v-if="isProcessing"
|
||||
class="spinner mr-2"
|
||||
></span>
|
||||
{{ isProcessing ? t('creator.donation.processing') : t('creator.donation.send') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<v-text-field
|
||||
v-model="tipAmountInDollars"
|
||||
type="number"
|
||||
autofocus
|
||||
placeholder="0"
|
||||
:min="0"
|
||||
class="p-2"
|
||||
:label="t('creator.donation.amount')"
|
||||
density="comfortable"
|
||||
variant="outlined"
|
||||
hide-details
|
||||
clearable
|
||||
inputmode="numeric"
|
||||
@keydown="preventNonNumeric"
|
||||
prepend-inner-icon="mdi-currency-usd"
|
||||
></v-text-field>
|
||||
|
||||
<v-textarea
|
||||
v-model="tipMessage"
|
||||
:label="t('creator.donation.message')"
|
||||
class="p-2"
|
||||
rows="2"
|
||||
density="compact"
|
||||
variant="outlined"
|
||||
hide-details
|
||||
clearable
|
||||
auto-grow
|
||||
></v-textarea>
|
||||
|
||||
<div v-if="errorMessage" class="error-message">{{ errorMessage }}</div>
|
||||
</div>
|
||||
|
||||
<div class="card-actions">
|
||||
<button v-if="showCancelButton"
|
||||
class="secondary"
|
||||
@click="$emit('cancel')">
|
||||
{{ t('common.cancel') }}
|
||||
</button>
|
||||
|
||||
<button class="primary"
|
||||
@click="handleSubmit"
|
||||
:disabled="isProcessing">
|
||||
<span v-if="isProcessing" class="spinner mr-2"></span>
|
||||
{{ isProcessing ? t('creator.donation.processing') : t('creator.donation.send') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useClient } from '@/plugins/api.js';
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useClient } from '@/plugins/api.js';
|
||||
import { useToast } from 'vue-toastification';
|
||||
|
||||
const { t } = useI18n();
|
||||
const client = useClient();
|
||||
const { t } = useI18n();
|
||||
const client = useClient();
|
||||
const toast = useToast();
|
||||
|
||||
const props = defineProps({
|
||||
showCancelButton: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
creatorId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
onSuccessUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
onCancelledUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['cancel', 'submit']);
|
||||
|
||||
const tipAmountInDollars = ref('');
|
||||
const tipMessage = ref('');
|
||||
const errorMessage = ref('');
|
||||
const isProcessing = ref(false);
|
||||
|
||||
function preventNonNumeric(event) {
|
||||
const key = event.key;
|
||||
const allowedKeys = ['Backspace', 'ArrowLeft', 'ArrowRight', 'Delete'];
|
||||
|
||||
if (!/^\d$/.test(key) && !allowedKeys.includes(key)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (!tipAmountInDollars.value || tipAmountInDollars.value <= 0) {
|
||||
errorMessage.value = t('creator.donation.errors.invalidAmount');
|
||||
return;
|
||||
}
|
||||
|
||||
isProcessing.value = true;
|
||||
errorMessage.value = '';
|
||||
|
||||
try {
|
||||
const response = await client.post(`/api/tips`, {
|
||||
creatorId: props.creatorId,
|
||||
amount: tipAmountInDollars.value * 100,
|
||||
currency: 'CAD',
|
||||
message: tipMessage.value,
|
||||
checkoutSuccessUrl: props.onSuccessUrl,
|
||||
checkoutCancelledUrl: props.onCancelledUrl,
|
||||
const props = defineProps({
|
||||
showCancelButton: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
creatorId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
onSuccessUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
onCancelledUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.data?.stripeCheckoutUrl) {
|
||||
window.location.href = response.data.stripeCheckoutUrl;
|
||||
} else {
|
||||
throw new Error('No checkout URL received');
|
||||
const emit = defineEmits(['cancel', 'submit']);
|
||||
|
||||
const tipAmountInDollars = ref('');
|
||||
const tipMessage = ref('');
|
||||
const isProcessing = ref(false);
|
||||
|
||||
function preventNonNumeric(event) {
|
||||
const key = event.key;
|
||||
const allowedKeys = ['Backspace', 'ArrowLeft', 'ArrowRight', 'Delete'];
|
||||
|
||||
if (!/^\d$/.test(key) && !allowedKeys.includes(key)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (!tipAmountInDollars.value || tipAmountInDollars.value <= 0) {
|
||||
toast.warning(t('creator.donation.errors.invalidAmount'));
|
||||
return;
|
||||
}
|
||||
|
||||
isProcessing.value = true;
|
||||
|
||||
try {
|
||||
const response = await client.post(`/api/tips`, {
|
||||
creatorId: props.creatorId,
|
||||
amount: tipAmountInDollars.value * 100,
|
||||
currency: 'CAD',
|
||||
message: tipMessage.value,
|
||||
checkoutSuccessUrl: props.onSuccessUrl,
|
||||
checkoutCancelledUrl: props.onCancelledUrl,
|
||||
});
|
||||
|
||||
if (response.data?.url) {
|
||||
window.location.href = response.data.url;
|
||||
} else {
|
||||
throw new Error('No checkout URL received');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
toast.error(t('creator.donation.errors.payment'));
|
||||
isProcessing.value = false;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
errorMessage.value = t('creator.donation.errors.payment');
|
||||
isProcessing.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.error-message {
|
||||
@apply text-white bg-red-500;
|
||||
@apply rounded-md text-center w-full p-2;
|
||||
@apply mt-2;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
@apply inline-block;
|
||||
@apply w-4 h-4;
|
||||
@apply border-2;
|
||||
@apply border-current;
|
||||
@apply border-t-transparent;
|
||||
@apply rounded-full;
|
||||
@apply animate-spin;
|
||||
}
|
||||
.spinner {
|
||||
@apply inline-block;
|
||||
@apply w-4 h-4;
|
||||
@apply border-2;
|
||||
@apply border-current;
|
||||
@apply border-t-transparent;
|
||||
@apply rounded-full;
|
||||
@apply animate-spin;
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"common": {
|
||||
"cancel": "Cancel"
|
||||
},
|
||||
"creator": {
|
||||
"donation": {
|
||||
"isupport": "I Support",
|
||||
"amount": "Amount ($)",
|
||||
"message": "Message (optional)",
|
||||
"send": "Send",
|
||||
"processing": "Processing...",
|
||||
"errors": {
|
||||
"payment": "An error occurred during payment processing",
|
||||
"invalidAmount": "Please enter a valid amount"
|
||||
"en": {
|
||||
"common": {
|
||||
"cancel": "Cancel"
|
||||
},
|
||||
"creator": {
|
||||
"donation": {
|
||||
"isupport": "I Support",
|
||||
"amount": "Amount ($)",
|
||||
"message": "Message (optional)",
|
||||
"send": "Send",
|
||||
"processing": "Processing...",
|
||||
"errors": {
|
||||
"payment": "An error occurred during payment processing",
|
||||
"invalidAmount": "Please enter a valid amount"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"common": {
|
||||
"cancel": "Annuler"
|
||||
},
|
||||
"creator": {
|
||||
"donation": {
|
||||
"isupport": "Je Soutiens",
|
||||
"amount": "Montant ($)",
|
||||
"message": "Message (optionnel)",
|
||||
"send": "Envoyer",
|
||||
"processing": "Traitement en cours...",
|
||||
"errors": {
|
||||
"payment": "Une erreur s'est produite lors du traitement du paiement",
|
||||
"invalidAmount": "Veuillez entrer un montant valide"
|
||||
"fr": {
|
||||
"common": {
|
||||
"cancel": "Annuler"
|
||||
},
|
||||
"creator": {
|
||||
"donation": {
|
||||
"isupport": "Je Soutiens",
|
||||
"amount": "Montant ($)",
|
||||
"message": "Message (optionnel)",
|
||||
"send": "Envoyer",
|
||||
"processing": "Traitement en cours...",
|
||||
"errors": {
|
||||
"payment": "Une erreur s'est produite lors du traitement du paiement",
|
||||
"invalidAmount": "Veuillez entrer un montant valide"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"common": {
|
||||
"cancel": "Cancelar"
|
||||
},
|
||||
"creator": {
|
||||
"donation": {
|
||||
"isupport": "Apoyo",
|
||||
"amount": "Cantidad ($)",
|
||||
"message": "Mensaje (opcional)",
|
||||
"send": "Enviar",
|
||||
"processing": "Procesando...",
|
||||
"errors": {
|
||||
"payment": "Ocurrió un error durante el procesamiento del pago",
|
||||
"invalidAmount": "Por favor ingrese un monto válido"
|
||||
"es": {
|
||||
"common": {
|
||||
"cancel": "Cancelar"
|
||||
},
|
||||
"creator": {
|
||||
"donation": {
|
||||
"isupport": "Apoyo",
|
||||
"amount": "Cantidad ($)",
|
||||
"message": "Mensaje (opcional)",
|
||||
"send": "Enviar",
|
||||
"processing": "Procesando...",
|
||||
"errors": {
|
||||
"payment": "Ocurrió un error durante el procesamiento del pago",
|
||||
"invalidAmount": "Por favor ingrese un monto válido"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
</i18n>
|
||||
@@ -66,7 +66,7 @@ onMounted(() => {
|
||||
emits('update:creatorNameReservationId', reservationId.value);
|
||||
}
|
||||
|
||||
// If the name is the same as the original slug, set reservation state to "reserved"
|
||||
// If the name is the same as the original slug, set the reservation state to "reserved"
|
||||
if (isCurrentSlug.value) {
|
||||
reservationState.value = "reserved";
|
||||
}
|
||||
@@ -166,7 +166,7 @@ onUnmounted(() => {
|
||||
<v-text-field variant="outlined" :label="t('creator.name.label')" v-model="name" @input="handleInput"
|
||||
:error-messages="validationError">
|
||||
<template #prepend-inner>
|
||||
<span class="font-sans text-gray-400">{{ baseUrl }}</span>
|
||||
<span class="text-nowrap font-sans text-gray-400">{{ baseUrl }}</span>
|
||||
</template>
|
||||
|
||||
<template #append-inner>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,7 @@
|
||||
import { ref } from 'vue';
|
||||
import { useAuthStore } from '@/stores/authStore.js';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { mdiEye, mdiEyeOff } from '@mdi/js';
|
||||
|
||||
const { t } = useI18n();
|
||||
const authStore = useAuthStore();
|
||||
|
||||
@@ -8,12 +8,24 @@
|
||||
:label="t('email')"
|
||||
type="email"
|
||||
variant="outlined"
|
||||
:error-messages="emailErrors"
|
||||
:rules="emailRules"
|
||||
validate-on="blur"
|
||||
/>
|
||||
|
||||
<v-alert
|
||||
v-if="!!errorMessage"
|
||||
outlined
|
||||
type="error"
|
||||
class="mt-4">
|
||||
{{ errorMessage }}
|
||||
</v-alert>
|
||||
|
||||
<div class="card-actions">
|
||||
<button class="secondary" @click="$emit('closeRequested')">
|
||||
{{ t('cancel') }}
|
||||
</button>
|
||||
<button class="primary" @click="saveEmail" :disabled="isLoading">
|
||||
<button class="primary" @click="saveEmail" :disabled="!canSave || isLoading">
|
||||
{{ t('save') }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -22,7 +34,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useClient } from '@/plugins/api.js';
|
||||
import { useCreatorProfileStore } from '@/stores/creatorProfileStore.js';
|
||||
@@ -40,6 +52,34 @@ const props = defineProps({
|
||||
|
||||
const email = ref(props.creator.presentation?.email || '');
|
||||
const isLoading = ref(false);
|
||||
const errorMessage = ref('');
|
||||
|
||||
// Email validation
|
||||
const isValidEmail = (email) => {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return emailRegex.test(email);
|
||||
};
|
||||
|
||||
const emailRules = [
|
||||
v => !!v || t('validation.emailRequired'),
|
||||
v => isValidEmail(v) || t('validation.emailInvalid'),
|
||||
];
|
||||
|
||||
const emailErrors = computed(() => {
|
||||
if (!email.value) {
|
||||
return [t('validation.emailRequired')];
|
||||
}
|
||||
if (!isValidEmail(email.value)) {
|
||||
return [t('validation.emailInvalid')];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
const canSave = computed(() => {
|
||||
return email.value &&
|
||||
isValidEmail(email.value) &&
|
||||
email.value !== (props.creator.presentation?.email || '');
|
||||
});
|
||||
|
||||
async function saveEmail() {
|
||||
if (!props.creator.id) {
|
||||
@@ -47,24 +87,34 @@ async function saveEmail() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canSave.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
isLoading.value = true;
|
||||
errorMessage.value = '';
|
||||
|
||||
// Save email
|
||||
await client.post(
|
||||
`/api/creators/${props.creator.id}/email`,
|
||||
{
|
||||
email: email.value || ""
|
||||
email: email.value.trim()
|
||||
}
|
||||
);
|
||||
|
||||
// Refresh creator profile
|
||||
await creatorProfileStore.fetchCreatorProfile();
|
||||
|
||||
|
||||
// Close dialog
|
||||
emit('closeRequested');
|
||||
} catch (error) {
|
||||
console.error("Error saving email:", error);
|
||||
if (error?.response?.data?.errors) {
|
||||
errorMessage.value = error.response.data.errors[0]?.['reason'] || t('errors.unexpected');
|
||||
} else {
|
||||
errorMessage.value = error?.response?.data?.message || error.message || t('errors.unexpected');
|
||||
}
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
@@ -85,19 +135,40 @@ const emit = defineEmits(['closeRequested']);
|
||||
"changeEmail": "Change Email",
|
||||
"email": "Email",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel"
|
||||
"cancel": "Cancel",
|
||||
"validation": {
|
||||
"emailRequired": "Email is required",
|
||||
"emailInvalid": "Please enter a valid email address"
|
||||
},
|
||||
"errors": {
|
||||
"unexpected": "An unexpected error occurred"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"changeEmail": "Modifier l'email",
|
||||
"email": "Email",
|
||||
"save": "Enregistrer",
|
||||
"cancel": "Annuler"
|
||||
"cancel": "Annuler",
|
||||
"validation": {
|
||||
"emailRequired": "L'email est requis",
|
||||
"emailInvalid": "Veuillez entrer une adresse email valide"
|
||||
},
|
||||
"errors": {
|
||||
"unexpected": "Une erreur inattendue s'est produite"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"changeEmail": "Cambiar correo electrónico",
|
||||
"email": "Correo electrónico",
|
||||
"save": "Guardar",
|
||||
"cancel": "Cancelar"
|
||||
"cancel": "Cancelar",
|
||||
"validation": {
|
||||
"emailRequired": "El correo electrónico es obligatorio",
|
||||
"emailInvalid": "Por favor ingrese una dirección de correo electrónico válida"
|
||||
},
|
||||
"errors": {
|
||||
"unexpected": "Se produjo un error inesperado"
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
</i18n>
|
||||
@@ -3,17 +3,33 @@
|
||||
<div class="card-title">{{ t('changePhoneNumber') }}</div>
|
||||
<div class="card-content">
|
||||
<v-text-field
|
||||
v-model="phoneNumber"
|
||||
v-model="displayPhoneNumber"
|
||||
class="w-full p-2"
|
||||
:label="t('phoneNumber')"
|
||||
type="tel"
|
||||
variant="outlined"
|
||||
:error-messages="phoneErrors"
|
||||
:rules="phoneRules"
|
||||
validate-on="blur"
|
||||
:placeholder="t('phonePlaceholder')"
|
||||
@input="handlePhoneInput"
|
||||
@keydown="handleKeydown"
|
||||
maxlength="14"
|
||||
/>
|
||||
|
||||
<v-alert
|
||||
v-if="!!errorMessage"
|
||||
outlined
|
||||
type="error"
|
||||
class="mt-4">
|
||||
{{ errorMessage }}
|
||||
</v-alert>
|
||||
|
||||
<div class="card-actions">
|
||||
<button class="secondary" @click="$emit('closeRequested')">
|
||||
{{ t('cancel') }}
|
||||
</button>
|
||||
<button class="primary" @click="savePhoneNumber" :disabled="isLoading">
|
||||
<button class="primary" @click="savePhoneNumber" :disabled="!canSave || isLoading">
|
||||
{{ t('save') }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -22,7 +38,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useClient } from '@/plugins/api.js';
|
||||
import { useCreatorProfileStore } from '@/stores/creatorProfileStore.js';
|
||||
@@ -38,8 +54,99 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const phoneNumber = ref(props.creator.presentation?.phoneNumber || '');
|
||||
// Format existing phone number to display format
|
||||
const formatPhoneForDisplay = (phone) => {
|
||||
if (!phone) return '';
|
||||
const digits = phone.replace(/\D/g, '');
|
||||
if (digits.length === 10) {
|
||||
return `(${digits.slice(0, 3)}) ${digits.slice(3, 6)}-${digits.slice(6)}`;
|
||||
}
|
||||
return phone;
|
||||
};
|
||||
|
||||
// Extract just the digits from formatted phone
|
||||
const extractDigits = (formattedPhone) => {
|
||||
return formattedPhone.replace(/\D/g, '');
|
||||
};
|
||||
|
||||
const displayPhoneNumber = ref(formatPhoneForDisplay(props.creator.presentation?.phoneNumber || ''));
|
||||
const phoneDigits = ref(extractDigits(displayPhoneNumber.value));
|
||||
const isLoading = ref(false);
|
||||
const errorMessage = ref('');
|
||||
|
||||
// Phone number formatting and validation
|
||||
const formatPhoneNumber = (digits) => {
|
||||
// Remove all non-digits
|
||||
const cleaned = digits.replace(/\D/g, '');
|
||||
|
||||
// Apply formatting based on length
|
||||
if (cleaned.length === 0) return '';
|
||||
if (cleaned.length <= 3) return `(${cleaned}`;
|
||||
if (cleaned.length <= 6) return `(${cleaned.slice(0, 3)}) ${cleaned.slice(3)}`;
|
||||
return `(${cleaned.slice(0, 3)}) ${cleaned.slice(3, 6)}-${cleaned.slice(6, 10)}`;
|
||||
};
|
||||
|
||||
const handlePhoneInput = (event) => {
|
||||
const input = event.target.value;
|
||||
const digits = extractDigits(input);
|
||||
|
||||
// Limit to 10 digits
|
||||
if (digits.length > 10) return;
|
||||
|
||||
phoneDigits.value = digits;
|
||||
displayPhoneNumber.value = formatPhoneNumber(digits);
|
||||
};
|
||||
|
||||
const handleKeydown = (event) => {
|
||||
// Allow backspace, delete, tab, escape, enter
|
||||
if ([8, 9, 27, 13, 46].includes(event.keyCode)) return;
|
||||
|
||||
// Allow Ctrl+A, Ctrl+C, Ctrl+V, Ctrl+X
|
||||
if ((event.ctrlKey || event.metaKey) && [65, 67, 86, 88].includes(event.keyCode)) return;
|
||||
|
||||
// Allow arrow keys
|
||||
if (event.keyCode >= 35 && event.keyCode <= 40) return;
|
||||
|
||||
// Only allow numbers (0-9)
|
||||
if (event.keyCode < 48 || event.keyCode > 57) {
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
// Watch for changes to phoneDigits to update display
|
||||
watch(phoneDigits, (newDigits) => {
|
||||
displayPhoneNumber.value = formatPhoneNumber(newDigits);
|
||||
});
|
||||
|
||||
const isValidPhoneNumber = (digits) => {
|
||||
return digits.length === 10;
|
||||
};
|
||||
|
||||
const phoneRules = [
|
||||
v => {
|
||||
const digits = extractDigits(v);
|
||||
return digits.length > 0 || t('validation.phoneRequired');
|
||||
},
|
||||
v => {
|
||||
const digits = extractDigits(v);
|
||||
return isValidPhoneNumber(digits) || t('validation.phoneInvalid');
|
||||
},
|
||||
];
|
||||
|
||||
const phoneErrors = computed(() => {
|
||||
if (phoneDigits.value.length === 0) {
|
||||
return [t('validation.phoneRequired')];
|
||||
}
|
||||
if (!isValidPhoneNumber(phoneDigits.value)) {
|
||||
return [t('validation.phoneInvalid')];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
const canSave = computed(() => {
|
||||
return phoneDigits.value.length === 10 &&
|
||||
phoneDigits.value !== extractDigits(props.creator.presentation?.phoneNumber || '');
|
||||
});
|
||||
|
||||
async function savePhoneNumber() {
|
||||
if (!props.creator.id) {
|
||||
@@ -47,14 +154,21 @@ async function savePhoneNumber() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canSave.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
isLoading.value = true;
|
||||
errorMessage.value = '';
|
||||
|
||||
// Save phone number
|
||||
// Save the formatted phone number
|
||||
const formattedPhone = formatPhoneNumber(phoneDigits.value);
|
||||
|
||||
await client.post(
|
||||
`/api/creators/${props.creator.id}/phone`,
|
||||
{
|
||||
phoneNumber: phoneNumber.value || ""
|
||||
phoneNumber: formattedPhone
|
||||
}
|
||||
);
|
||||
|
||||
@@ -65,6 +179,11 @@ async function savePhoneNumber() {
|
||||
emit('closeRequested');
|
||||
} catch (error) {
|
||||
console.error("Error saving phone number:", error);
|
||||
if (error?.response?.data?.errors) {
|
||||
errorMessage.value = error.response.data.errors[0]?.['reason'] || t('errors.unexpected');
|
||||
} else {
|
||||
errorMessage.value = error?.response?.data?.message || error.message || t('errors.unexpected');
|
||||
}
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
@@ -84,20 +203,44 @@ const emit = defineEmits(['closeRequested']);
|
||||
"en": {
|
||||
"changePhoneNumber": "Change Phone Number",
|
||||
"phoneNumber": "Phone Number",
|
||||
"phonePlaceholder": "(555) 123-4567",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel"
|
||||
"cancel": "Cancel",
|
||||
"validation": {
|
||||
"phoneRequired": "Phone number is required",
|
||||
"phoneInvalid": "Please enter a complete 10-digit phone number"
|
||||
},
|
||||
"errors": {
|
||||
"unexpected": "An unexpected error occurred"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"changePhoneNumber": "Modifier le numéro de téléphone",
|
||||
"phoneNumber": "Numéro de téléphone",
|
||||
"phonePlaceholder": "(555) 123-4567",
|
||||
"save": "Enregistrer",
|
||||
"cancel": "Annuler"
|
||||
"cancel": "Annuler",
|
||||
"validation": {
|
||||
"phoneRequired": "Le numéro de téléphone est requis",
|
||||
"phoneInvalid": "Veuillez entrer un numéro de téléphone complet à 10 chiffres"
|
||||
},
|
||||
"errors": {
|
||||
"unexpected": "Une erreur inattendue s'est produite"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"changePhoneNumber": "Cambiar número de teléfono",
|
||||
"phoneNumber": "Número de teléfono",
|
||||
"phonePlaceholder": "(555) 123-4567",
|
||||
"save": "Guardar",
|
||||
"cancel": "Cancelar"
|
||||
"cancel": "Cancelar",
|
||||
"validation": {
|
||||
"phoneRequired": "El número de teléfono es obligatorio",
|
||||
"phoneInvalid": "Por favor ingrese un número de teléfono completo de 10 dígitos"
|
||||
},
|
||||
"errors": {
|
||||
"unexpected": "Se produjo un error inesperado"
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
</i18n>
|
||||
Reference in New Issue
Block a user