Procházet zdrojové kódy

refactor: fluxo de pedidos consta a taxa referente a cartao de credito deixando os alertas de desconto com pix para hora do pagamento

Gustavo Mantovani před 11 hodinami
rodič
revize
730b3bf205

+ 47 - 75
package-lock.json

@@ -9,12 +9,13 @@
       "version": "0.0.1",
       "dependencies": {
         "@bufbuild/protobuf": "^2.5.1",
-        "@capacitor/browser": "^8.0.3",
+        "@capacitor/browser": "^7.0.5",
         "@capacitor/camera": "^7.0.5",
+        "@capacitor/core": "^7.6.8",
         "@capacitor/device": "^7.0.1",
-        "@capacitor/geolocation": "^8.2.0",
-        "@capacitor/google-maps": "^8.0.1",
-        "@capacitor/push-notifications": "^8.1.1",
+        "@capacitor/geolocation": "^7.1.8",
+        "@capacitor/google-maps": "^7.2.2",
+        "@capacitor/push-notifications": "^7.0.7",
         "@quasar/cli": "^2.5.0",
         "@quasar/extras": "^1.17.0",
         "axios": "^1.9.0",
@@ -34,7 +35,7 @@
       "devDependencies": {
         "@bufbuild/buf": "^1.54.0",
         "@bufbuild/protoc-gen-es": "^2.5.1",
-        "@capacitor/cli": "^8.3.3",
+        "@capacitor/cli": "^7.6.8",
         "@capacitor/keyboard": "^7.0.1",
         "@capacitor/preferences": "^7.0.1",
         "@capacitor/status-bar": "^7.0.1",
@@ -318,12 +319,12 @@
       }
     },
     "node_modules/@capacitor/browser": {
-      "version": "8.0.3",
-      "resolved": "https://registry.npmjs.org/@capacitor/browser/-/browser-8.0.3.tgz",
-      "integrity": "sha512-WJWPHEPbweiFoHYmVlCbZf5yrqJ2Rchx2Xvbmd+3Lf+Zkpq3nXBThThY2CF69lYEg1NINGF9BcHThIOEU1gZlQ==",
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/@capacitor/browser/-/browser-7.0.5.tgz",
+      "integrity": "sha512-YF/kC1m1e6c81X/agtAnYItVlqiQ/nXLG+Q3QXNDuiMoRynqa3Guu8ZaV9kWvqQcHoE2w18xz7WGpPOuh+R1fA==",
       "license": "MIT",
       "peerDependencies": {
-        "@capacitor/core": ">=8.0.0"
+        "@capacitor/core": ">=7.0.0"
       }
     },
     "node_modules/@capacitor/camera": {
@@ -336,9 +337,9 @@
       }
     },
     "node_modules/@capacitor/cli": {
-      "version": "8.3.3",
-      "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-8.3.3.tgz",
-      "integrity": "sha512-FHebL02KEyU5vs+Os5s1yZuE8QT3FzxoO4nZLywGk7Ny957E6gOujKouGKsnKYq01eAWWJGGV/Fv04rY27tSsw==",
+      "version": "7.6.8",
+      "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-7.6.8.tgz",
+      "integrity": "sha512-sJYLoSS1wVHjDPwRc0grtNZcQZnkQc7TJKoVZdHL2HI5TPCq+27WBrMAo0mXvQQSH2axPYCz5cyRrcqqakOvxQ==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -365,7 +366,7 @@
         "capacitor": "bin/capacitor"
       },
       "engines": {
-        "node": ">=22.0.0"
+        "node": ">=20.0.0"
       }
     },
     "node_modules/@capacitor/cli/node_modules/commander": {
@@ -436,11 +437,10 @@
       }
     },
     "node_modules/@capacitor/core": {
-      "version": "8.3.1",
-      "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-8.3.1.tgz",
-      "integrity": "sha512-UF8ItlHguU1Z6GXfPTeT2gakf+ctNI8pAS1kwSBQlsJMlfD4OPoto/SmKnOxKCQvnF4WRcdWeg6C0zREUNaAQg==",
+      "version": "7.6.8",
+      "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-7.6.8.tgz",
+      "integrity": "sha512-x1xfxvNcTSnj6OoYaAB0n0a0HRvi5f2YjcVnMLxpMhbHDgGDAzzN9z8cnPCYV+SKTvqGF1hezHm82Op32XaAGg==",
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "tslib": "^2.1.0"
       }
@@ -455,29 +455,29 @@
       }
     },
     "node_modules/@capacitor/geolocation": {
-      "version": "8.2.0",
-      "resolved": "https://registry.npmjs.org/@capacitor/geolocation/-/geolocation-8.2.0.tgz",
-      "integrity": "sha512-N29QcoIPmme0xSxRkm7+3hjoHp6mBAOarxecvtCCZKyOBeKiJsFUq981cezg2XWBa6fhCXJMCCjQPngKK/dIag==",
+      "version": "7.1.8",
+      "resolved": "https://registry.npmjs.org/@capacitor/geolocation/-/geolocation-7.1.8.tgz",
+      "integrity": "sha512-x/rJieD2N2zlGvXFRD3ru4ArJWTwXAIYmyhfo5zg4F1DKGos7mCCOvIOSVMdfQmt14SCsmJeO9Qe8EtDGNGCrw==",
       "license": "MIT",
       "dependencies": {
-        "@capacitor/synapse": "^1.0.4"
+        "@capacitor/synapse": "^1.0.3"
       },
       "peerDependencies": {
-        "@capacitor/core": ">=8.0.0"
+        "@capacitor/core": ">=7.0.0"
       }
     },
     "node_modules/@capacitor/google-maps": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/@capacitor/google-maps/-/google-maps-8.0.1.tgz",
-      "integrity": "sha512-XSOyanbtOeO5KrSfoJOpbcSW4EXvfdxp+SUy6umdIGFeR2WJKNnPC6isXn+zjJgJH8kblT2X4fF0dxhZV8wLBg==",
+      "version": "7.2.2",
+      "resolved": "https://registry.npmjs.org/@capacitor/google-maps/-/google-maps-7.2.2.tgz",
+      "integrity": "sha512-BCVXHc+q6i2W3J4e5zM2PApt2eNpgcAiMsvaA6WJYE/GpGiIp6BI4lWsDOGbwZ4dYrUXG8mEozEcQTHZC88Ryw==",
       "license": "MIT",
       "dependencies": {
-        "@googlemaps/js-api-loader": "^2.0.2",
-        "@googlemaps/markerclusterer": "^2.6.2",
-        "@types/google.maps": "^3.58.1"
+        "@googlemaps/js-api-loader": "~1.16.8",
+        "@googlemaps/markerclusterer": "~2.5.3",
+        "@types/google.maps": "~3.58.1"
       },
       "peerDependencies": {
-        "@capacitor/core": ">=8.0.0"
+        "@capacitor/core": ">=7.0.0"
       }
     },
     "node_modules/@capacitor/keyboard": {
@@ -501,12 +501,12 @@
       }
     },
     "node_modules/@capacitor/push-notifications": {
-      "version": "8.1.1",
-      "resolved": "https://registry.npmjs.org/@capacitor/push-notifications/-/push-notifications-8.1.1.tgz",
-      "integrity": "sha512-WqzjPKIbYbARMN+GC0XMAJcxJpUUzqgzS/Ny8RODLrro38pQhm3GXYwX2Mwd+LZlLY39rGImkCkrKyQSNfuikA==",
+      "version": "7.0.7",
+      "resolved": "https://registry.npmjs.org/@capacitor/push-notifications/-/push-notifications-7.0.7.tgz",
+      "integrity": "sha512-TgFsPV4uOez0RtFKsWPz3XCrLxc9th+UyAkillUY9vL6ezVKT35te9Sn4vGR0jeU2U0KUNU7Dt6oSCALnSiEKg==",
       "license": "MIT",
       "peerDependencies": {
-        "@capacitor/core": ">=8.0.0"
+        "@capacitor/core": ">=7.0.0"
       }
     },
     "node_modules/@capacitor/status-bar": {
@@ -1164,22 +1164,18 @@
       }
     },
     "node_modules/@googlemaps/js-api-loader": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-2.0.2.tgz",
-      "integrity": "sha512-bKVuTqatS8Jven5aFqVB7rCHF1VFEzpzyi0ruzO0GUR+A7m9oMqMgtnmpANj7kMYEvvhty8Fk7TnJ1MKjWHu+Q==",
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@types/google.maps": "^3.53.1"
-      }
+      "version": "1.16.10",
+      "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.16.10.tgz",
+      "integrity": "sha512-c2erv2k7P2ilYzMmtYcMgAR21AULosQuUHJbStnrvRk2dG93k5cqptDrh9A8p+ZNlyhiqEOgHW7N9PAizdUM7Q==",
+      "license": "Apache-2.0"
     },
     "node_modules/@googlemaps/markerclusterer": {
-      "version": "2.6.2",
-      "resolved": "https://registry.npmjs.org/@googlemaps/markerclusterer/-/markerclusterer-2.6.2.tgz",
-      "integrity": "sha512-U6uVhq8iWhiIckA89sgRu8OK35mjd6/3CuoZKWakKEf0QmRRWpatlsPb3kqXkoWSmbcZkopRiI4dnW6DQSd7bQ==",
+      "version": "2.5.3",
+      "resolved": "https://registry.npmjs.org/@googlemaps/markerclusterer/-/markerclusterer-2.5.3.tgz",
+      "integrity": "sha512-x7lX0R5yYOoiNectr10wLgCBasNcXFHiADIBdmn7jQllF2B5ENQw5XtZK+hIw4xnV0Df0xhN4LN98XqA5jaiOw==",
       "license": "Apache-2.0",
       "dependencies": {
-        "@types/supercluster": "^7.1.3",
-        "fast-equals": "^5.2.2",
+        "fast-deep-equal": "^3.1.3",
         "supercluster": "^8.0.1"
       }
     },
@@ -2796,16 +2792,10 @@
         "@types/node": "*"
       }
     },
-    "node_modules/@types/geojson": {
-      "version": "7946.0.16",
-      "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
-      "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
-      "license": "MIT"
-    },
     "node_modules/@types/google.maps": {
-      "version": "3.64.0",
-      "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.64.0.tgz",
-      "integrity": "sha512-dN0H6tB4lgLQLovcbPXFYYOEV41TpyyJghzb5jrzjB96FZmjeOghevVdC+BMGd6YqyCqXaggyEtqRXLRjzCBZA==",
+      "version": "3.58.1",
+      "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.58.1.tgz",
+      "integrity": "sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==",
       "license": "MIT"
     },
     "node_modules/@types/har-format": {
@@ -2913,15 +2903,6 @@
       "dev": true,
       "license": "MIT"
     },
-    "node_modules/@types/supercluster": {
-      "version": "7.1.3",
-      "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz",
-      "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/geojson": "*"
-      }
-    },
     "node_modules/@typescript-eslint/project-service": {
       "version": "8.37.0",
       "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.37.0.tgz",
@@ -5672,15 +5653,6 @@
       "dev": true,
       "license": "Apache-2.0"
     },
-    "node_modules/fast-equals": {
-      "version": "5.4.0",
-      "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz",
-      "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
     "node_modules/fast-fifo": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
@@ -6886,9 +6858,9 @@
       }
     },
     "node_modules/kdbush": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz",
-      "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.1.0.tgz",
+      "integrity": "sha512-e9vurzrXJQrFX6ckpHP3bvj5l+9CnYzkxDNnNQ1h2QTqdWsUAJgXiKdGNcOa1EY85dU8KbQ+z/FdQdB7P+9yfQ==",
       "license": "ISC"
     },
     "node_modules/keyv": {

+ 6 - 5
package.json

@@ -23,12 +23,13 @@
   },
   "dependencies": {
     "@bufbuild/protobuf": "^2.5.1",
-    "@capacitor/browser": "^8.0.3",
+    "@capacitor/browser": "^7.0.5",
     "@capacitor/camera": "^7.0.5",
+    "@capacitor/core": "^7.6.8",
     "@capacitor/device": "^7.0.1",
-    "@capacitor/geolocation": "^8.2.0",
-    "@capacitor/google-maps": "^8.0.1",
-    "@capacitor/push-notifications": "^8.1.1",
+    "@capacitor/geolocation": "^7.1.8",
+    "@capacitor/google-maps": "^7.2.2",
+    "@capacitor/push-notifications": "^7.0.7",
     "@quasar/cli": "^2.5.0",
     "@quasar/extras": "^1.17.0",
     "axios": "^1.9.0",
@@ -48,7 +49,7 @@
   "devDependencies": {
     "@bufbuild/buf": "^1.54.0",
     "@bufbuild/protoc-gen-es": "^2.5.1",
-    "@capacitor/cli": "^8.3.3",
+    "@capacitor/cli": "^7.6.8",
     "@capacitor/keyboard": "^7.0.1",
     "@capacitor/preferences": "^7.0.1",
     "@capacitor/status-bar": "^7.0.1",

+ 61 - 81
src-capacitor/package-lock.json

@@ -8,29 +8,30 @@
       "name": "diarista-cliente-app",
       "version": "0.0.1",
       "dependencies": {
-        "@capacitor/android": "^7.2.0",
+        "@capacitor/android": "^7.6.8",
         "@capacitor/app": "^7.0.0",
-        "@capacitor/browser": "^8.0.3",
+        "@capacitor/browser": "^7.0.5",
         "@capacitor/camera": "^7.0.5",
-        "@capacitor/cli": "^8.3.3",
-        "@capacitor/core": "^7.0.0",
+        "@capacitor/cli": "^7.6.8",
+        "@capacitor/core": "^7.6.8",
         "@capacitor/device": "^7.0.1",
-        "@capacitor/geolocation": "^8.2.0",
-        "@capacitor/google-maps": "^8.0.1",
-        "@capacitor/ios": "^7.2.0",
+        "@capacitor/geolocation": "^7.1.8",
+        "@capacitor/google-maps": "^7.2.2",
+        "@capacitor/ios": "^7.6.8",
         "@capacitor/keyboard": "^7.0.1",
         "@capacitor/preferences": "^7.0.1",
-        "@capacitor/push-notifications": "^8.1.1",
+        "@capacitor/push-notifications": "^7.0.7",
         "@capacitor/splash-screen": "^7.0.5",
         "@capacitor/status-bar": "^7.0.1"
       }
     },
     "node_modules/@capacitor/android": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-7.2.0.tgz",
-      "integrity": "sha512-zdhEy3jZPG5Toe/pGzKtDgIiBGywjaoEuQWnGVjBYPlSAEUtAhpZ2At7V0SCb26yluAuzrAUV0Ue+LQeEtHwFQ==",
+      "version": "7.6.8",
+      "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-7.6.8.tgz",
+      "integrity": "sha512-N5LXe1ls+TA0mq+RhtyDdP1JISzAAI+OuLGL3G7OWQxfQQOZYkiEjEJMYqMV6JR421IqpRsYj08JOfC0PFC3NA==",
+      "license": "MIT",
       "peerDependencies": {
-        "@capacitor/core": "^7.2.0"
+        "@capacitor/core": "^7.6.0"
       }
     },
     "node_modules/@capacitor/app": {
@@ -43,12 +44,12 @@
       }
     },
     "node_modules/@capacitor/browser": {
-      "version": "8.0.3",
-      "resolved": "https://registry.npmjs.org/@capacitor/browser/-/browser-8.0.3.tgz",
-      "integrity": "sha512-WJWPHEPbweiFoHYmVlCbZf5yrqJ2Rchx2Xvbmd+3Lf+Zkpq3nXBThThY2CF69lYEg1NINGF9BcHThIOEU1gZlQ==",
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/@capacitor/browser/-/browser-7.0.5.tgz",
+      "integrity": "sha512-YF/kC1m1e6c81X/agtAnYItVlqiQ/nXLG+Q3QXNDuiMoRynqa3Guu8ZaV9kWvqQcHoE2w18xz7WGpPOuh+R1fA==",
       "license": "MIT",
       "peerDependencies": {
-        "@capacitor/core": ">=8.0.0"
+        "@capacitor/core": ">=7.0.0"
       }
     },
     "node_modules/@capacitor/camera": {
@@ -61,9 +62,9 @@
       }
     },
     "node_modules/@capacitor/cli": {
-      "version": "8.4.1",
-      "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-8.4.1.tgz",
-      "integrity": "sha512-t7F2s7fFHCq113xgrggrmK6ctV0/8E5YfLNVLfPHp4GCTDO+tly9fZvWPf2/sOI8lMm18dLT43qbXLRTz/OZgw==",
+      "version": "7.6.8",
+      "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-7.6.8.tgz",
+      "integrity": "sha512-sJYLoSS1wVHjDPwRc0grtNZcQZnkQc7TJKoVZdHL2HI5TPCq+27WBrMAo0mXvQQSH2axPYCz5cyRrcqqakOvxQ==",
       "license": "MIT",
       "dependencies": {
         "@ionic/cli-framework-output": "^2.2.8",
@@ -89,13 +90,13 @@
         "capacitor": "bin/capacitor"
       },
       "engines": {
-        "node": ">=22.0.0"
+        "node": ">=20.0.0"
       }
     },
     "node_modules/@capacitor/core": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-7.2.0.tgz",
-      "integrity": "sha512-2zCnA6RJeZ9ec4470o8QMZEQTWpekw9FNoqm5TLc10jeCrhvHVI8MPgxdZVc3mOdFlyieYu4AS1fNxSqbS57Pw==",
+      "version": "7.6.8",
+      "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-7.6.8.tgz",
+      "integrity": "sha512-x1xfxvNcTSnj6OoYaAB0n0a0HRvi5f2YjcVnMLxpMhbHDgGDAzzN9z8cnPCYV+SKTvqGF1hezHm82Op32XaAGg==",
       "license": "MIT",
       "dependencies": {
         "tslib": "^2.1.0"
@@ -110,37 +111,38 @@
       }
     },
     "node_modules/@capacitor/geolocation": {
-      "version": "8.2.0",
-      "resolved": "https://registry.npmjs.org/@capacitor/geolocation/-/geolocation-8.2.0.tgz",
-      "integrity": "sha512-N29QcoIPmme0xSxRkm7+3hjoHp6mBAOarxecvtCCZKyOBeKiJsFUq981cezg2XWBa6fhCXJMCCjQPngKK/dIag==",
+      "version": "7.1.8",
+      "resolved": "https://registry.npmjs.org/@capacitor/geolocation/-/geolocation-7.1.8.tgz",
+      "integrity": "sha512-x/rJieD2N2zlGvXFRD3ru4ArJWTwXAIYmyhfo5zg4F1DKGos7mCCOvIOSVMdfQmt14SCsmJeO9Qe8EtDGNGCrw==",
       "license": "MIT",
       "dependencies": {
-        "@capacitor/synapse": "^1.0.4"
+        "@capacitor/synapse": "^1.0.3"
       },
       "peerDependencies": {
-        "@capacitor/core": ">=8.0.0"
+        "@capacitor/core": ">=7.0.0"
       }
     },
     "node_modules/@capacitor/google-maps": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/@capacitor/google-maps/-/google-maps-8.0.1.tgz",
-      "integrity": "sha512-XSOyanbtOeO5KrSfoJOpbcSW4EXvfdxp+SUy6umdIGFeR2WJKNnPC6isXn+zjJgJH8kblT2X4fF0dxhZV8wLBg==",
+      "version": "7.2.2",
+      "resolved": "https://registry.npmjs.org/@capacitor/google-maps/-/google-maps-7.2.2.tgz",
+      "integrity": "sha512-BCVXHc+q6i2W3J4e5zM2PApt2eNpgcAiMsvaA6WJYE/GpGiIp6BI4lWsDOGbwZ4dYrUXG8mEozEcQTHZC88Ryw==",
       "license": "MIT",
       "dependencies": {
-        "@googlemaps/js-api-loader": "^2.0.2",
-        "@googlemaps/markerclusterer": "^2.6.2",
-        "@types/google.maps": "^3.58.1"
+        "@googlemaps/js-api-loader": "~1.16.8",
+        "@googlemaps/markerclusterer": "~2.5.3",
+        "@types/google.maps": "~3.58.1"
       },
       "peerDependencies": {
-        "@capacitor/core": ">=8.0.0"
+        "@capacitor/core": ">=7.0.0"
       }
     },
     "node_modules/@capacitor/ios": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-7.2.0.tgz",
-      "integrity": "sha512-MQgRZcXZpbpjN83bjkGrzQd7s3XeHBZplmWf38/msF/siMGJKLrXNmNzmmPIWA5Xpi/aH6UoJFk1wXuU2U+zMg==",
+      "version": "7.6.8",
+      "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-7.6.8.tgz",
+      "integrity": "sha512-TAM1FdI1Cfl8e/wLBo7x5m61V/J1fMEpyxU2psZzHzsa436k2pwEME6CQoBRYdw6Q6gud0jZSPwOVrNn+MI7Ag==",
+      "license": "MIT",
       "peerDependencies": {
-        "@capacitor/core": "^7.2.0"
+        "@capacitor/core": "^7.6.0"
       }
     },
     "node_modules/@capacitor/keyboard": {
@@ -162,12 +164,12 @@
       }
     },
     "node_modules/@capacitor/push-notifications": {
-      "version": "8.1.1",
-      "resolved": "https://registry.npmjs.org/@capacitor/push-notifications/-/push-notifications-8.1.1.tgz",
-      "integrity": "sha512-WqzjPKIbYbARMN+GC0XMAJcxJpUUzqgzS/Ny8RODLrro38pQhm3GXYwX2Mwd+LZlLY39rGImkCkrKyQSNfuikA==",
+      "version": "7.0.7",
+      "resolved": "https://registry.npmjs.org/@capacitor/push-notifications/-/push-notifications-7.0.7.tgz",
+      "integrity": "sha512-TgFsPV4uOez0RtFKsWPz3XCrLxc9th+UyAkillUY9vL6ezVKT35te9Sn4vGR0jeU2U0KUNU7Dt6oSCALnSiEKg==",
       "license": "MIT",
       "peerDependencies": {
-        "@capacitor/core": ">=8.0.0"
+        "@capacitor/core": ">=7.0.0"
       }
     },
     "node_modules/@capacitor/splash-screen": {
@@ -195,22 +197,18 @@
       "license": "ISC"
     },
     "node_modules/@googlemaps/js-api-loader": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-2.1.1.tgz",
-      "integrity": "sha512-yUpAwksbHrlZIWD49JmveNSfBG4oAK0AwMknfSaPMnP5N7UT8oFRVCqwjGb1XQovi//7KLbPQKZpbofiLGzpDw==",
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@types/google.maps": "^3.53.1"
-      }
+      "version": "1.16.10",
+      "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.16.10.tgz",
+      "integrity": "sha512-c2erv2k7P2ilYzMmtYcMgAR21AULosQuUHJbStnrvRk2dG93k5cqptDrh9A8p+ZNlyhiqEOgHW7N9PAizdUM7Q==",
+      "license": "Apache-2.0"
     },
     "node_modules/@googlemaps/markerclusterer": {
-      "version": "2.6.2",
-      "resolved": "https://registry.npmjs.org/@googlemaps/markerclusterer/-/markerclusterer-2.6.2.tgz",
-      "integrity": "sha512-U6uVhq8iWhiIckA89sgRu8OK35mjd6/3CuoZKWakKEf0QmRRWpatlsPb3kqXkoWSmbcZkopRiI4dnW6DQSd7bQ==",
+      "version": "2.5.3",
+      "resolved": "https://registry.npmjs.org/@googlemaps/markerclusterer/-/markerclusterer-2.5.3.tgz",
+      "integrity": "sha512-x7lX0R5yYOoiNectr10wLgCBasNcXFHiADIBdmn7jQllF2B5ENQw5XtZK+hIw4xnV0Df0xhN4LN98XqA5jaiOw==",
       "license": "Apache-2.0",
       "dependencies": {
-        "@types/supercluster": "^7.1.3",
-        "fast-equals": "^5.2.2",
+        "fast-deep-equal": "^3.1.3",
         "supercluster": "^8.0.1"
       }
     },
@@ -470,16 +468,10 @@
         "@types/node": "*"
       }
     },
-    "node_modules/@types/geojson": {
-      "version": "7946.0.16",
-      "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
-      "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
-      "license": "MIT"
-    },
     "node_modules/@types/google.maps": {
-      "version": "3.65.2",
-      "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.65.2.tgz",
-      "integrity": "sha512-e52bmOhGCQSNabFpL48iQlwJybq6rfns8NUVJ20MR7CdPlHQ2RmSCnPbJfrUYJfogrE4OiHQTZ4LXpop+eer1w==",
+      "version": "3.58.1",
+      "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.58.1.tgz",
+      "integrity": "sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==",
       "license": "MIT"
     },
     "node_modules/@types/node": {
@@ -497,15 +489,6 @@
       "integrity": "sha512-+OpjSaq85gvlZAYINyzKpLeiFkSC4EsC6IIiT6v6TLSU5k5U83fHGj9Lel8oKEXM0HqgrMVCjXPDPVICtxF7EQ==",
       "license": "MIT"
     },
-    "node_modules/@types/supercluster": {
-      "version": "7.1.3",
-      "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz",
-      "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/geojson": "*"
-      }
-    },
     "node_modules/@xmldom/xmldom": {
       "version": "0.9.10",
       "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.10.tgz",
@@ -731,14 +714,11 @@
         "node": ">=6"
       }
     },
-    "node_modules/fast-equals": {
-      "version": "5.4.0",
-      "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz",
-      "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6.0.0"
-      }
+    "node_modules/fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "license": "MIT"
     },
     "node_modules/fd-slicer": {
       "version": "1.1.0",

+ 8 - 8
src-capacitor/package.json

@@ -5,19 +5,19 @@
   "author": "zntt <zanattagg@gmail.com>",
   "private": true,
   "dependencies": {
-    "@capacitor/android": "^7.2.0",
+    "@capacitor/android": "^7.6.8",
     "@capacitor/app": "^7.0.0",
-    "@capacitor/browser": "^8.0.3",
+    "@capacitor/browser": "^7.0.5",
     "@capacitor/camera": "^7.0.5",
-    "@capacitor/cli": "^8.3.3",
-    "@capacitor/core": "^7.0.0",
+    "@capacitor/cli": "^7.6.8",
+    "@capacitor/core": "^7.6.8",
     "@capacitor/device": "^7.0.1",
-    "@capacitor/geolocation": "^8.2.0",
-    "@capacitor/google-maps": "^8.0.1",
-    "@capacitor/ios": "^7.2.0",
+    "@capacitor/geolocation": "^7.1.8",
+    "@capacitor/google-maps": "^7.2.2",
+    "@capacitor/ios": "^7.6.8",
     "@capacitor/keyboard": "^7.0.1",
     "@capacitor/preferences": "^7.0.1",
-    "@capacitor/push-notifications": "^8.1.1",
+    "@capacitor/push-notifications": "^7.0.7",
     "@capacitor/splash-screen": "^7.0.5",
     "@capacitor/status-bar": "^7.0.1"
   }

+ 2 - 2
src/App.vue

@@ -4,7 +4,7 @@
 
 <script setup>
 import { useQuasar } from "quasar";
-import { StatusBar } from "@capacitor/status-bar";
+import { StatusBar, Style } from "@capacitor/status-bar";
 import { Capacitor } from "@capacitor/core";
 import { watch, onBeforeMount } from "vue";
 import { useI18n } from "vue-i18n";
@@ -40,7 +40,7 @@ onBeforeMount(async () => {
   if (isNative) await StatusBar.show();
   const { value: themePref } = await Preferences.get({ key: "theme" });
   const theme = themePref || systemTheme;
-  if (isNative) await StatusBar.setStyle({ style: theme.toUpperCase() });
+  if (isNative) await StatusBar.setStyle({ style: Style.Dark });
   const { value: localePref } = await Preferences.get({ key: "locale" });
   const userLocale = localePref || window.navigator.language;
   console.log(theme, userLocale);

+ 43 - 5
src/components/dashboard/DashboardPendingSchedules.vue

@@ -252,16 +252,54 @@ const seeDetails = (item) => {
 
 .progress-track {
   width: 100%;
-  height: 5px;
+  height: 6px;
   background: #e2e8f0;
-  border-radius: 3px;
+  border-radius: 999px;
   overflow: hidden;
 }
 
 .progress-fill {
+  position: relative;
   height: 100%;
-  border-radius: 3px;
-  background: linear-gradient(90deg, #8b5cf6, #ec4899);
-  transition: width 0.4s ease;
+  border-radius: inherit;
+
+  background: linear-gradient(
+    90deg,
+    #3b5cff,
+    #7a4dff,
+    #d94cff
+  );
+
+  transition: width .4s ease;
+  overflow: hidden;
+}
+
+.progress-fill::after {
+  content: "";
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: -35%;
+  width: 35%;
+
+  background: linear-gradient(
+    90deg,
+    transparent,
+    rgba(255,255,255,.45),
+    transparent
+  );
+
+  transform: skewX(-20deg);
+  animation: progressShine 2s linear infinite;
+}
+
+@keyframes progressShine {
+  from {
+    left: -35%;
+  }
+
+  to {
+    left: 135%;
+  }
 }
 </style>

+ 26 - 7
src/components/dashboard/DashboardTodaySchedules.vue

@@ -39,10 +39,14 @@
                     {{ $t("dashboard_client.today_schedules.started_by") }}
                   </template>
 
-                  <template v-else>
+                  <template v-else-if="cardState(item) === 'finished'">
                     {{ $t("dashboard_client.today_schedules.finished_by") }}
                   </template>
 
+                  <template v-else-if="cardState(item) === 'cancelled'">
+                    {{ $t("dashboard_client.today_schedules.cancelled") }}
+                  </template>
+
                   <span class="fontbold">
                     {{ " " + (getFirstName(item.provider_name) || "—") }}
                   </span>
@@ -97,7 +101,7 @@
                   </div>
                 </template>
 
-                <template v-else>
+                <template v-else-if="cardState(item) === 'finished'">
                   <div
                     v-if="item.client_reviewed"
                     class="rate-btn reviewed-badge"
@@ -129,6 +133,12 @@
                     </div>
                   </q-btn>
                 </template>
+
+                <template v-else-if="cardState(item) === 'cancelled'">
+                  <div class="text-negative font10 fontbold text-center">
+                    {{ $t("dashboard_client.today_schedules.cancelled") }}
+                  </div>
+                </template>
               </div>
             </div>
 
@@ -211,6 +221,7 @@ import { useQuasar } from "quasar";
 
 import ProfileHelpDialog from "src/components/profile/ProfileHelpDialog.vue";
 
+
 defineProps({ data: { type: Array, default: () => [] } });
 
 const emit = defineEmits(["rate"]);
@@ -218,15 +229,23 @@ const emit = defineEmits(["rate"]);
 const $q = useQuasar();
 
 const cardState = (item) => {
-  if (!item.code_verified) return "awaiting_code";
+  switch (item.status) {
+    case "finished":
+      return "finished";
 
-  const [h, m] = (item.end_time || "23:59").slice(0, 5).split(":").map(Number);
+    case "started":
+      return "in_progress";
 
-  const endTime = new Date();
+    case "accepted":
+    case "paid":
+      return "awaiting_code";
 
-  endTime.setHours(h, m, 0, 0);
+    case "cancelled":
+      return "cancelled";
 
-  return new Date() >= endTime ? "finished" : "in_progress";
+    default:
+      return "awaiting_code";
+  }
 };
 
 const progressByState = (item) => {

+ 20 - 20
src/components/dashboard/NextSchedulesDetailsDialog.vue

@@ -73,37 +73,22 @@
 
         <template v-else>
           <div
-            v-for="sp in details?.specialities"
-            :key="sp.id"
+            v-for="service in servicesList"
+            :key="service.label"
             class="row col-12 items-center q-gutter-x-sm q-mb-xs text-center"
           >
             <div class="full-width">
               <q-icon
-                :name="sp.has_speciality ? 'mdi-check' : 'mdi-close'"
-                color="primary"
+                color="secondary"
+                name="mdi-check"
                 size="12px"
               />
 
               <span class="text-grey-8 font10 fontmedium q-pl-sm">
-                {{ sp.description }}
+                {{ service.label }}
               </span>
             </div>
           </div>
-
-          <div
-            v-if="!details?.specialities?.length"
-            class="row items-center q-gutter-x-sm"
-          >
-            <q-icon
-              color="secondary"
-              name="mdi-check"
-              size="16px"
-            />
-
-            <span class="text-grey-8 font10 fontmedium">
-              {{ $t("dashboard_client.next_schedules.default_service") }}
-            </span>
-          </div>
         </template>
       </q-card-section>
 
@@ -266,6 +251,21 @@ const providerAge = computed(() => {
   return age;
 });
 
+const servicesList = computed(() => {
+  const scheduleType =
+    details.value?.schedule_type ?? props.schedule.schedule_type;
+
+  const specialities = details.value?.specialities ?? [];
+
+  if (scheduleType === "custom" && specialities.length) {
+    return specialities.map((speciality) => ({
+      label: speciality.description,
+    }));
+  }
+
+  return [{ label: t("dashboard_client.next_schedules.default_service") }];
+});
+
 const total = computed(() =>
   getScheduleTotalWithPlatformFee(
     props.schedule,

+ 8 - 8
src/components/profile/ProfileAddressDialog.vue

@@ -58,14 +58,14 @@
                         </q-item>
 
                         <q-item v-if="!address.is_primary" v-close-popup clickable @click="markAsPrimary(address)">
-                          <q-item-section avatar>
-                            <q-icon name="mdi-star" color="primary" />
-                          </q-item-section>
-                          <q-item-section>
-                            <q-item-label class="text-text">{{ $t('profile.address.mark_as_primary') }}</q-item-label>
-                          </q-item-section>
-                        </q-item>
-
+                            <q-item-section avatar>
+                              <q-icon name="mdi-map-marker" class="gradient-diarista"/>
+                            </q-item-section>
+
+                            <q-item-section>
+                              <q-item-label class="text-text"> {{ $t('profile.address.mark_as_primary') }} </q-item-label>
+                            </q-item-section>
+                          </q-item>
                         <q-separator />
                       </q-list>
                     </q-menu>

+ 203 - 0
src/components/profile/ProfileInfoDialog.vue

@@ -0,0 +1,203 @@
+<template>
+  <q-dialog
+    ref="dialogRef"
+    @hide="onDialogHide"
+  >
+    <q-card class="provider-dialog">
+
+      <q-btn
+        flat
+        round
+        dense
+        icon="close"
+        class="close-btn"
+        @click="closeDialog"
+      />
+
+      <q-card-section class="provider-header">
+
+        <q-avatar
+          size="72px"
+          color="primary"
+          text-color="white"
+          class="provider-avatar"
+        >
+          <img
+            v-if="props.provider.provider_photo"
+            :src="props.provider.provider_photo"
+          >
+
+          <span
+            v-else
+            class="text-subtitle1 text-weight-bold"
+          >
+            {{ initials }}
+          </span>
+        </q-avatar>
+
+        <div class="provider-info">
+
+          <div class="text-h6 text-weight-bold">
+            {{ props.provider.provider_name }}
+          </div>
+
+          <div v-if="props.provider.age" class="text-grey-6 text-body2">
+            {{ `${props.provider.age}` }}
+            </div>
+
+          <div class="text-grey-6">
+            {{ props.provider.district }}
+          </div>
+
+          <div class="provider-stats">
+
+            <div class="row items-center">
+              <q-icon
+                color="amber"
+                name="mdi-star"
+                size="18px"
+              />
+
+              <span class="q-ml-xs">
+                {{ props.provider.average_rating }}
+              </span>
+
+              <span class="text-grey q-ml-xs">
+                {{ `(${props.provider.total_reviews})` }}
+              </span>
+            </div>
+
+            <div class="row items-center">
+              <q-icon
+                color="deep-purple"
+                name="mdi-broom"
+                size="18px"
+              />
+
+              <span class="q-ml-xs">
+                {{ `(${props.provider.total_services})` }}
+              </span>
+            </div>
+
+          </div>
+
+        </div>
+
+      </q-card-section>
+
+      <q-separator />
+
+      <!-- Especialidades -->
+      <q-list
+        v-if="props.provider.specialities?.length"
+        dense
+        class="q-pa-sm"
+      >
+        <q-item
+          v-for="speciality in props.provider.specialities"
+          :key="speciality.id"
+        >
+          <q-item-section avatar>
+            <q-icon
+              name="mdi-check-circle"
+              color="positive"
+            />
+          </q-item-section>
+
+          <q-item-section>
+            {{ speciality.description }}
+          </q-item-section>
+        </q-item>
+      </q-list>
+
+    </q-card>
+  </q-dialog>
+</template>
+
+<script setup>
+import { computed } from "vue";
+import { useDialogPluginComponent } from "quasar";
+
+const props = defineProps({
+  provider: {
+    type: Object,
+    required: true,
+  },
+});
+
+defineEmits(useDialogPluginComponent.emits);
+
+const {
+  dialogRef,
+  onDialogHide,
+} = useDialogPluginComponent();
+
+const closeDialog = () => {
+  dialogRef.value.hide();
+};
+
+const initials = computed(() => {
+  if (!props.provider.provider_name) {
+    return "?";
+  }
+
+  return props.provider.provider_name
+    .trim()
+    .split(" ")
+    .slice(0, 2)
+    .map(name => name[0].toUpperCase())
+    .join("");
+});
+</script>
+
+<style scoped>
+.provider-dialog {
+  width: 380px;
+  max-width: 95vw;
+  border-radius: 14px;
+  overflow: hidden;
+}
+
+.provider-header {
+  display: flex;
+  align-items: center;
+  gap: 18px;
+  padding: 20px;
+}
+
+.provider-avatar {
+  flex-shrink: 0;
+}
+
+.provider-avatar img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.provider-info {
+  flex: 1;
+}
+
+.provider-info .text-h6 {
+  line-height: 1.2;
+}
+
+.provider-stats {
+  display: flex;
+  align-items: center;
+  gap: 6px;
+  margin-top: 8px;
+}
+
+.close-btn {
+  position: absolute;
+  top: 10px;
+  right: 10px;
+  z-index: 2;
+}
+
+.q-list .q-item {
+  min-height: 38px;
+}
+</style>

+ 16 - 7
src/components/profile/ProfilePaymentAddDialog.vue

@@ -123,7 +123,7 @@
                 class="col bg-surface input-border-dark"
                 hide-bottom-space
                 input-class="text-text"
-                mask="##/####"
+                mask="##/##"
                 outlined
                 :error="!!serverErrors.expiration"
                 :error-message="serverErrors.expiration"
@@ -159,7 +159,7 @@
                 mask="####"
                 outlined
                 placeholder="***"
-                type="password"
+                type="text"
                 unmasked-value
                 :error="!!serverErrors.cvv"
                 :error-message="serverErrors.cvv"
@@ -426,17 +426,26 @@ const validateExpiration = (val) => {
     return true;
   }
 
-  if (!validateCardExpiration(val)) {
-    return t('profile.payments.expired_card');
+  const [month, year] = val.split("/");
+
+  if (!month || !year) {
+    return t("profile.payments.expired_card");
   }
 
-  return true;
+  return validateCardExpiration(`${month}/20${year}`)
+    ? true
+    : t("profile.payments.expired_card");
 };
 
 //
 
 const onOKClick = async () => {
   const valid = await formRef.value?.validate();
+  const expirationFormatted = (() => {
+  const [month, year] = form.expiration.split("/");
+
+  return `${month}/20${year}`;
+})();
 
   if (!valid) {
     return;
@@ -447,7 +456,7 @@ const onOKClick = async () => {
       brand: form.brand,
       card_name: form.card_name,
       client_id: props.paymentMethod ? props.paymentMethod.client_id : props.clientId,
-      expiration: form.expiration,
+      expiration: expirationFormatted,
       holder_name: form.holder_name,
       is_active: form.is_active,
       last_four_digits: form.last_four_digits,
@@ -465,7 +474,7 @@ const onOKClick = async () => {
 
     const payload = {
       client_id: props.paymentMethod ? props.paymentMethod.client_id : props.clientId,
-      expiration: form.expiration,
+      expiration: expirationFormatted,
       holder_name: form.holder_name,
       last_four_digits: form.last_four_digits,
       token,

+ 29 - 0
src/css/app.scss

@@ -1,6 +1,35 @@
 @use "sass:map";
 @use "src/css/quasar.variables.scss";
 
+:root {
+  --system-bar-bg: #757575;
+}
+
+body::before,
+body::after {
+  content: "";
+  position: fixed;
+  left: 0;
+  right: 0;
+  background: var(--system-bar-bg);
+  pointer-events: none;
+  z-index: 10000;
+}
+
+body::before {
+  top: 0;
+  height: env(safe-area-inset-top, 0px);
+}
+
+body::after {
+  bottom: 0;
+  height: env(safe-area-inset-bottom, 0px);
+}
+
+.system-bar-spacer {
+  background: var(--system-bar-bg) !important;
+}
+
 .q-page {
   font-family: "Inter", sans-serif;
 }

+ 4 - 3
src/i18n/locales/en.json

@@ -439,7 +439,8 @@
       "in_progress": "in progress",
       "end_time_label": "Ends at",
       "rate_btn": "Rate",
-      "help_btn": "help"
+      "help_btn": "help",
+      "cancelled": "Service cancelled"
     },
     "next_schedules": {
       "title": "Next services",
@@ -596,7 +597,7 @@
       "remove_cancel": "Cancel",
       "active": "Active",
       "inactive": "Inactive",
-      "mmyyyy": "mm/yyyy"
+      "mmyyyy": "mm/yy"
     },
     "favorites": {
       "title": "Favorites",
@@ -639,7 +640,7 @@
       "add_new_address_label": "Add a new address for your services",
       "edit_address": "Edit address",
       "edit": "Edit",
-      "mark_as_primary": "Mark as primary",
+      "mark_as_primary": "Use this",
       "main": "Primary",
       "no_addresses": "No addresses registered",
       "marked_as_primary": "Address marked as primary",

+ 6 - 4
src/i18n/locales/es.json

@@ -439,7 +439,8 @@
       "in_progress": "en progreso",
       "end_time_label": "Término a las",
       "rate_btn": "Avaliar",
-      "help_btn": "ayuda"
+      "help_btn": "ayuda",
+      "cancelled": "Servicio cancelado"
     },
     "next_schedules": {
       "title": "Próximos servicios",
@@ -454,7 +455,8 @@
       "place_home": "casa",
       "place_apartment": "apartamento",
       "place_unknown": "N/A",
-      "details": "ver detalles"
+      "details": "ver detalles",
+      "default_service": "Limpieza estándar"
     },
     "client_proposals": {
       "candidate": "Candidato",
@@ -592,7 +594,7 @@
       "remove_cancel": "Cancelar",
       "active": "Activa",
       "inactive": "Inactiva",
-      "mmyyyy": "mm/aaaa"
+      "mmyyyy": "mm/aa"
     },
     "favorites": {
       "title": "Favoritos",
@@ -635,7 +637,7 @@
       "add_new_address_label": "Agrega una nueva dirección para tus servicios",
       "edit_address": "Editar dirección",
       "edit": "Editar",
-      "mark_as_primary": "Marcar como principal",
+      "mark_as_primary": "Usar esta",
       "main": "Principal",
       "no_addresses": "Sin direcciones registradas",
       "marked_as_primary": "Dirección marcada como principal",

+ 5 - 4
src/i18n/locales/pt.json

@@ -439,7 +439,8 @@
       "in_progress": "em andamento",
       "end_time_label": "Término às",
       "rate_btn": "Avaliar",
-      "help_btn": "ajuda"
+      "help_btn": "ajuda",
+      "cancelled": "Serviço cancelado"
     },
     "next_schedules": {
       "title": "Próximos serviços",
@@ -456,7 +457,7 @@
       "place_unknown": "N/A",
       "details": "ver detalhes",
       "provider_age_unit": "anos",
-      "default_service": "Faxina padrão",
+      "default_service": "Limpeza padrão",
       "btn_close": "fechar",
       "btn_help": "Ajuda"
     },
@@ -596,7 +597,7 @@
       "remove_cancel": "Cancelar",
       "active": "Ativo",
       "inactive": "Inativo",
-      "mmyyyy": "mm/aaaa"
+      "mmyyyy": "mm/aa"
     },
     "favorites": {
       "title": "Favoritos",
@@ -639,7 +640,7 @@
       "add_new_address_label": "Adicione um novo endereço para agendamentos",
       "edit_address": "Editar endereço",
       "edit": "Editar",
-      "mark_as_primary": "Marcar como principal",
+      "mark_as_primary": "Usar este",
       "main": "Principal",
       "no_addresses": "Nenhum endereço cadastrado",
       "marked_as_primary": "Endereço marcado como principal",

+ 8 - 3
src/layouts/MainLayout.vue

@@ -5,7 +5,7 @@
   >
     <q-header
       v-if="$q.screen.lt.sm"
-      class="bg-surface"
+      class="system-bar-spacer"
       :style="{ height: `env(safe-area-inset-top)` }"
     >
     </q-header>
@@ -68,6 +68,8 @@
           </span>
         </router-link>
       </nav>
+
+      <div class="system-bar-spacer provider-bottom-nav-safe-area"></div>
     </q-footer>
   </q-layout>
 </template>
@@ -197,8 +199,11 @@ watch(
   display: grid;
   grid-template-columns: repeat(5, minmax(0, 1fr));
   align-items: end;
-  height: calc(60px + env(safe-area-inset-bottom));
-  padding: 0 0 env(safe-area-inset-bottom);
+  height: 60px;
+}
+
+.provider-bottom-nav-safe-area {
+  height: env(safe-area-inset-bottom, 0px);
 }
 
 .provider-bottom-nav-item {

+ 0 - 9
src/pages/profile/ProfilePage.vue

@@ -20,15 +20,6 @@
         class="profile-card bg-surface shadow-card card-border"
         :flat="false"
       >
-        <q-btn
-          class="absolute-top-right q-ma-sm"
-          color="grey-6"
-          dense
-          flat
-          icon="mdi-share-variant-outline"
-          round
-        />
-
         <q-card-section class="column items-center q-pb-md">
           <q-avatar
             class="shadow-card text-h5"

+ 19 - 2
src/pages/search/components/SchedulingDialog.vue

@@ -126,6 +126,7 @@
                     icon="mdi-information-outline"
                     round
                     size="sm"
+                    @click.stop="openProviderInfo"
                   />
                 </div>
               </div>
@@ -223,13 +224,13 @@
                     />
 
                     <span v-else>
-                      {{ review.schedule?.client?.name?.slice(0, 1) ?? "—" }}
+                      {{ getFirstName(review.schedule?.client?.name)?.slice(0, 1) ?? "—" }}
                     </span>
                   </q-avatar>
 
                   <div class="col-3 text-text font10 fontbold">
                     {{
-                      review.schedule?.client?.name ??
+                      getFirstName(review.schedule?.client?.name) ??
                       $t("scheduling_page.unknown_client")
                     }}
                   </div>
@@ -279,12 +280,14 @@ import {
 
 import { getProviderReceivedReviews } from "src/api/review";
 import { useI18n } from "vue-i18n";
+import { useRouter } from "vue-router";
 import { userStore } from "src/stores/user";
 import { useServicePackageStore } from "src/stores/servicePackage";
 
 import ServicePackageSummaryDialog from "./ServicePackageSummaryDialog.vue";
 import ServiceSelectionSheet from "./ServiceSelectionSheet.vue";
 import ServiceTimeSelectionDialog from "./ServiceTimeSelectionDialog.vue";
+import ProfileInfoDialog from "src/components/profile/ProfileInfoDialog.vue";
 
 defineEmits([...useDialogPluginComponent.emits]);
 
@@ -294,6 +297,7 @@ const props = defineProps({
 
 const { t } = useI18n();
 const $q = useQuasar();
+const router = useRouter();
 const { dialogRef } = useDialogPluginComponent();
 
 const servicePackage = useServicePackageStore();
@@ -573,6 +577,10 @@ const onDateSelected = (val) => {
           type: "positive",
         });
 
+        dialogRef.value.hide();
+
+        router.push({ name: "ScheduleCartPage" });
+
         return;
       }
 
@@ -588,6 +596,15 @@ const onDateSelected = (val) => {
   });
 };
 
+const openProviderInfo = () => {
+  $q.dialog({
+    component: ProfileInfoDialog,
+    componentProps: {
+      provider: props.provider,
+    },
+  });
+};
+
 const toggleFavorite = async () => {
   if (favoriteLoading.value) return;
 

+ 22 - 10
src/pages/search/components/ServiceSelectionSheet.vue

@@ -54,11 +54,14 @@
             </div>
           </div>
 
-          <div class="row items-center no-wrap q-gutter-x-sm">
-            <span class="font12 fontmedium text-text">
-              {{ formatServicePrice(type.price) }}
-            </span>
+           <div
+              v-if="type.price"
+               class="service-price"
+            >
+              {{ formatCurrency(type.price) }}
+            </div>
 
+          <div class="row no-wrap q-gutter-x-xs">
             <q-btn
               color="secondary"
               no-caps
@@ -79,8 +82,8 @@
 <script setup>
 import { computed } from "vue";
 import { useDialogPluginComponent, useQuasar } from "quasar";
-import { useI18n } from "vue-i18n";
 import { formatCurrency } from "src/helpers/utils";
+import { useI18n } from "vue-i18n";
 
 import ServiceTypeInfoDialog from "./ServiceTypeInfoDialog.vue";
 
@@ -99,11 +102,6 @@ const { dialogRef, onDialogCancel, onDialogHide, onDialogOK } =
 
 const { t } = useI18n();
 
-const formatServicePrice = (price) =>
-  price === null || price === undefined
-    ? t("search_page.no_price")
-    : formatCurrency(price);
-
 const slotConflicts = (slotStart, slotEnd, blocks) =>
   blocks.some((b) => {
     const blockEnd = parseInt(b.end_hour);
@@ -184,4 +182,18 @@ const openInfo = (type) => {
 .sheet-card {
   border-radius: 20px 20px 0 0;
 }
+
+.service-price {
+  min-width: 88px;
+  margin: 0 20px;
+  text-align: right;
+
+  font-size: 18px;
+  font-weight: 700;
+  color: var(--q-text);
+}
+
+.service-btn {
+  min-width: 82px;
+}
 </style>

+ 20 - 2
src/pages/search/components/ServiceTimeSelectionDialog.vue

@@ -152,18 +152,36 @@ const timeSlots = computed(() => {
 
   const slots = [];
 
+  const now = new Date();
+
+  const today =
+    `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
+
+  const isToday =
+    props.selectedDate.replace(/\//g, "-") === today;
+
+  const minimumHour = now.getHours() + 2;
+
   for (let start = 7; start + h <= 20; start++) {
     const end = start + h;
 
-    if (slotConflicts(start, end, props.partialBlocks)) continue;
+    // Se a data for hoje, bloqueia horários com menos de 2 horas de antecedência
+    if (isToday && start < minimumHour) {
+      continue;
+    }
+
+    if (slotConflicts(start, end, props.partialBlocks)) {
+      continue;
+    }
 
     slots.push({
+      startHour: start,
       endHour: end,
       label: `${start}h às ${end}h`,
-      startHour: start,
       value: `${start}-${end}`,
     });
   }
+
   return slots;
 });