Kaynağa Gözat

feat: :sparkles: feat (app na loja) ajustes finais para subir app na loja

foram feitos os ajustes finais para subir o app na loja, incluindo splash, icones, nomes, hotfixes para safearea, correcoes no mapa e pagamentos.

fase:dev | origin:escopo
Gustavo Zanatta 4 hafta önce
ebeveyn
işleme
2f775313a1
81 değiştirilmiş dosya ile 629 ekleme ve 826 silme
  1. 1 0
      .gitignore
  2. 10 0
      package-lock.json
  3. 2 1
      package.json
  4. 2 2
      src-capacitor/android/app/build.gradle
  5. 4 0
      src-capacitor/android/app/capacitor.build.gradle
  6. 7 0
      src-capacitor/android/app/src/main/AndroidManifest.xml
  7. 6 0
      src-capacitor/android/app/src/main/java/br/com/diarista/provider/MainActivity.java
  8. BIN
      src-capacitor/android/app/src/main/res/drawable-land-hdpi/splash.png
  9. BIN
      src-capacitor/android/app/src/main/res/drawable-land-mdpi/splash.png
  10. BIN
      src-capacitor/android/app/src/main/res/drawable-land-xhdpi/splash.png
  11. BIN
      src-capacitor/android/app/src/main/res/drawable-land-xxhdpi/splash.png
  12. BIN
      src-capacitor/android/app/src/main/res/drawable-land-xxxhdpi/splash.png
  13. BIN
      src-capacitor/android/app/src/main/res/drawable-port-hdpi/splash.png
  14. BIN
      src-capacitor/android/app/src/main/res/drawable-port-mdpi/splash.png
  15. BIN
      src-capacitor/android/app/src/main/res/drawable-port-xhdpi/splash.png
  16. BIN
      src-capacitor/android/app/src/main/res/drawable-port-xxhdpi/splash.png
  17. BIN
      src-capacitor/android/app/src/main/res/drawable-port-xxxhdpi/splash.png
  18. 0 34
      src-capacitor/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  19. 0 170
      src-capacitor/android/app/src/main/res/drawable/ic_launcher_background.xml
  20. BIN
      src-capacitor/android/app/src/main/res/drawable/splash.png
  21. 3 2
      src-capacitor/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  22. 3 2
      src-capacitor/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  23. BIN
      src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
  24. BIN
      src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png
  25. BIN
      src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
  26. BIN
      src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png
  27. BIN
      src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
  28. BIN
      src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
  29. BIN
      src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png
  30. BIN
      src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
  31. BIN
      src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png
  32. BIN
      src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
  33. BIN
      src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
  34. BIN
      src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png
  35. BIN
      src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
  36. BIN
      src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png
  37. BIN
      src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
  38. BIN
      src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  39. BIN
      src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
  40. BIN
      src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
  41. BIN
      src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png
  42. BIN
      src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
  43. BIN
      src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  44. BIN
      src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
  45. BIN
      src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
  46. BIN
      src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png
  47. BIN
      src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
  48. 0 4
      src-capacitor/android/app/src/main/res/values/ic_launcher_background.xml
  49. 2 2
      src-capacitor/android/app/src/main/res/values/strings.xml
  50. 12 0
      src-capacitor/android/capacitor.settings.gradle
  51. 10 2
      src-capacitor/capacitor.config.json
  52. BIN
      src-capacitor/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png
  53. BIN
      src-capacitor/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png
  54. BIN
      src-capacitor/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png
  55. 181 106
      src-capacitor/package-lock.json
  56. 4 0
      src-capacitor/package.json
  57. 2 2
      src-capacitor/www/index.html
  58. 4 17
      src/api/providerPaymentMethod.js
  59. 1 1
      src/components/dashboard/DashboardHeaderBar.vue
  60. 8 1
      src/components/dashboard/DashboardScrollAreaSchedules.vue
  61. 108 274
      src/components/login/LoginStepFourPanel.vue
  62. 3 0
      src/components/login/LoginStepThreePanel.vue
  63. 4 3
      src/components/profile/ProfileAddressDialog.vue
  64. 1 1
      src/components/profile/ProfileAvailabilityDialog.vue
  65. 102 137
      src/components/profile/ProfileBankDataDialog.vue
  66. 2 1
      src/components/profile/ProfileHelpDialog.vue
  67. 1 1
      src/components/profile/ProfilePrivacyDialog.vue
  68. 1 1
      src/components/profile/ProfileServiceDataDialog.vue
  69. 71 12
      src/components/shared/LocationMapDialog.vue
  70. 12 1
      src/composables/useAuth.js
  71. 13 6
      src/composables/useGeocodingApi.js
  72. 4 1
      src/css/app.scss
  73. 6 1
      src/i18n/locales/en.json
  74. 6 1
      src/i18n/locales/es.json
  75. 6 1
      src/i18n/locales/pt.json
  76. 6 19
      src/layouts/MainLayout.vue
  77. 17 17
      src/pages/LoginPage.vue
  78. 1 1
      src/pages/calendar/CalendarPage.vue
  79. 1 0
      src/pages/opportunities/components/OpportunityDetailsDialog.vue
  80. 1 1
      src/pages/payments/PaymentsPage.vue
  81. 1 1
      src/pages/profile/ProfileEditDialog.vue

+ 1 - 0
.gitignore

@@ -26,6 +26,7 @@ Thumbs.db
 /src-capacitor/platforms
 /src-capacitor/plugins
 /src-capacitor/www
+/src-capacitor/www/
 /src-capacitor/www/assets
 
 /android

+ 10 - 0
package-lock.json

@@ -10,6 +10,7 @@
       "dependencies": {
         "@bufbuild/protobuf": "^2.5.1",
         "@capacitor/browser": "^8.0.3",
+        "@capacitor/camera": "^7.0.5",
         "@capacitor/device": "^7.0.1",
         "@capacitor/geolocation": "^8.2.0",
         "@capacitor/google-maps": "^8.0.1",
@@ -323,6 +324,15 @@
         "@capacitor/core": ">=8.0.0"
       }
     },
+    "node_modules/@capacitor/camera": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/@capacitor/camera/-/camera-7.0.5.tgz",
+      "integrity": "sha512-+53f1xHq8on7O+ULXbgWp00ooWvn3fUkWxTP3p5zHi1nVriCxLbYnY0zTpZQqn52M96vclFKkoABbTVQ3x755w==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@capacitor/core": ">=7.0.0"
+      }
+    },
     "node_modules/@capacitor/core": {
       "version": "8.3.4",
       "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-8.3.4.tgz",

+ 2 - 1
package.json

@@ -2,7 +2,7 @@
   "name": "diarista-prestador-app",
   "version": "0.0.1",
   "description": "Aplicativo para o prestador do Diarista",
-  "productName": "Diarista Prestador App",
+  "productName": "Diarista Profissional App",
   "author": "zntt <zanattagg@gmail.com>",
   "type": "module",
   "private": true,
@@ -24,6 +24,7 @@
   "dependencies": {
     "@bufbuild/protobuf": "^2.5.1",
     "@capacitor/browser": "^8.0.3",
+    "@capacitor/camera": "^7.0.5",
     "@capacitor/device": "^7.0.1",
     "@capacitor/geolocation": "^8.2.0",
     "@capacitor/google-maps": "^8.0.1",

+ 2 - 2
src-capacitor/android/app/build.gradle

@@ -13,8 +13,8 @@ android {
         applicationId "br.com.diarista.provider"
         minSdkVersion rootProject.ext.minSdkVersion
         targetSdkVersion rootProject.ext.targetSdkVersion
-        versionCode 1
-        versionName "1.0"
+        versionCode 3
+        versionName "1.2"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         aaptOptions {
              // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.

+ 4 - 0
src-capacitor/android/app/capacitor.build.gradle

@@ -11,10 +11,14 @@ apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
 dependencies {
     implementation project(':capacitor-app')
     implementation project(':capacitor-browser')
+    implementation project(':capacitor-camera')
     implementation project(':capacitor-device')
+    implementation project(':capacitor-geolocation')
+    implementation project(':capacitor-google-maps')
     implementation project(':capacitor-keyboard')
     implementation project(':capacitor-preferences')
     implementation project(':capacitor-push-notifications')
+    implementation project(':capacitor-splash-screen')
     implementation project(':capacitor-status-bar')
 
 }

+ 7 - 0
src-capacitor/android/app/src/main/AndroidManifest.xml

@@ -9,6 +9,10 @@
         android:supportsRtl="true"
         android:theme="@style/AppTheme">
 
+        <meta-data
+            android:name="com.google.android.geo.API_KEY"
+            android:value="AIzaSyDrVs7amXuXKEu8sYMr-dl8VjNZbgS2frk" />
+
         <activity
             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"
             android:name=".MainActivity"
@@ -39,4 +43,7 @@
     <!-- Permissions -->
 
     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-feature android:name="android.hardware.camera" android:required="false" />
+    <uses-feature android:name="android.hardware.camera.front" android:required="false" />
 </manifest>

+ 6 - 0
src-capacitor/android/app/src/main/java/br/com/diarista/provider/MainActivity.java

@@ -1,5 +1,6 @@
 package br.com.diarista.provider;
 
+import android.graphics.Color;
 import android.os.Bundle;
 import android.webkit.WebView;
 
@@ -9,6 +10,11 @@ public class MainActivity extends BridgeActivity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        // Necessário para @capacitor/google-maps: o mapa nativo renderiza atrás do
+        // WebView, então o WebView precisa ser transparente onde o mapa é exibido.
+        // (O background do body cobre isso nas telas normais — só o LocationMapDialog
+        //  torna a cadeia html/body/#q-app transparente para revelar o mapa.)
+        getBridge().getWebView().setBackgroundColor(Color.TRANSPARENT);
     }
 
     @Override

BIN
src-capacitor/android/app/src/main/res/drawable-land-hdpi/splash.png


BIN
src-capacitor/android/app/src/main/res/drawable-land-mdpi/splash.png


BIN
src-capacitor/android/app/src/main/res/drawable-land-xhdpi/splash.png


BIN
src-capacitor/android/app/src/main/res/drawable-land-xxhdpi/splash.png


BIN
src-capacitor/android/app/src/main/res/drawable-land-xxxhdpi/splash.png


BIN
src-capacitor/android/app/src/main/res/drawable-port-hdpi/splash.png


BIN
src-capacitor/android/app/src/main/res/drawable-port-mdpi/splash.png


BIN
src-capacitor/android/app/src/main/res/drawable-port-xhdpi/splash.png


BIN
src-capacitor/android/app/src/main/res/drawable-port-xxhdpi/splash.png


BIN
src-capacitor/android/app/src/main/res/drawable-port-xxxhdpi/splash.png


+ 0 - 34
src-capacitor/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml

@@ -1,34 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:aapt="http://schemas.android.com/aapt"
-    android:width="108dp"
-    android:height="108dp"
-    android:viewportHeight="108"
-    android:viewportWidth="108">
-    <path
-        android:fillType="evenOdd"
-        android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
-        android:strokeColor="#00000000"
-        android:strokeWidth="1">
-        <aapt:attr name="android:fillColor">
-            <gradient
-                android:endX="78.5885"
-                android:endY="90.9159"
-                android:startX="48.7653"
-                android:startY="61.0927"
-                android:type="linear">
-                <item
-                    android:color="#44000000"
-                    android:offset="0.0" />
-                <item
-                    android:color="#00000000"
-                    android:offset="1.0" />
-            </gradient>
-        </aapt:attr>
-    </path>
-    <path
-        android:fillColor="#FFFFFF"
-        android:fillType="nonZero"
-        android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
-        android:strokeColor="#00000000"
-        android:strokeWidth="1" />
-</vector>

+ 0 - 170
src-capacitor/android/app/src/main/res/drawable/ic_launcher_background.xml

@@ -1,170 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="108dp"
-    android:height="108dp"
-    android:viewportHeight="108"
-    android:viewportWidth="108">
-    <path
-        android:fillColor="#26A69A"
-        android:pathData="M0,0h108v108h-108z" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M9,0L9,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,0L19,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M29,0L29,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M39,0L39,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M49,0L49,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M59,0L59,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M69,0L69,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M79,0L79,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M89,0L89,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M99,0L99,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,9L108,9"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,19L108,19"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,29L108,29"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,39L108,39"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,49L108,49"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,59L108,59"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,69L108,69"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,79L108,79"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,89L108,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,99L108,99"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,29L89,29"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,39L89,39"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,49L89,49"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,59L89,59"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,69L89,69"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,79L89,79"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M29,19L29,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M39,19L39,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M49,19L49,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M59,19L59,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M69,19L69,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M79,19L79,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-</vector>

BIN
src-capacitor/android/app/src/main/res/drawable/splash.png


+ 3 - 2
src-capacitor/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
-    <background android:drawable="@color/ic_launcher_background"/>
+    <background android:drawable="@mipmap/ic_launcher_background"/>
     <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
-</adaptive-icon>
+    <monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
+</adaptive-icon>

+ 3 - 2
src-capacitor/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
-    <background android:drawable="@color/ic_launcher_background"/>
+    <background android:drawable="@mipmap/ic_launcher_background"/>
     <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
-</adaptive-icon>
+    <monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
+</adaptive-icon>

BIN
src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher.png


BIN
src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png


BIN
src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png


BIN
src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png


BIN
src-capacitor/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png


BIN
src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher.png


BIN
src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png


BIN
src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png


BIN
src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png


BIN
src-capacitor/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png


BIN
src-capacitor/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png


+ 0 - 4
src-capacitor/android/app/src/main/res/values/ic_launcher_background.xml

@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <color name="ic_launcher_background">#FFFFFF</color>
-</resources>

+ 2 - 2
src-capacitor/android/app/src/main/res/values/strings.xml

@@ -1,7 +1,7 @@
 <?xml version='1.0' encoding='utf-8'?>
 <resources>
-    <string name="app_name">Diarista Prestador</string>
-    <string name="title_activity_main">Diarista Prestador</string>
+    <string name="app_name">Diária Profissionais</string>
+    <string name="title_activity_main">Diária Profissionais</string>
     <string name="package_name">br.com.diarista.provider</string>
     <string name="custom_url_scheme">br.com.diarista.provider</string>
 </resources>

+ 12 - 0
src-capacitor/android/capacitor.settings.gradle

@@ -8,9 +8,18 @@ project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/
 include ':capacitor-browser'
 project(':capacitor-browser').projectDir = new File('../node_modules/@capacitor/browser/android')
 
+include ':capacitor-camera'
+project(':capacitor-camera').projectDir = new File('../node_modules/@capacitor/camera/android')
+
 include ':capacitor-device'
 project(':capacitor-device').projectDir = new File('../node_modules/@capacitor/device/android')
 
+include ':capacitor-geolocation'
+project(':capacitor-geolocation').projectDir = new File('../node_modules/@capacitor/geolocation/android')
+
+include ':capacitor-google-maps'
+project(':capacitor-google-maps').projectDir = new File('../node_modules/@capacitor/google-maps/android')
+
 include ':capacitor-keyboard'
 project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor/keyboard/android')
 
@@ -20,5 +29,8 @@ project(':capacitor-preferences').projectDir = new File('../node_modules/@capaci
 include ':capacitor-push-notifications'
 project(':capacitor-push-notifications').projectDir = new File('../node_modules/@capacitor/push-notifications/android')
 
+include ':capacitor-splash-screen'
+project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capacitor/splash-screen/android')
+
 include ':capacitor-status-bar'
 project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')

+ 10 - 2
src-capacitor/capacitor.config.json

@@ -1,6 +1,6 @@
 {
   "appId": "br.com.diarista.provider",
-  "appName": "Diarista Prestador",
+  "appName": "Diarista Profissional",
   "webDir": "www",
   "plugins": {
     "Keyboard": {
@@ -10,11 +10,19 @@
     "StatusBar": {
       "overlaysWebView": true
     },
+    "SplashScreen": {
+      "launchAutoHide": false,
+      "backgroundColor": "#8B5CF6",
+      "androidScaleType": "CENTER_CROP",
+      "showSpinner": false,
+      "splashFullScreen": true,
+      "splashImmersive": true
+    },
     "CapacitorCookies": {
       "enabled": true
     },
     "CapacitorHttp": {
-      "enabled": true
+      "enabled": false
     }
   }
 }

BIN
src-capacitor/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png


BIN
src-capacitor/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png


BIN
src-capacitor/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png


+ 181 - 106
src-capacitor/package-lock.json

@@ -1,23 +1,27 @@
 {
-  "name": "quasar-skeleton",
+  "name": "diarista-prestador-app",
   "version": "0.0.1",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
-      "name": "quasar-skeleton",
+      "name": "diarista-prestador-app",
       "version": "0.0.1",
       "dependencies": {
         "@capacitor/android": "^7.2.0",
         "@capacitor/app": "^7.0.0",
         "@capacitor/browser": "^8.0.3",
-        "@capacitor/cli": "^7.0.0",
+        "@capacitor/camera": "^7.0.5",
+        "@capacitor/cli": "^8.3.3",
         "@capacitor/core": "^7.0.0",
         "@capacitor/device": "^7.0.1",
+        "@capacitor/geolocation": "^8.2.0",
+        "@capacitor/google-maps": "^8.0.1",
         "@capacitor/ios": "^7.2.0",
         "@capacitor/keyboard": "^7.0.1",
         "@capacitor/preferences": "^7.0.1",
-        "@capacitor/push-notifications": "^7.0.6",
+        "@capacitor/push-notifications": "^8.1.1",
+        "@capacitor/splash-screen": "^7.0.5",
         "@capacitor/status-bar": "^7.0.1"
       }
     },
@@ -47,10 +51,19 @@
         "@capacitor/core": ">=8.0.0"
       }
     },
+    "node_modules/@capacitor/camera": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/@capacitor/camera/-/camera-7.0.5.tgz",
+      "integrity": "sha512-+53f1xHq8on7O+ULXbgWp00ooWvn3fUkWxTP3p5zHi1nVriCxLbYnY0zTpZQqn52M96vclFKkoABbTVQ3x755w==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@capacitor/core": ">=7.0.0"
+      }
+    },
     "node_modules/@capacitor/cli": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-7.2.0.tgz",
-      "integrity": "sha512-RNW9vtYYYSDmOdguYBSW0VpRnG/d6lGydlc9DLrJ7qbSPxFrotTz9IjkM48O+SruUma61DyuSqJttdbay2xSxg==",
+      "version": "8.4.1",
+      "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-8.4.1.tgz",
+      "integrity": "sha512-t7F2s7fFHCq113xgrggrmK6ctV0/8E5YfLNVLfPHp4GCTDO+tly9fZvWPf2/sOI8lMm18dLT43qbXLRTz/OZgw==",
       "license": "MIT",
       "dependencies": {
         "@ionic/cli-framework-output": "^2.2.8",
@@ -61,13 +74,13 @@
         "env-paths": "^2.2.0",
         "fs-extra": "^11.2.0",
         "kleur": "^4.1.5",
-        "native-run": "^2.0.1",
+        "native-run": "^2.0.3",
         "open": "^8.4.0",
         "plist": "^3.1.0",
         "prompts": "^2.4.2",
         "rimraf": "^6.0.1",
         "semver": "^7.6.3",
-        "tar": "^6.1.11",
+        "tar": "^7.5.3",
         "tslib": "^2.8.1",
         "xml2js": "^0.6.2"
       },
@@ -76,7 +89,7 @@
         "capacitor": "bin/capacitor"
       },
       "engines": {
-        "node": ">=20.0.0"
+        "node": ">=22.0.0"
       }
     },
     "node_modules/@capacitor/core": {
@@ -96,6 +109,32 @@
         "@capacitor/core": ">=7.0.0"
       }
     },
+    "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==",
+      "license": "MIT",
+      "dependencies": {
+        "@capacitor/synapse": "^1.0.4"
+      },
+      "peerDependencies": {
+        "@capacitor/core": ">=8.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==",
+      "license": "MIT",
+      "dependencies": {
+        "@googlemaps/js-api-loader": "^2.0.2",
+        "@googlemaps/markerclusterer": "^2.6.2",
+        "@types/google.maps": "^3.58.1"
+      },
+      "peerDependencies": {
+        "@capacitor/core": ">=8.0.0"
+      }
+    },
     "node_modules/@capacitor/ios": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-7.2.0.tgz",
@@ -123,9 +162,18 @@
       }
     },
     "node_modules/@capacitor/push-notifications": {
-      "version": "7.0.6",
-      "resolved": "https://registry.npmjs.org/@capacitor/push-notifications/-/push-notifications-7.0.6.tgz",
-      "integrity": "sha512-zAhbHpdbc15ImuVGgoFwUZsKI+jjGxy/oO5mgfYKUx8Xl2OskndzhL79PYsCPjyGLbqUR9NRUZJthV9auVT3nw==",
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/@capacitor/push-notifications/-/push-notifications-8.1.1.tgz",
+      "integrity": "sha512-WqzjPKIbYbARMN+GC0XMAJcxJpUUzqgzS/Ny8RODLrro38pQhm3GXYwX2Mwd+LZlLY39rGImkCkrKyQSNfuikA==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@capacitor/core": ">=8.0.0"
+      }
+    },
+    "node_modules/@capacitor/splash-screen": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/@capacitor/splash-screen/-/splash-screen-7.0.5.tgz",
+      "integrity": "sha512-bPG2SamFL7VT5I3XsgsGgJhkiyxq3OXCOVKEDupSieVdtEiG7j2vLbSD0xL+91zteF/qLuxsjbugGy5LD8mS2A==",
       "license": "MIT",
       "peerDependencies": {
         "@capacitor/core": ">=7.0.0"
@@ -140,6 +188,32 @@
         "@capacitor/core": ">=7.0.0"
       }
     },
+    "node_modules/@capacitor/synapse": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/@capacitor/synapse/-/synapse-1.0.4.tgz",
+      "integrity": "sha512-/C1FUo8/OkKuAT4nCIu/34ny9siNHr9qtFezu4kxm6GY1wNFxrCFWjfYx5C1tUhVGz3fxBABegupkpjXvjCHrw==",
+      "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"
+      }
+    },
+    "node_modules/@googlemaps/markerclusterer": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/@googlemaps/markerclusterer/-/markerclusterer-2.6.2.tgz",
+      "integrity": "sha512-U6uVhq8iWhiIckA89sgRu8OK35mjd6/3CuoZKWakKEf0QmRRWpatlsPb3kqXkoWSmbcZkopRiI4dnW6DQSd7bQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@types/supercluster": "^7.1.3",
+        "fast-equals": "^5.2.2",
+        "supercluster": "^8.0.1"
+      }
+    },
     "node_modules/@ionic/cli-framework-output": {
       "version": "2.2.8",
       "resolved": "https://registry.npmjs.org/@ionic/cli-framework-output/-/cli-framework-output-2.2.8.tgz",
@@ -375,6 +449,18 @@
         "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
       }
     },
+    "node_modules/@isaacs/fs-minipass": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+      "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+      "license": "ISC",
+      "dependencies": {
+        "minipass": "^7.0.4"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
     "node_modules/@types/fs-extra": {
       "version": "8.1.5",
       "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz",
@@ -384,6 +470,18 @@
         "@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==",
+      "license": "MIT"
+    },
     "node_modules/@types/node": {
       "version": "22.14.1",
       "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz",
@@ -399,13 +497,22 @@
       "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.8.10",
-      "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
-      "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
+      "version": "0.9.10",
+      "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.10.tgz",
+      "integrity": "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==",
       "license": "MIT",
       "engines": {
-        "node": ">=10.0.0"
+        "node": ">=14.6"
       }
     },
     "node_modules/ansi-regex": {
@@ -516,12 +623,12 @@
       }
     },
     "node_modules/chownr": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
-      "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
-      "license": "ISC",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+      "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+      "license": "BlueOak-1.0.0",
       "engines": {
-        "node": ">=10"
+        "node": ">=18"
       }
     },
     "node_modules/color-convert": {
@@ -624,6 +731,15 @@
         "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/fd-slicer": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
@@ -675,30 +791,6 @@
         "node": ">=14.14"
       }
     },
-    "node_modules/fs-minipass": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
-      "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
-      "license": "ISC",
-      "dependencies": {
-        "minipass": "^3.0.0"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/fs-minipass/node_modules/minipass": {
-      "version": "3.3.6",
-      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
-      "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
-      "license": "ISC",
-      "dependencies": {
-        "yallist": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/glob": {
       "version": "11.0.1",
       "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz",
@@ -812,6 +904,12 @@
         "graceful-fs": "^4.1.6"
       }
     },
+    "node_modules/kdbush": {
+      "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/kleur": {
       "version": "4.1.5",
       "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
@@ -855,40 +953,15 @@
       }
     },
     "node_modules/minizlib": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
-      "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
+      "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
       "license": "MIT",
       "dependencies": {
-        "minipass": "^3.0.0",
-        "yallist": "^4.0.0"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/minizlib/node_modules/minipass": {
-      "version": "3.3.6",
-      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
-      "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
-      "license": "ISC",
-      "dependencies": {
-        "yallist": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/mkdirp": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
-      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
-      "license": "MIT",
-      "bin": {
-        "mkdirp": "bin/cmd.js"
+        "minipass": "^7.1.2"
       },
       "engines": {
-        "node": ">=10"
+        "node": ">= 18"
       }
     },
     "node_modules/ms": {
@@ -898,9 +971,9 @@
       "license": "MIT"
     },
     "node_modules/native-run": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/native-run/-/native-run-2.0.1.tgz",
-      "integrity": "sha512-XfG1FBZLM50J10xH9361whJRC9SHZ0Bub4iNRhhI61C8Jv0e1ud19muex6sNKB51ibQNUJNuYn25MuYET/rE6w==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/native-run/-/native-run-2.0.3.tgz",
+      "integrity": "sha512-U1PllBuzW5d1gfan+88L+Hky2eZx+9gv3Pf6rNBxKbORxi7boHzqiA6QFGSnqMem4j0A9tZ08NMIs5+0m/VS1Q==",
       "license": "MIT",
       "dependencies": {
         "@ionic/utils-fs": "^3.1.7",
@@ -977,12 +1050,12 @@
       "license": "MIT"
     },
     "node_modules/plist": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",
-      "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.1.tgz",
+      "integrity": "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==",
       "license": "MIT",
       "dependencies": {
-        "@xmldom/xmldom": "^0.8.8",
+        "@xmldom/xmldom": "^0.9.10",
         "base64-js": "^1.5.1",
         "xmlbuilder": "^15.1.1"
       },
@@ -1205,30 +1278,29 @@
         "node": ">=8"
       }
     },
-    "node_modules/tar": {
-      "version": "6.2.1",
-      "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
-      "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
+    "node_modules/supercluster": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz",
+      "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==",
       "license": "ISC",
       "dependencies": {
-        "chownr": "^2.0.0",
-        "fs-minipass": "^2.0.0",
-        "minipass": "^5.0.0",
-        "minizlib": "^2.1.1",
-        "mkdirp": "^1.0.3",
-        "yallist": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=10"
+        "kdbush": "^4.0.2"
       }
     },
-    "node_modules/tar/node_modules/minipass": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
-      "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
-      "license": "ISC",
+    "node_modules/tar": {
+      "version": "7.5.19",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.19.tgz",
+      "integrity": "sha512-4LeEWl96twnS2Q7Bz4MGqgazLqO+hJN63GZxXoIqh1T3VweYD997gbU1ItNsQafqqXTXd5WFyFdReLtwvRBNiw==",
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "@isaacs/fs-minipass": "^4.0.0",
+        "chownr": "^3.0.0",
+        "minipass": "^7.1.2",
+        "minizlib": "^3.1.0",
+        "yallist": "^5.0.0"
+      },
       "engines": {
-        "node": ">=8"
+        "node": ">=18"
       }
     },
     "node_modules/through2": {
@@ -1367,10 +1439,13 @@
       }
     },
     "node_modules/yallist": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-      "license": "ISC"
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+      "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=18"
+      }
     },
     "node_modules/yauzl": {
       "version": "2.10.0",

+ 4 - 0
src-capacitor/package.json

@@ -8,13 +8,17 @@
     "@capacitor/android": "^7.2.0",
     "@capacitor/app": "^7.0.0",
     "@capacitor/browser": "^8.0.3",
+    "@capacitor/camera": "^7.0.5",
     "@capacitor/cli": "^8.3.3",
     "@capacitor/core": "^7.0.0",
     "@capacitor/device": "^7.0.1",
+    "@capacitor/geolocation": "^8.2.0",
+    "@capacitor/google-maps": "^8.0.1",
     "@capacitor/ios": "^7.2.0",
     "@capacitor/keyboard": "^7.0.1",
     "@capacitor/preferences": "^7.0.1",
     "@capacitor/push-notifications": "^8.1.1",
+    "@capacitor/splash-screen": "^7.0.5",
     "@capacitor/status-bar": "^7.0.1"
   }
 }

+ 2 - 2
src-capacitor/www/index.html

@@ -1,3 +1,3 @@
-<!DOCTYPE html><html><head><title>Diarista Prestador App</title><meta charset=utf-8><meta name=description content="Aplicativo para o prestador do Diarista"><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width,viewport-fit=cover"><link rel=icon type=image/png sizes=128x128 href=icons/favicon-128x128.png><link rel=icon type=image/png sizes=96x96 href=icons/favicon-96x96.png><link rel=icon type=image/png sizes=32x32 href=icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=icons/favicon-16x16.png><link rel=icon type=image/ico href=favicon.ico>  <script type="module" crossorigin src="./assets/index-CasLVDNn.js"></script>
-  <link rel="stylesheet" crossorigin href="./assets/index-C7REI__B.css">
+<!DOCTYPE html><html><head><title>Diarista Profissional App</title><meta charset=utf-8><meta name=description content="Aplicativo para o prestador do Diarista"><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width,viewport-fit=cover"><link rel=icon type=image/png sizes=128x128 href=icons/favicon-128x128.png><link rel=icon type=image/png sizes=96x96 href=icons/favicon-96x96.png><link rel=icon type=image/png sizes=32x32 href=icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=icons/favicon-16x16.png><link rel=icon type=image/ico href=favicon.ico>  <script type="module" crossorigin src="./assets/index-BFdxlQrK.js"></script>
+  <link rel="stylesheet" crossorigin href="./assets/index-DNrVWvRO.css">
 </head><body><div id=q-app></div></body></html>

+ 4 - 17
src/api/providerPaymentMethod.js

@@ -1,21 +1,8 @@
 import api from "src/api";
 
-export const getProviderPaymentMethods = async (providerId) => {
-  const { data } = await api.get(`/provider/payment-methods/${providerId}`);
-  return data.payload;
-};
-
-export const createProviderPaymentMethod = async (info) => {
-  const { data } = await api.post("/provider/payment-method", info);
-  return data.payload;
-};
-
-export const updateProviderPaymentMethod = async (id, info) => {
-  const { data } = await api.put(`/provider/payment-method/${id}`, info);
-  return data.payload;
-};
-
-export const deleteProviderPaymentMethod = async (id) => {
-  const { data } = await api.delete(`/provider/payment-method/${id}`);
+export const updateProviderBankAccount = async (providerId, bankAccount) => {
+  const { data } = await api.patch(`/provider/${providerId}/bank-account`, {
+    recipient_default_bank_account: bankAccount,
+  });
   return data.payload;
 };

+ 1 - 1
src/components/dashboard/DashboardHeaderBar.vue

@@ -84,7 +84,7 @@ const goToNotifications = () => {
 
 <style scoped lang="scss">
 .dashboard-header {
-  padding-top: calc(env(safe-area-inset-top) + 8px);
+  padding-top: 8px;
   width: 100%;
   box-sizing: border-box;
 }

+ 8 - 1
src/components/dashboard/DashboardScrollAreaSchedules.vue

@@ -17,15 +17,22 @@ import Banner1 from 'src/assets/banner_1.svg';
 import Banner2 from 'src/assets/banner_2.svg';
 
 import { useRouter } from 'vue-router';
+import { useQuasar } from 'quasar';
+import ProfileHelpDialog from 'src/components/profile/ProfileHelpDialog.vue';
 
 const router = useRouter();
+const $q = useQuasar();
 
 const cards = [
   { id: 1, image: Banner1, alt: 'Diária sob medida', routeName: 'OpportunitiesPage' },
-  { id: 2, image: Banner2, alt: 'Escolha profissionais' },
+  { id: 2, image: Banner2, alt: 'Como aceitar uma diária', action: 'help' },
 ];
 
 const goToCard = (card) => {
+  if (card.action === 'help') {
+    $q.dialog({ component: ProfileHelpDialog })
+    return
+  }
   if (card.routeName) {
     router.push({ name: card.routeName })
   }

+ 108 - 274
src/components/login/LoginStepFourPanel.vue

@@ -6,7 +6,7 @@
         <div
           class="photo-circle"
           :class="selfieDone ? 'photo-circle--done' : 'photo-circle--pending'"
-          @click="subStep = 'selfie_camera'"
+          @click="takeSelfie"
         >
           <q-icon name="photo_camera" size="52px" color="white" />
         </div>
@@ -18,7 +18,8 @@
             rounded
             no-caps
             padding="10px 28px"
-            @click="subStep = 'selfie_camera'"
+            :loading="loadingSelfie"
+            @click="takeSelfie"
           />
           <div class="text-text text-center font12">{{ t('provider.login.steps.step_4.selfie_hint') }}</div>
         </template>
@@ -34,7 +35,7 @@
         <div
           class="photo-circle"
           :class="docDone ? 'photo-circle--done' : 'photo-circle--pending'"
-          @click="subStep = 'doc_front_camera'"
+          @click="takeDocFront"
         >
           <q-icon name="mdi-card-account-details-outline" size="52px" color="white" />
         </div>
@@ -46,7 +47,8 @@
             rounded
             no-caps
             padding="10px 28px"
-            @click="subStep = 'doc_front_camera'"
+            :loading="loadingDoc"
+            @click="takeDocFront"
           />
           <div class="text-text text-center font12">{{ t('provider.login.steps.step_4.document_hint') }}</div>
         </template>
@@ -61,113 +63,56 @@
     </div>
 
     <Teleport to="body">
-      <div v-if="subStep !== 'main'" class="fs-overlay">
-        <div v-if="isCameraState" class="fs-camera">
-          <div class="fs-header">
-            <q-btn flat dense round icon="chevron_left" color="black" @click="goBack" />
-            <span class="font14">{{ t('common.actions.back') }}</span>
-          </div>
-          <div class="fs-viewport">
-            <video ref="videoRef" autoplay playsinline muted class="fs-video" />
-            <div v-if="subStep === 'selfie_camera'" class="guide-oval" />
-            <div v-else class="guide-doc" />
-          </div>
-          <div class="fs-footer">
-            <q-btn
-              color="primary-button"
-              :label="captureLabel"
-              rounded
-              no-caps
-              padding="14px 32px"
-              class="full-width"
-              @click="capturePhoto"
-            />
-          </div>
-        </div>
-
-        <div v-else-if="isPreviewState" class="fs-camera">
-          <div class="fs-header">
-            <q-btn flat dense round icon="chevron_left" color="black" @click="goBack" />
-            <span class="font14">{{ t('common.actions.back') }}</span>
-          </div>
-          <div class="fs-viewport">
-            <img :src="currentPreview" class="fs-video fs-preview-img" />
-            <div v-if="subStep === 'selfie_preview'" class="guide-oval" />
-            <div v-else class="guide-doc" />
-          </div>
-          <div class="fs-footer column q-gutter-y-sm">
-            <q-btn
-              outline
-              color="primary-button"
-              :label="t('provider.login.steps.step_4.btn_retake')"
-              rounded
-              no-caps
-              padding="12px 32px"
-              class="full-width"
-              @click="retakePhoto"
-            />
-            <q-btn
-              color="primary-button"
-              :label="subStep === 'selfie_preview' ? t('provider.login.steps.step_4.btn_confirm') : t('provider.login.steps.step_4.btn_use_photo')"
-              rounded
-              no-caps
-              padding="12px 32px"
-              class="full-width"
-              @click="usePhoto"
-            />
-          </div>
-        </div>
-
-        <div v-else class="fs-result">
+      <div v-if="showResult" class="fs-overlay">
+        <div class="fs-result">
           <q-img :src="LogoDiaria" class="q-mb-xl" style="max-width: 150px" />
 
           <div
             class="result-circle"
-            :class="docResult === 'error' ? 'result-circle--error' : 'result-circle--done'"
+            :class="resultError ? 'result-circle--error' : 'result-circle--done'"
           >
             <q-icon
-              :name="subStep === 'selfie_result' ? 'photo_camera' : 'mdi-card-account-details-outline'"
+              :name="resultIcon"
               size="56px"
               color="white"
             />
           </div>
 
-          <template v-if="docResult === 'error'">
+          <template v-if="resultError">
             <q-icon name="cancel" color="negative" size="28px" class="q-mt-md" />
             <div class="text-primary text-center q-mt-xs q-px-lg font14">
               {{ t('provider.login.steps.step_4.error_message') }}
             </div>
           </template>
           <div v-else class="text-primary text-center q-mt-md q-px-lg font14">
-            {{ subStep === 'selfie_result' ? t('provider.login.steps.step_4.selfie_success') : t('provider.login.steps.step_4.document_success') }}
+            {{ resultMessage }}
           </div>
 
           <q-btn
             color="primary-button"
-            :label="docResult === 'error' ? t('provider.login.steps.step_4.btn_retry') : t('provider.login.steps.step_4.btn_continue')"
+            :label="resultError ? t('provider.login.steps.step_4.btn_retry') : t('provider.login.steps.step_4.btn_continue')"
             rounded
             no-caps
             padding="14px 48px"
             class="q-mt-xl"
             style="min-width: 200px"
-            @click="handleResult"
+            @click="closeResult"
           />
 
-          <div v-if="subStep === 'doc_result' && docResult !== 'error'" class="text-grey-6 text-center q-mt-sm font12">
+          <div v-if="!resultError && showDocHint" class="text-grey-6 text-center q-mt-sm font12">
             {{ t('provider.login.steps.step_4.document_hint_result') }}
           </div>
         </div>
-
       </div>
     </Teleport>
 
-    <canvas ref="canvasRef" style="display: none" />
   </q-card-section>
 </template>
 
 <script setup>
-import { ref, computed, watch, onUnmounted, nextTick } from 'vue';
+import { ref, computed } from 'vue';
 import { useI18n } from 'vue-i18n';
+import { Camera, CameraResultType, CameraSource, CameraDirection } from '@capacitor/camera';
 import LogoDiaria from 'src/assets/logo_diaria_campos_login.svg';
 
 const { t } = useI18n();
@@ -175,168 +120,120 @@ const { t } = useI18n();
 const form = defineModel({ type: Object, required: true });
 const emit = defineEmits(['update:show-sub-step']);
 
-const subStep = ref('main');
-const docResult = ref(null); // null | 'success' | 'error'
+const loadingSelfie = ref(false);
+const loadingDoc = ref(false);
 
-const tempDocFront = ref(null);
-const tempDocBack = ref(null);
-const tempSelfie = ref(null);
+const showResult = ref(false);
+const resultError = ref(false);
+const resultIcon = ref('photo_camera');
+const resultMessage = ref('');
+const showDocHint = ref(false);
 
-const tempSelfieFile = ref(null);
+// foto de documento frente — aguarda verso antes de fechar
 const tempDocFrontFile = ref(null);
-const tempDocBackFile = ref(null);
-
-const stream = ref(null);
-const videoRef = ref(null);
-const canvasRef = ref(null);
-
-const CAMERA_STATES = ['selfie_camera', 'doc_front_camera', 'doc_back_camera'];
-const PREVIEW_STATES = ['selfie_preview', 'doc_front_preview', 'doc_back_preview'];
-
-const isCameraState = computed(() => CAMERA_STATES.includes(subStep.value));
-const isPreviewState = computed(() => PREVIEW_STATES.includes(subStep.value));
 
 const selfieDone = computed(() => !!form.value.selfie);
 const docDone = computed(() => !!form.value.document_front && !!form.value.document_back);
 
-const currentPreview = computed(() => {
-  if (subStep.value === 'selfie_preview') return tempSelfie.value;
-  if (subStep.value === 'doc_front_preview') return tempDocFront.value;
-  if (subStep.value === 'doc_back_preview') return tempDocBack.value;
-  return null;
-});
-
-const captureLabel = computed(() => {
-  if (subStep.value === 'selfie_camera') return t('provider.login.steps.step_4.btn_capture_selfie');
-  if (subStep.value === 'doc_front_camera') return t('provider.login.steps.step_4.btn_capture_front');
-  return t('provider.login.steps.step_4.btn_capture_back');
-});
-
-const stopCamera = () => {
-  if (stream.value) {
-    stream.value.getTracks().forEach((t) => t.stop());
-    stream.value = null;
-  }
-  if (videoRef.value) {
-    videoRef.value.srcObject = null;
+const base64ToFile = (base64, filename, mimeType = 'image/jpeg') => {
+  const byteString = atob(base64);
+  const ab = new ArrayBuffer(byteString.length);
+  const ia = new Uint8Array(ab);
+  for (let i = 0; i < byteString.length; i++) {
+    ia[i] = byteString.charCodeAt(i);
   }
+  return new File([ab], filename, { type: mimeType });
 };
 
-const startCameraStream = async (facingMode) => {
+const openCamera = async (direction) => {
+  const photo = await Camera.getPhoto({
+    resultType: CameraResultType.Base64,
+    source: CameraSource.Camera,
+    quality: 85,
+    direction: direction === 'front' ? CameraDirection.Front : CameraDirection.Rear,
+    allowEditing: false,
+    saveToGallery: false,
+  });
+  return base64ToFile(photo.base64String.replace(/\s/g, ''), 'photo.jpg', `image/${photo.format}`);
+};
+
+const takeSelfie = async () => {
+  if (loadingSelfie.value) return;
+  loadingSelfie.value = true;
   try {
-    stopCamera();
-    stream.value = await navigator.mediaDevices.getUserMedia({
-      video: { facingMode, width: { ideal: 1280 }, height: { ideal: 720 } },
-    });
-    await nextTick();
-    if (videoRef.value) {
-      videoRef.value.srcObject = stream.value;
-      await videoRef.value.play().catch(() => {});
+    const file = await openCamera('front');
+    form.value.selfie = file;
+    resultIcon.value = 'photo_camera';
+    resultMessage.value = t('provider.login.steps.step_4.selfie_success');
+    resultError.value = false;
+    showDocHint.value = false;
+    showResult.value = true;
+    emit('update:show-sub-step', true);
+  } catch (err) {
+    const msg = (err?.message || '').toLowerCase();
+    if (!msg.includes('cancel') && !msg.includes('dismiss') && !msg.includes('no image')) {
+      resultIcon.value = 'photo_camera';
+      resultError.value = true;
+      showDocHint.value = false;
+      showResult.value = true;
+      emit('update:show-sub-step', true);
     }
-    return true;
-  } catch {
-    stopCamera();
-    return false;
+  } finally {
+    loadingSelfie.value = false;
   }
 };
 
-watch(subStep, async (newStep) => {
-  emit('update:show-sub-step', newStep !== 'main');
-
-  if (!CAMERA_STATES.includes(newStep)) {
-    stopCamera();
-  }
-
-  if (newStep === 'selfie_camera') {
-    const ok = await startCameraStream('user');
-    if (!ok) subStep.value = 'main';
-  } else if (newStep === 'doc_front_camera' || newStep === 'doc_back_camera') {
-    const ok = await startCameraStream('environment');
-    if (!ok) {
-      docResult.value = 'error';
-      subStep.value = 'doc_result';
+const takeDocFront = async () => {
+  if (loadingDoc.value) return;
+  loadingDoc.value = true;
+  try {
+    const file = await openCamera('rear');
+    tempDocFrontFile.value = file;
+    await takeDocBack();
+  } catch (err) {
+    const msg = (err?.message || '').toLowerCase();
+    if (!msg.includes('cancel') && !msg.includes('dismiss') && !msg.includes('no image')) {
+      resultIcon.value = 'mdi-card-account-details-outline';
+      resultError.value = true;
+      showDocHint.value = false;
+      showResult.value = true;
+      emit('update:show-sub-step', true);
     }
+  } finally {
+    loadingDoc.value = false;
   }
-});
-
-onUnmounted(stopCamera);
-
-const capturePhoto = () => {
-  const video = videoRef.value;
-  const canvas = canvasRef.value;
-  if (!video || !canvas) return;
-
-  canvas.width = video.videoWidth || 1280;
-  canvas.height = video.videoHeight || 720;
-  canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
-
-  const capturing = subStep.value;
-  canvas.toBlob((blob) => {
-    const file = new File([blob], 'photo.jpg', { type: 'image/jpeg' });
-    const preview = URL.createObjectURL(blob);
-
-    if (capturing === 'selfie_camera') {
-      if (tempSelfie.value) URL.revokeObjectURL(tempSelfie.value);
-      tempSelfie.value = preview;
-      tempSelfieFile.value = file;
-      subStep.value = 'selfie_preview';
-    } else if (capturing === 'doc_front_camera') {
-      if (tempDocFront.value) URL.revokeObjectURL(tempDocFront.value);
-      tempDocFront.value = preview;
-      tempDocFrontFile.value = file;
-      subStep.value = 'doc_front_preview';
-    } else if (capturing === 'doc_back_camera') {
-      if (tempDocBack.value) URL.revokeObjectURL(tempDocBack.value);
-      tempDocBack.value = preview;
-      tempDocBackFile.value = file;
-      subStep.value = 'doc_back_preview';
-    }
-  }, 'image/jpeg', 0.85);
 };
 
-const usePhoto = () => {
-  if (subStep.value === 'selfie_preview') {
-    form.value.selfie = tempSelfieFile.value;
-    subStep.value = 'selfie_result';
-  } else if (subStep.value === 'doc_front_preview') {
-    subStep.value = 'doc_back_camera';
-  } else if (subStep.value === 'doc_back_preview') {
+const takeDocBack = async () => {
+  try {
+    const file = await openCamera('rear');
     form.value.document_front = tempDocFrontFile.value;
-    form.value.document_back = tempDocBackFile.value;
-    docResult.value = 'success';
-    subStep.value = 'doc_result';
+    form.value.document_back = file;
+    tempDocFrontFile.value = null;
+    resultIcon.value = 'mdi-card-account-details-outline';
+    resultMessage.value = t('provider.login.steps.step_4.document_success');
+    resultError.value = false;
+    showDocHint.value = true;
+    showResult.value = true;
+    emit('update:show-sub-step', true);
+  } catch (err) {
+    const msg = (err?.message || '').toLowerCase();
+    if (!msg.includes('cancel') && !msg.includes('dismiss') && !msg.includes('no image')) {
+      resultIcon.value = 'mdi-card-account-details-outline';
+      resultError.value = true;
+      showDocHint.value = false;
+      showResult.value = true;
+      emit('update:show-sub-step', true);
+    }
+    tempDocFrontFile.value = null;
   }
 };
 
-const retakePhoto = () => {
-  const retakeMap = {
-    selfie_preview: 'selfie_camera',
-    doc_front_preview: 'doc_front_camera',
-    doc_back_preview: 'doc_back_camera',
-  };
-  subStep.value = retakeMap[subStep.value] || 'main';
-};
-
-const goBack = () => {
-  const backMap = {
-    selfie_camera: 'main',
-    selfie_preview: 'selfie_camera',
-    doc_front_camera: 'main',
-    doc_front_preview: 'doc_front_camera',
-    doc_back_camera: 'doc_front_preview',
-    doc_back_preview: 'doc_back_camera',
-  };
-  subStep.value = backMap[subStep.value] || 'main';
-};
-
-const handleResult = () => {
-  if (docResult.value === 'error') {
-    docResult.value = null;
-    tempDocFront.value = null;
-    tempDocBack.value = null;
-    subStep.value = 'doc_front_camera';
-  } else {
-    subStep.value = 'main';
+const closeResult = () => {
+  showResult.value = false;
+  emit('update:show-sub-step', false);
+  if (resultError.value) {
+    resultError.value = false;
   }
 };
 </script>
@@ -370,69 +267,6 @@ const handleResult = () => {
   background: white;
 }
 
-.fs-camera {
-  height: 100%;
-  display: flex;
-  flex-direction: column;
-}
-
-.fs-header {
-  display: flex;
-  align-items: center;
-  gap: 4px;
-  padding: 8px 12px;
-  background: white;
-  flex-shrink: 0;
-}
-
-.fs-viewport {
-  flex: 1;
-  background: #000;
-  position: relative;
-  overflow: hidden;
-}
-
-.fs-video {
-  width: 100%;
-  height: 100%;
-  object-fit: cover;
-  display: block;
-}
-
-.fs-preview-img {
-  object-fit: contain;
-}
-
-.fs-footer {
-  padding: 16px 20px;
-  background: white;
-  flex-shrink: 0;
-}
-
-.guide-oval {
-  position: absolute;
-  top: 50%;
-  left: 50%;
-  transform: translate(-50%, -50%);
-  width: 62%;
-  height: 70%;
-  border: 3px solid #8b5cf6;
-  border-radius: 50%;
-  pointer-events: none;
-}
-
-.guide-doc {
-  position: absolute;
-  top: 50%;
-  left: 50%;
-  transform: translate(-50%, -50%);
-  width: 86%;
-  height: 52%;
-  border: 2px solid rgba(255, 255, 255, 0.65);
-  border-radius: 14px;
-  pointer-events: none;
-}
-
 .fs-result {
   height: 100%;
   display: flex;

+ 3 - 0
src/components/login/LoginStepThreePanel.vue

@@ -66,6 +66,7 @@
       :rules="[inputRules.required, validateRG]"
       lazy-rules
       mask="##.###.###-#"
+      type="tel"
     />
 
     <div class="text-text">
@@ -83,6 +84,7 @@
       :rules="[inputRules.required, inputRules.cpf]"
       lazy-rules
       mask="###.###.###-##"
+      type="tel"
     />
 
     <div class="text-text">
@@ -117,6 +119,7 @@
       :rules="[inputRules.required, inputRules.cep]"
       lazy-rules
       mask="#####-###"
+      type="tel"
       :loading="loadingCep"
       @update:model-value="onCepChange"
     />

+ 4 - 3
src/components/profile/ProfileAddressDialog.vue

@@ -1,7 +1,7 @@
 <template>
   <q-dialog ref="dialogRef" persistent maximized transition-show="slide-left" transition-hide="slide-right">
     <div class="bg-page full-height no-shadow">
-      <div class="row items-center q-pa-md q-pb-sm bg-white shadow-profile bg-surface">
+      <div class="row items-center q-px-md q-pb-sm bg-white shadow-profile bg-surface dialog-safe-header">
         <q-btn v-close-popup icon="mdi-chevron-left" flat round dense color="primary" />
         <q-space />
         <span class="font16 fontbold gradient-diarista">{{ $t('profile.address.title') }}</span>
@@ -197,6 +197,7 @@ const openMapDialog = async () => {
   let initialLng = null;
 
   const hasAddress = form.address || form.zip_code;
+
   if (hasAddress) {
     geocodingCep.value = true;
     try {
@@ -212,8 +213,8 @@ const openMapDialog = async () => {
         initialLat = geo.lat;
         initialLng = geo.lng;
       }
-    } catch {
-      // fallback to default
+    } catch (err) {
+      console.error('geocodeFullAddress falhou, usando coordenada default:', err);
     } finally {
       geocodingCep.value = false;
     }

+ 1 - 1
src/components/profile/ProfileAvailabilityDialog.vue

@@ -2,7 +2,7 @@
   <q-dialog ref="dialogRef" persistent maximized transition-show="slide-left" transition-hide="slide-right">
     <div class="bg-page full-height column no-shadow">
 
-      <div class="row items-center q-px-md q-pt-md q-pb-sm bg-white shadow-profile bg-surface">
+      <div class="row items-center q-px-md q-pb-sm bg-white shadow-profile bg-surface dialog-safe-header">
         <q-btn v-close-popup icon="mdi-chevron-left" flat round dense color="primary" />
         <q-space />
         <span class="gradient-diarista font16 fontbold">{{ $t('profile.availability.title') }}</span>

+ 102 - 137
src/components/profile/ProfileBankDataDialog.vue

@@ -1,7 +1,7 @@
 <template>
   <q-dialog ref="dialogRef" persistent maximized transition-show="slide-left" transition-hide="slide-right">
     <div class="bg-page full-height no-shadow">
-      <div class="row items-center q-px-md q-pt-md q-pb-sm bg-white shadow-profile bg-surface">
+      <div class="row items-center q-px-md q-pb-sm bg-white shadow-profile bg-surface dialog-safe-header">
         <q-btn v-close-popup icon="mdi-chevron-left" flat round dense color="primary" />
         <q-space />
         <span class="gradient-diarista font16 fontbold">{{ $t('profile.bank_data.title') }}</span>
@@ -22,18 +22,17 @@
             </div>
           </div>
 
-
-
           <q-card class="q-pa-md bg-white shadow-card q-mb-md" style="border-radius: 20px;" :flat="false">
             <div class="text-center text-text q-mb-sm font14 fontbold">
               <div>
                 {{ $t('profile.bank_data.pix_title') }}
+                <q-badge color="grey-5" class="q-ml-xs" :label="$t('profile.bank_data.in_development')" />
               </div>
             </div>
             <q-input
-              v-model="pixForm.pix_key"
               outlined
               dense
+              disable
               input-class="text-text"
               :placeholder="$t('profile.bank_data.pix_key_placeholder')"
               class="q-mb-sm"
@@ -43,24 +42,35 @@
               unelevated
               rounded
               no-caps
-              color="primary"
+              color="grey-4"
+              text-color="grey-7"
               class="full-width"
               padding="4px 12px"
-              :label="pixAlreadyRegistered ? $t('profile.bank_data.att_pix') : $t('profile.bank_data.save_pix')"
-              :loading="savingPix"
-              :disable="!hasPixUpdatedFields"
-              @click="savePix"
+              disable
+              :label="$t('profile.bank_data.in_development')"
             />
           </q-card>
 
-
           <q-card class="q-pa-md bg-white row shadow-card q-mb-md" style="border-radius: 20px;" :flat="false">
             <div class="text-center text-text q-mb-sm col-12 font14 fontbold">
               {{ $t('profile.bank_data.bank_account_title') }}
             </div>
+
+            <q-input
+              v-model="bankForm.bank"
+              outlined
+              dense
+              inputmode="numeric"
+              maxlength="3"
+              input-class="text-text"
+              :label="$t('profile.bank_data.bank_code')"
+              :placeholder="$t('profile.bank_data.bank_code_placeholder')"
+              class="q-mb-sm col-12"
+            />
+
             <div class="row q-mb-sm q-my-auto col-12 row items-center">
               <q-radio
-                v-model="bankForm.bank_account_type"
+                v-model="bankForm.type"
                 val="checking"
                 :label="$t('profile.bank_data.checking')"
                 color="primary"
@@ -68,7 +78,7 @@
                 class="q-mr-lg text-text"
               />
               <q-radio
-                v-model="bankForm.bank_account_type"
+                v-model="bankForm.type"
                 val="savings"
                 :label="$t('profile.bank_data.savings')"
                 color="primary"
@@ -77,32 +87,47 @@
               />
             </div>
 
-            <q-input
-              v-model="bankForm.agency"
-              outlined
-              dense
-              input-class="text-text"
-              :placeholder="$t('profile.bank_data.agency')"
-              class="q-mb-sm col-12"
-            />
-
-            <q-input
-              v-model="bankForm.account"
-              outlined
-              dense
-              input-class="text-text"
-              :placeholder="$t('profile.bank_data.account')"
-              class="q-mb-sm col-12"
-            />
+            <div class="row col-12 q-col-gutter-sm q-mb-sm">
+              <q-input
+                v-model="bankForm.branch_number"
+                outlined
+                dense
+                inputmode="numeric"
+                input-class="text-text"
+                :label="$t('profile.bank_data.agency')"
+                class="col-8"
+              />
+              <q-input
+                v-model="bankForm.branch_check_digit"
+                outlined
+                dense
+                maxlength="2"
+                input-class="text-text"
+                :label="$t('profile.bank_data.agency_digit')"
+                class="col-4"
+              />
+            </div>
 
-            <q-input
-              v-model="bankForm.digit"
-              outlined
-              dense
-              input-class="text-text"
-              :placeholder="$t('profile.bank_data.digit')"
-              class="q-mb-sm col-3"
-            />
+            <div class="row col-12 q-col-gutter-sm q-mb-sm">
+              <q-input
+                v-model="bankForm.account_number"
+                outlined
+                dense
+                inputmode="numeric"
+                input-class="text-text"
+                :label="$t('profile.bank_data.account')"
+                class="col-8"
+              />
+              <q-input
+                v-model="bankForm.account_check_digit"
+                outlined
+                dense
+                maxlength="2"
+                input-class="text-text"
+                :label="$t('profile.bank_data.account_digit')"
+                class="col-4"
+              />
+            </div>
 
             <q-btn
               unelevated
@@ -113,7 +138,7 @@
               class="full-width"
               :label="bankAlreadyRegistered ? $t('profile.bank_data.att_bank') : $t('profile.bank_data.save_account')"
               :loading="savingBank"
-              :disable="!hasBankUpdatedFields"
+              :disable="!canSaveBank"
               @click="saveBank"
             />
           </q-card>
@@ -125,15 +150,10 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue';
+import { ref, reactive, computed, onMounted } from 'vue';
 import { useDialogPluginComponent, useQuasar } from 'quasar';
-import {
-  getProviderPaymentMethods,
-  createProviderPaymentMethod,
-  updateProviderPaymentMethod,
-} from 'src/api/providerPaymentMethod';
+import { updateProviderBankAccount } from 'src/api/providerPaymentMethod';
 import { userStore } from 'src/stores/user';
-import { useFormUpdateTracker } from 'src/composables/useFormUpdateTracker';
 import { useI18n } from 'vue-i18n';
 
 defineEmits([...useDialogPluginComponent.emits]);
@@ -143,89 +163,48 @@ const $q = useQuasar();
 const { t } = useI18n();
 const user = userStore();
 
-const pixId = ref(null);
-const bankId = ref(null);
-const savingPix = ref(false);
 const savingBank = ref(false);
-const pixAlreadyRegistered = ref(false);
 const bankAlreadyRegistered = ref(false);
-const {
-  form: pixForm,
-  hasUpdatedFields: hasPixUpdatedFields,
-  getUpdatedFields: getPixUpdatedFields,
-  setUpdateFormAsOriginal: setPixOriginal,
-} = useFormUpdateTracker({
-  pix_key: '',
-});
 
-const {
-  form: bankForm,
-  hasUpdatedFields: hasBankUpdatedFields,
-  getUpdatedFields: getBankUpdatedFields,
-  setUpdateFormAsOriginal: setBankOriginal,
-} = useFormUpdateTracker({
-  bank_account_type: 'checking',
-  agency: '',
-  account: '',
-  digit: '',
+const bankForm = reactive({
+  bank: '',
+  type: 'checking',
+  branch_number: '',
+  branch_check_digit: '',
+  account_number: '',
+  account_check_digit: '',
 });
 
-const savePix = async () => {
-  if (!pixForm.pix_key) {
-    $q.notify({ type: 'negative', message: t('profile.bank_data.pix_key_required') });
-    return;
-  }
-
-  savingPix.value = true;
-  try {
-    const payload = {
-      provider_id: user.user.provider.id,
-      account_type: 'pix',
-      pix_key: pixForm.pix_key,
-    };
-
-    if (pixId.value) {
-      await updateProviderPaymentMethod(pixId.value, getPixUpdatedFields.value);
-    } else {
-      const created = await createProviderPaymentMethod(payload);
-      pixId.value = created.id;
-    }
-
-    setPixOriginal();
-    $q.notify({ type: 'positive', message: t('profile.bank_data.pix_saved') });
-  } catch (error) {
-    $q.notify({ type: 'negative', message: t('profile.bank_data.save_error') });
-    console.log(error);
-  } finally {
-    savingPix.value = false;
-  }
-};
+const canSaveBank = computed(
+  () =>
+    !!bankForm.bank &&
+    !!bankForm.branch_number &&
+    !!bankForm.account_number &&
+    !!bankForm.account_check_digit,
+);
 
 const saveBank = async () => {
-  if (!bankForm.agency || !bankForm.account) {
+  if (!canSaveBank.value) {
     $q.notify({ type: 'negative', message: t('profile.bank_data.bank_fields_required') });
     return;
   }
 
   savingBank.value = true;
   try {
-    const payload = {
-      provider_id: user.user.provider.id,
-      account_type: 'bank_account',
-      bank_account_type: bankForm.bank_account_type,
-      agency: bankForm.agency,
-      account: bankForm.account,
-      digit: bankForm.digit,
+    // Holder (nome/CPF) é derivado do prestador no backend; aqui só os campos digitados.
+    const bankAccount = {
+      bank: bankForm.bank,
+      type: bankForm.type,
+      branch_number: bankForm.branch_number,
+      branch_check_digit: bankForm.branch_check_digit || null,
+      account_number: bankForm.account_number,
+      account_check_digit: bankForm.account_check_digit,
     };
 
-    if (bankId.value) {
-      await updateProviderPaymentMethod(bankId.value, getBankUpdatedFields.value);
-    } else {
-      const created = await createProviderPaymentMethod(payload);
-      bankId.value = created.id;
-    }
+    await updateProviderBankAccount(user.user.provider.id, bankAccount);
+    await user.fetchUser();
 
-    setBankOriginal();
+    bankAlreadyRegistered.value = true;
     $q.notify({ type: 'positive', message: t('profile.bank_data.account_saved') });
   } catch (error) {
     $q.notify({ type: 'negative', message: t('profile.bank_data.save_error') });
@@ -235,31 +214,17 @@ const saveBank = async () => {
   }
 };
 
-onMounted(async () => {
-  try {
-    const methods = await getProviderPaymentMethods(user.user.provider.id);
-    if (!methods) return;
-
-    const pix = methods.find((m) => m.account_type === 'pix');
-    if (pix) {
-      pixId.value = pix.id;
-      pixForm.pix_key = pix.pix_key || '';
-      setPixOriginal();
-      pixAlreadyRegistered.value = true;
-    }
-
-    const bank = methods.find((m) => m.account_type === 'bank_account');
-    if (bank) {
-      bankId.value = bank.id;
-      bankForm.bank_account_type = bank.bank_account_type || 'checking';
-      bankForm.agency = bank.agency || '';
-      bankForm.account = bank.account || '';
-      bankForm.digit = bank.digit || '';
-      setBankOriginal();
-      bankAlreadyRegistered.value = true;
-    }
-  } catch (error) {
-    console.error('Erro ao carregar dados bancários:', error);
+onMounted(() => {
+  const bank = user.user?.provider?.recipient_default_bank_account;
+
+  if (bank && Object.keys(bank).length) {
+    bankForm.bank = bank.bank || '';
+    bankForm.type = bank.type || 'checking';
+    bankForm.branch_number = bank.branch_number || '';
+    bankForm.branch_check_digit = bank.branch_check_digit || '';
+    bankForm.account_number = bank.account_number || '';
+    bankForm.account_check_digit = bank.account_check_digit || '';
+    bankAlreadyRegistered.value = true;
   }
 });
 </script>

+ 2 - 1
src/components/profile/ProfileHelpDialog.vue

@@ -2,7 +2,7 @@
   <q-dialog ref="dialogRef" persistent maximized transition-show="slide-left" transition-hide="slide-right">
     <div class="bg-page full-height column no-shadow">
 
-      <div class="row items-center q-px-md q-pt-md q-pb-sm bg-white shadow-profile bg-surface">
+      <div class="row items-center q-px-md q-pb-sm bg-white shadow-profile bg-surface dialog-safe-header">
         <q-btn v-close-popup icon="mdi-chevron-left" flat round dense color="primary" />
         <q-space />
         <span class="text-primary font16 fontbold gradient-diarista">{{ $t('profile.help.title') }}</span>
@@ -275,6 +275,7 @@ onMounted(() => {
 .chat-footer {
   border-top: 1px solid rgba(0, 0, 0, 0.06);
   flex-shrink: 0;
+  padding-bottom: env(safe-area-inset-bottom, 0px);
 }
 
 .shadow-up {

+ 1 - 1
src/components/profile/ProfilePrivacyDialog.vue

@@ -2,7 +2,7 @@
   <q-dialog ref="dialogRef" persistent maximized transition-show="slide-left" transition-hide="slide-right">
     <div class="bg-page full-height column no-shadow">
 
-      <div class="row items-center q-px-md q-pt-md q-pb-sm bg-white shadow-profile bg-surface">
+      <div class="row items-center q-px-md q-pb-sm bg-white shadow-profile bg-surface dialog-safe-header">
         <q-btn v-close-popup icon="mdi-chevron-left" flat round dense color="primary" />
         <q-space />
         <span class="text-primary font16 fontbold gradient-diarista">{{ $t('profile.privacy.title') }}</span>

+ 1 - 1
src/components/profile/ProfileServiceDataDialog.vue

@@ -1,7 +1,7 @@
 <template>
   <q-dialog ref="dialogRef" persistent maximized transition-show="slide-left" transition-hide="slide-right">
     <div class="bg-page full-height column no-shadow">
-      <div class="row items-center q-px-md q-pt-md q-pb-sm bg-white shadow-profile bg-surface">
+      <div class="row items-center q-px-md q-pb-sm bg-white shadow-profile bg-surface dialog-safe-header">
         <q-btn v-close-popup icon="mdi-chevron-left" flat round dense color="primary" />
         <q-space />
         <span class="gradient-diarista font16 fontbold">{{ $t('profile.service_data.title') }}</span>

+ 71 - 12
src/components/shared/LocationMapDialog.vue

@@ -1,5 +1,5 @@
 <template>
-  <q-dialog ref="dialogRef" persistent maximized @show="initMap">
+  <q-dialog ref="dialogRef" persistent maximized class="map-dialog-transparent" @show="initMap" @hide="onDialogHide">
     <div class="location-map-dialog">
       <div ref="mapRef" class="location-map-container" />
 
@@ -41,7 +41,7 @@
 </template>
 
 <script setup>
-import { ref, onUnmounted } from 'vue';
+import { ref, nextTick, onUnmounted } from 'vue';
 import { useDialogPluginComponent, useQuasar } from 'quasar';
 import { useI18n } from 'vue-i18n';
 import { GoogleMap } from '@capacitor/google-maps';
@@ -73,13 +73,45 @@ const currentGeoData = ref(null);
 let googleMap = null;
 const markerId = ref(null);
 
+let hiddenEls = [];
+const applyMapTransparency = () => {
+  document.documentElement.style.setProperty('background', 'transparent', 'important');
+  document.body.style.setProperty('background', 'transparent', 'important');
+  const qApp = document.getElementById('q-app');
+  if (qApp) qApp.style.setProperty('background', 'transparent', 'important');
+
+  hiddenEls = [];
+  document
+    .querySelectorAll('.q-layout, .q-dialog:not(.map-dialog-transparent)')
+    .forEach((el) => {
+      el.style.setProperty('visibility', 'hidden', 'important');
+      hiddenEls.push(el);
+    });
+};
+
+const removeMapTransparency = () => {
+  document.documentElement.style.removeProperty('background');
+  document.body.style.removeProperty('background');
+  const qApp = document.getElementById('q-app');
+  if (qApp) qApp.style.removeProperty('background');
+
+  hiddenEls.forEach((el) => el.style.removeProperty('visibility'));
+  hiddenEls = [];
+};
+
+const onDialogHide = () => {
+  removeMapTransparency();
+};
+
 const handleCancel = async () => {
+  removeMapTransparency();
   await destroyMap();
   onDialogCancel();
 };
 
 const handleConfirm = async () => {
   if (!currentGeoData.value) return;
+  removeMapTransparency();
   await destroyMap();
   onDialogOK(currentGeoData.value);
 };
@@ -124,15 +156,31 @@ const moveMarkerTo = async (lat, lng) => {
 };
 
 const initMap = async () => {
-  googleMap = await GoogleMap.create({
-    id: 'location-map-dialog',
-    element: mapRef.value,
-    apiKey: process.env.GOOGLE_MAPS_API_KEY,
-    config: {
-      center: { lat: props.initialLat, lng: props.initialLng },
-      zoom: 17,
-    },
-  });
+  applyMapTransparency();
+  await nextTick();
+  await new Promise(resolve => setTimeout(resolve, 100));
+
+  const apiKey = process.env.GOOGLE_MAPS_API_KEY;
+
+  if (!apiKey) {
+    $q.notify({ type: 'negative', message: 'API key do mapa não configurada.' });
+    return;
+  }
+
+  try {
+    googleMap = await GoogleMap.create({
+      id: 'location-map-dialog',
+      element: mapRef.value,
+      apiKey,
+      config: {
+        center: { lat: props.initialLat, lng: props.initialLng },
+        zoom: 17,
+      },
+    });
+  } catch (err) {
+    $q.notify({ type: 'negative', message: `Erro ao abrir o mapa: ${err?.message ?? err}` });
+    return;
+  }
 
   markerId.value = await googleMap.addMarker({
     coordinate: { lat: props.initialLat, lng: props.initialLng },
@@ -154,22 +202,33 @@ const initMap = async () => {
 };
 
 onUnmounted(async () => {
+  removeMapTransparency();
   await destroyMap();
 });
 </script>
 
+<style lang="scss">
+.map-dialog-transparent .q-dialog__inner {
+  background: transparent !important;
+}
+.map-dialog-transparent .q-dialog__backdrop {
+  display: none !important;
+}
+</style>
+
 <style lang="scss" scoped>
 .location-map-dialog {
   position: relative;
   width: 100vw;
   height: 100dvh;
   overflow: hidden;
-  background: #e5e3df;
+  background: transparent;
 }
 
 .location-map-container {
   width: 100%;
   height: 100%;
+  background: transparent;
 }
 
 .location-map-back-btn {

+ 12 - 1
src/composables/useAuth.js

@@ -3,6 +3,8 @@ import { permissionStore } from "src/stores/permission";
 import { userStore } from "src/stores/user";
 import { useAuthStorage } from "src/composables/useAuthStorage";
 
+let refreshPromise = null;
+
 export const useAuth = () => {
   const { setRefreshToken, getRefreshToken, clearRefreshToken } = useAuthStorage();
 
@@ -48,7 +50,7 @@ export const useAuth = () => {
     }
   };
 
-  const refresh = async () => {
+  const doRefresh = async () => {
     try {
       const refreshToken = await getRefreshToken();
 
@@ -70,6 +72,15 @@ export const useAuth = () => {
     }
   };
 
+  const refresh = () => {
+    if (!refreshPromise) {
+      refreshPromise = doRefresh().finally(() => {
+        refreshPromise = null;
+      });
+    }
+    return refreshPromise;
+  };
+
   return {
     setAuthDataFromPayload,
     clearAuthData,

+ 13 - 6
src/composables/useGeocodingApi.js

@@ -25,8 +25,10 @@ const geocodeViaGoogleMaps = async (request) => {
 export const useGeocodingApi = () => {
   const geocodeCep = async (cep) => {
     const cleaned = cep.replace(/\D/g, '');
+    const apiKey = process.env.GOOGLE_MAPS_API_KEY;
+    const usandoGeocoderNativo = !!window.google?.maps?.Geocoder;
 
-    if (window.google?.maps?.Geocoder) {
+    if (usandoGeocoderNativo) {
       const results = await geocodeViaGoogleMaps({ address: `${cleaned}, Brazil` });
       if (!results.length) return null;
       const result = results[0];
@@ -39,7 +41,7 @@ export const useGeocodingApi = () => {
     }
 
     const { data } = await axios.get(GEOCODING_URL, {
-      params: { address: `${cleaned}, Brazil`, key: process.env.GOOGLE_MAPS_API_KEY },
+      params: { address: `${cleaned}, Brazil`, key: apiKey },
     });
     if (data.status !== 'OK' || !data.results.length) return null;
     const result = data.results[0];
@@ -48,14 +50,17 @@ export const useGeocodingApi = () => {
   };
 
   const reverseGeocode = async (lat, lng) => {
-    if (window.google?.maps?.Geocoder) {
+    const apiKey = process.env.GOOGLE_MAPS_API_KEY;
+    const usandoGeocoderNativo = !!window.google?.maps?.Geocoder;
+
+    if (usandoGeocoderNativo) {
       const results = await geocodeViaGoogleMaps({ location: { lat, lng } });
       if (!results.length) return null;
       return { lat, lng, ...parseAddressComponents(results[0].address_components) };
     }
 
     const { data } = await axios.get(GEOCODING_URL, {
-      params: { latlng: `${lat},${lng}`, key: process.env.GOOGLE_MAPS_API_KEY },
+      params: { latlng: `${lat},${lng}`, key: apiKey },
     });
     if (data.status !== 'OK' || !data.results.length) return null;
     const result = data.results[0];
@@ -65,8 +70,10 @@ export const useGeocodingApi = () => {
   const geocodeFullAddress = async ({ address, number, district, zip_code, city, state }) => {
     const parts = [address, number, district, zip_code, city, state, 'Brazil'].filter(Boolean);
     const query = parts.join(', ');
+    const apiKey = process.env.GOOGLE_MAPS_API_KEY;
+    const usandoGeocoderNativo = !!window.google?.maps?.Geocoder;
 
-    if (window.google?.maps?.Geocoder) {
+    if (usandoGeocoderNativo) {
       const results = await geocodeViaGoogleMaps({ address: query });
       if (!results.length) return null;
       const result = results[0];
@@ -78,7 +85,7 @@ export const useGeocodingApi = () => {
     }
 
     const { data } = await axios.get(GEOCODING_URL, {
-      params: { address: query, key: process.env.GOOGLE_MAPS_API_KEY },
+      params: { address: query, key: apiKey },
     });
     if (data.status !== 'OK' || !data.results.length) return null;
     const result = data.results[0];

+ 4 - 1
src/css/app.scss

@@ -180,11 +180,14 @@ box-shadow: 1px 4px 4px 0px rgba(0,0,0,0.2);
   font-weight: 300;
 }
 
-// ─── Layout utilities ──────────────────────────────────────────────────────────
 .card-border { border-radius: 18px; }
 
 .dashboard-section-title { line-height: 1.05; }
 
 .section-title {
   line-height: 1.05;
+}
+.dialog-safe-header {
+  padding-top: calc(env(safe-area-inset-top, 24px) + 12px) !important;
+  min-height: calc(50px + env(safe-area-inset-top, 24px));
 }

+ 6 - 1
src/i18n/locales/en.json

@@ -474,7 +474,12 @@
       "agency": "Agency",
       "account": "Account",
       "digit": "Digit",
-      "bank_fields_required": "Please enter agency and account",
+      "bank_code": "Bank (code)",
+      "bank_code_placeholder": "e.g. 341",
+      "agency_digit": "Digit",
+      "account_digit": "Digit",
+      "in_development": "Under development",
+      "bank_fields_required": "Please enter bank, agency and account",
       "save_account": "register account",
       "account_saved": "Bank account saved successfully!",
       "save_error": "Error saving. Please try again."

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

@@ -474,7 +474,12 @@
       "agency": "Agencia",
       "account": "Cuenta",
       "digit": "Dígito",
-      "bank_fields_required": "Por favor ingrese agencia y cuenta",
+      "bank_code": "Banco (código)",
+      "bank_code_placeholder": "Ej.: 341",
+      "agency_digit": "Dígito",
+      "account_digit": "Dígito",
+      "in_development": "En desarrollo",
+      "bank_fields_required": "Por favor ingrese banco, agencia y cuenta",
       "save_account": "registrar cuenta",
       "account_saved": "¡Cuenta bancaria guardada con éxito!",
       "save_error": "Error al guardar. Inténtelo de nuevo."

+ 6 - 1
src/i18n/locales/pt.json

@@ -477,7 +477,12 @@
       "agency": "Agência",
       "account": "Conta",
       "digit": "Dígito",
-      "bank_fields_required": "Informe agência e conta",
+      "bank_code": "Banco (código)",
+      "bank_code_placeholder": "Ex.: 341",
+      "agency_digit": "Dígito",
+      "account_digit": "Dígito",
+      "in_development": "Em desenvolvimento",
+      "bank_fields_required": "Informe banco, agência e conta",
       "save_account": "cadastrar conta",
       "account_saved": "Conta bancária salva com sucesso!",
       "save_error": "Erro ao salvar. Tente novamente."

+ 6 - 19
src/layouts/MainLayout.vue

@@ -1,11 +1,8 @@
 <template>
   <q-layout class="main-layout relative" view="hHh lpR fFf">
     <q-header
-      v-if="$q.screen.lt.sm"
-      class="bg-surface column justify-end"
-      :style="{
-        height: `calc(50px + env(safe-area-inset-top))`,
-      }"
+      class="bg-surface"
+      :style="{ height: 'env(safe-area-inset-top)' }"
     >
     </q-header>
     <q-page-container>
@@ -22,14 +19,13 @@
               <component
                 :is="Component"
                 class="main-layout-view"
-                :class="{ 'main-layout-view--mobile': $q.screen.lt.sm }"
               />
             </Transition>
           </router-view>
         </q-scroll-area>
       </q-page>
     </q-page-container>
-    <q-footer v-if="$q.screen.lt.sm" class="provider-bottom-nav bg-white">
+    <q-footer class="provider-bottom-nav bg-white">
       <nav class="provider-bottom-nav-inner">
         <router-link
           v-for="item in navItems"
@@ -48,7 +44,6 @@
 
 <script setup>
 import { computed, useTemplateRef, watch } from "vue";
-import { useQuasar } from "quasar";
 import { useRoute } from "vue-router";
 import { useI18n } from "vue-i18n";
 
@@ -56,7 +51,6 @@ defineOptions({
   name: "MainLayout",
 });
 
-const $q = useQuasar();
 const route = useRoute();
 const scrollAreaRef = useTemplateRef("scrollAreaRef");
 const { t } = useI18n();
@@ -89,10 +83,7 @@ const navItems = computed(() => [
 const isNavItemActive = (item) => route.name === item.name;
 
 const scrollAreaHeight = computed(() => {
-  if ($q.screen.lt.sm) {
-    return 'height: calc(100dvh - 50px - env(safe-area-inset-top) - 80px - env(safe-area-inset-bottom)) !important;';
-  }
-  return 'height: 100dvh !important;';
+  return 'height: calc(100dvh - env(safe-area-inset-top) - 60px - env(safe-area-inset-bottom)) !important;';
 });
 
 watch(
@@ -134,10 +125,6 @@ watch(
   overflow-x: hidden;
 }
 
-.main-layout-view--mobile {
-  padding: 0 !important;
-}
-
 .v-enter-active {
   opacity: 1;
   transition: all 0.15s ease-in;
@@ -167,8 +154,8 @@ watch(
   display: grid;
   grid-template-columns: repeat(4, minmax(0, 1fr));
   align-items: end;
-  height: 60px;
-  padding: 0px 0px calc(12px + env(safe-area-inset-bottom));
+  height: calc(60px + env(safe-area-inset-bottom));
+  padding: 0 0 env(safe-area-inset-bottom);
 }
 
 .provider-bottom-nav-item {

+ 17 - 17
src/pages/LoginPage.vue

@@ -59,7 +59,7 @@
 </template>
 
 <script setup>
-import { computed, ref } from 'vue';
+import { computed, onMounted, ref } from 'vue';
 import { useQuasar } from 'quasar';
 import { useRouter } from 'vue-router';
 import { useI18n } from 'vue-i18n';
@@ -84,6 +84,7 @@ const router = useRouter();
 const { setAuthDataFromPayload } = useAuth();
 
 const clicked = ref(false);
+
 const showSubStep = ref(false);
 const steps = ref(1);
 const submitting = ref(false);
@@ -112,12 +113,9 @@ const stepThreeForm = ref({
 });
 
 const stepFourForm = ref({
-  selfie_file: null,
-  selfie_base64: '',
-  document_front_file: null,
-  document_front_base64: '',
-  document_back_file: null,
-  document_back_base64: '',
+  selfie: null,
+  document_front: null,
+  document_back: null,
 });
 
 const stepFiveForm = ref({
@@ -142,7 +140,7 @@ const stepSixForm = ref({
 const actionLabel = computed(() => {
   if (steps.value === 1) return t('provider.login.steps.step_1.action');
   if (steps.value === 2) return t('provider.login.steps.step_2.action');
-  if (steps.value === 7) return t('provider.login.steps.step_6.action');
+  if (steps.value === 6) return t('provider.login.steps.step_6.action');
   return t('provider.login.steps.step_3.action');
 });
 
@@ -194,7 +192,7 @@ const validateCurrentStep = async () => {
     }
   }
 
-  if (steps.value === 7 && !hasWorkingDaySelected()) {
+  if (steps.value === 6 && !hasWorkingDaySelected()) {
     $q.notify({
       type: 'negative',
       message: t('provider.login.steps.step_6.select_at_least_one'),
@@ -234,7 +232,7 @@ const registerUserAndProvider = async () => {
   const form = new FormData();
 
   const append = (key, val) => {
-    if (val === null || val === undefined) return;
+    if (val === null || val === undefined || val === '') return;
     if (typeof val === 'boolean') form.append(key, val ? '1' : '0');
     else form.append(key, val);
   };
@@ -332,12 +330,6 @@ const onSubmit = async () => {
         break;
       }
       case 6: {
-        if (await validateCurrentStep()) {
-          steps.value = 7;
-        }
-        break;
-      }
-      case 7: {
         if (await validateCurrentStep()) {
           await registerUserAndProvider();
         }
@@ -348,10 +340,18 @@ const onSubmit = async () => {
     }
   } catch (error) {
     console.error(error);
+    const msg = error?.response?.data?.message ?? error?.message ?? 'Erro ao concluir cadastro. Tente novamente.';
+    $q.notify({ type: 'negative', message: msg });
   } finally {
     submitting.value = false;
   }
 };
+
+onMounted(() => {
+  setTimeout(() => {
+    clicked.value = true;
+  }, 1500);
+});
 </script>
 
 <style lang="scss" scoped>
@@ -450,6 +450,6 @@ const onSubmit = async () => {
 }
 
 .flow-footer {
-  padding: 20px 0 12px;
+  padding: 20px 0 calc(12px + env(safe-area-inset-bottom));
 }
 </style>

+ 1 - 1
src/pages/calendar/CalendarPage.vue

@@ -291,7 +291,7 @@ onMounted(async () => {
 
 <style scoped lang="scss">
 .calendar-header {
-  padding-top: calc(env(safe-area-inset-top) + 12px);
+  padding-top: 12px;
   padding-bottom: 12px;
   box-shadow: 0px 1px 8px rgba(0, 0, 0, 0.08);
 }

+ 1 - 0
src/pages/opportunities/components/OpportunityDetailsDialog.vue

@@ -316,6 +316,7 @@ onMounted(async () => {
   position: relative;
 
   padding: 14px 16px;
+  padding-top: calc(env(safe-area-inset-top, 24px) + 14px);
   background: #fff;
 
   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);

+ 1 - 1
src/pages/payments/PaymentsPage.vue

@@ -433,7 +433,7 @@ onMounted(() => {
 
 <style scoped lang="scss">
 .payments-header {
-  padding-top: calc(env(safe-area-inset-top) + 12px);
+  padding-top: 12px;
   padding-bottom: 12px;
   box-shadow: 0px 1px 8px rgba(0, 0, 0, 0.08);
 }

+ 1 - 1
src/pages/profile/ProfileEditDialog.vue

@@ -1,7 +1,7 @@
 <template>
   <q-dialog ref="dialogRef" persistent maximized transition-show="slide-left" transition-hide="slide-right">
     <q-card class="bg-white full-width full-height">
-      <div class="row items-center q-px-md q-pt-md q-pb-sm bg-white shadow-profile">
+      <div class="row items-center q-px-md q-pb-sm bg-white shadow-profile dialog-safe-header">
         <q-btn flat round dense icon="mdi-chevron-left" color="primary" @click="onDialogCancel" />
         <q-space />
         <span class="font16 fontbold gradient-diarista">{{ $t('profile.edit_data') }}</span>