Ver Fonte

chore version 2.7 + aba pedidos com agendamentos

Gustavo Zanatta há 2 semanas atrás
pai
commit
f1812beadf

+ 2 - 2
package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "diarista-cliente-app",
-  "version": "2.6",
+  "version": "2.7",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "diarista-cliente-app",
-      "version": "2.6",
+      "version": "2.7",
       "dependencies": {
         "@bufbuild/protobuf": "^2.5.1",
         "@capacitor/browser": "^7.0.5",

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "diarista-cliente-app",
-  "version": "2.6",
+  "version": "2.7",
   "description": "Aplicativo para o cliente do Diaria",
   "productName": "Diaria App",
   "author": "zntt <zanattagg@gmail.com>",

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

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

+ 2 - 2
src-capacitor/package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "diarista-cliente-app",
-  "version": "2.6",
+  "version": "2.7",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "diarista-cliente-app",
-      "version": "2.6",
+      "version": "2.7",
       "dependencies": {
         "@capacitor/android": "^7.6.8",
         "@capacitor/app": "^7.0.0",

+ 1 - 1
src-capacitor/package.json

@@ -1,6 +1,6 @@
 {
   "name": "diarista-cliente-app",
-  "version": "2.6",
+  "version": "2.7",
   "description": "Aplicativo para o cliente do Diaria",
   "author": "zntt <zanattagg@gmail.com>",
   "private": true,

+ 1 - 3
src/components/dashboard/DashboardPendingSchedules.vue

@@ -281,9 +281,7 @@ const displayScheduleTime = (item) => {
 };
 
 const seeDetails = (item) => {
-  if (isServicePackage.value || item.status === "accepted") {
-    emit("view-details", item);
-  }
+  emit("view-details", item);
 };
 </script>
 

+ 194 - 0
src/components/dashboard/PackageScheduleDetailsDialog.vue

@@ -0,0 +1,194 @@
+<template>
+  <q-dialog
+    ref="dialogRef"
+    @hide="onDialogHide"
+  >
+    <q-card
+      class="package-details-card bg-surface shadow-card"
+      :flat="false"
+    >
+      <div class="row justify-end q-pt-sm q-pr-sm">
+        <q-btn
+          color="grey-6"
+          dense
+          flat
+          icon="close"
+          round
+          size="sm"
+          @click="onDialogCancel"
+        />
+      </div>
+
+      <q-card-section class="column items-center q-pt-xs q-pb-sm">
+        <q-avatar
+          class="q-mb-sm"
+          size="72px"
+        >
+          <img
+            v-if="schedule.provider_photo"
+            :src="schedule.provider_photo"
+            style="object-fit: cover"
+          />
+
+          <span
+            v-else
+            class="full-width full-height flex flex-center"
+            style="font-size: 20px; border-radius: 50%"
+            :style="avatarColors[schedule.id % avatarColors.length]"
+          >
+            {{ providerInitials }}
+          </span>
+        </q-avatar>
+
+        <div class="text-text font16 fontbold">
+          {{ schedule.provider_name || "—" }}
+        </div>
+
+        <div class="text-primary font16 fontbold q-mt-xs">
+          {{ formatCurrency(packageTotal) }}
+        </div>
+
+        <div class="text-grey-6 font10">
+          {{ $t("service_package.services_total") }}
+        </div>
+
+        <div
+          v-if="packageItems.length > 1"
+          class="text-grey-6 font12 q-mt-xs"
+        >
+          {{ $t("service_package.package_count", { count: packageItems.length }) }}
+        </div>
+      </q-card-section>
+
+      <q-card-section class="q-pt-none q-pb-sm q-px-md text-text">
+        <div
+          v-for="item in packageItems"
+          :key="item.id"
+          class="package-item-row"
+        >
+          <div class="row items-center no-wrap justify-between">
+            <span class="fontbold font12">
+              {{ formatWeekday(item.date) + ", " + formatFullDate(item.date) }}
+            </span>
+
+            <span class="fontbold font12">
+              {{ formatCurrency(Number(item.total_amount) || 0) }}
+            </span>
+          </div>
+
+          <div class="row items-center no-wrap justify-between">
+            <span class="text-grey-6 font12">
+              {{ item.start_time?.slice(0, 5) }}
+              {{ $t("dashboard_client.next_schedules.to") }}
+              {{ item.end_time?.slice(0, 5) }}
+            </span>
+
+            <span class="text-grey-7 font12">
+              {{
+                item.offers_meal
+                  ? $t("service_package.with_meal")
+                  : $t("service_package.without_meal")
+              }}
+            </span>
+          </div>
+        </div>
+      </q-card-section>
+
+      <q-card-section class="column items-center q-pt-xs q-pb-sm text-text">
+        <div class="row items-start no-wrap self-start q-gutter-x-xs">
+          <q-icon
+            class="q-mt-xs"
+            color="primary"
+            name="mdi-map-marker"
+            size="20px"
+          />
+
+          <span class="font14 fontbold">
+            {{ formatAddress(schedule.address) || "—" }}
+          </span>
+        </div>
+      </q-card-section>
+
+      <q-separator />
+
+      <q-card-section class="q-py-md">
+        <q-btn
+          class="full-width"
+          color="primary"
+          no-caps
+          padding="8px 16px"
+          rounded
+          unelevated
+          :label="$t('common.actions.close')"
+          @click="onDialogCancel"
+        />
+      </q-card-section>
+    </q-card>
+  </q-dialog>
+</template>
+
+<script setup>
+import { computed } from "vue";
+import { avatarColors } from "src/helpers/avatarColors";
+import { formatAddress, formatCurrency } from "src/helpers/utils";
+import { formatWeekday, parseLocalDate } from "src/helpers/scheduleDate";
+import { useDialogPluginComponent } from "quasar";
+
+const props = defineProps({
+  schedule: {
+    type: Object,
+    required: true,
+  },
+});
+
+defineEmits([...useDialogPluginComponent.emits]);
+
+const { dialogRef, onDialogCancel, onDialogHide } = useDialogPluginComponent();
+
+const packageItems = computed(() => {
+  const items = props.schedule?.package_items;
+
+  return Array.isArray(items) && items.length ? items : [props.schedule];
+});
+
+const packageTotal = computed(() =>
+  packageItems.value.reduce(
+    (total, item) => total + (Number(item.total_amount) || 0),
+    0,
+  ),
+);
+
+const providerInitials = computed(
+  () => props.schedule.provider_name?.slice(0, 2).toUpperCase() ?? "??",
+);
+
+const formatFullDate = (value) => {
+  const date = parseLocalDate(value);
+
+  if (!date) return "";
+
+  return date.toLocaleDateString("pt-BR", {
+    day: "2-digit",
+    month: "2-digit",
+    year: "numeric",
+  });
+};
+</script>
+
+<style scoped lang="scss">
+.package-details-card {
+  width: 320px;
+  max-width: 92vw;
+  border-radius: 20px !important;
+  overflow: hidden;
+}
+
+.package-item-row {
+  border-bottom: 1px solid #ececf2;
+  padding: 6px 0;
+
+  &:last-child {
+    border-bottom: none;
+  }
+}
+</style>

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

@@ -838,6 +838,8 @@
     "local_cart_title": "Orders",
     "orders_title": "Orders",
     "pending_custom_title": "Requests in progress",
+    "pending_default_title": "Requested bookings",
+    "awaiting_payment_title": "Awaiting payment",
     "no_orders": "No orders created.",
     "order_title": "Order #{id}",
     "view_favorites": "view favorites",
@@ -865,6 +867,7 @@
     "address": "Address",
     "quantity": "Quantity",
     "schedule_count": "{count} time slot(s)",
+    "package_count": "Package with {count} services",
     "submit": "send request",
     "close": "close orders",
     "closed_success": "Orders closed. Wait for provider approval.",

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

@@ -835,6 +835,8 @@
     "local_cart_title": "Pedidos",
     "orders_title": "Pedidos",
     "pending_custom_title": "Solicitudes en curso",
+    "pending_default_title": "Reservas solicitadas",
+    "awaiting_payment_title": "Esperando el pago",
     "no_orders": "Ningún pedido creado.",
     "order_title": "Pedido #{id}",
     "view_favorites": "ver favoritos",
@@ -862,6 +864,7 @@
     "address": "Dirección",
     "quantity": "Cantidad",
     "schedule_count": "{count} horario(s)",
+    "package_count": "Paquete con {count} servicios",
     "submit": "enviar solicitud",
     "close": "cerrar pedidos",
     "closed_success": "Pedidos cerrados. Espere la aprobación de los profesionales.",

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

@@ -845,7 +845,9 @@
     "other_provider_blocked": "Seu pedido já possui horários com outro profissional. Finalize ou esvazie o pedido atual antes de agendar com outro profissional.",
     "local_cart_title": "Pedidos",
     "orders_title": "Pedidos",
-    "pending_custom_title": "Solicitações em andamento",
+    "pending_custom_title": "Solicitações Sob Medida em andamento",
+    "pending_default_title": "Agendamentos solicitados",
+    "awaiting_payment_title": "Aguardando pagamento",
     "no_orders": "Nenhum pedido criado.",
     "order_title": "Pedido #{id}",
     "view_favorites": "ver favoritos",
@@ -873,6 +875,7 @@
     "address": "Endereço",
     "quantity": "Quantidade",
     "schedule_count": "{count} horário(s)",
+    "package_count": "Pacote com {count} serviços",
     "submit": "enviar solicitação",
     "close": "confirmar pedido(s)",
     "closed_success": "Pedidos fechados. Aguarde a aprovação dos profissionais.",

+ 9 - 0
src/pages/dashboard/DashboardPage.vue

@@ -29,6 +29,7 @@
           :data="pendingRequests"
           progress-class="progress-fill--loop"
           @cancel="openCancelRequestDialog"
+          @view-details="openPackageDetailsDialog"
         />
         <DashboardTodaySchedules v-if="todaySchedules.length > 0" :data="todaySchedules" @rate="openRatingDialog" />
         <DashboardScrollAreaSchedules />
@@ -47,6 +48,7 @@ import DashboardSummaryInfos from 'src/components/dashboard/DashboardSummaryInfo
 import DashboardRegistrationIncomplete from 'src/components/dashboard/DashboardRegistrationIncomplete.vue';
 import DashboardPaymentIncomplete from 'src/components/dashboard/DashboardPaymentIncomplete.vue';
 import DashboardPendingSchedules from 'src/components/dashboard/DashboardPendingSchedules.vue';
+import PackageScheduleDetailsDialog from 'src/components/dashboard/PackageScheduleDetailsDialog.vue';
 import ScheduleAcceptedDialog from 'src/components/dashboard/ScheduleAcceptedDialog.vue';
 import ScheduleCancelDialog from 'src/components/dashboard/ScheduleCancelDialog.vue';
 import DashboardScrollAreaSchedules from 'src/components/dashboard/DashboardScrollAreaSchedules.vue';
@@ -125,6 +127,13 @@ const pendingRequests = computed(() => {
   });
 });
 
+const openPackageDetailsDialog = (schedule) => {
+  $q.dialog({
+    component: PackageScheduleDetailsDialog,
+    componentProps: { schedule },
+  });
+};
+
 const openCancelRequestDialog = (schedule) => {
   $q.dialog({
     component: ScheduleCancelDialog,

+ 73 - 4
src/pages/orders/ServicePackagePage.vue

@@ -238,7 +238,7 @@
       v-if="schedulesProposals.length > 0"
       :data="schedulesProposals"
       class="q-pt-md"
-      @refresh-data="loadCustomRequests"
+      @refresh-data="loadOrders"
     />
 
     <div
@@ -258,7 +258,39 @@
     </div>
 
     <div
-      v-if="servicePackage.items.length === 0 && !hasPendingCustomRequests"
+      v-if="pendingServicePackages.length > 0"
+      class="q-pt-md"
+    >
+      <div class="section-title gradient-diarista q-px-md q-mb-sm font16 fontbold">
+        {{ $t("service_package.awaiting_payment_title") }}
+      </div>
+
+      <DashboardPendingSchedules
+        :data="pendingServicePackages"
+        progress-class="progress-fill--urgent"
+        type="servicePackage"
+        @view-details="openServicePackagePaymentDialog"
+      />
+    </div>
+
+    <div
+      v-if="pendingSchedules.length > 0"
+      class="q-pt-md"
+    >
+      <div class="section-title gradient-diarista q-px-md q-mb-sm font16 fontbold">
+        {{ $t("service_package.pending_default_title") }}
+      </div>
+
+      <DashboardPendingSchedules
+        :data="pendingSchedules"
+        progress-class="progress-fill--urgent"
+        @cancel="openCancelRequestDialog"
+        @view-details="openPackageDetailsDialog"
+      />
+    </div>
+
+    <div
+      v-if="servicePackage.items.length === 0 && !hasPendingCustomRequests && !hasPendingDefaultSchedules"
       class="q-px-md q-pt-md"
     >
       <q-card
@@ -330,7 +362,11 @@
 import { computed, onMounted, ref } from "vue";
 import SchedulingDialog from "src/pages/search/components/SchedulingDialog.vue";
 import DashboardClientProposals from "src/pages/dashboard/components/DashboardClientProposals.vue";
+import DashboardPendingSchedules from "src/components/dashboard/DashboardPendingSchedules.vue";
 import CustomScheduleRequestCard from "src/pages/orders/components/CustomScheduleRequestCard.vue";
+import PackageScheduleDetailsDialog from "src/components/dashboard/PackageScheduleDetailsDialog.vue";
+import ScheduleAcceptedDialog from "src/components/dashboard/ScheduleAcceptedDialog.vue";
+import ScheduleCancelDialog from "src/components/dashboard/ScheduleCancelDialog.vue";
 import { createScheduleServicePackage } from "src/api/servicePackage";
 import { dadosPedidosCliente } from "src/api/dashboard";
 import { getAddresses } from "src/api/address";
@@ -355,6 +391,8 @@ const primaryAddress = ref(null);
 const submitting = ref(false);
 const customSchedulesNoProposals = ref([]);
 const schedulesProposals = ref([]);
+const pendingSchedules = ref([]);
+const pendingServicePackages = ref([]);
 
 const pendingCustomRequests = computed(() => {
   const groups = new Map();
@@ -390,6 +428,35 @@ const pendingCustomRequests = computed(() => {
 
 const hasPendingCustomRequests = computed(() => pendingCustomRequests.value.length > 0);
 
+const hasPendingDefaultSchedules = computed(
+  () => pendingSchedules.value.length > 0 || pendingServicePackages.value.length > 0,
+);
+
+const openServicePackagePaymentDialog = (packageToPay) => {
+  $q.dialog({
+    component: ScheduleAcceptedDialog,
+    componentProps: { servicePackage: packageToPay },
+  }).onOk(() => {
+    loadOrders();
+  });
+};
+
+const openPackageDetailsDialog = (schedule) => {
+  $q.dialog({
+    component: PackageScheduleDetailsDialog,
+    componentProps: { schedule },
+  });
+};
+
+const openCancelRequestDialog = (schedule) => {
+  $q.dialog({
+    component: ScheduleCancelDialog,
+    componentProps: { schedule },
+  }).onDismiss(() => {
+    loadOrders();
+  });
+};
+
 const isValidFee = (fee) =>
   fee !== null && fee !== undefined && Number.isFinite(Number(fee));
 
@@ -668,19 +735,21 @@ const submitServicePackage = async () => {
   }
 };
 
-const loadCustomRequests = async () => {
+const loadOrders = async () => {
   const response = await dadosPedidosCliente();
 
   if (response) {
     customSchedulesNoProposals.value = response.customSchedulesNoProposals ?? [];
     schedulesProposals.value = response.schedulesProposals ?? [];
+    pendingSchedules.value = response.pendingSchedules ?? [];
+    pendingServicePackages.value = response.pendingServicePackages ?? [];
   }
 };
 
 onMounted(() => {
   loadPrimaryAddress();
   loadPlatformFees().catch(() => {});
-  loadCustomRequests();
+  loadOrders();
 });
 </script>