DashboardNextSchedules.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <template>
  2. <div class="q-mx-md q-mb-md">
  3. <div class="section-title gradient-diarista q-mb-sm">{{ $t('provider.dashboard.next_schedules.title') }}</div>
  4. <div class="scroll-wrapper">
  5. <div class="scroll-track">
  6. <q-card
  7. v-for="item in data"
  8. :key="item.id"
  9. class="schedule-card card-border shadow-card bg-surface"
  10. :flat="false"
  11. >
  12. <q-card-section class="q-pa-sm">
  13. <div class="row no-wrap items-center q-gutter-x-sm">
  14. <q-avatar size="48px">
  15. <img v-if="item.customer_photo" :src="item.customer_photo" style="object-fit:cover" />
  16. <span v-else class="text-weight-bold full-width full-height flex flex-center" :style="avatarColors[item.id % avatarColors.length]" style="font-size:14px;border-radius:50%">{{ (item.customer_name ?? item.client_name)?.slice(0,2).toUpperCase() ?? '??' }}</span>
  17. </q-avatar>
  18. <div class="column flex-1">
  19. <div class="row items-center q-gutter-x-xs">
  20. <span class="text-name ellipsis">{{ item.customer_name ?? item.client_name }}</span>
  21. <div v-if="item.customer_rating" class="row items-center">
  22. <q-icon name="mdi-star" color="warning" size="14px" />
  23. <span class="text-rating text-text">{{ item.customer_rating }}</span>
  24. </div>
  25. </div>
  26. <div class="row items-center no-wrap">
  27. <span class="text-schedule-date-bold">{{ formatWeekday(item.date) }}</span>
  28. <span class="text-schedule-date-regular">{{ ', ' + formatDayMonth(item.date) }}</span>
  29. </div>
  30. <div class="text-schedule-date-regular">
  31. {{ $t('common.from') }}
  32. <span class="text-schedule-date-bold">{{ item.start_time?.slice(0, 5) }}</span>
  33. {{ $t('common.to') }}
  34. <span class="text-schedule-date-bold">{{ item.end_time?.slice(0, 5) }}</span>
  35. </div>
  36. </div>
  37. <div class="column items-end text-text">
  38. <div class="text-price">{{ formatCurrency(item.total_amount) }}</div>
  39. <div class="text-type">{{ t(labelsPeriodTypes.find(label => label.value == item.period_type)?.label) }}</div>
  40. <div class="text-distance">{{ item.distance_km ?? 0 }}{{ $t('common.km') }}</div>
  41. </div>
  42. </div>
  43. <div class="row q-mt-md items-center text-text text-caption q-px-xs">
  44. <div class="col ellipsis text-grey-7">
  45. {{ formatAddress(item.address) || 'N/A' }}
  46. </div>
  47. <q-icon name="mdi-content-copy" color="primary" size="16px" class="q-ml-xs" @click="copyAddress(item.address)"/>
  48. </div>
  49. <div class="row q-mt-sm items-center">
  50. <q-btn
  51. flat
  52. no-caps
  53. color="primary"
  54. size="sm"
  55. class="col-auto q-px-none btn-details"
  56. :label="$t('provider.dashboard.next_schedules.details')"
  57. @click="emit('view-details', item)"
  58. />
  59. <q-space />
  60. <div class="row items-center q-gutter-x-xs text-grey-7" style="font-size: 11px;">
  61. <q-icon
  62. :name="item.offers_meal ? 'mdi-silverware' : 'mdi-close-outline'"
  63. :color="item.offers_meal ? 'secondary' : 'grey-5'"
  64. size="14px"
  65. />
  66. <span :class="item.offers_meal ? 'text-weight-medium' : ''">
  67. {{ item.offers_meal ? $t('provider.dashboard.next_schedules.offers_meal') : $t('provider.dashboard.next_schedules.no_meal') }}
  68. </span>
  69. </div>
  70. </div>
  71. </q-card-section>
  72. </q-card>
  73. </div>
  74. </div>
  75. </div>
  76. </template>
  77. <script setup>
  78. import { useI18n } from 'vue-i18n';
  79. import { formatCurrency } from 'src/helpers/utils';
  80. import { labelsPeriodTypes } from 'src/helpers/arraysOptions/labelsPeriodTypes.js';
  81. import { useQuasar } from 'quasar';
  82. import { formatAddress } from 'src/helpers/utils';
  83. defineProps({ data: { type: Array, default: () => [] } });
  84. const emit = defineEmits(['view-details']);
  85. const t = useI18n().t;
  86. const $q = useQuasar();
  87. const avatarColors = [
  88. { background: '#ffd5df', color: '#932e57' },
  89. { background: '#d7e8ff', color: '#2158a8' },
  90. { background: '#dfd', color: '#2a7a3b' },
  91. { background: '#ffe5cc', color: '#8a4500' },
  92. ];
  93. const formatWeekday = (iso) => {
  94. if (!iso) return '';
  95. const d = new Date(iso);
  96. const w = d.toLocaleDateString('pt-BR', { weekday: 'long' });
  97. return w.charAt(0).toUpperCase() + w.slice(1);
  98. };
  99. const formatDayMonth = (iso) => {
  100. if (!iso) return '';
  101. return new Date(iso).toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' });
  102. };
  103. const copyAddress = (address) => {
  104. const formatted = formatAddress(address);
  105. if (formatted) {
  106. navigator.clipboard.writeText(formatted);
  107. }
  108. $q.notify({ message: t('provider.dashboard.next_schedules.address_copied'), color: 'positive' });
  109. };
  110. </script>
  111. <style scoped lang="scss">
  112. .scroll-wrapper { overflow: hidden; }
  113. .scroll-track {
  114. display: flex;
  115. flex-direction: row;
  116. gap: 12px;
  117. overflow-x: auto;
  118. overscroll-behavior-x: contain;
  119. scroll-snap-type: x proximity;
  120. padding-bottom: 8px;
  121. &::-webkit-scrollbar { display: none; }
  122. &::after { content: ''; flex: 0 0 1px; }
  123. }
  124. .schedule-card {
  125. min-width: 85vw;
  126. border-radius: 12px;
  127. }
  128. .text-name {
  129. font-weight: 700;
  130. color: #3a3a4a;
  131. }
  132. .text-rating {
  133. font-size: 12px;
  134. font-weight: 600;
  135. }
  136. .text-schedule-date-bold {
  137. font-family: "Inter", sans-serif;
  138. font-size: 11px;
  139. font-weight: 700;
  140. color: #3a3a4a;
  141. }
  142. .text-schedule-date-regular {
  143. font-family: "Inter", sans-serif;
  144. font-size: 11px;
  145. font-weight: 400;
  146. color: #666;
  147. }
  148. .text-date, .text-time, .text-type, .text-region, .text-distance {
  149. font-size: 11px;
  150. color: #666;
  151. }
  152. .text-price {
  153. font-weight: 700;
  154. color: #3a3a4a;
  155. font-size: 14px;
  156. }
  157. .btn-details {
  158. font-weight: 700;
  159. font-size: 13px;
  160. }
  161. .flex-1 {
  162. flex: 1;
  163. min-width: 0;
  164. }
  165. </style>