| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- <template>
- <div class="q-mx-md q-mb-md">
- <div class="scroll-wrapper">
- <div class="scroll-track">
- <q-card
- v-for="item in data"
- :key="item.id"
- :flat="false"
- class="pending-card card-border shadow-card bg-surface"
- @click="seeDetails(item)"
- >
- <q-card-section class="q-pa-md">
- <div class="row no-wrap items-start q-mb-sm">
- <q-avatar
- class="q-mr-sm flex-shrink-0"
- size="40px"
- :style="avatarColors[item.id % avatarColors.length]"
- >
- <img
- v-if="providerPhoto(item)"
- :src="providerPhoto(item)"
- style="object-fit: cover; border-radius: 50%"
- />
- <span v-else>
- {{
- providerName(item).slice(0, 2).toUpperCase() || "??"
- }}
- </span>
- </q-avatar>
- <div class="col column no-wrap overflow-hidden">
- <span class="font12 fontmedium text-text">
- <span v-if="type === 'servicePackage'">
- {{
- $t("dashboard_client.pending_schedules.pay_to_provider")
- }}
- </span>
- <span v-else-if="item.status == 'pending'">
- {{
- $t("dashboard_client.pending_schedules.requesting_with")
- }}
- </span>
- <span v-else-if="item.status == 'accepted'">
- {{
- $t("dashboard_client.pending_schedules.pay_to_provider")
- }}
- </span>
- <span class="font12 fontbold">
- {{ " " + (getFirstName(providerName(item)) || "—") }}</span
- >
- </span>
- <div class="row items-center q-mt-xs">
- <q-icon
- class="q-mr-xs"
- color="grey-5"
- name="mdi-clock-outline"
- size="13px"
- />
- <span class="font9 fontmedium text-grey-5">
- {{ displayTime(item) }}
- </span>
- </div>
- </div>
- <div
- class="clock-badge-col q-ml-sm flex-shrink-0 column items-center"
- >
- <div class="clock-badge">
- <q-icon
- color="white"
- name="mdi-clock-outline"
- size="14px"
- />
- </div>
- <span
- class="font10 fontmedium text-primary q-mt-xs badge-status-text"
- >
- {{
- type === 'servicePackage'
- ? $t("dashboard_client.pending_schedules.status.accepted")
- : $t(
- `dashboard_client.pending_schedules.status.${item.status ?? "pending"}`,
- )
- }}
- </span>
- </div>
- </div>
- <div class="progress-track q-mb-md">
- <div
- class="progress-fill"
- :style="{ width: progressPercent(item.status) + '%' }"
- />
- </div>
- <div class="row items-center no-wrap">
- <q-btn
- v-if="type !== 'servicePackage'"
- class="q-mr-sm flex-shrink-0"
- color="primary"
- dense
- flat
- no-caps
- size="xs"
- :label="$t('dashboard_client.pending_schedules.cancel_btn')"
- @click="$emit('cancel', item)"
- />
- <q-space />
- <span
- class="font9 fontregular text-grey-6 col ellipsis text-right"
- >
- <q-icon
- class="q-mr-xs flex-shrink-0"
- color="grey-6"
- name="mdi-map-marker-outline"
- size="13px"
- />
- {{
- displayAddress(item)
- }}
- </span>
- </div>
- </q-card-section>
- </q-card>
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import { computed } from "vue";
- import { avatarColors } from "src/helpers/avatarColors";
- import { getFirstName } from "src/helpers/utils";
- const props = defineProps({
- data: { type: Array, default: () => [] },
- type: { type: String, default: 'schedule' },
- });
- const emit = defineEmits(["view-details", "cancel"]);
- const isServicePackage = computed(() => props.type === 'servicePackage');
- const providerPhoto = (item) => {
- if (isServicePackage.value) {
- return item.provider?.profile_media?.url ?? item.provider_photo ?? null;
- }
- return item.provider_photo;
- };
- const providerName = (item) => {
- if (isServicePackage.value) {
- return item.provider?.user?.name ?? item.provider_name ?? '';
- }
- return item.provider_name ?? '';
- };
- const displayAddress = (item) => {
- if (isServicePackage.value) {
- const firstSchedule = item.schedules?.[0];
- const addr = firstSchedule?.address;
- if (addr) {
- return [addr.address, addr.number, addr.district].filter(Boolean).join(', ') || '—';
- }
- return '—';
- }
- return [
- item.address?.address,
- item.address?.number,
- item.address?.district,
- ].filter(Boolean).join(', ') || '—';
- };
- const displayTime = (item) => {
- if (isServicePackage.value) {
- return item.schedules?.length
- ? `${item.schedules.length} agendamentos`
- : '—';
- }
- return item.time_since_request;
- };
- const statusProgressMap = {
- pending: 20,
- accepted: 40,
- paid: 60,
- started: 80,
- finished: 100,
- };
- const progressPercent = (status) => statusProgressMap[status] ?? 20;
- const seeDetails = (item) => {
- if (isServicePackage.value || item.status === "accepted") {
- emit("view-details", item);
- }
- };
- </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;
- }
- }
- .pending-card {
- min-width: 80%;
- scroll-snap-align: start;
- }
- .clock-badge-col {
- min-width: 52px;
- align-items: center;
- }
- .clock-badge {
- width: 24px;
- height: 24px;
- border-radius: 50%;
- background: linear-gradient(135deg, #8b5cf6, #ec4899);
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .badge-status-text {
- white-space: nowrap;
- }
- .progress-track {
- width: 100%;
- height: 6px;
- background: #e2e8f0;
- border-radius: 999px;
- overflow: hidden;
- }
- .progress-fill {
- position: relative;
- height: 100%;
- border-radius: inherit;
- background: linear-gradient(
- 90deg,
- #3b5cff,
- #7a4dff,
- #d94cff
- );
- transition: width .4s ease;
- overflow: hidden;
- }
- .progress-fill::after {
- content: "";
- position: absolute;
- top: 0;
- bottom: 0;
- left: -35%;
- width: 35%;
- background: linear-gradient(
- 90deg,
- transparent,
- rgba(255,255,255,.45),
- transparent
- );
- transform: skewX(-20deg);
- animation: progressShine 2s linear infinite;
- }
- @keyframes progressShine {
- from {
- left: -35%;
- }
- to {
- left: 135%;
- }
- }
- </style>
|