|
@@ -0,0 +1,210 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <q-dialog ref="dialogRef" @hide="onDialogHide">
|
|
|
|
|
+ <q-card class="next-schedule-dialog-card bg-surface shadow-card" :flat="false">
|
|
|
|
|
+
|
|
|
|
|
+ <div class="row justify-end q-pt-sm q-pr-sm">
|
|
|
|
|
+ <q-btn flat round dense icon="close" color="grey-6" size="sm" @click="onDialogCancel" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <q-card-section class="column items-center q-pt-xs q-pb-sm">
|
|
|
|
|
+ <q-avatar size="72px" class="q-mb-sm">
|
|
|
|
|
+ <img :src="schedule.customer_photo || 'https://cdn.quasar.dev/img/avatar.png'" />
|
|
|
|
|
+ </q-avatar>
|
|
|
|
|
+ <div class="text-subtitle1 text-weight-bold text-text">
|
|
|
|
|
+ {{ schedule.customer_name ?? schedule.client_name }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="text-price q-mt-xs">{{ formatCurrency(schedule.total_amount) }}</div>
|
|
|
|
|
+ <div class="text-caption text-grey-6 q-mt-xxs">{{ periodLabel }}</div>
|
|
|
|
|
+ </q-card-section>
|
|
|
|
|
+
|
|
|
|
|
+ <q-separator class="q-mx-lg" />
|
|
|
|
|
+
|
|
|
|
|
+ <q-card-section class="column items-center q-py-sm text-text">
|
|
|
|
|
+ <div class="text-body2 text-center">
|
|
|
|
|
+ <span class="text-weight-bold">{{ weekdayLabel }}</span>
|
|
|
|
|
+ <span class="text-grey-7">{{', ' + dayMonthLabel }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="text-body2 text-center q-mt-xxs">
|
|
|
|
|
+ {{ $t('common.from') }}
|
|
|
|
|
+ <span class="text-weight-bold">{{ schedule.start_time?.slice(0, 5) }}</span>
|
|
|
|
|
+ {{ $t('common.to') }}
|
|
|
|
|
+ <span class="text-weight-bold">{{ schedule.end_time?.slice(0, 5) }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </q-card-section>
|
|
|
|
|
+
|
|
|
|
|
+ <q-separator class="q-mx-lg" />
|
|
|
|
|
+
|
|
|
|
|
+ <q-card-section class="column items-center q-py-sm">
|
|
|
|
|
+ <div class="row items-center q-gutter-x-xs">
|
|
|
|
|
+ <q-icon
|
|
|
|
|
+ :name="schedule.offers_meal ? 'mdi-silverware' : 'mdi-close-circle-outline'"
|
|
|
|
|
+ :color="schedule.offers_meal ? 'secondary' : 'grey-5'"
|
|
|
|
|
+ size="18px"
|
|
|
|
|
+ />
|
|
|
|
|
+ <span class="text-body2" :class="schedule.offers_meal ? 'text-text' : 'text-grey-6'">
|
|
|
|
|
+ {{ schedule.offers_meal
|
|
|
|
|
+ ? $t('provider.dashboard.next_schedules.offers_meal')
|
|
|
|
|
+ : $t('provider.dashboard.next_schedules.no_meal') }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </q-card-section>
|
|
|
|
|
+
|
|
|
|
|
+ <q-separator class="q-mx-lg" />
|
|
|
|
|
+
|
|
|
|
|
+ <q-card-section class="column items-center q-py-sm q-px-lg">
|
|
|
|
|
+ <div class="row items-start q-gutter-x-xs no-wrap">
|
|
|
|
|
+ <q-icon name="mdi-map-marker-outline" color="primary" size="20px" class="q-mt-xxs flex-shrink-0" />
|
|
|
|
|
+ <span class="text-body2 text-grey-8 text-center">{{ formattedAddress || 'N/A' }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <q-btn
|
|
|
|
|
+ flat
|
|
|
|
|
+ no-caps
|
|
|
|
|
+ dense
|
|
|
|
|
+ color="primary"
|
|
|
|
|
+ icon="mdi-content-copy"
|
|
|
|
|
+ :label="$t('provider.dashboard.next_schedules.copy_address')"
|
|
|
|
|
+ class="q-mt-xs btn-copy"
|
|
|
|
|
+ @click="copyAddress"
|
|
|
|
|
+ />
|
|
|
|
|
+ </q-card-section>
|
|
|
|
|
+
|
|
|
|
|
+ <q-card-section class="q-pt-xs q-pb-sm q-px-lg">
|
|
|
|
|
+ <q-btn
|
|
|
|
|
+ unelevated
|
|
|
|
|
+ rounded
|
|
|
|
|
+ no-caps
|
|
|
|
|
+ color="primary"
|
|
|
|
|
+ class="full-width btn-close"
|
|
|
|
|
+ :label="$t('provider.dashboard.cancel_schedule.close')"
|
|
|
|
|
+ @click="onDialogCancel"
|
|
|
|
|
+ />
|
|
|
|
|
+ </q-card-section>
|
|
|
|
|
+
|
|
|
|
|
+ <q-card-section class="q-pt-none q-pb-md text-center">
|
|
|
|
|
+ <div class="row justify-center q-gutter-x-lg">
|
|
|
|
|
+ <q-btn
|
|
|
|
|
+ flat
|
|
|
|
|
+ no-caps
|
|
|
|
|
+ color="grey-7"
|
|
|
|
|
+ size="sm"
|
|
|
|
|
+ :label="$t('provider.dashboard.next_schedules.btn_cancel_service')"
|
|
|
|
|
+ @click="openCancelDialog"
|
|
|
|
|
+ />
|
|
|
|
|
+ <q-btn
|
|
|
|
|
+ flat
|
|
|
|
|
+ no-caps
|
|
|
|
|
+ color="grey-7"
|
|
|
|
|
+ size="sm"
|
|
|
|
|
+ :label="$t('provider.dashboard.next_schedules.btn_need_help')"
|
|
|
|
|
+ @click="openHelp"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </q-card-section>
|
|
|
|
|
+
|
|
|
|
|
+ </q-card>
|
|
|
|
|
+ </q-dialog>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import { computed } from 'vue'
|
|
|
|
|
+import { useDialogPluginComponent, useQuasar } from 'quasar'
|
|
|
|
|
+import { useI18n } from 'vue-i18n'
|
|
|
|
|
+import { formatCurrency, formatAddress } from 'src/helpers/utils'
|
|
|
|
|
+import { labelsPeriodTypes } from 'src/helpers/arraysOptions/labelsPeriodTypes.js'
|
|
|
|
|
+import ScheduleCancelDialog from './ScheduleCancelDialog.vue'
|
|
|
|
|
+import ProfileHelpDialog from 'src/components/profile/ProfileHelpDialog.vue'
|
|
|
|
|
+
|
|
|
|
|
+const props = defineProps({
|
|
|
|
|
+ schedule: {
|
|
|
|
|
+ type: Object,
|
|
|
|
|
+ required: true
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const { t } = useI18n()
|
|
|
|
|
+const $q = useQuasar()
|
|
|
|
|
+const { dialogRef, onDialogHide, onDialogCancel, onDialogOK } = useDialogPluginComponent()
|
|
|
|
|
+
|
|
|
|
|
+const periodLabel = computed(() => {
|
|
|
|
|
+ const found = labelsPeriodTypes.find(l => l.value == props.schedule.period_type)
|
|
|
|
|
+ return found ? t(found.label) : ''
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const parseLocalDate = (dateStr) => {
|
|
|
|
|
+ if (!dateStr) return null
|
|
|
|
|
+ const s = String(dateStr)
|
|
|
|
|
+ const iso = s.match(/^(\d{4})-(\d{2})-(\d{2})/)
|
|
|
|
|
+ if (iso) return new Date(+iso[1], +iso[2] - 1, +iso[3])
|
|
|
|
|
+ const dmy = s.match(/^(\d{2})\/(\d{2})\/(\d{4})/)
|
|
|
|
|
+ if (dmy) return new Date(+dmy[3], +dmy[2] - 1, +dmy[1])
|
|
|
|
|
+ return null
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const weekdayLabel = computed(() => {
|
|
|
|
|
+ const d = parseLocalDate(props.schedule.date)
|
|
|
|
|
+ if (!d) return ''
|
|
|
|
|
+ const w = d.toLocaleDateString('pt-BR', { weekday: 'long' })
|
|
|
|
|
+ return w.charAt(0).toUpperCase() + w.slice(1)
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const dayMonthLabel = computed(() => {
|
|
|
|
|
+ const d = parseLocalDate(props.schedule.date)
|
|
|
|
|
+ if (!d) return ''
|
|
|
|
|
+ return d.toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' })
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const formattedAddress = computed(() => formatAddress(props.schedule.address))
|
|
|
|
|
+
|
|
|
|
|
+const copyAddress = () => {
|
|
|
|
|
+ const addr = formattedAddress.value
|
|
|
|
|
+ if (addr) navigator.clipboard.writeText(addr)
|
|
|
|
|
+ $q.notify({ message: t('provider.dashboard.next_schedules.address_copied'), color: 'positive' })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const openCancelDialog = () => {
|
|
|
|
|
+ $q.dialog({
|
|
|
|
|
+ component: ScheduleCancelDialog,
|
|
|
|
|
+ componentProps: { schedule: props.schedule }
|
|
|
|
|
+ }).onOk(() => {
|
|
|
|
|
+ onDialogOK({ action: 'cancelled', id: props.schedule.id })
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const openHelp = () => {
|
|
|
|
|
+ $q.dialog({ component: ProfileHelpDialog })
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped lang="scss">
|
|
|
|
|
+.next-schedule-dialog-card {
|
|
|
|
|
+ width: 320px;
|
|
|
|
|
+ max-width: 92vw;
|
|
|
|
|
+ border-radius: 20px !important;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.text-price {
|
|
|
|
|
+ font-size: 26px;
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ color: var(--q-primary);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.btn-close {
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ padding: 10px 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.btn-copy {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.flex-shrink-0 {
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.q-mt-xxs {
|
|
|
|
|
+ margin-top: 2px;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|