Forráskód Böngészése

feat: :sparkles: feat(agendamento-sob-medida) ajuste na listagem e validação de envio

Foram realizados ajustes nos templates para garantir a correta listagem das informações na dashboard do prestador, permitindo a visualização das oportunidades disponíveis

fase:dev | origin:escopo
kayo henrique 2 napja
szülő
commit
f89c309678

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

@@ -289,7 +289,8 @@
         "address_not_found": "Address not provided",
         "hour_not_found": "Time not provided",
         "button_accept": "accept job",
-        "alert_text": "If your request is accepted by the client, you will receive a notification confirming the booking."
+        "alert_text": "If your request is accepted by the client, you will receive a notification confirming the booking.",
+        "offers_meal": "On-site meal"
       },
       "favorites": {
         "title": "Your favorites",

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

@@ -289,7 +289,8 @@
         "address_not_found": "Dirección no informada",
         "hour_not_found": "Horario no informado",
         "button_accept": "quiero atender",
-        "alert_text": "Si el cliente acepta tu solicitud, recibirás una notificación confirmando el servicio."
+        "alert_text": "Si el cliente acepta tu solicitud, recibirás una notificación confirmando el servicio.",
+        "offers_meal": "Comida en el lugar"
       },
       "favorites": {
         "title": "Tus favoritos",

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

@@ -289,7 +289,8 @@
         "address_not_found": "Endereço não informado",
         "hour_not_found": "Horário não informado",
         "button_accept": "quero atender",
-        "alert_text": "Se seu pedido for aceito pelo cliente você receberá um aviso confirmando o agendamento."
+        "alert_text": "Se seu pedido for aceito pelo cliente você receberá um aviso confirmando o agendamento.",
+        "offers_meal": "Refeição no local"
       },
       "favorites": {
         "title": "Seus favoritos",

+ 35 - 4
src/pages/opportunities/OpportunitiesPage.vue

@@ -33,20 +33,21 @@
 
         <div class="center-content">
           <div class="client-name-row">
-            <span class="client-name">{{ item.clientName }}</span>
+            <span class="client-name">{{ item.client?.user.name }}</span>
 
+            <!-- campo de avaliação -->
             <span class="rating">
               <q-icon name="star" size="11px" />
-              {{ item.rating }}
+              {{ item.client?.average_rating }}
             </span>
           </div>
 
           <div class="service-date">
-            {{ item.date }}
+            {{ formatDate(item.date) }}
           </div>
 
           <div class="service-hour">
-            {{ item.hour }}
+           {{ `Das ${formatHour(item.start_time)} às ${formatHour(item.end_time)}` }}
           </div>
         </div>
 
@@ -59,10 +60,17 @@
             {{ item.custom_schedule?.address_type }}
           </div>
 
+          <div class="district">
+             {{ item.address?.district }}
+          </div>
+
+
           <div class="distance">
             {{ $t('provider.dashboard.opportunities.distance_km', { distance: item.distance }) }}
           </div>
 
+          
+
           <q-btn unelevated rounded no-caps color="secondary" :label="$t('provider.dashboard.opportunities.details')" class="details-btn" @click="goToOpportunityDetails(item)" />
         </div>
       </q-card>
@@ -109,6 +117,23 @@ const chooseprice = (periodType) => {
   }
 }
 
+// formatando a data
+const formatDate = (date) => {
+  if (!date) return ''
+
+  return new Date(date).toLocaleDateString('pt-BR', {
+    weekday: 'long',
+    day: '2-digit',
+    month: '2-digit'
+  })
+}
+
+// formatando hora para exibir só HH:mm
+const formatHour = (time) => {
+  if (!time) return ''
+  return time.slice(0, 5) 
+}
+
 const loadOpportunities = async () => {
   loading.value = true
 
@@ -226,6 +251,12 @@ onMounted(loadOpportunities)
   color: #2d2d2d;
 }
 
+.district {
+  margin-top: 4px;
+  font-size: 11px;
+  color: #666;
+}
+
 .rating {
   display: flex;
   align-items: center;

+ 129 - 104
src/pages/opportunities/components/OpportunityDetailsPage.vue

@@ -14,35 +14,24 @@
       <img :src="details.avatar" class="client-avatar" />
 
       <div class="client-name">
-        {{ details.clientName }}
-        <span class="rating"> {{ details.rating }}</span>
+        {{ details.schedule?.client_name }}
+        <span class="rating"> {{ details.schedule?.rating }}</span>
       </div>
 
-      <div class="client-price">{{ details.price }}</div>
+      <div class="client-price">{{ $t('provider.dashboard.opportunities.currency', { value: chooseprice(details.schedule?.period_type) }) }}</div>
 
-      <div class="date">{{ details.date }}</div>
-      <div class="hour">{{ details.hour }}</div>
+      <div class="date">  {{ formatDate(details.schedule?.date) }}</div>
+      <div class="hour">{{ formatHour(details.schedule?.start_time ) }} {{ formatHour(details.schedule?.end_time ) }}</div>
     </div>
 
     <!-- ENDEREÇO -->
     <div class="address">
       <q-icon name="place" size="16px" />
-      {{ details.address }}
+      {{ details.schedule?.address?.district }}
     </div>
 
     <div class="distance">
-      {{ $t('provider.dashboard.opportunity_details.distance_text', { distance: details.distance }) }}
-    </div>
-
-    <!-- TIPO -->
-    <div class="service-type">
-      {{ $t('provider.dashboard.opportunity_details.sob_medida') }}
-      <span>
-        {{ $t('provider.dashboard.opportunity_details.sob_medida_highlight') }}
-      </span>
-      <br />
-      {{ $t('provider.dashboard.opportunity_details.para') }}
-      <!-- <strong>{{ details.tags[0] }}</strong> -->
+      {{ $t('provider.dashboard.opportunity_details.distance_text', { distance: details.schedule?.distance }) }}
     </div>
 
     <!-- TAGS -->
@@ -53,10 +42,34 @@
     </div>
 
     <!-- INFO -->
-    <div class="info-title">
-      {{ $t('provider.dashboard.opportunity_details.info_title') }}
-    </div>
-
+    <div class="service-type">
+  {{ $t('provider.dashboard.opportunity_details.sob_medida') }}
+  <span>
+    {{ $t('provider.dashboard.opportunity_details.sob_medida_highlight') }}
+  </span>
+  <br />
+  {{ $t('provider.dashboard.opportunity_details.para') }}
+  <strong class="highlight-service">
+    {{ details.service_type_name }}
+  </strong>
+</div>
+    
+
+
+    <div class="address-type">
+  <span class="chip-type">
+    {{ (details.address_type) }}
+  </span> 
+  <span v-if="details.offers_meal" class="chip-type">
+    {{ $t('provider.dashboard.opportunity_details.offers_meal') }}
+  </span>    
+</div>
+    
+
+
+     <div v-if="details.description" class="service-type gradient-diarista">
+  {{ $t('provider.dashboard.opportunity_details.info_title') }}
+  </div>
     <!-- DESCRIÇÃO -->
     <div class="description-box">
       {{ details.description }}
@@ -90,40 +103,43 @@ const user = userStore()
 const details = ref(null)
 const loading = ref(true)
 
-// const formatHour = (time) =>
-//   time ? time.slice(0, 5).replace(':', 'h') : ''
-
-// const normalizeDetails = (item) => ({
-//   avatar: AvatarMock,
-
-//   clientName:
-//     item?.schedule?.client_name ||
-//     t('provider.dashboard.opportunity_details.client_default'),
-
-//   price: `R$ ${Number(item?.max_price || 0).toFixed(2)}`,
+const chooseprice = (periodType) => {
+  switch (periodType) {
+    case "8":
+      return user.user.provider_daily_price_8h
+    case "6":
+      return user.user.provider_daily_price_6h
+    case "4":
+      return user.user.provider_daily_price_4h
+    case "2":
+      return user.user.provider_daily_price_2h
+    default:
+      return 0
+  }
+}
 
-//   date: item?.schedule?.date || '',
+// formatando a data
+const formatDate = (date) => {
+  if (!date) return ''
 
-//   hour:
-//     item?.schedule?.start_time && item?.schedule?.end_time
-//       ? `Das ${formatHour(item.schedule.start_time)} às ${formatHour(item.schedule.end_time)}`
-//       : t('provider.dashboard.opportunity_details.hour_not_found'),
+  const [day, month, year] = date.split('/')
 
-//   address:
-//     item?.schedule?.address?.address ||
-//     t('provider.dashboard.opportunity_details.address_not_found'),
+  const parsedDate = new Date(`${year}-${month}-${day}`)
 
-//   distance:
-//     item?.distance
-//       ? `${item.distance} km`
-//       : t('provider.dashboard.opportunity_details.distance_default'),
+  const formatted = parsedDate.toLocaleDateString('pt-BR', {
+    weekday: 'long',
+    day: '2-digit',
+    month: '2-digit'
+  })
 
-//   tags: [item?.service_type_name].filter(Boolean),
+  return formatted.charAt(0).toUpperCase() + formatted.slice(1)
+}
 
-//   description:
-//     item?.description ||
-//     t('provider.dashboard.opportunity_details.description_not_found')
-// })
+// formatando hora para exibir só HH:mm
+const formatHour = (time) => {
+  if (!time) return ''
+  return time.slice(0, 5) 
+}
 
 onMounted(async () => {
   try {
@@ -152,21 +168,16 @@ const goToProposalFlow = async () => {
 <style scoped lang="scss">
 .details-page {
   padding: 16px;
-  background: #f7f7fb;
-  min-height: 100vh;
-}
-
-.details-page {
-  padding: 16px;
-  background: #f7f7fb;
+  background: #f4f5f7;
   min-height: 100vh;
 }
 
+/* HEADER */
 .page-header {
   display: flex;
   justify-content: center;
   position: relative;
-  margin-bottom: 20px;
+  margin-bottom: 16px;
 }
 
 .back-btn {
@@ -176,8 +187,8 @@ const goToProposalFlow = async () => {
 }
 
 .page-title {
-  font-size: 16px;
-  font-weight: 700;
+  font-size: 15px;
+  font-weight: 600;
   color: #7c5cff;
 }
 
@@ -187,16 +198,16 @@ const goToProposalFlow = async () => {
 }
 
 .client-avatar {
-  width: 90px;
-  height: 90px;
+  width: 88px;
+  height: 88px;
   border-radius: 50%;
   object-fit: cover;
 }
 
 .client-name {
-  margin-top: 8px;
-  font-size: 16px;
-  color: #555;
+  margin-top: 6px;
+  font-size: 14px;
+  color: #666;
 }
 
 .rating {
@@ -206,103 +217,117 @@ const goToProposalFlow = async () => {
 }
 
 .client-price {
-  margin-top: 10px;
-  font-size: 28px;
-  font-weight: bold;
+  margin-top: 8px;
+  font-size: 24px;
+  font-weight: 700;
   color: #7c5cff;
 }
 
-.price-sub {
-  font-size: 12px;
-  color: #888;
-}
-
 /* DATA */
 .date {
-  margin-top: 10px;
+  margin-top: 6px;
+  font-size: 12px;
   font-weight: 600;
+  color: #555;
 }
 
 .hour {
-  font-size: 13px;
-  color: #666;
+  font-size: 12px;
+  color: #777;
+}
+
+.highlight-service{
+  color: #7c5cff;
+  font-weight: 600;
 }
 
 /* ENDEREÇO */
 .address {
-  margin-top: 16px;
+  margin-top: 12px;
   display: flex;
   justify-content: center;
   align-items: center;
   gap: 4px;
   color: #7c5cff;
+  font-size: 13px;
   font-weight: 600;
 }
 
 .distance {
   text-align: center;
-  font-size: 12px;
-  color: #888;
-  margin-bottom: 12px;
+  font-size: 11px;
+  color: #999;
+  margin-top: 4px;
 }
 
-/* TIPO */
-.service-type {
-  text-align: center;
-  font-size: 13px;
-  margin-top: 12px;
+/* ADDRESS TYPE (CHIPS) */
+.address-type {
+  display: flex;
+  justify-content: center;
+  gap: 10px;
+  margin-top: 10px;
 }
 
-.service-type span {
+.chip-type {
+  border: 1.5px solid #7c5cff;
   color: #7c5cff;
+  padding: 6px 14px;
+  border-radius: 999px;
+  font-size: 12px;
   font-weight: 600;
+  background: white;
+  text-transform: lowercase;
 }
 
-/* TAGS */
-.tags-row {
-  display: flex;
-  justify-content: center;
-  gap: 10px;
-  margin: 16px 0;
+/* TEXTO SOB MEDIDA */
+.service-type {
+  text-align: center;
+  font-size: 12px;
+  margin-top: 12px;
+  color: #666;
 }
 
-.chip {
-  border: 1px solid #7c5cff;
+.service-type span {
   color: #7c5cff;
-  background: white;
+  font-weight: 600;
 }
 
 /* INFO */
 .info-title {
   text-align: center;
-  font-weight: bold;
+  font-weight: 700;
   color: #7c5cff;
-  margin-top: 10px;
+  margin-top: 14px;
+  font-size: 13px;
 }
 
+/* DESCRIÇÃO */
 .description-box {
   text-align: center;
-  font-size: 13px;
+  font-size: 12px;
   color: #666;
   margin: 10px 0 20px;
+  line-height: 1.4;
 }
 
 /* BOTÃO */
 .accept-btn {
   width: 100%;
-  height: 50px;
+  height: 48px;
+  border-radius: 25px;
   background: linear-gradient(90deg, #7c5cff, #9f7aea);
   color: white;
-  font-weight: bold;
+  font-weight: 600;
+  font-size: 14px;
 }
 
 /* ALERTA */
 .alert-box {
-  margin-top: 15px;
-  background: #e8f0ff;
-  padding: 12px;
+  margin-top: 12px;
+  background: #e9f0ff;
+  padding: 10px;
   border-radius: 12px;
-  font-size: 12px;
+  font-size: 11px;
   text-align: center;
   color: #5c6b8a;
   display: flex;