Browse Source

implementacao API na dashboard do cliente + internacionalizacao dos titulos

Gustavo Zanatta 1 tháng trước cách đây
mục cha
commit
d45b36ee10

+ 6 - 0
src/api/dashboard.js

@@ -0,0 +1,6 @@
+import api from "src/api";
+
+export const dadosDashboard = async () => {
+  const { data } = await api.get("/dados-dashboard-cliente");
+  return data.payload;
+}

+ 19 - 52
src/components/dashboard/DashboardFavoriteProviders.vue

@@ -1,49 +1,40 @@
-<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
 <template>
   <div class="q-mx-md q-mb-md">
-    <div class="dashboard-section-title gradient-diarista q-mb-sm">Favoritos</div>
+    <div class="dashboard-section-title gradient-diarista q-mb-sm">{{ $t('dashboard_client.favorites.title') }}</div>
 
-    <div class="scroll-track col-12">
+    <div class="scroll-track">
       <q-card
-        v-for="item in items"
+        v-for="item in data"
         :key="item.id"
         class="fav-card shadow-card bg-surface card-border"
+        :flat="false"
       >
         <q-card-section class="q-pa-sm column text-text">
           <div class="row items-start no-wrap q-gutter-x-sm">
             <div class="col-3">
-              <q-avatar :style="item.avatarStyle" size="46px" class="text-weight-bold col-auto">
-                {{ item.initials }}
+              <q-avatar :style="avatarColors[item.id % avatarColors.length]" size="46px" class="text-weight-bold">
+                {{ item.provider_name?.slice(0,1).toUpperCase() ?? '—' }}
               </q-avatar>
             </div>
             <div class="col-9 row">
               <div class="col-6 column full-height justify-between">
-                
                 <div class="column q-gutter-y-xs">
-                  <span class="text-fav-name">{{ item.name }}</span>
-                  <span class="text-fav-region">{{ item.region }}</span>
-
+                  <span class="text-fav-name">{{ item.provider_name ?? 'Prestador' }}</span>
                   <div class="row items-center q-gutter-x-xs">
                     <q-icon name="mdi-star" color="warning" size="sm" />
-                    <span class="text-fav-name">{{ item.rating }}</span>
+                    <span class="text-fav-name">{{ item.average_rating ?? '-' }}</span>
                   </div>
                 </div>
-
-                
               </div>
               <div class="column col-5 items-end justify-end">
                 <q-btn
-                  rounded
-                  color="primary"
-                  padding="1px 5px"
-                  size="sm"
-                  class=""
-                  label="ver agenda"
+                  rounded color="primary"
+                  padding="1px 5px" size="sm"
+                  :label="$t('dashboard_client.favorites.view_schedule')"
                 />
               </div>
             </div>
           </div>
-
         </q-card-section>
       </q-card>
     </div>
@@ -51,31 +42,13 @@
 </template>
 
 <script setup>
-const items = [
-  {
-    id: 1,
-    initials: 'M',
-    name: 'Marina',
-    region: 'Santo Amaro',
-    rating: '4.9',
-    avatarStyle: { background: '#fdd', color: '#932e57' },
-  },
-  {
-    id: 2,
-    initials: 'O',
-    name: 'Odete',
-    region: 'Piraporinha',
-    rating: '4.7',
-    avatarStyle: { background: '#d7e8ff', color: '#2158a8' },
-  },
-  {
-    id: 3,
-    initials: 'K',
-    name: 'Kimberly',
-    region: 'Largo 13',
-    rating: '4.8',
-    avatarStyle: { background: '#dfd', color: '#2a7a3b' },
-  },
+defineProps({ data: { type: Array, default: () => [] } });
+
+const avatarColors = [
+  { background: '#ffd5df', color: '#932e57' },
+  { background: '#d7e8ff', color: '#2158a8' },
+  { background: '#dfd',    color: '#2a7a3b' },
+  { background: '#ffe5cc', color: '#8a4500' },
 ];
 </script>
 
@@ -88,15 +61,9 @@ const items = [
   overscroll-behavior-x: contain;
   scroll-snap-type: x proximity;
   padding-bottom: 8px;
-
   &::-webkit-scrollbar { display: none; }
-
-  &::after {
-    content: '';
-    flex: 0 0 1px;
-  }
+  &::after { content: ''; flex: 0 0 1px; }
 }
-
 .fav-card {
   flex: 0 0 200px;
   scroll-snap-align: start;

+ 5 - 6
src/components/dashboard/DashboardHeaderBar.vue

@@ -4,12 +4,12 @@
     <div class="col column q-gutter-y-xs">
       <div class="row items-center q-gutter-x-xs">
         <q-icon name="mdi-star" color="warning" size="14px" />
-        <span class="dashboard-metric-value">5,0</span>
-        <span class="dashboard-metric-meta">(33)</span>
+        <span class="dashboard-metric-value">{{ data?.rating != null ? Number(data.rating).toFixed(1).replace('.', ',') : '-' }}</span>
+        <span class="dashboard-metric-meta">({{ data?.total_ratings ?? 0 }})</span>
       </div>
       <div class="row items-center q-gutter-x-xs">
         <q-icon name="mdi-broom" color="secondary" size="14px" />
-        <span class="dashboard-metric-value">13</span>
+        <span class="dashboard-metric-value">{{ data?.total_services ?? 0 }}</span>
       </div>
     </div>
 
@@ -25,6 +25,8 @@
 
 <script setup>
 import LogoDiariaColorida from 'src/assets/logo_diaria_colorido_sem_texto.svg';
+
+defineProps({ data: { type: Object, default: () => null } });
 </script>
 
 <style scoped lang="scss">
@@ -33,12 +35,10 @@ import LogoDiariaColorida from 'src/assets/logo_diaria_colorido_sem_texto.svg';
   width: 100%;
   box-sizing: border-box;
 }
-
 .dashboard-logo {
   width: 32px;
   height: 32px;
 }
-
 .dashboard-metric-value {
   font-family: "Inter", sans-serif;
   font-size: 11px;
@@ -46,7 +46,6 @@ import LogoDiariaColorida from 'src/assets/logo_diaria_colorido_sem_texto.svg';
   color: #3a3a4a;
   line-height: 1;
 }
-
 .dashboard-metric-meta {
   font-family: "Inter", sans-serif;
   font-size: 10px;

+ 19 - 43
src/components/dashboard/DashboardLastDoneSchedules.vue

@@ -1,27 +1,24 @@
-<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
 <template>
-  <div class="q-mx-md q-mb-md bg">
-    <div class="dashboard-section-title gradient-diarista q-mb-sm">Últimos serviços</div>
+  <div class="q-mx-md q-mb-md">
+    <div class="dashboard-section-title gradient-diarista q-mb-sm">{{ $t('dashboard_client.last_schedules.title') }}</div>
 
     <div class="scroll-track">
       <q-card
-        v-for="item in items"
+        v-for="item in data"
         :key="item.id"
         class="mini-card shadow-card bg-surface card-border"
+        :flat="false"
       >
-        <q-card-section class="column items-center q-pa-sm q-gutter-y-xs text-text q-pa-md">
-          <q-avatar :style="item.avatarStyle" size="56px" class="text-weight-bold">
-            {{ item.initials }}
+        <q-card-section class="column items-center q-pa-md q-gutter-y-xs text-text">
+          <q-avatar :style="avatarColors[item.id % avatarColors.length]" size="56px" class="text-weight-bold">
+            {{ item.provider_name?.slice(0,1).toUpperCase() ?? '—' }}
           </q-avatar>
-          <span class="text-done-name">{{ item.name }}</span>
-          <span class="text-fav-region">{{ item.region }}</span>
+          <span class="text-done-name">{{ item.provider_name ?? 'Prestador' }}</span>
           <q-btn
-            rounded
-            color="secondary"
-            padding="1px 5px"
-            size="sm"
+            rounded color="secondary"
+            padding="1px 5px" size="sm"
             class="q-mt-xs full-width"
-            label="reagendar"
+            :label="$t('dashboard_client.last_schedules.reschedule')"
           />
         </q-card-section>
       </q-card>
@@ -30,28 +27,13 @@
 </template>
 
 <script setup>
-const items = [
-  {
-    id: 1,
-    initials: 'M',
-    name: 'Marina',
-    region: 'Santo Amaro',
-    avatarStyle: { background: '#fdd', color: '#932e57' },
-  },
-  {
-    id: 2,
-    initials: 'O',
-    name: 'Odete',
-    region: 'Piraporinha',
-    avatarStyle: { background: '#d7e8ff', color: '#2158a8' },
-  },
-  {
-    id: 3,
-    initials: 'K',
-    name: 'Kimberly',
-    region: 'Largo 13',
-    avatarStyle: { background: '#dfd', color: '#2a7a3b' },
-  },
+defineProps({ data: { type: Array, default: () => [] } });
+
+const avatarColors = [
+  { background: '#ffd5df', color: '#932e57' },
+  { background: '#d7e8ff', color: '#2158a8' },
+  { background: '#dfd',    color: '#2a7a3b' },
+  { background: '#ffe5cc', color: '#8a4500' },
 ];
 </script>
 
@@ -64,15 +46,9 @@ const items = [
   overscroll-behavior-x: contain;
   scroll-snap-type: x proximity;
   padding-bottom: 8px;
-
   &::-webkit-scrollbar { display: none; }
-
-  &::after {
-    content: '';
-    flex: 0 0 1px;
-  }
+  &::after { content: ''; flex: 0 0 1px; }
 }
-
 .mini-card {
   flex: 0 0 130px;
   scroll-snap-align: start;

+ 89 - 99
src/components/dashboard/DashboardNextSchedules.vue

@@ -1,71 +1,74 @@
-<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
 <template>
   <div class="q-mx-md q-mb-md">
-    <div class="dashboard-section-title gradient-diarista q-mb-sm">Próximos serviços</div>
+    <div class="dashboard-section-title gradient-diarista q-mb-sm">{{ $t('dashboard_client.next_schedules.title') }}</div>
 
     <div class="scroll-wrapper">
       <div class="scroll-track">
         <q-card
-          v-for="item in items"
+          v-for="item in data"
           :key="item.id"
           class="schedule-card card-border shadow-card bg-surface"
+          :flat="false"
         >
           <q-card-section class="q-pa-md row col-12 no-wrap">
-              <div class="col-3 column text-center">
-                <div class="col-7">
-                  <q-avatar :style="item.avatarStyle" class="text-weight-bold q-mx-auto">
-                    {{ item.initials }}
-                  </q-avatar>
-                </div>
-                <div class="col-5 column justify-end">
-                  <span class="text-pill text-primary q-pb-xs">{{ item.tag }}</span>
-                  <span class="text-pill text-secondary">{{ item.tag2 }}</span>
-                </div>
+            <div class="col-3 column text-center">
+              <div class="col-7">
+                <q-avatar :style="avatarColors[item.id % avatarColors.length]" class="text-weight-bold q-mx-auto">
+                  {{ item.provider_name?.slice(0,1) ?? '—' }}
+                </q-avatar>
               </div>
+              <div class="col-5 column justify-end">
+                <span class="text-pill text-primary">
+                  {{ item.schedule_type === 'custom' ? $t('dashboard_client.next_schedules.custom') : $t('dashboard_client.next_schedules.default') }}
+                </span>
+              </div>
+            </div>
 
-
-              <div class="col-5 column text-text q-px-sm">
-                  <div class="col-7 column">
-                    <div class="col-4">
-                      <span class="text-provider-name">{{ item.name }}</span>
-                    </div>
-                    <div class="col-4 column">
-                      <div class="col-6">
-                        <span class="text-schedule-date-bold">{{ item.dateBold }}</span>
-                        <span class="text-schedule-date-regular">{{ item.dateRegular }}</span>
-                      </div>
-                      <div class="col-6 q-pt-sm">
-                        <span class="text-schedule-date-regular">{{ item.hourRegular }}</span>
-                        <span class="text-schedule-date-bold">{{ item.hourBold }}</span>
-                      </div>
-                    </div>
+            <div class="col-5 column text-text q-px-sm">
+              <div class="col-7 column">
+                <div class="col-4">
+                  <span class="text-provider-name">{{ item.provider_name ?? $t('dashboard_client.next_schedules.no_provider') }}</span>
+                </div>
+                <div class="col-4 column">
+                  <div class="col-6">
+                    <span class="text-schedule-date-bold">{{ formatWeekday(item.date) }}</span><span class="text-schedule-date-regular">{{ ', ' + formatDayMonth(item.date) }}</span>
                   </div>
-                  <div class="col-5">
-                    <div class="full-height column justify-end">
-                      <div class="row text-pill-place">
-                        <q-icon :name="item.placeIcon" size="15px" color="primary"/>
-                        <div class="row items-end">{{ item.place }}</div>
-                      </div>
-                    </div>
+                  <div class="col-6 q-pt-sm">
+                    <span class="text-schedule-date-regular">{{ $t('dashboard_client.next_schedules.from') }} </span>
+                    <span class="text-schedule-date-bold">{{ item.start_time?.slice(0,5) }} {{ $t('dashboard_client.next_schedules.to') }} {{ item.end_time?.slice(0,5) }}</span>
                   </div>
-              </div>
-
-              <div class="col-4 column text-text">
-                <div class="column col-5">
-                  <span class="text-price-main col-6 q-mx-auto">{{ item.priceMain }}</span>
-                  <span class="text-price-label col-6 q-mx-auto">{{ item.priceLabel }}</span>
                 </div>
-                <div class="col-7 column justify-end items-end">
-                  <q-btn
-                    unelevated rounded no-caps
-                    color="primary"
-                    padding="1px 5px"
-                    size="sm"
-                    class="full-width"
-                    label="ver detalhes"
-                  />
+              </div>
+              <div class="col-5">
+                <div class="full-height column justify-end">
+                  <div class="row text-pill-place">
+                    <q-icon :name="addressIcon(item.address_type)" size="15px" color="primary" />
+                    <span class="row items-end">{{ addressLabel(item.address_type) }}</span>
+                  </div>
                 </div>
               </div>
+            </div>
+
+            <div class="col-4 column text-text">
+              <div class="column col-5">
+                <span class="text-price-main col-6 q-mx-auto">
+                  {{ item.total_amount && item.total_amount !== '0.00' ? formatCurrency(item.total_amount) : $t('dashboard_client.next_schedules.to_combine') }}
+                </span>
+                <span class="text-price-label col-6 q-mx-auto">
+                  {{ item.schedule_type === 'custom' ? $t('dashboard_client.next_schedules.tag_custom') : $t('dashboard_client.next_schedules.tag_default') }}
+                </span>
+              </div>
+              <div class="col-7 column justify-end items-end">
+                <q-btn
+                  unelevated rounded no-caps
+                  color="primary"
+                  padding="1px 5px"
+                  size="sm"
+                  class="full-width"
+                  :label="$t('dashboard_client.next_schedules.details')"
+                />
+              </div>
+            </div>
           </q-card-section>
         </q-card>
       </div>
@@ -74,48 +77,43 @@
 </template>
 
 <script setup>
-const items = [
-  {
-    id: 1,
-    initials: 'F',
-    name: 'Fátima',
-    dateBold: 'Segunda-feira',
-    dateRegular: ', 04/10',
-    hourBold: ' 09h30 às 17h30',
-    hourRegular: 'Das',
-    priceLabel: 'integral (até 8h)',
-    priceMain: 'R$245,00',
-    tag: 'solicitação',
-    tag2: 'sob medida',
-    place: 'apartamento',
-    placeIcon: 'mdi-home-map-marker',
-    avatarStyle: { background: '#ffd5df', color: '#932e57' },
-  },
-  {
-    id: 2,
-    initials: 'S',
-    name: 'Sandra',
-    dateBold: 'Quarta-feira',
-    dateRegular: ', 06/10',
-    hourBold: ' 08h às 16h',
-    hourRegular: 'Das',
-    priceLabel: 'integral (até 8h)',
-    priceMain: 'R$198,00',
-    tag: 'solicitação',
-    tag2: 'sob medida',
-    place: 'casa',
-    placeIcon: 'mdi-home-map-marker',
-    avatarStyle: { background: '#d7e8ff', color: '#2158a8' },
-  },
+import { useI18n } from 'vue-i18n';
+import { formatCurrency } from 'src/helpers/utils';
+
+defineProps({ data: { type: Array, default: () => [] } });
+
+const { t } = useI18n();
+
+const avatarColors = [
+  { background: '#ffd5df', color: '#932e57' },
+  { background: '#d7e8ff', color: '#2158a8' },
+  { background: '#dfd',    color: '#2a7a3b' },
+  { background: '#ffe5cc', color: '#8a4500' },
 ];
-</script>
 
-<style scoped lang="scss">
+const formatWeekday = (iso) => {
+  if (!iso) return '';
+  const d = new Date(iso);
+  const w = d.toLocaleDateString('pt-BR', { weekday: 'long' });
+  return w.charAt(0).toUpperCase() + w.slice(1);
+};
 
-.scroll-wrapper {
-  overflow: hidden;
-}
+const formatDayMonth = (iso) => {
+  if (!iso) return '';
+  return new Date(iso).toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' });
+};
+
+const addressIcon = (type) => type === 'home' ? 'mdi-home-outline' : 'mdi-office-building-outline';
 
+const addressLabel = (type) => {
+  if (type === 'home') return t('dashboard_client.next_schedules.place_home');
+  if (type === 'apartment') return t('dashboard_client.next_schedules.place_apartment');
+  return t('dashboard_client.next_schedules.place_unknown');
+};
+</script>
+
+<style scoped lang="scss">
+.scroll-wrapper { overflow: hidden; }
 .scroll-track {
   display: flex;
   flex-direction: row;
@@ -124,19 +122,11 @@ const items = [
   overscroll-behavior-x: contain;
   scroll-snap-type: x proximity;
   padding-bottom: 8px;
-
   &::-webkit-scrollbar { display: none; }
-
-  &::after {
-    content: '';
-    flex: 0 0 1px;
-  }
+  &::after { content: ''; flex: 0 0 1px; }
 }
-
 .schedule-card {
-  // border-radius: 18px;
   min-width: 80%;
-  min-height: 90px
+  min-height: 90px;
 }
-
 </style>

+ 34 - 56
src/components/dashboard/DashboardProvidersClose.vue

@@ -1,58 +1,61 @@
-<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
 <template>
   <div class="q-mx-md q-mb-lg">
     <div class="row items-center justify-between no-wrap q-mb-sm">
-      <div class="dashboard-section-title gradient-diarista">Perto de você</div>
-        <div>
-          <q-icon name="mdi-chevron-left" />
-          <span>Até 8h</span>
-          <q-icon name="mdi-chevron-right" />
-        </div>
+      <div class="dashboard-section-title gradient-diarista">{{ $t('dashboard_client.providers_close.title') }}</div>
+      <div>
+        <q-icon name="mdi-chevron-left" />
+        <span>{{ $t('dashboard_client.providers_close.until_8h') }}</span>
+        <q-icon name="mdi-chevron-right" />
+      </div>
     </div>
 
-    <div class="column ">
+    <div class="column">
       <q-card
-        v-for="p in providers"
+        v-for="p in data"
         :key="p.id"
-        class="shadow-card card-border bg-page text-text"
+        class="card-border bg-page text-text q-mb-sm"
+        :flat="false"
       >
         <q-card-section class="row no-wrap q-pa-sm">
           <div class="row no-wrap full-width">
             <div class="col-2">
-              <q-avatar :style="p.avatarStyle" class="text-weight-bold col-2">
-                {{ p.initials }}
+              <q-avatar :style="avatarColors[p.id % avatarColors.length]" class="text-weight-bold">
+                {{ p.provider_name?.slice(0,1).toUpperCase() ?? '—' }}
               </q-avatar>
             </div>
 
             <div class="col-10 row">
               <div class="column col-9 justify-between">
-                <span class="text-provider-close-name">{{ p.name }}</span>
-                <span class="text-provider-close-region">{{ p.region }}</span>
+                <span class="text-provider-close-name">{{ p.provider_name ?? 'Prestador' }}</span>
+                <span class="text-provider-close-region">{{ p.address_type === 'home' ? $t('dashboard_client.providers_close.place_home') : '' }}</span>
                 <div class="row items-center justify-between q-pr-lg">
                   <div class="row items-center">
                     <q-icon name="mdi-star" color="warning" size="10px" />
-                    <span class="text-provider-close-rating">{{ p.rating }}</span>
+                    <span class="text-provider-close-rating">
+                      {{ (p.average_rating ?? '-') + ' (' + (p.total_reviews ?? 0) + ')' }}
+                    </span>
                   </div>
                   <div class="row items-center">
-                    <q-icon name="mdi-broom" color="secondary" />
-                    <span class="text-provider-close-jobs">{{ p.jobs }}</span>
+                    <q-icon name="mdi-broom" color="secondary" size="12px" />
+                    <span class="text-provider-close-jobs">{{ p.total_services ?? 0 }}</span>
                   </div>
                   <div class="row items-center">
-                    <q-icon name="mdi-map-marker-outline" size="10px" color="grey-6" />
-                    <span class="text-provider-close-distance">{{ p.distance }}</span>
+                    <q-icon name="mdi-map-marker-outline" color="text" size="12px" />
+                    <span class="text-provider-close-jobs">{{ 0 + ' km' }}</span>
                   </div>
                 </div>
               </div>
 
               <div class="column col-3 justify-between text-center items-center">
-                <span class="text-provider-close-price">{{ p.price }}</span>
+                <span class="text-provider-close-price">
+                  {{ p.daily_price_8h ? formatCurrency(p.daily_price_8h) : noPrice }}</span>
                 <div class="full-width">
                   <q-btn
                     unelevated rounded no-caps
                     color="primary"
                     size="sm"
                     padding="3px 12px"
-                    label="agendar"
+                    :label="$t('dashboard_client.providers_close.schedule')"
                   />
                 </div>
               </div>
@@ -65,44 +68,19 @@
 </template>
 
 <script setup>
+import { formatCurrency } from 'src/helpers/utils';
 
-const providers = [
-  {
-    id: 1,
-    initials: 'S',
-    name: 'Silvia',
-    region: 'Largo 13',
-    rating: '4.9 (99+)',
-    jobs: 312,
-    distance: '0,8 km',
-    price: 'R$165,00',
-    avatarStyle: { background: '#ffe0f0', color: '#932e57' },
-  },
-  {
-    id: 2,
-    initials: 'M',
-    name: 'Marina',
-    region: 'Santo Amaro',
-    rating: '4.8 (99+)',
-    jobs: 128,
-    distance: '1,2 km',
-    price: 'R$145,00',
-    avatarStyle: { background: '#fdd', color: '#7b2640' },
-  },
-  {
-    id: 3,
-    initials: 'E',
-    name: 'Elton',
-    region: 'Santo Amaro',
-    rating: '4.7 (99+)',
-    jobs: 74,
-    distance: '1,5 km',
-    price: 'R$130,00',
-    avatarStyle: { background: '#d7e8ff', color: '#2158a8' },
-  },
+defineProps({ data: { type: Array, default: () => [] } });
+
+const noPrice = '\u2014';
+
+const avatarColors = [
+  { background: '#ffd5df', color: '#932e57' },
+  { background: '#d7e8ff', color: '#2158a8' },
+  { background: '#dfd',    color: '#2a7a3b' },
+  { background: '#ffe5cc', color: '#8a4500' },
 ];
 </script>
 
 <style scoped lang="scss">
-
 </style>

+ 16 - 39
src/components/dashboard/DashboardSummaryInfos.vue

@@ -1,31 +1,28 @@
-<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
 <template>
-  <q-card class="summary-card shadow-card q-ma-md bg-surface card-border">
+  <q-card class="summary-card shadow-card q-ma-md bg-surface card-border" :flat="false">
     <q-card-section class="q-pa-md">
       <div class="row items-center no-wrap q-gutter-x-md">
         <div class="row items-center no-wrap q-gutter-x-sm col">
           <q-avatar size="54px" :style="avatarStyle" class="text-weight-bold text-h6">
-            {{ initials }}
+            {{ data?.name?.slice(0, 2).toUpperCase() ?? '??' }}
           </q-avatar>
           <div class="column q-gutter-y-xs min-width-0">
-            <span class="summary-greeting text-greeting">Bem-vindo (a),</span>
-            <span class="summary-name text-name text-primary">Helena</span>
+            <span class="summary-greeting text-greeting">{{ $t('dashboard_client.summary.welcome') }}</span>
+            <span class="summary-name text-name text-primary">{{ data?.name ?? $t('dashboard_client.summary.welcome') }}</span>
           </div>
         </div>
         <div class="column items-end q-gutter-y-xs col-auto">
-          <div class="row items-center justify-end q-gutter-x-xs">
-            <span class="summary-label text-label-bold text-grey-6">Minhas diárias</span>
-          </div>
-          <span class="summary-count row">        
+          <span class="summary-label text-label-bold text-grey-6">{{ $t('dashboard_client.summary.my_schedules') }}</span>
+          <span class="summary-count row">
             <q-icon name="mdi-clock-check-outline" class="q-my-auto" size="sm" color="grey-6" />
-            <span class="q-my-auto q-ml-sm">0</span>
+            <span class="q-my-auto q-ml-sm">{{ data?.pending_services ?? 0 }}</span>
           </span>
         </div>
       </div>
 
       <div class="row items-center justify-between no-wrap q-mt-xs">
         <div class="summary-address text-address text-grey-6 ellipsis col">
-          Rua Dr. Ferreira Lopes 317, Santo Amaro, CEP 04671-071
+          {{ data?.address ?? '' }}
         </div>
         <q-icon name="mdi-chevron-down" color="secondary" size="18px" class="col-auto" />
       </div>
@@ -34,46 +31,26 @@
 </template>
 
 <script setup>
-import { computed } from 'vue';
+defineProps({ data: { type: Object, default: () => null } });
 
-const fullName = 'Helena';
-const initials = computed(() => fullName.slice(0, 2).toUpperCase());
-const avatarStyle = computed(() => ({
+const avatarStyle = {
   background: 'linear-gradient(135deg, #ffd7e8 0%, #ff9acc 100%)',
   color: '#7a154f',
-}));
+};
 </script>
 
 <style scoped lang="scss">
-.summary-card {
-  overflow: hidden;
-}
-
-.min-width-0 {
-  min-width: 0;
-}
-
-.summary-greeting {
-  color: #8c8c98;
-  display: block;
-}
-
-.summary-name {
-  display: block;
-  line-height: 1.1;
-}
-
-.summary-label {
-  white-space: nowrap;
-}
-
+.summary-card { overflow: hidden; }
+.min-width-0 { min-width: 0; }
+.summary-greeting { color: #8c8c98; display: block; }
+.summary-name { display: block; line-height: 1.1; }
+.summary-label { white-space: nowrap; }
 .summary-count {
   font-family: "Inter", sans-serif;
   font-size: 20px;
   font-weight: 500;
   color: #3a3a4a;
 }
-
 .summary-address {
   overflow: hidden;
   text-overflow: ellipsis;

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

@@ -314,6 +314,28 @@
       "detractors": "Detractors"
     }
   },
+  "dashboard_client": {
+    "header": { "rating": "Rating", "services": "Services" },
+    "summary": { "welcome": "Welcome,", "my_schedules": "My schedules" },
+    "next_schedules": {
+      "title": "Next services",
+      "no_provider": "No provider assigned",
+      "to_combine": "To be agreed",
+      "from": "From",
+      "to": "to",
+      "custom": "custom",
+      "default": "full day (up to 8h)",
+      "tag_custom": "custom request",
+      "tag_default": "standard booking",
+      "place_home": "home",
+      "place_apartment": "apartment",
+      "place_unknown": "N/A",
+      "details": "view details"
+    },
+    "last_schedules": { "title": "Last services", "reschedule": "reschedule" },
+    "favorites": { "title": "Favorites", "view_schedule": "view schedule" },
+    "providers_close": { "title": "Near you", "schedule": "book", "until_8h": "Up to 8h", "place_home": "Home" }
+  },
   "dashboard": {
     "currency_format": "$ {value}",
     "cards": {

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

@@ -314,6 +314,28 @@
       "detractors": "Detractores"
     }
   },
+  "dashboard_client": {
+    "header": { "rating": "Calificación", "services": "Servicios" },
+    "summary": { "welcome": "Bienvenido (a),", "my_schedules": "Mis jornadas" },
+    "next_schedules": {
+      "title": "Próximos servicios",
+      "no_provider": "Sin prestador asignado",
+      "to_combine": "A convenir",
+      "from": "De",
+      "to": "a",
+      "custom": "a medida",
+      "default": "jornada completa (hasta 8h)",
+      "tag_custom": "solicitud a medida",
+      "tag_default": "reserva estándar",
+      "place_home": "casa",
+      "place_apartment": "apartamento",
+      "place_unknown": "N/A",
+      "details": "ver detalles"
+    },
+    "last_schedules": { "title": "Últimos servicios", "reschedule": "reagendar" },
+    "favorites": { "title": "Favoritos", "view_schedule": "ver agenda" },
+    "providers_close": { "title": "Cerca de ti", "schedule": "reservar", "until_8h": "Hasta 8h", "place_home": "Casa" }
+  },
   "dashboard": {
     "currency_format": "R$ {value}",
     "cards": {

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

@@ -314,6 +314,45 @@
       "detractors": "Detratores"
     }
   },
+  "dashboard_client": {
+    "header": {
+      "rating": "Avaliação",
+      "services": "Serviços"
+    },
+    "summary": {
+      "welcome": "Bem-vindo (a),",
+      "my_schedules": "Minhas diárias"
+    },
+    "next_schedules": {
+      "title": "Próximos serviços",
+      "no_provider": "Sem prestador definido",
+      "to_combine": "A combinar",
+      "from": "Das",
+      "to": "às",
+      "custom": "sob medida",
+      "default": "integral (até 8h)",
+      "tag_custom": "solicitação sob medida",
+      "tag_default": "agendamento padrão",
+      "place_home": "casa",
+      "place_apartment": "apartamento",
+      "place_unknown": "N/A",
+      "details": "ver detalhes"
+    },
+    "last_schedules": {
+      "title": "Últimos serviços",
+      "reschedule": "reagendar"
+    },
+    "favorites": {
+      "title": "Favoritos",
+      "view_schedule": "ver agenda"
+    },
+    "providers_close": {
+      "title": "Perto de você",
+      "schedule": "agendar",
+      "until_8h": "Até 8h",
+      "place_home": "Casa"
+    }
+  },
   "dashboard": {
     "currency_format": "R$ {value}",
     "cards": {

+ 8 - 9
src/layouts/MainLayout.vue

@@ -9,11 +9,11 @@
     >
     </q-header>
     <q-page-container>
-      <q-page class="bg-surface main-layout-page">
+      <q-page class="bg-surface main-layout-page" style="overflow: hidden;">
         <q-scroll-area
           ref="scrollAreaRef"
           class="main-layout-scroll-area"
-          :style="scrollAreaStyle"
+          :style="scrollAreaHeight"
           :content-style="{ width: '100%', maxWidth: '100%', overflowX: 'hidden', boxSizing: 'border-box' }"
           :content-active-style="{ width: '100%', maxWidth: '100%', overflowX: 'hidden', boxSizing: 'border-box' }"
         >
@@ -84,16 +84,15 @@ const navItems = [
   },
 ];
 
-const scrollAreaStyle = computed(() => {
+const isNavItemActive = (item) => route.name === item.name;
+
+const scrollAreaHeight = computed(() => {
   if ($q.screen.lt.sm) {
-    return `height: calc(100dvh  - env(safe-area-inset-top)  - env(safe-area-inset-bottom)) !important;`;
+    return 'height: calc(100dvh - 50px - env(safe-area-inset-top) - 80px - env(safe-area-inset-bottom)) !important;';
   }
-
-  return "height: calc(100dvh - env(safe-area-inset-top)) !important;";
+  return 'height: 100dvh !important;';
 });
 
-const isNavItemActive = (item) => route.name === item.name;
-
 watch(
   () => route.path,
   (value) => {
@@ -115,7 +114,7 @@ watch(
 .main-layout-page {
   width: 100%;
   max-width: 100%;
-  overflow-x: hidden;
+  overflow: hidden;
 }
 
 .main-layout-scroll-area {

+ 36 - 7
src/pages/dashboard/DashboardPage.vue

@@ -1,12 +1,19 @@
 <template>
   <div class="dashboard-page bg-page">
-    <DashboardHeaderBar />
-    <DashboardSummaryInfos />
-    <DashboardScrollAreaSchedules />
-    <DashboardNextSchedules />
-    <DashboardLastDoneSchedules />
-    <DashboardFavoriteProviders />
-    <DashboardProvidersClose />
+    <template v-if="loading">
+      <div class="row items-center justify-center full-width bg-surface" style="height: 80vh">
+        <q-spinner-dots color="primary" />
+      </div>
+    </template>
+    <template v-else>
+      <DashboardHeaderBar :data="headerBar" />
+      <DashboardSummaryInfos :data="summaryInfos" />
+      <DashboardScrollAreaSchedules />
+      <DashboardNextSchedules :data="nextSchedules" />
+      <DashboardLastDoneSchedules :data="lastDoneSchedules" />
+      <DashboardFavoriteProviders :data="favoriteProviders" />
+      <DashboardProvidersClose :data="providersClose" />
+    </template>
   </div>
 </template>
 
@@ -18,6 +25,28 @@ import DashboardNextSchedules from 'src/components/dashboard/DashboardNextSchedu
 import DashboardLastDoneSchedules from 'src/components/dashboard/DashboardLastDoneSchedules.vue';
 import DashboardFavoriteProviders from 'src/components/dashboard/DashboardFavoriteProviders.vue';
 import DashboardProvidersClose from 'src/components/dashboard/DashboardProvidersClose.vue';
+import { onMounted, ref } from 'vue';
+import { dadosDashboard } from 'src/api/dashboard';
+
+const headerBar = ref(null);
+const summaryInfos = ref(null);
+const nextSchedules = ref(null);
+const lastDoneSchedules = ref(null);
+const favoriteProviders = ref(null);
+const providersClose = ref(null);
+const loading = ref(true);
+onMounted( async () => {
+  const response = await dadosDashboard();
+  if(response) {
+    headerBar.value = response.headerBar;
+    summaryInfos.value = response.summaryInfos;
+    nextSchedules.value = response.nextSchedules;
+    lastDoneSchedules.value = response.lastDoneSchedules;
+    favoriteProviders.value = response.favoriteProviders;
+    providersClose.value = response.providersClose;
+  }
+  loading.value = false;
+});
 </script>
 
 <style scoped>