Browse Source

feat: :sparkles: feat (config-apk) configuracao para apk/aab

foi configurado e instalado pacotes necessarios para gerar apk/aab

fase:dev | origin:escopo
Gustavo Zanatta 1 tuần trước cách đây
mục cha
commit
485810eb08

+ 10 - 0
package-lock.json

@@ -9,6 +9,7 @@
       "version": "0.0.1",
       "version": "0.0.1",
       "dependencies": {
       "dependencies": {
         "@bufbuild/protobuf": "^2.5.1",
         "@bufbuild/protobuf": "^2.5.1",
+        "@capacitor/browser": "^8.0.3",
         "@capacitor/device": "^7.0.1",
         "@capacitor/device": "^7.0.1",
         "@capacitor/geolocation": "^8.2.0",
         "@capacitor/geolocation": "^8.2.0",
         "@capacitor/google-maps": "^8.0.1",
         "@capacitor/google-maps": "^8.0.1",
@@ -313,6 +314,15 @@
         "typescript": "5.4.5"
         "typescript": "5.4.5"
       }
       }
     },
     },
+    "node_modules/@capacitor/browser": {
+      "version": "8.0.3",
+      "resolved": "https://registry.npmjs.org/@capacitor/browser/-/browser-8.0.3.tgz",
+      "integrity": "sha512-WJWPHEPbweiFoHYmVlCbZf5yrqJ2Rchx2Xvbmd+3Lf+Zkpq3nXBThThY2CF69lYEg1NINGF9BcHThIOEU1gZlQ==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@capacitor/core": ">=8.0.0"
+      }
+    },
     "node_modules/@capacitor/core": {
     "node_modules/@capacitor/core": {
       "version": "8.3.4",
       "version": "8.3.4",
       "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-8.3.4.tgz",
       "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-8.3.4.tgz",

+ 1 - 0
package.json

@@ -23,6 +23,7 @@
   },
   },
   "dependencies": {
   "dependencies": {
     "@bufbuild/protobuf": "^2.5.1",
     "@bufbuild/protobuf": "^2.5.1",
+    "@capacitor/browser": "^8.0.3",
     "@capacitor/device": "^7.0.1",
     "@capacitor/device": "^7.0.1",
     "@capacitor/geolocation": "^8.2.0",
     "@capacitor/geolocation": "^8.2.0",
     "@capacitor/google-maps": "^8.0.1",
     "@capacitor/google-maps": "^8.0.1",

+ 3 - 3
src-capacitor/android/.gitignore

@@ -53,9 +53,9 @@ captures/
 .idea/navEditor.xml
 .idea/navEditor.xml
 
 
 # Keystore files
 # Keystore files
-# Uncomment the following lines if you do not want to check your keystore files in.
-#*.jks
-#*.keystore
+*.jks
+*.keystore
+keystore.properties
 
 
 # External native build folder generated in Android Studio 2.2 and later
 # External native build folder generated in Android Studio 2.2 and later
 .externalNativeBuild
 .externalNativeBuild

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

@@ -1,5 +1,11 @@
 apply plugin: 'com.android.application'
 apply plugin: 'com.android.application'
 
 
+def keystorePropertiesFile = rootProject.file("keystore.properties")
+def keystoreProperties = new Properties()
+if (keystorePropertiesFile.exists()) {
+    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
+}
+
 android {
 android {
     namespace "br.com.diarista.provider"
     namespace "br.com.diarista.provider"
     compileSdk rootProject.ext.compileSdkVersion
     compileSdk rootProject.ext.compileSdkVersion
@@ -16,10 +22,22 @@ android {
             ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
             ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
         }
         }
     }
     }
+    signingConfigs {
+        release {
+            if (keystorePropertiesFile.exists()) {
+                storeFile file(keystoreProperties['storeFile'])
+                storePassword keystoreProperties['storePassword']
+                keyAlias keystoreProperties['keyAlias']
+                keyPassword keystoreProperties['keyPassword']
+            }
+        }
+    }
     buildTypes {
     buildTypes {
         release {
         release {
-            minifyEnabled false
-            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+            signingConfig signingConfigs.release
+            minifyEnabled true
+            shrinkResources true
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
         }
     }
     }
 }
 }

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

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

+ 45 - 18
src-capacitor/android/app/proguard-rules.pro

@@ -1,21 +1,48 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-#   http://developer.android.com/guide/developing/tools/proguard.html
+# Capacitor core
+-keep class com.getcapacitor.** { *; }
+-keep @com.getcapacitor.annotation.CapacitorPlugin class * { *; }
+-keep @com.getcapacitor.annotation.Permission class * { *; }
+-keepclassmembers class * extends com.getcapacitor.Plugin {
+    @com.getcapacitor.annotation.CapacitorPlugin <methods>;
+    @com.getcapacitor.PluginMethod <methods>;
+}
 
 
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-#   public *;
-#}
+# JavaScript Interface (WebView <-> Java bridge)
+-keepclassmembers class * {
+    @android.webkit.JavascriptInterface <methods>;
+}
 
 
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
+# WebView
+-keepclassmembers class * extends android.webkit.WebViewClient {
+    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
+    public boolean *(android.webkit.WebView, java.lang.String);
+    public void *(android.webkit.WebView, java.lang.String);
+}
 
 
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
+# Firebase
+-keep class com.google.firebase.** { *; }
+-keep class com.google.android.gms.** { *; }
+-dontwarn com.google.firebase.**
+-dontwarn com.google.android.gms.**
+
+# OkHttp (Capacitor HTTP plugin)
+-dontwarn okhttp3.**
+-dontwarn okio.**
+-keep class okhttp3.** { *; }
+-keep interface okhttp3.** { *; }
+
+# Kotlin
+-keep class kotlin.** { *; }
+-dontwarn kotlin.**
+-keepclassmembers class **$WhenMappings {
+    <fields>;
+}
+
+# Preserve stack traces in crash reports
+-keepattributes SourceFile,LineNumberTable
+-renamesourcefileattribute SourceFile
+
+# Annotations
+-keepattributes *Annotation*
+-keepattributes Signature
+-keepattributes Exceptions

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

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

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

@@ -5,6 +5,9 @@ project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/
 include ':capacitor-app'
 include ':capacitor-app'
 project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')
 project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')
 
 
+include ':capacitor-browser'
+project(':capacitor-browser').projectDir = new File('../node_modules/@capacitor/browser/android')
+
 include ':capacitor-device'
 include ':capacitor-device'
 project(':capacitor-device').projectDir = new File('../node_modules/@capacitor/device/android')
 project(':capacitor-device').projectDir = new File('../node_modules/@capacitor/device/android')
 
 
@@ -14,5 +17,8 @@ project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor
 include ':capacitor-preferences'
 include ':capacitor-preferences'
 project(':capacitor-preferences').projectDir = new File('../node_modules/@capacitor/preferences/android')
 project(':capacitor-preferences').projectDir = new File('../node_modules/@capacitor/preferences/android')
 
 
+include ':capacitor-push-notifications'
+project(':capacitor-push-notifications').projectDir = new File('../node_modules/@capacitor/push-notifications/android')
+
 include ':capacitor-status-bar'
 include ':capacitor-status-bar'
 project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')
 project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')

+ 1 - 1
src-capacitor/capacitor.config.json

@@ -1,6 +1,6 @@
 {
 {
   "appId": "br.com.diarista.provider",
   "appId": "br.com.diarista.provider",
-  "appName": "Quasar App",
+  "appName": "Diarista Prestador",
   "webDir": "www",
   "webDir": "www",
   "plugins": {
   "plugins": {
     "Keyboard": {
     "Keyboard": {

+ 2 - 0
src-capacitor/ios/App/Podfile

@@ -12,9 +12,11 @@ def capacitor_pods
   pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
   pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
   pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
   pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
   pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
   pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
+  pod 'CapacitorBrowser', :path => '../../node_modules/@capacitor/browser'
   pod 'CapacitorDevice', :path => '../../node_modules/@capacitor/device'
   pod 'CapacitorDevice', :path => '../../node_modules/@capacitor/device'
   pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
   pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
   pod 'CapacitorPreferences', :path => '../../node_modules/@capacitor/preferences'
   pod 'CapacitorPreferences', :path => '../../node_modules/@capacitor/preferences'
+  pod 'CapacitorPushNotifications', :path => '../../node_modules/@capacitor/push-notifications'
   pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
   pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
 end
 end
 
 

+ 10 - 0
src-capacitor/package-lock.json

@@ -10,6 +10,7 @@
       "dependencies": {
       "dependencies": {
         "@capacitor/android": "^7.2.0",
         "@capacitor/android": "^7.2.0",
         "@capacitor/app": "^7.0.0",
         "@capacitor/app": "^7.0.0",
+        "@capacitor/browser": "^8.0.3",
         "@capacitor/cli": "^7.0.0",
         "@capacitor/cli": "^7.0.0",
         "@capacitor/core": "^7.0.0",
         "@capacitor/core": "^7.0.0",
         "@capacitor/device": "^7.0.1",
         "@capacitor/device": "^7.0.1",
@@ -37,6 +38,15 @@
         "@capacitor/core": ">=7.0.0"
         "@capacitor/core": ">=7.0.0"
       }
       }
     },
     },
+    "node_modules/@capacitor/browser": {
+      "version": "8.0.3",
+      "resolved": "https://registry.npmjs.org/@capacitor/browser/-/browser-8.0.3.tgz",
+      "integrity": "sha512-WJWPHEPbweiFoHYmVlCbZf5yrqJ2Rchx2Xvbmd+3Lf+Zkpq3nXBThThY2CF69lYEg1NINGF9BcHThIOEU1gZlQ==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@capacitor/core": ">=8.0.0"
+      }
+    },
     "node_modules/@capacitor/cli": {
     "node_modules/@capacitor/cli": {
       "version": "7.2.0",
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-7.2.0.tgz",
       "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-7.2.0.tgz",

+ 3 - 2
src-capacitor/package.json

@@ -7,13 +7,14 @@
   "dependencies": {
   "dependencies": {
     "@capacitor/android": "^7.2.0",
     "@capacitor/android": "^7.2.0",
     "@capacitor/app": "^7.0.0",
     "@capacitor/app": "^7.0.0",
-    "@capacitor/cli": "^7.0.0",
+    "@capacitor/browser": "^8.0.3",
+    "@capacitor/cli": "^8.3.3",
     "@capacitor/core": "^7.0.0",
     "@capacitor/core": "^7.0.0",
     "@capacitor/device": "^7.0.1",
     "@capacitor/device": "^7.0.1",
     "@capacitor/ios": "^7.2.0",
     "@capacitor/ios": "^7.2.0",
     "@capacitor/keyboard": "^7.0.1",
     "@capacitor/keyboard": "^7.0.1",
     "@capacitor/preferences": "^7.0.1",
     "@capacitor/preferences": "^7.0.1",
-    "@capacitor/push-notifications": "^7.0.6",
+    "@capacitor/push-notifications": "^8.1.1",
     "@capacitor/status-bar": "^7.0.1"
     "@capacitor/status-bar": "^7.0.1"
   }
   }
 }
 }

+ 1 - 0
src-capacitor/www/index.html

@@ -0,0 +1 @@
+<!DOCTYPE html><html><head></head><body></body></html>

+ 5 - 36
src/api/user.js

@@ -33,45 +33,14 @@ export const userTypes = async () => {
 export const sendCode = async (email, phone) => {
 export const sendCode = async (email, phone) => {
   const data = await api.post("/provider-send-code", { email, phone });
   const data = await api.post("/provider-send-code", { email, phone });
   return data;
   return data;
-};
+}
 
 
 export const validateCode = async (email, phone, code, isLogin = false) => {
 export const validateCode = async (email, phone, code, isLogin = false) => {
-  const data = await api.post("/validate-code-provider", {
-    email,
-    phone,
-    code,
-    isLogin,
-  });
+  const data = await api.post("/validate-code-provider", { email, phone, code, isLogin });
   return data;
   return data;
-};
-
-const removeEmptyRegistrationFields = (data) => {
-  if (Array.isArray(data)) {
-    return data.map(removeEmptyRegistrationFields);
-  }
-
-  if (!data || typeof data !== "object") {
-    return data;
-  }
-
-  return Object.entries(data).reduce((payload, [key, value]) => {
-    if (
-      value === undefined ||
-      key === "no_complement" ||
-      key.endsWith("_file")
-    ) {
-      return payload;
-    }
-
-    payload[key] = removeEmptyRegistrationFields(value);
-    return payload;
-  }, {});
-};
+}
 
 
 export const createUserAndProvider = async (data) => {
 export const createUserAndProvider = async (data) => {
-  const response = await api.post(
-    "/register-provider",
-    removeEmptyRegistrationFields(data),
-  );
+  const response = await api.post("/register-provider", data);
   return response;
   return response;
-};
+}

+ 8 - 0
src/i18n/locales/en.json

@@ -595,6 +595,14 @@
       "footer_disclaimer": "⚡ Automatic AI responses • Human support available",
       "footer_disclaimer": "⚡ Automatic AI responses • Human support available",
       "coming_soon": "Coming soon"
       "coming_soon": "Coming soon"
     },
     },
+    "privacy_policy": {
+      "title": "Privacy Policy",
+      "description": "How we handle your data"
+    },
+    "support_page": {
+      "title": "Support Center",
+      "description": "Usage guide and tutorials"
+    },
     "logout": {
     "logout": {
       "title": "Logout",
       "title": "Logout",
       "description": "Disconnect from your account"
       "description": "Disconnect from your account"

+ 8 - 0
src/i18n/locales/es.json

@@ -593,6 +593,14 @@
       "footer_disclaimer": "⚡ Respuestas automáticas por IA • Atención humana disponible",
       "footer_disclaimer": "⚡ Respuestas automáticas por IA • Atención humana disponible",
       "coming_soon": "Próximamente disponible"
       "coming_soon": "Próximamente disponible"
     },
     },
+    "privacy_policy": {
+      "title": "Política de Privacidad",
+      "description": "Cómo tratamos tus datos"
+    },
+    "support_page": {
+      "title": "Centro de Soporte",
+      "description": "Guía de uso y tutoriales"
+    },
     "logout": {
     "logout": {
       "title": "Salir",
       "title": "Salir",
       "description": "Desconectar de su cuenta"
       "description": "Desconectar de su cuenta"

+ 8 - 0
src/i18n/locales/pt.json

@@ -606,6 +606,14 @@
       "empty_sub": "Você pode bloquear clientes que não deseja receber novos pedidos.",
       "empty_sub": "Você pode bloquear clientes que não deseja receber novos pedidos.",
       "unblock_btn": "Desbloquear"
       "unblock_btn": "Desbloquear"
     },
     },
+    "privacy_policy": {
+      "title": "Política de Privacidade",
+      "description": "Como tratamos seus dados"
+    },
+    "support_page": {
+      "title": "Central de Suporte",
+      "description": "Guia de uso e tutoriais"
+    },
     "logout": {
     "logout": {
       "title": "Sair",
       "title": "Sair",
       "description": "Desconectar da sua conta"
       "description": "Desconectar da sua conta"

+ 92 - 317
src/pages/LoginPage.vue

@@ -2,12 +2,7 @@
 <template>
 <template>
   <q-page class="login-page bg-surface-dark">
   <q-page class="login-page bg-surface-dark">
     <Transition name="fade-slide" mode="out-in">
     <Transition name="fade-slide" mode="out-in">
-      <div
-        v-if="!clicked"
-        key="splash"
-        class="splash-screen"
-        @click="clicked = true"
-      >
+      <div v-if="!clicked" key="splash" class="splash-screen" @click="clicked = true">
         <img :src="BackgroundLogin" class="splash-layer splash-layer--bg" />
         <img :src="BackgroundLogin" class="splash-layer splash-layer--bg" />
         <img :src="FotoDiarista" class="splash-layer splash-layer--photo" />
         <img :src="FotoDiarista" class="splash-layer splash-layer--photo" />
         <img :src="LogoLogin" class="splash-layer splash-layer--logo" />
         <img :src="LogoLogin" class="splash-layer splash-layer--logo" />
@@ -27,190 +22,26 @@
           spellcheck="false"
           spellcheck="false"
           @submit="onSubmit"
           @submit="onSubmit"
         >
         >
-          <div
-            class="flow-content"
-            :class="{ 'flow-content--centered': steps <= 2 && !showSubStep }"
-          >
-            <LoginStepOnePanel
-              v-if="steps === 1"
-              v-model:email="email"
-              v-model:phone="phone"
-            />
+          <div class="flow-content" :class="{ 'flow-content--centered': steps <= 2 && !showSubStep }">
+            <LoginStepOnePanel v-if="steps === 1" v-model:email="email" v-model:phone="phone" />
             <LoginStepTwoPanel v-else-if="steps === 2" v-model:code="code" />
             <LoginStepTwoPanel v-else-if="steps === 2" v-model:code="code" />
-            <LoginStepThreePanel
-              v-else-if="steps === 3"
-              v-model="stepThreeForm"
-            />
+            <LoginStepThreePanel v-else-if="steps === 3" v-model="stepThreeForm" />
             <LoginStepFourPanel
             <LoginStepFourPanel
               v-else-if="steps === 4"
               v-else-if="steps === 4"
               v-model="stepFourForm"
               v-model="stepFourForm"
               @update:show-sub-step="showSubStep = $event"
               @update:show-sub-step="showSubStep = $event"
             />
             />
-            <LoginStepFivePanel
-              v-else-if="steps === 5"
-              v-model="stepFiveForm"
-            />
-            <q-card-section v-else-if="steps === 6" class="no-padding">
-              <div
-                class="text-subtitle1 text-center text-weight-bold text-text q-mb-md"
-              >
-                Dados bancários
-              </div>
-
-              <div class="text-caption text-grey-7 text-center q-mb-md">
-                Informe uma conta vinculada ao mesmo CPF do cadastro para
-                receber os pagamentos.
-              </div>
-
-              <div class="row q-mb-sm items-center">
-                <q-radio
-                  v-model="stepSixForm.account_type"
-                  val="checking"
-                  label="Conta corrente"
-                  color="primary"
-                  keep-color
-                  class="q-mr-lg text-text"
-                />
-                <q-radio
-                  v-model="stepSixForm.account_type"
-                  val="savings"
-                  label="Poupança"
-                  color="primary"
-                  keep-color
-                  class="text-text"
-                />
-              </div>
-
-              <div class="text-text">
-                <span class="text-weight-medium">Código do banco</span>
-              </div>
-              <q-input
-                v-model="stepSixForm.bank"
-                no-error-icon
-                outlined
-                rounded
-                class="bg-surface q-mt-sm q-mb-md"
-                input-class="text-text"
-                placeholder="Ex: 001"
-                hide-bottom-space
-                :rules="[requiredRule]"
-                lazy-rules
-                maxlength="20"
-              />
-
-              <div class="row q-col-gutter-sm">
-                <div class="col-8">
-                  <div class="text-text">
-                    <span class="text-weight-medium">Agência</span>
-                  </div>
-                  <q-input
-                    v-model="stepSixForm.branch_number"
-                    no-error-icon
-                    outlined
-                    rounded
-                    class="bg-surface q-mt-sm q-mb-md"
-                    input-class="text-text"
-                    placeholder="0000"
-                    hide-bottom-space
-                    :rules="[requiredRule]"
-                    lazy-rules
-                    maxlength="20"
-                  />
-                </div>
-                <div class="col-4">
-                  <div class="text-text">
-                    <span class="text-weight-medium">Dígito</span>
-                  </div>
-                  <q-input
-                    v-model="stepSixForm.branch_check_digit"
-                    no-error-icon
-                    outlined
-                    rounded
-                    class="bg-surface q-mt-sm q-mb-md"
-                    input-class="text-text"
-                    placeholder="0"
-                    hide-bottom-space
-                    lazy-rules
-                    maxlength="10"
-                  />
-                </div>
-              </div>
-
-              <div class="row q-col-gutter-sm">
-                <div class="col-8">
-                  <div class="text-text">
-                    <span class="text-weight-medium">Conta</span>
-                  </div>
-                  <q-input
-                    v-model="stepSixForm.account_number"
-                    no-error-icon
-                    outlined
-                    rounded
-                    class="bg-surface q-mt-sm q-mb-md"
-                    input-class="text-text"
-                    placeholder="000000"
-                    hide-bottom-space
-                    :rules="[requiredRule]"
-                    lazy-rules
-                    maxlength="20"
-                  />
-                </div>
-                <div class="col-4">
-                  <div class="text-text">
-                    <span class="text-weight-medium">Dígito</span>
-                  </div>
-                  <q-input
-                    v-model="stepSixForm.account_check_digit"
-                    no-error-icon
-                    outlined
-                    rounded
-                    class="bg-surface q-mt-sm q-mb-md"
-                    input-class="text-text"
-                    placeholder="0"
-                    hide-bottom-space
-                    :rules="[requiredRule]"
-                    lazy-rules
-                    maxlength="10"
-                  />
-                </div>
-              </div>
-
-              <div class="text-text">
-                <span class="text-weight-medium">Chave Pix</span>
-              </div>
-              <q-input
-                v-model="stepSixForm.pix_key"
-                no-error-icon
-                outlined
-                rounded
-                class="bg-surface q-mt-sm q-mb-md"
-                input-class="text-text"
-                placeholder="Opcional"
-                hide-bottom-space
-                lazy-rules
-                maxlength="255"
-              />
-            </q-card-section>
-            <LoginStepSixPanel
-              v-else-if="steps === 7"
-              v-model="stepSevenForm"
-            />
+            <LoginStepFivePanel v-else-if="steps === 5" v-model="stepFiveForm" />
+            <LoginStepSixPanel v-else-if="steps === 6" v-model="stepSixForm" />
 
 
-            <div
-              v-else-if="steps === 8"
-              class="column items-center justify-center q-gutter-md text-center"
-            >
+            <div v-else-if="steps === 7" class="column items-center justify-center q-gutter-md text-center">
               <q-icon name="mdi-clock-outline" size="64px" color="warning" />
               <q-icon name="mdi-clock-outline" size="64px" color="warning" />
-              <div class="text-h6 text-text">
-                {{ $t("provider.login.pending_approval.title") }}
-              </div>
-              <div class="text-body2 text-grey-5">
-                {{ $t("provider.login.pending_approval.description") }}
-              </div>
+              <div class="text-h6 text-text">{{ $t('provider.login.pending_approval.title') }}</div>
+              <div class="text-body2 text-grey-5">{{ $t('provider.login.pending_approval.description') }}</div>
             </div>
             </div>
           </div>
           </div>
 
 
-          <div v-if="!showSubStep && steps !== 8" class="flow-footer">
+          <div v-if="!showSubStep && steps !== 7" class="flow-footer">
             <q-btn
             <q-btn
               color="primary-button"
               color="primary-button"
               :label="actionLabel"
               :label="actionLabel"
@@ -232,24 +63,24 @@
 </template>
 </template>
 
 
 <script setup>
 <script setup>
-import { computed, ref } from "vue";
-import { useQuasar } from "quasar";
-import { useRouter } from "vue-router";
-import { useI18n } from "vue-i18n";
-import { createUserAndProvider, sendCode, validateCode } from "src/api/user";
-import { useAuth } from "src/composables/useAuth";
-
-import BackgroundLogin from "src/assets/background-login.svg";
-import FotoDiarista from "src/assets/foto_diarista_login.svg";
-import LogoLogin from "src/assets/logo_diaria_login.svg";
-import LogoDiariaCampos from "src/assets/logo_diaria_campos_login.svg";
-
-import LoginStepOnePanel from "src/components/login/LoginStepOnePanel.vue";
-import LoginStepTwoPanel from "src/components/login/LoginStepTwoPanel.vue";
-import LoginStepThreePanel from "src/components/login/LoginStepThreePanel.vue";
-import LoginStepFourPanel from "src/components/login/LoginStepFourPanel.vue";
-import LoginStepFivePanel from "src/components/login/LoginStepFivePanel.vue";
-import LoginStepSixPanel from "src/components/login/LoginStepSixPanel.vue";
+import { computed, ref } from 'vue';
+import { useQuasar } from 'quasar';
+import { useRouter } from 'vue-router';
+import { useI18n } from 'vue-i18n';
+import { createUserAndProvider, sendCode, validateCode } from 'src/api/user';
+import { useAuth } from 'src/composables/useAuth';
+
+import BackgroundLogin from 'src/assets/background-login.svg';
+import FotoDiarista from 'src/assets/foto_diarista_login.svg';
+import LogoLogin from 'src/assets/logo_diaria_login.svg';
+import LogoDiariaCampos from 'src/assets/logo_diaria_campos_login.svg';
+
+import LoginStepOnePanel from 'src/components/login/LoginStepOnePanel.vue';
+import LoginStepTwoPanel from 'src/components/login/LoginStepTwoPanel.vue';
+import LoginStepThreePanel from 'src/components/login/LoginStepThreePanel.vue';
+import LoginStepFourPanel from 'src/components/login/LoginStepFourPanel.vue';
+import LoginStepFivePanel from 'src/components/login/LoginStepFivePanel.vue';
+import LoginStepSixPanel from 'src/components/login/LoginStepSixPanel.vue';
 
 
 const { t } = useI18n();
 const { t } = useI18n();
 const $q = useQuasar();
 const $q = useQuasar();
@@ -263,32 +94,35 @@ const submitting = ref(false);
 const loginForm = ref(null);
 const loginForm = ref(null);
 const isLogin = ref(false);
 const isLogin = ref(false);
 
 
-const email = ref("");
-const phone = ref("");
-const code = ref("");
+const email = ref('');
+const phone = ref('');
+const code = ref('');
 
 
 const stepThreeForm = ref({
 const stepThreeForm = ref({
-  name: "",
-  phone: "",
-  email: "",
-  rg: "",
-  document: "",
-  birth_date: "",
-  zip_code: "",
-  address: "",
-  complement: "",
+  name: '',
+  phone: '',
+  email: '',
+  rg: '',
+  document: '',
+  birth_date: '',
+  zip_code: '',
+  address: '',
+  complement: '',
   no_complement: false,
   no_complement: false,
-  city: "",
-  state: "",
-  address_type: "home",
-  nickname: "Principal",
-  instructions: "",
+  city: '',
+  state: '',
+  address_type: 'home',
+  nickname: 'Principal',
+  instructions: '',
 });
 });
 
 
 const stepFourForm = ref({
 const stepFourForm = ref({
-  selfie: null,
-  document_front: null,
-  document_back: null,
+  selfie_file: null,
+  selfie_base64: '',
+  document_front_file: null,
+  document_front_base64: '',
+  document_back_file: null,
+  document_back_base64: '',
 });
 });
 
 
 const stepFiveForm = ref({
 const stepFiveForm = ref({
@@ -300,30 +134,18 @@ const stepFiveForm = ref({
 });
 });
 
 
 const stepSixForm = ref({
 const stepSixForm = ref({
-  account_type: "checking",
-  bank: "",
-  branch_number: "",
-  branch_check_digit: "",
-  account_number: "",
-  account_check_digit: "",
-  pix_key: "",
-});
-
-const stepSevenForm = ref({
   working_days: {},
   working_days: {},
 });
 });
 
 
 const actionLabel = computed(() => {
 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");
-  return t("provider.login.steps.step_3.action");
+  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 === 6) return t('provider.login.steps.step_6.action');
+  return t('provider.login.steps.step_3.action');
 });
 });
 
 
-const requiredRule = (value) => !!value || t("validation.rules.required");
-
 const toISODate = (value) => {
 const toISODate = (value) => {
-  const matches = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(value || "");
+  const matches = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(value || '');
   if (!matches) return null;
   if (!matches) return null;
 
 
   return `${matches[3]}-${matches[2]}-${matches[1]}`;
   return `${matches[3]}-${matches[2]}-${matches[1]}`;
@@ -331,14 +153,14 @@ const toISODate = (value) => {
 
 
 const mapWorkingDays = () => {
 const mapWorkingDays = () => {
   const mapped = [];
   const mapped = [];
-  const workingDays = stepSevenForm.value.working_days || {};
+  const workingDays = stepSixForm.value.working_days || {};
 
 
   Object.entries(workingDays).forEach(([dayKey, periods]) => {
   Object.entries(workingDays).forEach(([dayKey, periods]) => {
     if (periods?.morning) {
     if (periods?.morning) {
-      mapped.push({ day: Number(dayKey), period: "morning" });
+      mapped.push({ day: Number(dayKey), period: 'morning' });
     }
     }
     if (periods?.afternoon) {
     if (periods?.afternoon) {
-      mapped.push({ day: Number(dayKey), period: "afternoon" });
+      mapped.push({ day: Number(dayKey), period: 'afternoon' });
     }
     }
   });
   });
 
 
@@ -349,11 +171,6 @@ const hasWorkingDaySelected = () => {
   return mapWorkingDays().length > 0;
   return mapWorkingDays().length > 0;
 };
 };
 
 
-const normalizeCurrency = (value) => {
-  const numberValue = Number(value);
-  return Number.isFinite(numberValue) ? numberValue : 0;
-};
-
 const validateCurrentStep = async () => {
 const validateCurrentStep = async () => {
   const isValid = await loginForm.value?.validate();
   const isValid = await loginForm.value?.validate();
 
 
@@ -362,35 +179,23 @@ const validateCurrentStep = async () => {
   }
   }
 
 
   if(steps.value === 4) {
   if(steps.value === 4) {
-    const hasSelfie = !!stepFourForm.value.selfie;
-    const hasDocumentFront = !!stepFourForm.value.document_front;
-    const hasDocumentBack = !!stepFourForm.value.document_back;
+    const hasSelfie = !!stepFourForm.value.selfie_base64;
+    const hasDocumentFront = !!stepFourForm.value.document_front_base64;
+    const hasDocumentBack = !!stepFourForm.value.document_back_base64;
 
 
     if (!hasSelfie || !hasDocumentFront || !hasDocumentBack) {
     if (!hasSelfie || !hasDocumentFront || !hasDocumentBack) {
       $q.notify({
       $q.notify({
-        type: "negative",
-        message: t("provider.login.steps.step_4.upload_all_photos"),
-      });
-      return false;
-    }
-  }
-
-  if (steps.value === 5) {
-    const dailyPrice8h = normalizeCurrency(stepFiveForm.value.daily_price_8h);
-
-    if (dailyPrice8h < 100 || dailyPrice8h > 500) {
-      $q.notify({
-        type: "negative",
-        message: "Informe uma diária entre R$ 100,00 e R$ 500,00.",
+        type: 'negative',
+        message: t('provider.login.steps.step_4.upload_all_photos'),
       });
       });
       return false;
       return false;
     }
     }
   }
   }
 
 
-  if (steps.value === 7 && !hasWorkingDaySelected()) {
+  if (steps.value === 6 && !hasWorkingDaySelected()) {
     $q.notify({
     $q.notify({
-      type: "negative",
-      message: t("provider.login.steps.step_6.select_at_least_one"),
+      type: 'negative',
+      message: t('provider.login.steps.step_6.select_at_least_one'),
     });
     });
     return false;
     return false;
   }
   }
@@ -407,17 +212,12 @@ const sendValidationCode = async () => {
 };
 };
 
 
 const validateCodeInput = async () => {
 const validateCodeInput = async () => {
-  const response = await validateCode(
-    email.value,
-    phone.value,
-    code.value,
-    isLogin.value,
-  );
+  const response = await validateCode(email.value, phone.value, code.value, isLogin.value);
 
 
   if (response.status === 200) {
   if (response.status === 200) {
     if (isLogin.value === true) {
     if (isLogin.value === true) {
       await setAuthDataFromPayload(response.data.payload);
       await setAuthDataFromPayload(response.data.payload);
-      router.push({ name: "DashboardPage" });
+      router.push({ name: 'DashboardPage' });
       return;
       return;
     }
     }
 
 
@@ -429,55 +229,38 @@ const validateCodeInput = async () => {
 
 
 const registerUserAndProvider = async () => {
 const registerUserAndProvider = async () => {
   const workingDays = mapWorkingDays();
   const workingDays = mapWorkingDays();
-  const form = new FormData();
 
 
-  const append = (key, val) => {
-    if (val === null || val === undefined) return;
-    if (typeof val === 'boolean') form.append(key, val ? '1' : '0');
-    else form.append(key, val);
-  };
+  const payload = {
+    ...stepThreeForm.value,
+    email: stepThreeForm.value.email || email.value,
+    phone: stepThreeForm.value.phone || phone.value,
+    code: code.value,
+    birth_date: toISODate(stepThreeForm.value.birth_date),
+    has_complement: !stepThreeForm.value.no_complement,
+    complement: stepThreeForm.value.no_complement ? null : stepThreeForm.value.complement,
 
 
-  append('name', stepThreeForm.value.name);
-  append('email', stepThreeForm.value.email || email.value);
-  append('phone', stepThreeForm.value.phone || phone.value);
-  append('code', code.value);
-  append('rg', stepThreeForm.value.rg);
-  append('document', stepThreeForm.value.document);
-  append('birth_date', toISODate(stepThreeForm.value.birth_date));
-  append('zip_code', stepThreeForm.value.zip_code);
-  append('address', stepThreeForm.value.address);
-  append('has_complement', !stepThreeForm.value.no_complement);
-  append('complement', stepThreeForm.value.no_complement ? null : stepThreeForm.value.complement);
-  append('nickname', stepThreeForm.value.nickname);
-  append('instructions', stepThreeForm.value.instructions);
-  append('city', stepThreeForm.value.city);
-  append('state', stepThreeForm.value.state);
-  append('address_type', stepThreeForm.value.address_type);
-
-  append('daily_price_8h', Number(stepFiveForm.value.daily_price_8h));
-  append('daily_price_6h', Number(stepFiveForm.value.daily_price_6h));
-  append('daily_price_4h', Number(stepFiveForm.value.daily_price_4h));
-  append('daily_price_2h', Number(stepFiveForm.value.daily_price_2h));
-
-  (stepFiveForm.value.services_types_ids ?? []).forEach(id => form.append('services_types_ids[]', id));
-
-  workingDays.forEach((wd, i) => {
-    form.append(`working_days[${i}][day]`, wd.day);
-    form.append(`working_days[${i}][period]`, wd.period);
-  });
+    selfie_base64: stepFourForm.value.selfie_base64,
+    document_front_base64: stepFourForm.value.document_front_base64,
+    document_back_base64: stepFourForm.value.document_back_base64,
+
+    daily_price_8h: Number(stepFiveForm.value.daily_price_8h),
+    daily_price_6h: Number(stepFiveForm.value.daily_price_6h),
+    daily_price_4h: Number(stepFiveForm.value.daily_price_4h),
+    daily_price_2h: Number(stepFiveForm.value.daily_price_2h),
+    services_types_ids: stepFiveForm.value.services_types_ids,
 
 
-  form.append('selfie', stepFourForm.value.selfie);
-  form.append('document_front', stepFourForm.value.document_front);
-  form.append('document_back', stepFourForm.value.document_back);
+    working_days: workingDays,
 
 
-  const response = await createUserAndProvider(form);
+  };
+
+  const response = await createUserAndProvider(payload);
   if (response.status === 200) {
   if (response.status === 200) {
     steps.value = 7;
     steps.value = 7;
   }
   }
 };
 };
 
 
 const onSubmit = async () => {
 const onSubmit = async () => {
-  if (showSubStep.value) return;
+  if (showSubStep.value) return; // Não submete o form principal se estiver em um sub-passo
 
 
   const isValid = await loginForm.value.validate();
   const isValid = await loginForm.value.validate();
   if (!isValid) return;
   if (!isValid) return;
@@ -513,12 +296,6 @@ const onSubmit = async () => {
         break;
         break;
       }
       }
       case 6: {
       case 6: {
-        if (await validateCurrentStep()) {
-          steps.value = 7;
-        }
-        break;
-      }
-      case 7: {
         if (await validateCurrentStep()) {
         if (await validateCurrentStep()) {
           await registerUserAndProvider();
           await registerUserAndProvider();
         }
         }
@@ -538,9 +315,7 @@ const onSubmit = async () => {
 <style lang="scss" scoped>
 <style lang="scss" scoped>
 .fade-slide-enter-active,
 .fade-slide-enter-active,
 .fade-slide-leave-active {
 .fade-slide-leave-active {
-  transition:
-    opacity 0.35s ease,
-    transform 0.35s ease;
+  transition: opacity 0.35s ease, transform 0.35s ease;
 }
 }
 .fade-slide-enter-from {
 .fade-slide-enter-from {
   opacity: 0;
   opacity: 0;

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

@@ -92,6 +92,24 @@
         <q-icon name="mdi-chevron-right" color="primary" size="md" />
         <q-icon name="mdi-chevron-right" color="primary" size="md" />
       </div>
       </div>
 
 
+      <div class="menu-item row items-center no-wrap cursor-pointer q-py-sm" @click="openPrivacyPolicy">
+        <div class="column">
+          <span class="menu-title gradient-diarista text-weight-bold">{{ $t('profile.privacy_policy.title') }}</span>
+          <span class="menu-description text-text">{{ $t('profile.privacy_policy.description') }}</span>
+        </div>
+        <q-space/>
+        <q-icon name="mdi-chevron-right" color="primary" size="md" />
+      </div>
+
+      <div class="menu-item row items-center no-wrap cursor-pointer q-py-sm" @click="openSupportPage">
+        <div class="column">
+          <span class="menu-title gradient-diarista text-weight-bold">{{ $t('profile.support_page.title') }}</span>
+          <span class="menu-description text-text">{{ $t('profile.support_page.description') }}</span>
+        </div>
+        <q-space/>
+        <q-icon name="mdi-chevron-right" color="primary" size="md" />
+      </div>
+
       <q-separator class="q-my-sm bg-grey-3" inset />
       <q-separator class="q-my-sm bg-grey-3" inset />
 
 
       <div class="menu-item row items-center no-wrap cursor-pointer q-py-sm" @click="logOutPrestador">
       <div class="menu-item row items-center no-wrap cursor-pointer q-py-sm" @click="logOutPrestador">
@@ -109,6 +127,7 @@
 <script setup>
 <script setup>
 import { ref, onMounted } from 'vue';
 import { ref, onMounted } from 'vue';
 import { useQuasar } from 'quasar';
 import { useQuasar } from 'quasar';
+import { Browser } from '@capacitor/browser';
 import { useAuth } from 'src/composables/useAuth';
 import { useAuth } from 'src/composables/useAuth';
 import { getUser } from 'src/api/user';
 import { getUser } from 'src/api/user';
 import ProfileEditDialog from './ProfileEditDialog.vue';
 import ProfileEditDialog from './ProfileEditDialog.vue';
@@ -120,6 +139,9 @@ import ProfileHelpDialog from 'src/components/profile/ProfileHelpDialog.vue';
 import ProfilePrivacyDialog from 'src/components/profile/ProfilePrivacyDialog.vue';
 import ProfilePrivacyDialog from 'src/components/profile/ProfilePrivacyDialog.vue';
 import { useRouter } from 'vue-router';
 import { useRouter } from 'vue-router';
 
 
+const PRIVACY_POLICY_URL = 'https://https://politicas.softpar.inf.br/politicas/politicaDiaristaPrestador.html';
+const SUPPORT_PAGE_URL   = 'https://https://politicas.softpar.inf.br/suportes/suporteDiaristaPrestador.html';
+
 const $q = useQuasar();
 const $q = useQuasar();
 
 
 const { logout } = useAuth();
 const { logout } = useAuth();
@@ -177,6 +199,14 @@ const openPrivacyDialog = () => {
   });
   });
 };
 };
 
 
+const openPrivacyPolicy = async () => {
+  await Browser.open({ url: PRIVACY_POLICY_URL });
+};
+
+const openSupportPage = async () => {
+  await Browser.open({ url: SUPPORT_PAGE_URL });
+};
+
 const logOutPrestador = async () => {
 const logOutPrestador = async () => {
   await logout();
   await logout();
   router.push('/login');
   router.push('/login');