Kaynağa Gözat

feat: :sparkles: adiciona abas de avaliacoes no cliente e prestador

adiciona abas de avaliacoes no cliente e prestador
Gustavo Zanatta 1 ay önce
ebeveyn
işleme
5038f5bb9c

+ 20 - 0
src/api/review.js

@@ -34,3 +34,23 @@ export const getFinishedSchedules = async () => {
   const { data } = await api.get('/schedules/finished')
   return data.payload
 }
+
+export const getClientSentReviews = async (clientId) => {
+  const { data } = await api.get(`/reviews/client/${clientId}/sent`)
+  return data.payload
+}
+
+export const getClientReceivedReviews = async (clientId) => {
+  const { data } = await api.get(`/reviews/client/${clientId}/received`)
+  return data.payload
+}
+
+export const getProviderSentReviews = async (providerId) => {
+  const { data } = await api.get(`/reviews/provider/${providerId}/sent`)
+  return data.payload
+}
+
+export const getProviderReceivedReviews = async (providerId) => {
+  const { data } = await api.get(`/reviews/provider/${providerId}/received`)
+  return data.payload
+}

+ 55 - 55
src/css/quasar.variables.scss

@@ -89,74 +89,74 @@ $colors: (
 
 // Dark Theme Color Overrides
 $colors-dark: (
-  // Primary Colors and Variants (Purple - adjusted for dark mode)
+  // Primary Colors and Variants (Purple Theme)
   "primary": #8B5CF6,
-  // Vibrant Purple (same as light)
+  // Base - Vibrant Purple
   "primary-light": #A78BFA,
   // Light Purple
-  "primary-dark": #6D28D9,
-  // Darker Purple for dark mode
-
-  "dark": #1d1d1d,
+  "primary-dark": #7C3AED,
+  // Dark Purple
 
-  // Secondary Colors (Pink - adjusted for dark mode)
-  "secondary": #F472B6,
-  // Lighter Pink for dark mode
-  "secondary-light": #FBCFE8,
-  // Very Light Pink
+  // Secondary Colors and Variants (Pink/Magenta Theme)
+  "secondary": #EC4899,
+  // Base - Pink
+  "secondary-light": #F9A8D4,
+  // Light Pink
   "secondary-dark": #DB2777,
   // Dark Pink
 
-  // Tertiary Colors (Amber - adjusted for dark mode)
-  "terciary": #FBBF24,
-  // Lighter Amber for dark mode
-  "terciary-light": #FDE68A,
-  // Very Light Amber
-  "terciary-dark": #F59E0B,
-  // Amber
+  // Tertiary Colors and Variants (Amber/Orange Accent)
+  "terciary": #F59E0B,
+  // Base - Amber
+  "terciary-light": #FCD34D,
+  // Light Amber
+  "terciary-dark": #D97706,
+  // Dark Amber
+
+  // Background Colors
+  "page": #F9FAFB,
+  // Very Light Gray (App Background)
 
-  // Dark Mode Backgrounds
-  "page": #0F172A,
-  // Very Dark Blue-Gray
-
-  "surface": #1E293B,
-  // Dark Blue-Gray (Cards)
-  "surface-light": #334155,
-  // Medium Blue-Gray
-  "surface-dark": #0F172A,
-  // Very Dark Blue-Gray
-
-  "text": #F1F5F9,
-  // Almost White
-
-  // Status Colors - Adjusted for Dark Mode
-  "success": #34D399,
-  // Lighter Emerald for visibility
-  "success-light": #6EE7B7,
-  // Very Light Green
-  "success-dark": #10B981,
-  // Emerald
-
-  "error": #F87171,
-  // Lighter Red for visibility
-  "error-light": #FCA5A5,
-  // Very Light Red
-  "error-dark": #EF4444,
+  // Surface Colors (Cards, Panels)
+  "surface": #FFFFFF,
+  // Pure White
+  "surface-light": #F9FAFB,
+  // Very Light Gray
+  "surface-dark": #F3F4F6,
+  // Light Gray
+
+  // Text Colors
+  "text": #111827,
+  // Very Dark Gray (almost black)
+
+  // Status Colors with Variants
+  "success": #10B981,
+  // Emerald Green
+  "success-light": #34D399,
+  // Light Green
+  "success-dark": #059669,
+  // Dark Green
+
+  "error": #EF4444,
   // Red
+  "error-light": #F87171,
+  // Light Red
+  "error-dark": #DC2626,
+  // Dark Red
 
-  "warning": #FBBF24,
-  // Lighter Amber for visibility
-  "warning-light": #FDE68A,
-  // Very Light Amber
-  "warning-dark": #F59E0B,
+  "warning": #F59E0B,
   // Amber
+  "warning-light": #FCD34D,
+  // Light Amber
+  "warning-dark": #D97706,
+  // Dark Amber
 
-  "info": #60A5FA,
-  // Lighter Blue for visibility
-  "info-light": #93C5FD,
-  // Very Light Blue
-  "info-dark": #3B82F6
+  "info": #3B82F6,
   // Blue
+  "info-light": #60A5FA,
+  // Light Blue
+  "info-dark": #2563EB
+  // Dark Blue
 );
 
 // Generate color utility classes for light theme

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

@@ -588,13 +588,48 @@
     "reviewed_at": "Reviewed at",
     "origins": {
       "providers": "Provider",
-      "clients": "Client"
+      "clients": "Client",
+      "provider": "Provider",
+      "client": "Client"
     },
     "improvements_suggested": "Improvements Suggested",
     "no_improvements_suggested": "No improvements suggested",
     "block_client": "Do not receive more requests from this client",
     "block_provider": "Do not request this provider anymore"
   },
+  "client_reviews": {
+    "sent_tab": "Sent Reviews",
+    "received_tab": "Received Reviews",
+    "sent_empty": "No reviews sent",
+    "received_empty": "No reviews received",
+    "provider": "Provider",
+    "client": "Client",
+    "date": "Date",
+    "time": "Time",
+    "schedule_id": "Schedule ID",
+    "stars": "Stars",
+    "comment": "Comment",
+    "schedule_details": "Schedule Details",
+    "improvements": "Improvements",
+    "service_type": "Service Type",
+    "specialities": "Specialities",
+    "price_range": "Price Range",
+    "offers_meal": "Offers Meal",
+    "description": "Description",
+    "address_type": "Address Type",
+    "address": "Address",
+    "status": "Status",
+    "period": "Period",
+    "total_amount": "Amount",
+    "code": "Code",
+    "view_title": "Review Details"
+  },
+  "provider_reviews": {
+    "sent_tab": "Sent Reviews",
+    "received_tab": "Received Reviews",
+    "sent_empty": "No reviews sent",
+    "received_empty": "No reviews received"
+  },
   "orders": {
     "singular": "Order",
     "plural": "Orders",

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

@@ -588,13 +588,48 @@
     "reviewed_at": "Evaluado en",
     "origins": {
       "providers": "Proveedor",
-      "clients": "Cliente"
+      "clients": "Cliente",
+      "provider": "Proveedor",
+      "client": "Cliente"
     },
     "improvements_suggested": "Mejoras Sugeridas",
     "no_improvements_suggested": "No se sugirieron mejoras",
     "block_client": "No recibir más pedidos de este cliente",
     "block_provider": "No solicitar más este diarista"
   },
+  "client_reviews": {
+    "sent_tab": "Ev. Enviadas",
+    "received_tab": "Ev. Recibidas",
+    "sent_empty": "No hay evaluaciones enviadas",
+    "received_empty": "No hay evaluaciones recibidas",
+    "provider": "Proveedor",
+    "client": "Cliente",
+    "date": "Fecha",
+    "time": "Horario",
+    "schedule_id": "ID Agendamiento",
+    "stars": "Estrellas",
+    "comment": "Comentario",
+    "schedule_details": "Detalles del Agendamiento",
+    "improvements": "Mejoras",
+    "service_type": "Tipo de Servicio",
+    "specialities": "Especialidades",
+    "price_range": "Rango de Precio",
+    "offers_meal": "Ofrece Comida",
+    "description": "Descripción",
+    "address_type": "Tipo de Dirección",
+    "address": "Dirección",
+    "status": "Estado",
+    "period": "Período",
+    "total_amount": "Valor",
+    "code": "Código",
+    "view_title": "Detalles de la Evaluación"
+  },
+  "provider_reviews": {
+    "sent_tab": "Ev. Enviadas",
+    "received_tab": "Ev. Recibidas",
+    "sent_empty": "No hay evaluaciones enviadas",
+    "received_empty": "No hay evaluaciones recibidas"
+  },
   "orders": {
     "singular": "Pedido",
     "plural": "Pedidos",

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

@@ -588,13 +588,48 @@
     "reviewed_at": "Avaliado em",
     "origins": {
       "providers": "Prestador",
-      "clients": "Cliente"
+      "clients": "Cliente",
+      "provider": "Prestador",
+      "client": "Cliente"
     },
     "improvements_suggested": "Melhorias Sugeridas",
     "no_improvements_suggested": "Nenhuma melhoria sugerida",
     "block_client": "Não receber mais pedidos deste cliente",
     "block_provider": "Não solicitar mais este diarista"
   },
+  "client_reviews": {
+    "sent_tab": "Av. Enviadas",
+    "received_tab": "Av. Recebidas",
+    "sent_empty": "Nenhuma avaliação enviada",
+    "received_empty": "Nenhuma avaliação recebida",
+    "provider": "Prestador",
+    "client": "Cliente",
+    "date": "Data",
+    "time": "Horário",
+    "schedule_id": "ID Agendamento",
+    "stars": "Estrelas",
+    "comment": "Comentário",
+    "schedule_details": "Detalhes do Agendamento",
+    "improvements": "Melhorias",
+    "service_type": "Tipo de Serviço",
+    "specialities": "Especialidades",
+    "price_range": "Faixa de Preço",
+    "offers_meal": "Oferece Refeição",
+    "description": "Descrição",
+    "address_type": "Tipo de Endereço",
+    "address": "Endereço",
+    "status": "Status",
+    "period": "Período",
+    "total_amount": "Valor",
+    "code": "Código",
+    "view_title": "Detalhes da Avaliação"
+  },
+  "provider_reviews": {
+    "sent_tab": "Av. Enviadas",
+    "received_tab": "Av. Recebidas",
+    "sent_empty": "Nenhuma avaliação enviada",
+    "received_empty": "Nenhuma avaliação recebida"
+  },
   "orders": {
     "singular": "Pedido",
     "plural": "Pedidos",

+ 11 - 0
src/pages/client/components/AddEditClientDialog.vue

@@ -16,6 +16,8 @@
         <q-tab v-if="client" name="favorites" :label="$t('client_favorite_providers.header')" />
         <q-tab v-if="client" name="payment_methods" :label="$t('client_payment_methods.header')" />
         <q-tab v-if="client" name="blocked_providers" :label="$t('client_provider_blocks.tab')" />
+        <q-tab v-if="client" name="sent_reviews" :label="$t('client_reviews.sent_tab')" />
+        <q-tab v-if="client" name="received_reviews" :label="$t('client_reviews.received_tab')" />
       </q-tabs>
 
       <q-separator v-if="client" />
@@ -80,6 +82,14 @@
         <q-tab-panel v-if="client" name="blocked_providers">
           <ClientProvidersBlocksPanel :client-id="client.id" />
         </q-tab-panel>
+
+        <q-tab-panel v-if="client" name="sent_reviews">
+          <ClientReviewsPanel :client-id="client.id" type="sent" />
+        </q-tab-panel>
+
+        <q-tab-panel v-if="client" name="received_reviews">
+          <ClientReviewsPanel :client-id="client.id" type="received" />
+        </q-tab-panel>
       </q-tab-panels>
     </q-card>
   </q-dialog>
@@ -101,6 +111,7 @@ import AddressesPanel from 'src/pages/address/components/AddressesPanel.vue';
 import ClientFavoriteProvidersPanel from './ClientFavoriteProvidersPanel.vue';
 import ClientPaymentMethodsPanel from './ClientPaymentMethodsPanel.vue';
 import ClientProvidersBlocksPanel from './ClientProvidersBlocksPanel.vue';
+import ClientReviewsPanel from './ClientReviewsPanel.vue';
 
 defineEmits([
   ...useDialogPluginComponent.emits,

+ 98 - 0
src/pages/client/components/ClientReviewsPanel.vue

@@ -0,0 +1,98 @@
+<template>
+  <DefaultTable
+    :columns="columns"
+    :api-call="apiCall"
+    :empty-message="emptyMessage"
+    :mostrar-selecao-de-colunas="false"
+    :mostrar-botao-fullscreen="false"
+    :mostrar-toggle-inativos="false"
+    :open-item="true"
+    :show-add-button="false"
+    @on-row-click="openReviewDetail"
+  />
+</template>
+
+<script setup>
+import { computed } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { useQuasar } from 'quasar'
+import { getClientSentReviews, getClientReceivedReviews } from 'src/api/review'
+import DefaultTable from 'src/components/defaults/DefaultTable.vue'
+import ViewReviewScheduleDialog from './ViewReviewScheduleDialog.vue'
+
+const props = defineProps({
+  clientId: {
+    type: Number,
+    required: true,
+  },
+  type: {
+    type: String,
+    default: 'sent', // 'sent' | 'received'
+  },
+})
+
+const { t } = useI18n()
+const $q = useQuasar()
+
+const apiCall = computed(() =>
+  props.type === 'sent'
+    ? () => getClientSentReviews(props.clientId)
+    : () => getClientReceivedReviews(props.clientId)
+)
+
+const emptyMessage = computed(() =>
+  props.type === 'sent'
+    ? t('client_reviews.sent_empty')
+    : t('client_reviews.received_empty')
+)
+
+const columns = computed(() => [
+  {
+    name: 'schedule_id',
+    label: t('client_reviews.schedule_id'),
+    align: 'left',
+    field: (row) => row.schedule?.id,
+    sortable: true,
+  },
+  {
+    name: 'provider',
+    label: t('client_reviews.provider'),
+    align: 'left',
+    field: (row) => row.schedule?.provider?.name,
+    sortable: true,
+  },
+  {
+    name: 'date',
+    label: t('client_reviews.date'),
+    align: 'left',
+    field: (row) => row.schedule?.date,
+    sortable: true,
+  },
+  {
+    name: 'time',
+    label: t('client_reviews.time'),
+    align: 'left',
+    field: (row) => row.schedule ? `${row.schedule.start_time} - ${row.schedule.end_time}` : '',
+    sortable: false,
+  },
+  {
+    name: 'stars',
+    label: t('client_reviews.stars'),
+    align: 'center',
+    field: 'stars',
+    sortable: true,
+  },
+])
+
+const openReviewDetail = ({row}) => {
+  console.log(row)
+  $q.dialog({
+    component: ViewReviewScheduleDialog,
+    componentProps: {
+      review: row,
+      title: () => t('client_reviews.view_title'),
+    },
+  })
+}
+</script>
+

+ 194 - 0
src/pages/client/components/ViewReviewScheduleDialog.vue

@@ -0,0 +1,194 @@
+<template>
+  <q-dialog ref="dialogRef" @hide="onDialogHide">
+    <q-card class="q-dialog-plugin" style="width: 800px; max-width: 90vw">
+      <DefaultDialogHeader :title="title" @close="onDialogCancel" />
+
+      <q-card-section>
+        <div class="text-subtitle1 text-weight-bold q-mb-sm">{{ $t('reviews.singular') }}</div>
+        <q-separator class="q-mb-md" />
+
+        <div class="row q-col-gutter-sm q-mb-md">
+          <div class="col-12">
+            <div class="text-caption text-grey">{{ $t('client_reviews.stars') }}</div>
+            <q-rating
+              :model-value="review.stars"
+              :max="5"
+              size="1.5rem"
+              color="amber"
+              readonly
+            />
+          </div>
+          <div v-if="review.comment" class="col-12">
+            <div class="text-caption text-grey">{{ $t('client_reviews.comment') }}</div>
+            <div>{{ review.comment }}</div>
+          </div>
+
+          <div v-if="review.improvements && review.improvements.length" class="col-12">
+            <div class="text-caption text-grey q-mb-xs">{{ $t('client_reviews.improvements') }}</div>
+            <div class="row q-gutter-xs">
+              <q-chip
+                v-for="imp in review.improvements"
+                :key="imp.id"
+                color="primary"
+                text-color="white"
+                dense
+              >
+                {{ imp.description }}
+              </q-chip>
+            </div>
+          </div>
+        </div>
+
+        <template v-if="review.schedule">
+          <div class="text-subtitle1 text-weight-bold q-mb-sm">{{ $t('client_reviews.schedule_details') }}</div>
+          <q-separator class="q-mb-md" />
+
+          <div class="row q-col-gutter-sm q-mb-md">
+            <div class="col-6 col-sm-3">
+              <div class="text-caption text-grey">{{ $t('client_reviews.schedule_id') }}</div>
+              <div>{{ review.schedule.id + ' - ' + (review.schedule.schedule_type == 'custom' ? 'Oportunidade' : 'Agendamento') }}</div>
+            </div>
+
+            <div class="col-6 col-sm-3">
+              <div class="text-caption text-grey">{{ $t('client_reviews.status') }}</div>
+              <div>{{ $t('schedules.statuses.' + review.schedule.status) }}</div>
+            </div>
+
+            <div class="col-6 col-sm-3">
+              <div class="text-caption text-grey">{{ $t('client_reviews.date') }}</div>
+              <div>{{ review.schedule.date }}</div>
+            </div>
+
+            <div class="col-6 col-sm-3">
+              <div class="text-caption text-grey">{{ $t('client_reviews.time') }}</div>
+              <div>{{ `${review.schedule.start_time} - ${review.schedule.end_time}` }}</div>
+            </div>
+
+            <div class="col-6 col-sm-3">
+              <div class="text-caption text-grey">{{ $t('client_reviews.period') }}</div>
+              <div>{{ `${review.schedule.period_type}h` }}</div>
+            </div>
+
+            <div class="col-6 col-sm-3">
+              <div class="text-caption text-grey">{{ $t('client_reviews.total_amount') }}</div>
+              <div>{{ formatToBRLCurrency(review.schedule.total_amount) }}</div>
+            </div>
+
+            <div v-if="review.schedule.code" class="col-6 col-sm-3">
+              <div class="text-caption text-grey">{{ $t('client_reviews.code') }}</div>
+              <div>{{ review.schedule.code }}</div>
+            </div>
+
+            <div v-if="review.schedule.client" class="col-6 col-sm-6">
+              <div class="text-caption text-grey">{{ $t('client_reviews.client') }}</div>
+              <div>{{ review.schedule.client.name }}</div>
+              <div class="text-caption text-grey-7">{{ review.schedule.client.email }}</div>
+            </div>
+
+            <div v-if="review.schedule.provider" class="col-6 col-sm-6">
+              <div class="text-caption text-grey">{{ $t('client_reviews.provider') }}</div>
+              <div>{{ review.schedule.provider.name }}</div>
+              <div class="text-caption text-grey-7">{{ review.schedule.provider.email }}</div>
+            </div>
+
+            <div v-if="review.schedule.address" class="col-12">
+              <div class="text-caption text-grey">{{ $t('client_reviews.address') }}</div>
+              <div>{{ addressLine }}</div>
+            </div>
+          </div>
+
+          <template v-if="review.schedule.custom_schedule">
+            <div class="text-subtitle1 text-weight-bold q-mb-sm">{{ $t('schedules.schedule_types.custom') }}</div>
+            <q-separator class="q-mb-md" />
+
+            <div class="row q-col-gutter-sm">
+              <div v-if="review.schedule.custom_schedule.address_type" class="col-6 col-sm-4">
+                <div class="text-caption text-grey">{{ $t('client_reviews.address_type') }}</div>
+                <div>{{ review.schedule.custom_schedule.address_type }}</div>
+              </div>
+
+              <div v-if="review.schedule.custom_schedule.service_type" class="col-6 col-sm-4">
+                <div class="text-caption text-grey">{{ $t('client_reviews.service_type') }}</div>
+                <div>{{ review.schedule.custom_schedule.service_type }}</div>
+              </div>
+
+              <div v-if="review.schedule.custom_schedule.min_price != null" class="col-6 col-sm-4">
+                <div class="text-caption text-grey">{{ $t('client_reviews.price_range') }}</div>
+                <div>{{ `${formatToBRLCurrency(review.schedule.custom_schedule.min_price)} - ${formatToBRLCurrency(review.schedule.custom_schedule.max_price)}` }}</div>
+              </div>
+
+              <div class="col-6 col-sm-4">
+                <div class="text-caption text-grey">{{ $t('client_reviews.offers_meal') }}</div>
+                <div>{{ review.schedule.custom_schedule.offers_meal ? $t('common.status.yes') : $t('common.status.no') }}</div>
+              </div>
+
+              <div v-if="review.schedule.custom_schedule.description" class="col-12">
+                <div class="text-caption text-grey">{{ $t('client_reviews.description') }}</div>
+                <div>{{ review.schedule.custom_schedule.description }}</div>
+              </div>
+
+              <div v-if="review.schedule.custom_schedule.specialities && review.schedule.custom_schedule.specialities.length" class="col-12">
+                <div class="text-caption text-grey q-mb-xs">{{ $t('client_reviews.specialities') }}</div>
+                <div class="row q-gutter-xs">
+                  <q-chip
+                    v-for="spec in review.schedule.custom_schedule.specialities"
+                    :key="spec.id"
+                    color="secondary"
+                    text-color="white"
+                    dense
+                  >
+                    {{ spec.description }}
+                  </q-chip>
+                </div>
+              </div>
+            </div>
+          </template>
+        </template>
+      </q-card-section>
+
+      <q-card-actions align="center">
+        <q-btn color="primary" :label="$t('common.actions.close')" @click="onDialogCancel" />
+      </q-card-actions>
+    </q-card>
+  </q-dialog>
+</template>
+
+<script setup>
+import { computed } from 'vue'
+import { useDialogPluginComponent } from 'quasar'
+import { useI18n } from 'vue-i18n'
+import DefaultDialogHeader from 'src/components/defaults/DefaultDialogHeader.vue'
+import { formatToBRLCurrency } from 'src/helpers/utils'
+
+const props = defineProps({
+  review: {
+    type: Object,
+    required: true,
+  },
+  title: {
+    type: Function,
+    required: true
+  }
+})
+
+defineEmits([
+  ...useDialogPluginComponent.emits,
+])
+
+useI18n()
+
+const { dialogRef, onDialogHide, onDialogCancel } = useDialogPluginComponent()
+
+const addressLine = computed(() => {
+  const addr = props.review?.schedule?.address
+  if (!addr) return ''
+  const parts = [
+    addr.street && addr.number ? `${addr.street}, ${addr.number}` : addr.street,
+    addr.complement || null,
+    addr.neighborhood || null,
+    addr.city || null,
+    addr.state || null,
+  ].filter(Boolean)
+  return parts.join(' - ')
+})
+</script>

+ 11 - 0
src/pages/provider/components/AddEditProviderDialog.vue

@@ -10,6 +10,8 @@
         <q-tab v-if="provider" name="working_days" :label="$t('provider_working_days.header')" />
         <q-tab v-if="provider" name="blocked_days" :label="$t('provider_blocked_days.header')" />
         <q-tab v-if="provider" name="blocked_clients" :label="$t('provider_client_blocks.tab')" />
+        <q-tab v-if="provider" name="sent_reviews" :label="$t('provider_reviews.sent_tab')" />
+        <q-tab v-if="provider" name="received_reviews" :label="$t('provider_reviews.received_tab')" />
       </q-tabs>
 
       <q-separator v-if="provider" />
@@ -191,6 +193,14 @@
           <q-tab-panel v-if="provider" name="blocked_clients">
             <ProviderClientsBlocksPanel :provider-id="provider.id" />
           </q-tab-panel>
+
+          <q-tab-panel v-if="provider" name="sent_reviews">
+            <ProviderReviewsPanel :provider-id="provider.id" type="sent" />
+          </q-tab-panel>
+
+          <q-tab-panel v-if="provider" name="received_reviews">
+            <ProviderReviewsPanel :provider-id="provider.id" type="received" />
+          </q-tab-panel>
         </q-tab-panels>
       </div>
     </q-card>
@@ -216,6 +226,7 @@ import ProviderPaymentMethodsPanel from "./ProviderPaymentMethodsPanel.vue";
 import ProviderWorkingDaysPanel from "./ProviderWorkingDaysPanel.vue";
 import ProviderBlockedDaysPanel from "./ProviderBlockedDaysPanel.vue";
 import ProviderClientsBlocksPanel from "./ProviderClientsBlocksPanel.vue";
+import ProviderReviewsPanel from "./ProviderReviewsPanel.vue";
 
 defineEmits([
   ...useDialogPluginComponent.emits,

+ 96 - 0
src/pages/provider/components/ProviderReviewsPanel.vue

@@ -0,0 +1,96 @@
+<template>
+  <DefaultTable
+    :columns="columns"
+    :api-call="apiCall"
+    :empty-message="emptyMessage"
+    :mostrar-selecao-de-colunas="false"
+    :mostrar-botao-fullscreen="false"
+    :mostrar-toggle-inativos="false"
+    :open-item="true"
+    :show-add-button="false"
+    @on-row-click="openReviewDetail"
+  />
+</template>
+
+<script setup>
+import { computed } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { useQuasar } from 'quasar'
+import { getProviderSentReviews, getProviderReceivedReviews } from 'src/api/review'
+import DefaultTable from 'src/components/defaults/DefaultTable.vue'
+import ViewReviewScheduleDialog from 'src/pages/client/components/ViewReviewScheduleDialog.vue'
+
+const props = defineProps({
+  providerId: {
+    type: Number,
+    required: true,
+  },
+  type: {
+    type: String,
+    default: 'sent', // 'sent' | 'received'
+  },
+})
+
+const { t } = useI18n()
+const $q = useQuasar()
+
+const apiCall = computed(() =>
+  props.type === 'sent'
+    ? () => getProviderSentReviews(props.providerId)
+    : () => getProviderReceivedReviews(props.providerId)
+)
+
+const emptyMessage = computed(() =>
+  props.type === 'sent'
+    ? t('provider_reviews.sent_empty')
+    : t('provider_reviews.received_empty')
+)
+
+const columns = computed(() => [
+  {
+    name: 'schedule_id',
+    label: t('client_reviews.schedule_id'),
+    align: 'left',
+    field: (row) => row.schedule?.id,
+    sortable: true,
+  },
+  {
+    name: 'client',
+    label: t('client_reviews.client'),
+    align: 'left',
+    field: (row) => row.schedule?.client?.name,
+    sortable: true,
+  },
+  {
+    name: 'date',
+    label: t('client_reviews.date'),
+    align: 'left',
+    field: (row) => row.schedule?.date,
+    sortable: true,
+  },
+  {
+    name: 'time',
+    label: t('client_reviews.time'),
+    align: 'left',
+    field: (row) => row.schedule ? `${row.schedule.start_time} - ${row.schedule.end_time}` : '',
+    sortable: false,
+  },
+  {
+    name: 'stars',
+    label: t('client_reviews.stars'),
+    align: 'center',
+    field: 'stars',
+    sortable: true,
+  },
+])
+
+const openReviewDetail = ({ row }) => {
+  $q.dialog({
+    component: ViewReviewScheduleDialog,
+    componentProps: {
+      review: row,
+      title: () => t('client_reviews.view_title'),
+    },
+  })
+}
+</script>

+ 1 - 1
src/pages/review/components/AddEditReviewDialog.vue

@@ -277,7 +277,7 @@ onMounted(async () => {
   try {
     const [schedules, improvements] = await Promise.all([
       getFinishedSchedules(),
-      getImprovementTypes(),
+      getImprovementTypes(props.review?.origin),
     ])
     scheduleOptions.value = schedules.map((s) => ({
       value: s.id,