Selaa lähdekoodia

fix: :bug: fix(ajustes no agendamento) Foi realizado ajustes no agendamaneto

Foi realizado ajustes no agendamento, ajustado a questão de selecionar horas onde antes aparecia as horas que já haviam passado agora ele calcular e mostra apenas horas diponiveis de acordo com a regra, tambem foi adicionado um modal de visualização de informações basicas do prestador

Origin: bug-interno
kayo henrique 10 tuntia sitten
vanhempi
commit
69dea8b90f

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

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

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

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

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

@@ -439,7 +439,8 @@
       "in_progress": "in progress",
       "end_time_label": "Ends at",
       "rate_btn": "Rate",
-      "help_btn": "help"
+      "help_btn": "help",
+      "cancelled": "Service cancelled"
     },
     "next_schedules": {
       "title": "Next services",

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

@@ -439,7 +439,8 @@
       "in_progress": "en progreso",
       "end_time_label": "Término a las",
       "rate_btn": "Avaliar",
-      "help_btn": "ayuda"
+      "help_btn": "ayuda",
+      "cancelled": "Servicio cancelado"
     },
     "next_schedules": {
       "title": "Próximos servicios",

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

@@ -439,7 +439,8 @@
       "in_progress": "em andamento",
       "end_time_label": "Término às",
       "rate_btn": "Avaliar",
-      "help_btn": "ajuda"
+      "help_btn": "ajuda",
+      "cancelled": "Serviço cancelado"
     },
     "next_schedules": {
       "title": "Próximos serviços",

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

@@ -126,6 +126,7 @@
                     icon="mdi-information-outline"
                     round
                     size="sm"
+                    @click.stop="openProviderInfo"
                   />
                 </div>
               </div>
@@ -223,13 +224,13 @@
                     />
 
                     <span v-else>
-                      {{ review.schedule?.client?.name?.slice(0, 1) ?? "—" }}
+                      {{ getFirstName(review.schedule?.client?.name)?.slice(0, 1) ?? "—" }}
                     </span>
                   </q-avatar>
 
                   <div class="col-3 text-text font10 fontbold">
                     {{
-                      review.schedule?.client?.name ??
+                      getFirstName(review.schedule?.client?.name) ??
                       $t("scheduling_page.unknown_client")
                     }}
                   </div>
@@ -285,6 +286,7 @@ import { useServicePackageStore } from "src/stores/servicePackage";
 import ServicePackageSummaryDialog from "./ServicePackageSummaryDialog.vue";
 import ServiceSelectionSheet from "./ServiceSelectionSheet.vue";
 import ServiceTimeSelectionDialog from "./ServiceTimeSelectionDialog.vue";
+import ProfileInfoDialog from "src/components/profile/ProfileInfoDialog.vue";
 
 defineEmits([...useDialogPluginComponent.emits]);
 
@@ -588,6 +590,15 @@ const onDateSelected = (val) => {
   });
 };
 
+const openProviderInfo = () => {
+  $q.dialog({
+    component: ProfileInfoDialog,
+    componentProps: {
+      provider: props.provider,
+    },
+  });
+};
+
 const toggleFavorite = async () => {
   if (favoriteLoading.value) return;
 

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

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