DashboardProvidersClose.vue 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. <template>
  2. <div class="q-mx-md q-mb-lg">
  3. <div class="row items-center justify-between no-wrap q-mb-sm">
  4. <div class="dashboard-section-title gradient-diarista font16 fontbold">
  5. {{ $t("dashboard_client.providers_close.title") }}
  6. </div>
  7. <div
  8. v-if="data.length"
  9. class="row items-center no-wrap text-text"
  10. >
  11. <q-btn
  12. color="text"
  13. dense
  14. flat
  15. icon="mdi-chevron-left"
  16. round
  17. size="sm"
  18. @click="setPeriodTypePrevious"
  19. />
  20. <span class="font10 fontbold">
  21. {{ showCorrectLabels() }}
  22. </span>
  23. <q-btn
  24. color="text"
  25. dense
  26. flat
  27. icon="mdi-chevron-right"
  28. round
  29. size="sm"
  30. @click="setPeriodTypeNext"
  31. />
  32. </div>
  33. </div>
  34. <div
  35. v-if="!data.length"
  36. class="empty-alert row no-wrap items-start"
  37. >
  38. <q-icon
  39. class="empty-alert__icon"
  40. name="mdi-alert-outline"
  41. size="28px"
  42. />
  43. <div class="empty-alert__text font10">
  44. {{ $t("dashboard_client.providers_close.empty_alert_text") }}
  45. </div>
  46. </div>
  47. <div
  48. v-else
  49. class="column"
  50. >
  51. <q-card
  52. v-for="p in data"
  53. :key="p.provider_id"
  54. :flat="false"
  55. class="card-border bg-page text-text q-mb-sm"
  56. >
  57. <q-card-section class="row no-wrap q-pa-sm">
  58. <div class="row no-wrap full-width">
  59. <div class="col-2">
  60. <q-avatar
  61. class=""
  62. :style="avatarColors[p.provider_id % avatarColors.length]"
  63. >
  64. <img
  65. v-if="p.provider_photo"
  66. :src="p.provider_photo"
  67. style="object-fit: cover; border-radius: 50%"
  68. />
  69. <span v-else>
  70. {{ p.provider_name?.slice(0, 1).toUpperCase() ?? "—" }}
  71. </span>
  72. </q-avatar>
  73. </div>
  74. <div class="col-10 row">
  75. <div class="column col-9 justify-between">
  76. <span class="text-provider-close-name font12 fontmedium">
  77. {{ getFirstName(p.provider_name) }}
  78. </span>
  79. <span class="text-provider-close-region font9 fontmedium">
  80. {{ p.district }}
  81. </span>
  82. <div class="row items-center justify-between q-pr-lg">
  83. <div class="row items-center">
  84. <q-icon
  85. color="warning"
  86. name="mdi-star"
  87. size="12px"
  88. />
  89. <span class="text-provider-close-rating font9 fontmedium">
  90. {{
  91. p.average_rating != null
  92. ? Number(p.average_rating).toFixed(1) +
  93. " (" +
  94. (p.total_reviews ?? 0) +
  95. ")"
  96. : "(" + (p.total_reviews ?? 0) + ")"
  97. }}
  98. </span>
  99. </div>
  100. <div class="row items-center">
  101. <q-icon
  102. color="secondary"
  103. name="mdi-broom"
  104. size="16px"
  105. />
  106. <span class="text-provider-close-jobs font9 fontmedium">
  107. {{ p.total_services ?? 0 }}
  108. </span>
  109. </div>
  110. <div class="row items-center">
  111. <q-icon
  112. color="text"
  113. name="mdi-map-marker-outline"
  114. size="16px"
  115. />
  116. <span class="text-provider-close-jobs font9 fontmedium">
  117. {{ formatDistance(p.distance_km) }}
  118. </span>
  119. </div>
  120. </div>
  121. </div>
  122. <div
  123. class="column col-3 justify-between text-center items-center"
  124. >
  125. <span class="text-provider-close-price font12 fontmedium">
  126. {{ showCorrectValues(p) }}
  127. </span>
  128. <div class="full-width">
  129. <q-btn
  130. class="full-width"
  131. color="primary"
  132. no-caps
  133. padding="1px 5px"
  134. rounded
  135. size="sm"
  136. unelevated
  137. :label="$t('dashboard_client.favorites.view_schedule')"
  138. @click="goToScheduling(p)"
  139. />
  140. </div>
  141. </div>
  142. </div>
  143. </div>
  144. </q-card-section>
  145. </q-card>
  146. </div>
  147. </div>
  148. </template>
  149. <script setup>
  150. import { avatarColors } from "src/helpers/avatarColors";
  151. import { formatCurrency, getFirstName } from "src/helpers/utils";
  152. import { ref } from "vue";
  153. import { useI18n } from "vue-i18n";
  154. import { useQuasar } from "quasar";
  155. import SchedulingDialog from "src/pages/search/components/SchedulingDialog.vue";
  156. defineProps({ data: { type: Array, default: () => [] } });
  157. const { t } = useI18n();
  158. const $q = useQuasar();
  159. const currentPeriodType = ref(6);
  160. const periodTypeMap = ref({
  161. 2: "daily_price_2h",
  162. 4: "daily_price_4h",
  163. 6: "daily_price_6h",
  164. 8: "daily_price_8h",
  165. });
  166. const formatDistance = (distance) => {
  167. if (distance === null || distance === undefined || distance === "")
  168. return "—";
  169. const numericDistance = Number(distance);
  170. if (!Number.isFinite(numericDistance)) return "—";
  171. return `${numericDistance.toLocaleString("pt-BR", { maximumFractionDigits: 1 })} km`;
  172. };
  173. const setPeriodTypePrevious = () => {
  174. const previousPeriod = currentPeriodType.value - 2;
  175. if (periodTypeMap.value[previousPeriod]) {
  176. currentPeriodType.value = previousPeriod;
  177. }
  178. };
  179. const setPeriodTypeNext = () => {
  180. const nextPeriod = currentPeriodType.value + 2;
  181. if (periodTypeMap.value[nextPeriod]) {
  182. currentPeriodType.value = nextPeriod;
  183. }
  184. };
  185. const showCorrectLabels = () => {
  186. switch (currentPeriodType.value) {
  187. case 8:
  188. return t("dashboard_client.providers_close.until_8h");
  189. case 6:
  190. return t("dashboard_client.providers_close.until_6h");
  191. case 4:
  192. return t("dashboard_client.providers_close.until_4h");
  193. case 2:
  194. return t("dashboard_client.providers_close.until_2h");
  195. default:
  196. return "";
  197. }
  198. };
  199. const showCorrectValues = (p) => {
  200. const priceKey = periodTypeMap.value[currentPeriodType.value];
  201. const price = priceKey ? p[priceKey] : null;
  202. return price !== null && price !== undefined
  203. ? formatCurrency(price)
  204. : t("dashboard_client.providers_close.no_price");
  205. };
  206. //
  207. const goToScheduling = (provider) => {
  208. $q.dialog({
  209. component: SchedulingDialog,
  210. componentProps: { provider },
  211. });
  212. };
  213. </script>
  214. <style scoped lang="scss">
  215. .empty-alert {
  216. background: #e3efff;
  217. border-radius: 8px;
  218. gap: 12px;
  219. padding: 13px 14px;
  220. }
  221. .empty-alert__icon {
  222. color: #6554d9;
  223. flex: 0 0 auto;
  224. }
  225. .empty-alert__text {
  226. color: #6554d9;
  227. line-height: 1.2;
  228. padding-top: 1px;
  229. }
  230. </style>