Bladeren bron

layout cliente com dados mocados + layouts dos modulos da dashboard

Gustavo Zanatta 1 maand geleden
bovenliggende
commit
e27e6ba0c0

File diff suppressed because it is too large
+ 6 - 0
src/assets/banner_1.svg


File diff suppressed because it is too large
+ 6 - 0
src/assets/banner_2.svg


+ 12 - 0
src/assets/logo_diaria_colorido_sem_texto.svg

@@ -0,0 +1,12 @@
+<svg width="24" height="23" viewBox="0 0 24 23" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12.8391 0.000430053H2.10087C0.232825 0.000430053 -0.702493 2.25278 0.618337 3.57013L2.13408 5.08188C2.58082 5.52744 3.18669 5.77775 3.81886 5.77775H12.8391C15.8038 5.77775 18.207 8.17461 18.207 11.1314V11.851C18.207 13.4849 17.4579 14.9523 16.2863 15.9234C15.9564 16.197 15.8577 16.6593 16.0591 17.0369L16.9763 18.7564C17.157 19.0854 16.7714 19.4342 16.4605 19.2231L14.0418 17.338C13.8745 17.2077 13.6658 17.1389 13.4536 17.1505C13.2557 17.1612 13.0785 17.1436 12.8279 17.1436H3.81886C3.18712 17.1436 2.58082 17.3939 2.13408 17.8395L0.7007 19.2691C-0.650747 20.617 0.306564 22.9213 2.21774 22.9213H12.8353C19.0013 22.9213 24 17.9358 24 11.786V11.1314C24 4.98382 19.003 0 12.8391 0V0.000430053Z" fill="url(#paint0_linear_3102_1251)"/>
+<path d="M5.70554 9.41709L6.05263 10.1518C6.08152 10.2124 6.13685 10.2548 6.20114 10.2646L6.9771 10.3828C7.13864 10.4074 7.20334 10.6143 7.08656 10.7334L6.52422 11.3066C6.47784 11.3537 6.45668 11.4215 6.46766 11.488L6.60031 12.2978C6.62798 12.4657 6.4583 12.5937 6.31345 12.5144L5.6205 12.1333C5.56272 12.1015 5.49395 12.1015 5.43617 12.1333L4.74282 12.5144C4.59796 12.5941 4.42869 12.4661 4.45596 12.2978L4.5886 11.488C4.59959 11.4215 4.57843 11.3537 4.53205 11.3066L3.96971 10.7334C3.85293 10.6143 3.91763 10.4074 4.07917 10.3828L4.85594 10.2646C4.92023 10.2548 4.97597 10.2124 5.00445 10.1518L5.35113 9.41752C5.42356 9.26447 5.63311 9.26447 5.70513 9.41752L5.70554 9.41709Z" fill="#FE7FFF"/>
+<path d="M10.1696 9.41709L10.5456 10.1518C10.5769 10.2124 10.6369 10.2548 10.7065 10.2646L11.5471 10.3828C11.7221 10.4074 11.7922 10.6143 11.6657 10.7334L11.0565 11.3066C11.0063 11.3537 10.9833 11.4215 10.9952 11.488L11.1389 12.2978C11.1689 12.4657 10.9851 12.5937 10.8282 12.5144L10.0775 12.1333C10.0149 12.1015 9.94039 12.1015 9.8778 12.1333L9.12666 12.5144C8.96973 12.5941 8.78636 12.4661 8.81589 12.2978L8.95959 11.488C8.9715 11.4215 8.94857 11.3537 8.89832 11.3066L8.28913 10.7334C8.16262 10.6143 8.2327 10.4074 8.4077 10.3828L9.2492 10.2646C9.31885 10.2548 9.37924 10.2124 9.4101 10.1518L9.78567 9.41752C9.86413 9.26447 10.0911 9.26447 10.1692 9.41752L10.1696 9.41709Z" fill="#FE7FFF"/>
+<path d="M14.7536 9.41709L15.1296 10.1518C15.1609 10.2124 15.2209 10.2548 15.2905 10.2646L16.1311 10.3828C16.3061 10.4074 16.3762 10.6143 16.2497 10.7334L15.6405 11.3066C15.5902 11.3537 15.5673 11.4215 15.5792 11.488L15.7229 12.2978C15.7529 12.4657 15.5691 12.5937 15.4122 12.5144L14.6615 12.1333C14.5989 12.1015 14.5244 12.1015 14.4618 12.1333L13.7106 12.5144C13.5537 12.5941 13.3703 12.4661 13.3999 12.2978L13.5436 11.488C13.5555 11.4215 13.5326 11.3537 13.4823 11.3066L12.8731 10.7334C12.7466 10.6143 12.8167 10.4074 12.9917 10.3828L13.8332 10.2646C13.9028 10.2548 13.9632 10.2124 13.9941 10.1518L14.3697 9.41752C14.4481 9.26447 14.6751 9.26447 14.7532 9.41752L14.7536 9.41709Z" fill="#FE7FFF"/>
+<defs>
+<linearGradient id="paint0_linear_3102_1251" x1="12" y1="0.000430084" x2="12" y2="22.9218" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FE7FFF"/>
+<stop offset="1" stop-color="#2F80ED"/>
+</linearGradient>
+</defs>
+</svg>

+ 105 - 0
src/components/dashboard/DashboardFavoriteProviders.vue

@@ -0,0 +1,105 @@
+<!-- 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="scroll-track col-12">
+      <q-card
+        v-for="item in items"
+        :key="item.id"
+        class="fav-card shadow-card bg-surface card-border"
+      >
+        <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>
+            </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>
+
+                  <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>
+                  </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"
+                />
+              </div>
+            </div>
+          </div>
+
+        </q-card-section>
+      </q-card>
+    </div>
+  </div>
+</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' },
+  },
+];
+</script>
+
+<style scoped lang="scss">
+.scroll-track {
+  display: flex;
+  flex-direction: row;
+  gap: 12px;
+  overflow-x: auto;
+  overscroll-behavior-x: contain;
+  scroll-snap-type: x proximity;
+  padding-bottom: 8px;
+
+  &::-webkit-scrollbar { display: none; }
+
+  &::after {
+    content: '';
+    flex: 0 0 1px;
+  }
+}
+
+.fav-card {
+  flex: 0 0 200px;
+  scroll-snap-align: start;
+  min-width: 70%;
+}
+</style>

+ 57 - 0
src/components/dashboard/DashboardHeaderBar.vue

@@ -0,0 +1,57 @@
+<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
+<template>
+  <div class="dashboard-header shadow-card bg-white row items-center no-wrap q-px-md q-pb-sm">
+    <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>
+      </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>
+      </div>
+    </div>
+
+    <div class="col-auto row justify-center">
+      <img :src="LogoDiariaColorida" alt="Diária" class="dashboard-logo" />
+    </div>
+
+    <div class="col row justify-end items-center">
+      <q-btn flat round dense icon="mdi-bell-outline" color="grey-7" size="sm" />
+    </div>
+  </div>
+</template>
+
+<script setup>
+import LogoDiariaColorida from 'src/assets/logo_diaria_colorido_sem_texto.svg';
+</script>
+
+<style scoped lang="scss">
+.dashboard-header {
+  padding-top: calc(env(safe-area-inset-top) + 8px);
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.dashboard-logo {
+  width: 32px;
+  height: 32px;
+}
+
+.dashboard-metric-value {
+  font-family: "Inter", sans-serif;
+  font-size: 11px;
+  font-weight: 700;
+  color: #3a3a4a;
+  line-height: 1;
+}
+
+.dashboard-metric-meta {
+  font-family: "Inter", sans-serif;
+  font-size: 10px;
+  font-weight: 400;
+  color: #999;
+  line-height: 1;
+}
+</style>

+ 80 - 0
src/components/dashboard/DashboardLastDoneSchedules.vue

@@ -0,0 +1,80 @@
+<!-- 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="scroll-track">
+      <q-card
+        v-for="item in items"
+        :key="item.id"
+        class="mini-card shadow-card bg-surface card-border"
+      >
+        <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-avatar>
+          <span class="text-done-name">{{ item.name }}</span>
+          <span class="text-fav-region">{{ item.region }}</span>
+          <q-btn
+            rounded
+            color="secondary"
+            padding="1px 5px"
+            size="sm"
+            class="q-mt-xs full-width"
+            label="reagendar"
+          />
+        </q-card-section>
+      </q-card>
+    </div>
+  </div>
+</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' },
+  },
+];
+</script>
+
+<style scoped lang="scss">
+.scroll-track {
+  display: flex;
+  flex-direction: row;
+  gap: 10px;
+  overflow-x: auto;
+  overscroll-behavior-x: contain;
+  scroll-snap-type: x proximity;
+  padding-bottom: 8px;
+
+  &::-webkit-scrollbar { display: none; }
+
+  &::after {
+    content: '';
+    flex: 0 0 1px;
+  }
+}
+
+.mini-card {
+  flex: 0 0 130px;
+  scroll-snap-align: start;
+}
+</style>

+ 142 - 0
src/components/dashboard/DashboardNextSchedules.vue

@@ -0,0 +1,142 @@
+<!-- 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="scroll-wrapper">
+      <div class="scroll-track">
+        <q-card
+          v-for="item in items"
+          :key="item.id"
+          class="schedule-card card-border shadow-card bg-surface"
+        >
+          <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>
+
+
+              <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>
+                  <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>
+              </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>
+          </q-card-section>
+        </q-card>
+      </div>
+    </div>
+  </div>
+</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' },
+  },
+];
+</script>
+
+<style scoped lang="scss">
+
+.scroll-wrapper {
+  overflow: hidden;
+}
+
+.scroll-track {
+  display: flex;
+  flex-direction: row;
+  gap: 12px;
+  overflow-x: auto;
+  overscroll-behavior-x: contain;
+  scroll-snap-type: x proximity;
+  padding-bottom: 8px;
+
+  &::-webkit-scrollbar { display: none; }
+
+  &::after {
+    content: '';
+    flex: 0 0 1px;
+  }
+}
+
+.schedule-card {
+  // border-radius: 18px;
+  min-width: 80%;
+  min-height: 90px
+}
+
+</style>

+ 108 - 0
src/components/dashboard/DashboardProvidersClose.vue

@@ -0,0 +1,108 @@
+<!-- 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>
+
+    <div class="column ">
+      <q-card
+        v-for="p in providers"
+        :key="p.id"
+        class="shadow-card card-border bg-page text-text"
+      >
+        <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>
+            </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>
+                <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>
+                  </div>
+                  <div class="row items-center">
+                    <q-icon name="mdi-broom" color="secondary" />
+                    <span class="text-provider-close-jobs">{{ p.jobs }}</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>
+                  </div>
+                </div>
+              </div>
+
+              <div class="column col-3 justify-between text-center items-center">
+                <span class="text-provider-close-price">{{ p.price }}</span>
+                <div class="full-width">
+                  <q-btn
+                    unelevated rounded no-caps
+                    color="primary"
+                    size="sm"
+                    padding="3px 12px"
+                    label="agendar"
+                  />
+                </div>
+              </div>
+            </div>
+          </div>
+        </q-card-section>
+      </q-card>
+    </div>
+  </div>
+</template>
+
+<script setup>
+
+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' },
+  },
+];
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 61 - 0
src/components/dashboard/DashboardScrollAreaSchedules.vue

@@ -0,0 +1,61 @@
+<template>
+  <section class="promo-scroll-wrapper q-ma-md">
+    <div class="promo-scroll">
+      <div v-for="card in cards" :key="card.id" class="promo-card">
+        <img :src="card.image" :alt="card.alt" class="promo-card__img" />
+      </div>
+    </div>
+  </section>
+</template>
+
+<script setup>
+import Banner1 from 'src/assets/banner_1.svg';
+import Banner2 from 'src/assets/banner_2.svg';
+
+const cards = [
+  { id: 1, image: Banner1, alt: 'Diária sob medida' },
+  { id: 2, image: Banner2, alt: 'Escolha profissionais' },
+];
+</script>
+
+<style scoped lang="scss">
+.promo-scroll-wrapper {
+  width: 100%;
+  overflow: hidden;
+}
+
+.promo-scroll {
+  display: flex;
+  gap: 12px;
+  overflow-x: auto;
+  overscroll-behavior-x: contain;
+  padding: 0 0 4px 16px;
+  scroll-snap-type: x mandatory;
+
+  &::-webkit-scrollbar {
+    display: none;
+  }
+
+  &::after {
+    content: '';
+    flex: 0 0 16px;
+  }
+}
+
+.promo-card {
+  height: 120px;
+  border-radius: 10px;
+  overflow: hidden;
+  scroll-snap-align: start;
+  background: #e8e4f5;
+  flex-shrink: 0;
+}
+
+.promo-card__img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+  display: block;
+  border-radius: 10px;
+}
+</style>

+ 82 - 0
src/components/dashboard/DashboardSummaryInfos.vue

@@ -0,0 +1,82 @@
+<!-- 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-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 }}
+          </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>
+          </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">        
+            <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>
+        </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
+        </div>
+        <q-icon name="mdi-chevron-down" color="secondary" size="18px" class="col-auto" />
+      </div>
+    </q-card-section>
+  </q-card>
+</template>
+
+<script setup>
+import { computed } from 'vue';
+
+const fullName = 'Helena';
+const initials = computed(() => fullName.slice(0, 2).toUpperCase());
+const avatarStyle = computed(() => ({
+  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-count {
+  font-family: "Inter", sans-serif;
+  font-size: 20px;
+  font-weight: 500;
+  color: #3a3a4a;
+}
+
+.summary-address {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+</style>

+ 2 - 2
src/composables/useAuth.js

@@ -22,7 +22,7 @@ export const useAuth = () => {
 
   const login = async (email, password) => {
     try {
-      const response = await api.post("/login", {
+      const response = await api.post("/login-app", {
         email: email,
         password: password,
       });
@@ -56,7 +56,7 @@ export const useAuth = () => {
         return Promise.reject(new Error("No refresh token available"));
       }
 
-      const response = await api.post("/refresh", {
+      const response = await api.post("/refresh-app", {
         refresh_token: refreshToken,
       });
 

+ 211 - 0
src/css/app.scss

@@ -113,4 +113,215 @@ input[type="number"]::-webkit-outer-spin-button {
   font-size: 15px;
   color: #ffffff;
   text-transform: lowercase;
+}
+
+.gradient-diarista {
+  background: linear-gradient(
+    -90deg,
+    #ec48d1 5%,
+    #6b11cb 65%,
+    #2574fc 100%
+  );
+
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+
+  background-clip: text;
+  color: transparent;
+}
+
+.gradient-diarista-bg {
+  background: linear-gradient(
+    -90deg,
+    #ec48d1 1%,
+    #6b11cbcb 65%,
+    #2574fcbd 100%
+  );
+}
+
+// SummaryInfos / HeaderBar
+.text-greeting {
+  font-family: "Inter", sans-serif;
+  font-weight: 400;
+  font-size: 12px;
+  line-height: 100%;
+  letter-spacing: -0.04em;
+}
+
+.text-name {
+  font-family: "Inter", sans-serif;
+  font-weight: 700;
+  font-size: 16px;
+  line-height: 100%;
+  letter-spacing: 0;
+}
+
+.text-label-bold {
+  font-family: "Inter", sans-serif;
+  font-weight: 700;
+  font-size: 12px;
+  line-height: 100%;
+  letter-spacing: 0;
+}
+
+.text-address {
+  font-family: "Inter", sans-serif;
+  font-weight: 500;
+  font-size: 8px;
+  line-height: 100%;
+  letter-spacing: 0;
+}
+
+// NextSchedules
+.text-provider-name {
+  font-family: "Inter", sans-serif;
+  font-weight: 500;
+  font-size: 12px;
+  line-height: 100%;
+  letter-spacing: -0.04em;
+}
+
+.text-price-main {
+  font-family: "Inter", sans-serif;
+  font-weight: 700;
+  font-size: 14px;
+  line-height: 100%;
+  letter-spacing: -0.04em;
+  text-align: right;
+}
+
+.text-price-label {
+  font-family: "Inter", sans-serif;
+  font-weight: 500;
+  font-size: 10px;
+  line-height: 100%;
+  letter-spacing: -0.04em;
+  text-align: right;
+}
+
+.text-schedule-date-bold {
+  font-family: "Inter", sans-serif;
+  font-weight: 700;
+  font-size: 8px;
+  line-height: 100%;
+  letter-spacing: -0.04em;
+}
+
+.text-schedule-date-regular {
+  font-family: "Inter", sans-serif;
+  font-weight: 400;
+  font-size: 8px;
+  line-height: 100%;
+  letter-spacing: -0.04em;
+}
+
+.text-pill {
+  font-family: "Inter", sans-serif;
+  font-weight: 600;
+  font-size: 10px;
+  line-height: 100%;
+  letter-spacing: 0;
+}
+
+.text-pill-place {
+  font-family: "Inter", sans-serif;
+  font-weight: 600;
+  font-size: 10px;
+  line-height: 100%;
+  letter-spacing: -0.04em;
+}
+
+// LastDoneSchedules
+.text-done-name {
+  font-family: "Inter", sans-serif;
+  font-weight: 400;
+  font-size: 12px;
+  line-height: 100%;
+  letter-spacing: -0.04em;
+  text-align: center;
+}
+
+// FavoriteProviders
+.text-fav-name {
+  font-family: "Inter", sans-serif;
+  font-weight: 500;
+  font-size: 12px;
+  line-height: 100%;
+  letter-spacing: -0.04em;
+}
+
+.text-fav-region {
+  font-family: "Inter", sans-serif;
+  font-weight: 600;
+  font-size: 8px;
+  line-height: 100%;
+  letter-spacing: -0.04em;
+}
+
+// ProvidersClose
+.text-provider-close-name {
+  font-family: "Inter", sans-serif;
+  font-weight: 700;
+  font-size: 8px;
+  line-height: 100%;
+  letter-spacing: -0.04em;
+}
+
+.text-provider-close-region {
+  font-family: "Inter", sans-serif;
+  font-weight: 600;
+  font-size: 8px;
+  line-height: 100%;
+  letter-spacing: 0;
+}
+
+.text-provider-close-price {
+  font-family: "Inter", sans-serif;
+  font-weight: 500;
+  font-size: 12px;
+  line-height: 100%;
+  letter-spacing: 0;
+  text-align: right;
+}
+
+.text-provider-close-rating {
+  font-family: "Inter", sans-serif;
+  font-weight: 400;
+  font-size: 8px;
+  line-height: 100%;
+  letter-spacing: 0;
+}
+
+.text-provider-close-jobs {
+  font-family: "Inter", sans-serif;
+  font-weight: 400;
+  font-size: 8px;
+  line-height: 100%;
+  letter-spacing: 0;
+  text-align: center;
+}
+
+.text-provider-close-distance {
+  font-family: "Inter", sans-serif;
+  font-weight: 300;
+  font-size: 8px;
+  line-height: 100%;
+  letter-spacing: 0;
+  text-align: right;
+}
+
+.shadow-card {
+box-shadow: 1px 4px 4px 0px rgba(0,0,0,0.2);
+-webkit-box-shadow: 1px 4px 4px 0px rgba(0,0,0,0.2);
+-moz-box-shadow: 1px 4px 4px 0px rgba(0,0,0,0.2);
+}
+
+.card-border {
+  border-radius: 18px;
+}
+
+.dashboard-section-title {
+  font-size: 20px;
+  font-weight: 600;
+  line-height: 1.05;
 }

+ 141 - 89
src/layouts/MainLayout.vue

@@ -1,135 +1,142 @@
 <template>
-  <q-layout class="relative" view="hHh lpR fFf">
-    <LeftMenuLayout v-if="!$q.screen.lt.sm" />
-    <LeftMenuLayoutMobile v-else v-model="leftDrawerOpen" />
+  <q-layout class="main-layout relative" view="hHh lpR fFf">
     <q-header
       v-if="$q.screen.lt.sm"
-      class="bg-transparent column justify-end"
+      class="bg-surface column justify-end"
       :style="{
         height: `calc(50px + env(safe-area-inset-top))`,
       }"
     >
-      <q-toolbar
-        class="flex justify-between bg-primary"
-        style="border-radius: 0 0 6px 6px !important"
-      >
-        <q-btn dense flat @click="toggleLeftDrawer">
-          <q-icon name="menu" :color="$q.dark.isActive ? 'white' : 'black'" />
-        </q-btn>
-        <q-btn dense flat>
-          <img
-            :src="someAvatar()"
-            alt="avatar"
-            style="width: 20px; height: 20px; border-radius: 50%"
-          />
-          <q-menu anchor="center right" self="top start">
-            <q-list class="column no-wrap overflow-hidden">
-              <q-item
-                v-ripple
-                v-close-popup
-                clickable
-                :to="{ name: 'ProfilePage' }"
-                exact
-                exact-active-class="menu-selected"
-              >
-                <div class="flex">
-                  <q-item-section avatar>
-                    <q-icon
-                      name="account_circle"
-                      color="primary"
-                      style="font-size: 18px"
-                    />
-                  </q-item-section>
-                  <q-item-section>{{
-                    $t("user.profile.singular")
-                  }}</q-item-section>
-                </div>
-              </q-item>
-              <q-item v-ripple clickable @click="logoutFn">
-                <div class="flex">
-                  <q-item-section avatar>
-                    <q-icon
-                      name="logout"
-                      color="negative"
-                      style="font-size: 18px"
-                    />
-                  </q-item-section>
-                  <q-item-section>{{ $t("auth.logout") }}</q-item-section>
-                </div>
-              </q-item>
-            </q-list>
-          </q-menu>
-        </q-btn>
-      </q-toolbar>
     </q-header>
     <q-page-container>
-      <q-page>
+      <q-page class="bg-surface main-layout-page">
         <q-scroll-area
           ref="scrollAreaRef"
-          :style="
-            $q.screen.lt.sm
-              ? 'height: calc(100dvh - 68px - env(safe-area-inset-top)) !important;'
-              : 'height: calc(100dvh - env(safe-area-inset-top)) !important;'
-          "
+          class="main-layout-scroll-area"
+          :style="scrollAreaStyle"
+          :content-style="{ width: '100%', maxWidth: '100%', overflowX: 'hidden', boxSizing: 'border-box' }"
+          :content-active-style="{ width: '100%', maxWidth: '100%', overflowX: 'hidden', boxSizing: 'border-box' }"
         >
           <router-view v-slot="{ Component }">
             <Transition mode="out-in">
               <component
                 :is="Component"
-                style="padding: 20px !important; padding-right: 10px !important"
-                :style="$q.screen.lt.sm ? 'padding-left: 10px !important;' : ''"
+                class="main-layout-view"
+                :class="{ 'main-layout-view--mobile': $q.screen.lt.sm }"
               />
             </Transition>
           </router-view>
         </q-scroll-area>
       </q-page>
     </q-page-container>
+    <q-footer v-if="$q.screen.lt.sm" class="provider-bottom-nav bg-white">
+      <nav class="provider-bottom-nav-inner">
+        <router-link
+          v-for="item in navItems"
+          :key="item.name"
+          :to="{ name: item.name }"
+          class="provider-bottom-nav-item"
+          :class="{ 'provider-bottom-nav-item--active': isNavItemActive(item) }"
+        >
+          <q-icon :name="item.icon" class="provider-bottom-nav-icon" />
+          <span class="provider-bottom-nav-label">{{ item.label }}</span>
+        </router-link>
+      </nav>
+    </q-footer>
   </q-layout>
 </template>
 
 <script setup>
-import { ref, useTemplateRef, watch } from "vue";
+import { computed, useTemplateRef, watch } from "vue";
+import { useQuasar } from "quasar";
 import { useRoute } from "vue-router";
-import { useAuth } from "src/composables/useAuth";
-import { useRouter } from "vue-router";
-import LeftMenuLayout from "src/components/layout/LeftMenuLayout.vue";
-import LeftMenuLayoutMobile from "src/components/layout/LeftMenuLayoutMobile.vue";
 
 defineOptions({
   name: "MainLayout",
 });
 
-const { logout } = useAuth();
+const $q = useQuasar();
 const route = useRoute();
-const leftDrawerOpen = ref(false);
 const scrollAreaRef = useTemplateRef("scrollAreaRef");
-const router = useRouter();
 
 let oldValue = route.path;
 
-const someAvatar = () => {
-  let random = Math.floor(Math.random() * 5) + 1;
-  return "https://cdn.quasar.dev/img/avatar" + random + ".jpg";
-};
+const navItems = [
+  {
+    name: "DashboardPage",
+    label: "Início",
+    icon: "mdi-home-outline",
+  },
+  {
+    name: "SearchPage",
+    label: "Busca",
+    icon: "mdi-magnify",
+  },
+  {
+    name: "AgendaPage",
+    label: "Agenda",
+    icon: "mdi-calendar-blank-outline",
+  },
+  {
+    name: "ProfilePage",
+    label: "Perfil",
+    icon: "mdi-account-circle-outline",
+  },
+];
+
+const scrollAreaStyle = computed(() => {
+  if ($q.screen.lt.sm) {
+    return `height: calc(100dvh  - env(safe-area-inset-top)  - env(safe-area-inset-bottom)) !important;`;
+  }
 
-const logoutFn = async () => {
-  await logout();
-  router.push({ name: "LoginPage" });
-};
+  return "height: calc(100dvh - env(safe-area-inset-top)) !important;";
+});
 
-const toggleLeftDrawer = () => {
-  leftDrawerOpen.value = !leftDrawerOpen.value;
-};
+const isNavItemActive = (item) => route.name === item.name;
 
-watch(route, (value) => {
-  if (oldValue.path != value.path) {
-    scrollAreaRef.value.setScrollPosition("vertical", 0, 0);
-    scrollAreaRef.value.setScrollPosition("horizontal", 0, 0);
+watch(
+  () => route.path,
+  (value) => {
+    if (oldValue !== value) {
+      scrollAreaRef.value?.setScrollPosition("vertical", 0, 0);
+      scrollAreaRef.value?.setScrollPosition("horizontal", 0, 0);
+    }
+    oldValue = value;
   }
-  oldValue = value.path;
-});
+);
 </script>
 <style scoped>
+.main-layout {
+  width: 100%;
+  max-width: 100%;
+  overflow-x: hidden;
+}
+
+.main-layout-page {
+  width: 100%;
+  max-width: 100%;
+  overflow-x: hidden;
+}
+
+.main-layout-scroll-area {
+  width: 100%;
+  max-width: 100%;
+  overflow: hidden;
+}
+
+.main-layout-view {
+  width: 100%;
+  max-width: 100%;
+  min-width: 0;
+  padding: 0 !important;
+  box-sizing: border-box;
+  overflow-x: hidden;
+}
+
+.main-layout-view--mobile {
+  padding: 0 !important;
+}
+
 .v-enter-active {
   opacity: 1;
   transition: all 0.15s ease-in;
@@ -149,4 +156,49 @@ watch(route, (value) => {
 .v-leave-to {
   transition: all 0.15s ease-out;
 }
+
+.provider-bottom-nav {
+  background: #ffffff;
+  box-shadow: 0 -12px 30px rgba(38, 27, 52, 0.1);
+}
+
+.provider-bottom-nav-inner {
+  display: grid;
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  align-items: end;
+  height: 80px;
+  padding: 12px 10px calc(12px + env(safe-area-inset-bottom));
+}
+
+.provider-bottom-nav-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: flex-end;
+  gap: 8px;
+  min-height: 56px;
+  color: #a1a1a1;
+  text-decoration: none;
+  transition: color 0.2s ease;
+}
+
+.provider-bottom-nav-item--active {
+  color: #ff00ea;
+}
+
+.provider-bottom-nav-icon {
+  font-size: 30px;
+  line-height: 1;
+}
+
+.provider-bottom-nav-label {
+  font-size: 12px;
+  font-weight: 400;
+  line-height: 1.1;
+  letter-spacing: -0.02em;
+}
+
+.provider-bottom-nav-item--active .provider-bottom-nav-label {
+  font-weight: 700;
+}
 </style>

+ 52 - 0
src/pages/agenda/AgendaPage.vue

@@ -0,0 +1,52 @@
+<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
+<template>
+  <section class="mobile-placeholder">
+    <div class="mobile-placeholder__badge">
+      <q-icon name="mdi-calendar-blank-outline" />
+    </div>
+    <h1 class="mobile-placeholder__title">Agenda</h1>
+    <p class="mobile-placeholder__description">
+      Área reservada para exibir compromissos, confirmações e próximas diárias.
+    </p>
+  </section>
+</template>
+
+<style scoped>
+.mobile-placeholder {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  min-height: calc(100dvh - 240px);
+  padding: 32px 20px;
+  text-align: center;
+}
+
+.mobile-placeholder__badge {
+  display: grid;
+  place-items: center;
+  width: 88px;
+  height: 88px;
+  border-radius: 28px;
+  margin-bottom: 20px;
+  background: linear-gradient(180deg, rgba(255, 0, 234, 0.14), rgba(107, 17, 203, 0.08));
+  color: #ff00ea;
+  font-size: 44px;
+}
+
+.mobile-placeholder__title {
+  margin: 0 0 8px;
+  font-size: 28px;
+  font-weight: 700;
+  line-height: 1.1;
+  color: #4d4d4d;
+}
+
+.mobile-placeholder__description {
+  max-width: 280px;
+  margin: 0;
+  font-size: 16px;
+  line-height: 1.5;
+  color: #8d8d8d;
+}
+</style>

+ 19 - 15
src/pages/dashboard/DashboardPage.vue

@@ -1,25 +1,29 @@
 <template>
-  <div>
-    <!-- <DefaultHeaderPage> -->
-
-    <!-- </DefaultHeaderPage> -->
-    {{ userStore().user.name + ' é o usuario logado'  }}<br>
-    {{ userStore().user }}
-
+  <div class="dashboard-page bg-page">
+    <DashboardHeaderBar />
+    <DashboardSummaryInfos />
+    <DashboardScrollAreaSchedules />
+    <DashboardNextSchedules />
+    <DashboardLastDoneSchedules />
+    <DashboardFavoriteProviders />
+    <DashboardProvidersClose />
   </div>
 </template>
 
 <script setup>
-import { onMounted } from "vue";
-// import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
-import { userStore } from 'src/stores/user';
-
-onMounted(async () => {
-});
+import DashboardHeaderBar from 'src/components/dashboard/DashboardHeaderBar.vue';
+import DashboardSummaryInfos from 'src/components/dashboard/DashboardSummaryInfos.vue';
+import DashboardScrollAreaSchedules from 'src/components/dashboard/DashboardScrollAreaSchedules.vue';
+import DashboardNextSchedules from 'src/components/dashboard/DashboardNextSchedules.vue';
+import DashboardLastDoneSchedules from 'src/components/dashboard/DashboardLastDoneSchedules.vue';
+import DashboardFavoriteProviders from 'src/components/dashboard/DashboardFavoriteProviders.vue';
+import DashboardProvidersClose from 'src/components/dashboard/DashboardProvidersClose.vue';
 </script>
 
 <style scoped>
-.gap {
-  gap: 16px;
+.dashboard-page {
+  width: 100%;
+  min-height: 100%;
+  box-sizing: border-box;
 }
 </style>

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

@@ -0,0 +1,52 @@
+<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
+<template>
+  <section class="mobile-placeholder">
+    <div class="mobile-placeholder__badge">
+      <q-icon name="mdi-account-circle-outline" />
+    </div>
+    <h1 class="mobile-placeholder__title">Perfil</h1>
+    <p class="mobile-placeholder__description">
+      Área reservada para informações da conta, dados profissionais e preferências.
+    </p>
+  </section>
+</template>
+
+<style scoped>
+.mobile-placeholder {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  min-height: calc(100dvh - 240px);
+  padding: 32px 20px;
+  text-align: center;
+}
+
+.mobile-placeholder__badge {
+  display: grid;
+  place-items: center;
+  width: 88px;
+  height: 88px;
+  border-radius: 28px;
+  margin-bottom: 20px;
+  background: linear-gradient(180deg, rgba(255, 0, 234, 0.14), rgba(107, 17, 203, 0.08));
+  color: #ff00ea;
+  font-size: 44px;
+}
+
+.mobile-placeholder__title {
+  margin: 0 0 8px;
+  font-size: 28px;
+  font-weight: 700;
+  line-height: 1.1;
+  color: #4d4d4d;
+}
+
+.mobile-placeholder__description {
+  max-width: 280px;
+  margin: 0;
+  font-size: 16px;
+  line-height: 1.5;
+  color: #8d8d8d;
+}
+</style>

+ 52 - 0
src/pages/search/SearchPage.vue

@@ -0,0 +1,52 @@
+<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
+<template>
+  <section class="mobile-placeholder">
+    <div class="mobile-placeholder__badge">
+      <q-icon name="mdi-magnify" />
+    </div>
+    <h1 class="mobile-placeholder__title">Busca</h1>
+    <p class="mobile-placeholder__description">
+      Área reservada para a busca de diárias e oportunidades próximas.
+    </p>
+  </section>
+</template>
+
+<style scoped>
+.mobile-placeholder {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  min-height: calc(100dvh - 240px);
+  padding: 32px 20px;
+  text-align: center;
+}
+
+.mobile-placeholder__badge {
+  display: grid;
+  place-items: center;
+  width: 88px;
+  height: 88px;
+  border-radius: 28px;
+  margin-bottom: 20px;
+  background: linear-gradient(180deg, rgba(255, 0, 234, 0.14), rgba(107, 17, 203, 0.08));
+  color: #ff00ea;
+  font-size: 44px;
+}
+
+.mobile-placeholder__title {
+  margin: 0 0 8px;
+  font-size: 28px;
+  font-weight: 700;
+  line-height: 1.1;
+  color: #4d4d4d;
+}
+
+.mobile-placeholder__description {
+  max-width: 280px;
+  margin: 0;
+  font-size: 16px;
+  line-height: 1.5;
+  color: #8d8d8d;
+}
+</style>

+ 59 - 0
src/router/routes/navbar.route.js

@@ -0,0 +1,59 @@
+export default [
+  {
+    path: "busca",
+    name: "SearchPage",
+    component: () => import("src/pages/search/SearchPage.vue"),
+    meta: {
+      title: "Busca",
+      requireAuth: true,
+      breadcrumbs: [
+        {
+          name: "DashboardPage",
+          title: "ui.navigation.dashboard",
+        },
+        {
+          name: "SearchPage",
+          title: "Busca",
+        },
+      ],
+    },
+  },
+  {
+    path: "agenda",
+    name: "AgendaPage",
+    component: () => import("src/pages/agenda/AgendaPage.vue"),
+    meta: {
+      title: "Agenda",
+      requireAuth: true,
+      breadcrumbs: [
+        {
+          name: "DashboardPage",
+          title: "ui.navigation.dashboard",
+        },
+        {
+          name: "AgendaPage",
+          title: "Agenda",
+        },
+      ],
+    },
+  },
+  {
+    path: "perfil",
+    name: "ProfilePage",
+    component: () => import("src/pages/profile/ProfilePage.vue"),
+    meta: {
+      title: "Perfil",
+      requireAuth: true,
+      breadcrumbs: [
+        {
+          name: "DashboardPage",
+          title: "ui.navigation.dashboard",
+        },
+        {
+          name: "ProfilePage",
+          title: "Perfil",
+        },
+      ],
+    },
+  },
+];

Some files were not shown because too many files changed in this diff