|
|
@@ -1,51 +1,99 @@
|
|
|
<template>
|
|
|
- <q-dialog ref="dialogRef" maximized transition-show="slide-up" transition-hide="slide-down">
|
|
|
+ <q-dialog
|
|
|
+ ref="dialogRef"
|
|
|
+ maximized
|
|
|
+ transition-hide="slide-down"
|
|
|
+ transition-show="slide-up"
|
|
|
+ >
|
|
|
<div class="dialog-root">
|
|
|
-
|
|
|
<div class="dialog-header row items-center q-px-md q-pt-md q-pb-sm bg-white">
|
|
|
- <q-btn v-close-popup flat round dense icon="mdi-chevron-left" color="primary" />
|
|
|
+ <q-btn
|
|
|
+ v-close-popup
|
|
|
+ color="primary"
|
|
|
+ dense
|
|
|
+ flat
|
|
|
+ icon="mdi-chevron-left"
|
|
|
+ round
|
|
|
+ />
|
|
|
+
|
|
|
<div class="col text-center font16 fontbold text-primary gradient-diarista q-mb-xs">
|
|
|
{{ $t('scheduling_page.title') }}
|
|
|
</div>
|
|
|
- <div style="width: 36px" />
|
|
|
+
|
|
|
+ <div style="width: 36px"></div>
|
|
|
</div>
|
|
|
|
|
|
<div class="dialog-body">
|
|
|
-
|
|
|
<div class="q-px-md q-pt-md">
|
|
|
<div class="font16 fontbold gradient-diarista q-mb-xs">
|
|
|
{{ $t('scheduling_page.about_provider') }}
|
|
|
</div>
|
|
|
- <q-card class="card-border shadow-card bg-surface text-text" :flat="false">
|
|
|
+
|
|
|
+ <q-card :flat="false" class="card-border shadow-card bg-surface text-text">
|
|
|
<q-card-section class="q-pa-md">
|
|
|
<div class="row items-center no-wrap q-gutter-x-md">
|
|
|
<div class="col-2">
|
|
|
<q-avatar :style="avatarColors[provider.provider_id % avatarColors.length]">
|
|
|
- <img v-if="provider.provider_photo" :src="provider.provider_photo" style="object-fit:cover;border-radius:50%;" />
|
|
|
- <span v-else>{{ provider.provider_name?.slice(0,1) ?? '—' }}</span>
|
|
|
+ <img
|
|
|
+ v-if="provider.provider_photo"
|
|
|
+ :src="provider.provider_photo"
|
|
|
+ style="object-fit:cover;border-radius:50%;"
|
|
|
+ />
|
|
|
+
|
|
|
+ <span v-else>
|
|
|
+ {{ provider.provider_name?.slice(0,1) ?? '—' }}
|
|
|
+ </span>
|
|
|
</q-avatar>
|
|
|
</div>
|
|
|
+
|
|
|
<div class="col-3 column">
|
|
|
- <div class="font12 fontbold text-text">{{ provider?.provider_name ?? '—' }}</div>
|
|
|
- <div class="font10 fontmedium text-grey-7">{{ provider?.district ?? '—' }}</div>
|
|
|
+ <div class="font12 fontbold text-text">
|
|
|
+ {{ provider?.provider_name ?? '—' }}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="font10 fontmedium text-grey-7">
|
|
|
+ {{ provider?.district ?? '—' }}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
+
|
|
|
<div class="col-3">
|
|
|
<div class="row items-center q-gutter-x-md q-mt-xs">
|
|
|
<div class="row items-center">
|
|
|
- <q-icon name="mdi-star" color="warning" size="12px" />
|
|
|
+ <q-icon color="warning" name="mdi-star" size="12px" />
|
|
|
+
|
|
|
<span class="font9 fontmedium q-ml-xs">
|
|
|
{{ (provider?.average_rating != null ? Number(provider.average_rating).toFixed(1) : '') + ' (' + (provider?.total_reviews ?? 0) + ')' }}
|
|
|
</span>
|
|
|
</div>
|
|
|
+
|
|
|
<div class="row items-center">
|
|
|
- <q-icon name="mdi-broom" color="secondary" size="14px" />
|
|
|
- <span class="font9 fontmedium q-ml-xs">{{ provider?.total_services ?? 0 }}</span>
|
|
|
+ <q-icon color="secondary" name="mdi-broom" size="14px" />
|
|
|
+
|
|
|
+ <span class="font9 fontmedium q-ml-xs">
|
|
|
+ {{ provider?.total_services ?? 0 }}
|
|
|
+ </span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
<div class="col-2 column items-center q-gutter-y-xs">
|
|
|
- <q-btn flat round dense icon="mdi-heart-outline" color="pink-4" size="sm" />
|
|
|
- <q-btn flat round dense icon="mdi-information-outline" color="grey-5" size="sm" />
|
|
|
+ <q-btn
|
|
|
+ color="pink-4"
|
|
|
+ dense
|
|
|
+ flat
|
|
|
+ icon="mdi-heart-outline"
|
|
|
+ round
|
|
|
+ size="sm"
|
|
|
+ />
|
|
|
+
|
|
|
+ <q-btn
|
|
|
+ color="grey-5"
|
|
|
+ dense
|
|
|
+ flat
|
|
|
+ icon="mdi-information-outline"
|
|
|
+ round
|
|
|
+ size="sm"
|
|
|
+ />
|
|
|
</div>
|
|
|
</div>
|
|
|
</q-card-section>
|
|
|
@@ -64,11 +112,11 @@
|
|
|
<div v-else class="calendar-wrapper shadow-card q-mb-md">
|
|
|
<q-date
|
|
|
v-model="selectedDate"
|
|
|
- square
|
|
|
class="full-width"
|
|
|
+ minimal
|
|
|
+ square
|
|
|
:first-day-of-week="0"
|
|
|
:options="dateOptions"
|
|
|
- minimal
|
|
|
@update:model-value="onDateSelected"
|
|
|
/>
|
|
|
</div>
|
|
|
@@ -79,14 +127,22 @@
|
|
|
<div class="font16 fontbold gradient-diarista">
|
|
|
{{ $t('scheduling_page.reviews_title') }}
|
|
|
</div>
|
|
|
+
|
|
|
<span class=" text-text cursor-pointer">
|
|
|
{{ $t('scheduling_page.see_all') }}
|
|
|
- <q-icon name="mdi-chevron-right" class="text-text" />
|
|
|
+
|
|
|
+ <q-icon
|
|
|
+ class="text-text"
|
|
|
+ name="mdi-chevron-right"
|
|
|
+ />
|
|
|
</span>
|
|
|
</div>
|
|
|
|
|
|
<div v-if="loadingReviews" class="row items-center justify-center q-py-md">
|
|
|
- <q-spinner-dots color="primary" size="36px" />
|
|
|
+ <q-spinner-dots
|
|
|
+ color="primary"
|
|
|
+ size="36px"
|
|
|
+ />
|
|
|
</div>
|
|
|
|
|
|
<div v-else-if="reviews.length === 0" class="text-center text-grey-6 text-body2 q-py-md">
|
|
|
@@ -97,18 +153,27 @@
|
|
|
<q-card
|
|
|
v-for="review in reviews"
|
|
|
:key="review.id"
|
|
|
- class="review-card card-border bg-white q-mr-sm shadow-card"
|
|
|
:flat="false"
|
|
|
+ class="review-card card-border bg-white q-mr-sm shadow-card"
|
|
|
>
|
|
|
<q-card-section class="q-pa-sm">
|
|
|
<div class="row items-center no-wrap q-gutter-x-sm q-mb-xs">
|
|
|
<q-avatar :style="avatarColors[review.schedule?.client?.id % avatarColors.length]">
|
|
|
- <img v-if="review.schedule?.client?.profile_photo" :src="review.schedule?.client?.profile_photo" style="object-fit:cover;border-radius:50%;" />
|
|
|
- <span v-else>{{review.schedule?.client?.name?.slice(0,1) ?? '—' }}</span>
|
|
|
+ <img
|
|
|
+ v-if="review.schedule?.client?.profile_photo"
|
|
|
+ :src="review.schedule?.client?.profile_photo"
|
|
|
+ style="object-fit:cover;border-radius:50%;"
|
|
|
+ />
|
|
|
+
|
|
|
+ <span v-else>
|
|
|
+ {{review.schedule?.client?.name?.slice(0,1) ?? '—' }}
|
|
|
+ </span>
|
|
|
</q-avatar>
|
|
|
+
|
|
|
<div class="col-3 text-text font10 fontbold">
|
|
|
{{ review.schedule?.client?.name ?? $t('scheduling_page.unknown_client') }}
|
|
|
</div>
|
|
|
+
|
|
|
<div class="row items-center q-mb-xs q-my-auto">
|
|
|
<q-icon
|
|
|
v-for="s in 5"
|
|
|
@@ -119,6 +184,7 @@
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
<div class="font9 fontregular text-text review-comment">
|
|
|
{{ review.comment ?? '--------' }}
|
|
|
</div>
|
|
|
@@ -132,36 +198,40 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, computed, onMounted } from 'vue';
|
|
|
-import { useDialogPluginComponent, useQuasar } from 'quasar';
|
|
|
+import { computed, onMounted, ref } from 'vue';
|
|
|
import { date } from 'quasar';
|
|
|
-import { getProviderWorkingDays, getProviderBlockedDays } from 'src/api/providerAvailability';
|
|
|
import { getClientProviderBlocks } from 'src/api/schedule';
|
|
|
+import { getProviderBlockedDays, getProviderWorkingDays } from 'src/api/providerAvailability';
|
|
|
import { getProviderReceivedReviews } from 'src/api/review';
|
|
|
+import { useDialogPluginComponent, useQuasar } from 'quasar';
|
|
|
+import { useI18n } from 'vue-i18n';
|
|
|
+import { useScheduleCartStore } from 'src/stores/scheduleCart';
|
|
|
import { userStore } from 'src/stores/user';
|
|
|
+import OrderSummaryDialog from './OrderSummaryDialog.vue';
|
|
|
import ServiceSelectionSheet from './ServiceSelectionSheet.vue';
|
|
|
import ServiceTimeSelectionDialog from './ServiceTimeSelectionDialog.vue';
|
|
|
-import OrderSummaryDialog from './OrderSummaryDialog.vue'
|
|
|
|
|
|
const props = defineProps({
|
|
|
- provider: {
|
|
|
- type: Object,
|
|
|
- required: true,
|
|
|
- },
|
|
|
+ provider: { required: true, type: Object },
|
|
|
});
|
|
|
|
|
|
defineEmits([...useDialogPluginComponent.emits]);
|
|
|
|
|
|
const { dialogRef } = useDialogPluginComponent();
|
|
|
-const $q = useQuasar();
|
|
|
+
|
|
|
+const $q = useQuasar();
|
|
|
+const { t } = useI18n();
|
|
|
+
|
|
|
const store = userStore();
|
|
|
|
|
|
-const selectedDate = ref(null);
|
|
|
-const workingDays = ref([]);
|
|
|
-const blockedDays = ref([]);
|
|
|
+const scheduleCart = useScheduleCartStore();
|
|
|
+
|
|
|
+const selectedDate = ref(null);
|
|
|
+const workingDays = ref([]);
|
|
|
+const blockedDays = ref([]);
|
|
|
const loadingAvailability = ref(true);
|
|
|
-const reviews = ref([]);
|
|
|
-const loadingReviews = ref(true);
|
|
|
+const reviews = ref([]);
|
|
|
+const loadingReviews = ref(true);
|
|
|
|
|
|
const avatarColors = [
|
|
|
{ background: '#ffd5df', color: '#932e57' },
|
|
|
@@ -171,17 +241,13 @@ const avatarColors = [
|
|
|
];
|
|
|
|
|
|
const bookings = ref([]);
|
|
|
-const providerClientBlocks = ref({
|
|
|
- existing_schedules: [],
|
|
|
- fully_blocked_weeks: [],
|
|
|
-});
|
|
|
|
|
|
+const providerClientBlocks = ref({ existing_schedules: [], fully_blocked_weeks: [] });
|
|
|
|
|
|
const availableWeekDays = computed(() =>
|
|
|
[...new Set(workingDays.value.map((wd) => wd.day))]
|
|
|
);
|
|
|
|
|
|
-
|
|
|
const blockedDateSet = computed(() =>
|
|
|
new Set(
|
|
|
blockedDays.value
|
|
|
@@ -190,71 +256,124 @@ const blockedDateSet = computed(() =>
|
|
|
)
|
|
|
);
|
|
|
|
|
|
+const blockedWeekStartSet = computed(() =>
|
|
|
+ new Set(providerClientBlocks.value.fully_blocked_weeks ?? [])
|
|
|
+);
|
|
|
|
|
|
-const normalizeDate = (dateStr) => (dateStr ?? '').replace(/\//g, '-');
|
|
|
+const dateOptions = (d) => {
|
|
|
+ const today = date.formatDate(new Date(), 'YYYY/MM/DD');
|
|
|
|
|
|
-const getWeekStart = (dateStr) => {
|
|
|
- const normalizedDate = normalizeDate(dateStr);
|
|
|
- const d = new Date(`${normalizedDate}T12:00:00`);
|
|
|
- d.setDate(d.getDate() - d.getDay());
|
|
|
- return d.toISOString().split('T')[0];
|
|
|
+ if (d < today) return false;
|
|
|
+
|
|
|
+ const raw = normalizeDate(d);
|
|
|
+ const parsed = new Date(`${raw}T12:00:00`);
|
|
|
+ const dayOfWeek = parsed.getDay();
|
|
|
+
|
|
|
+ const isWorkingDay = availableWeekDays.value.includes(dayOfWeek);
|
|
|
+ const isBlocked = blockedDateSet.value.has(raw);
|
|
|
+ const isWeekBlocked = blockedWeekStartSet.value.has(getWeekStart(raw));
|
|
|
+
|
|
|
+ if (!isWorkingDay || isBlocked || isWeekBlocked) return false;
|
|
|
+
|
|
|
+ if (wouldExceedWeekLimit(raw)) return false;
|
|
|
+
|
|
|
+ return true;
|
|
|
};
|
|
|
|
|
|
-const blockedWeekStartSet = computed(() =>
|
|
|
- new Set(providerClientBlocks.value.fully_blocked_weeks ?? [])
|
|
|
-);
|
|
|
+const formatHour = (h) => `${String(h).padStart(2, '0')}:00`;
|
|
|
|
|
|
-const getServerWeekCount = (selectedDate) => {
|
|
|
+const getCartWeekCount = (selectedDate) => {
|
|
|
const weekStart = getWeekStart(selectedDate);
|
|
|
- return (providerClientBlocks.value.existing_schedules ?? []).filter(
|
|
|
- (schedule) => getWeekStart(schedule.date) === weekStart
|
|
|
+
|
|
|
+ return scheduleCart.items.filter((item) =>
|
|
|
+ Number(item.provider_id) === Number(props.provider.provider_id) &&
|
|
|
+ getWeekStart(item.date) === weekStart
|
|
|
).length;
|
|
|
};
|
|
|
|
|
|
const getLocalWeekCount = (selectedDate) => {
|
|
|
const weekStart = getWeekStart(selectedDate);
|
|
|
+
|
|
|
return bookings.value.filter((booking) => getWeekStart(booking.date) === weekStart).length;
|
|
|
};
|
|
|
|
|
|
-const wouldExceedWeekLimit = (selectedDate) => {
|
|
|
- const serverCount = getServerWeekCount(selectedDate);
|
|
|
- const localCount = getLocalWeekCount(selectedDate);
|
|
|
- return (serverCount + localCount) >= 2;
|
|
|
+const getServerWeekCount = (selectedDate) => {
|
|
|
+ const weekStart = getWeekStart(selectedDate);
|
|
|
+
|
|
|
+ return (providerClientBlocks.value.existing_schedules ?? []).filter(
|
|
|
+ (schedule) => getWeekStart(schedule.date) === weekStart
|
|
|
+ ).length;
|
|
|
};
|
|
|
|
|
|
+const getWeekStart = (dateStr) => {
|
|
|
+ const normalizedDate = normalizeDate(dateStr);
|
|
|
|
|
|
-const dateOptions = (d) => {
|
|
|
- const today = date.formatDate(new Date(), 'YYYY/MM/DD');
|
|
|
- if (d < today) return false;
|
|
|
+ const d = new Date(`${normalizedDate}T12:00:00`);
|
|
|
|
|
|
- const raw = normalizeDate(d);
|
|
|
- const parsed = new Date(`${raw}T12:00:00`);
|
|
|
- const dayOfWeek = parsed.getDay();
|
|
|
+ d.setDate(d.getDate() - d.getDay());
|
|
|
|
|
|
- const isWorkingDay = availableWeekDays.value.includes(dayOfWeek);
|
|
|
- const isBlocked = blockedDateSet.value.has(raw);
|
|
|
- const isWeekBlocked = blockedWeekStartSet.value.has(getWeekStart(raw));
|
|
|
+ return d.toISOString().split('T')[0];
|
|
|
+};
|
|
|
|
|
|
- if (!isWorkingDay || isBlocked || isWeekBlocked) return false;
|
|
|
+const loadAvailability = async () => {
|
|
|
+ loadingAvailability.value = true;
|
|
|
|
|
|
- if (wouldExceedWeekLimit(raw)) return false;
|
|
|
+ try {
|
|
|
+ const clientId = store.user?.client?.id;
|
|
|
|
|
|
- return true;
|
|
|
+ const defaultClientBlocks = { existing_schedules: [], fully_blocked_weeks: [] };
|
|
|
+
|
|
|
+ const [wd, bd, clientBlocks] = await Promise.all([
|
|
|
+ getProviderWorkingDays(props.provider.provider_id),
|
|
|
+ getProviderBlockedDays(props.provider.provider_id),
|
|
|
+ clientId
|
|
|
+ ? getClientProviderBlocks(clientId, props.provider.provider_id)
|
|
|
+ : Promise.resolve(defaultClientBlocks),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ blockedDays.value = bd ?? [];
|
|
|
+
|
|
|
+ providerClientBlocks.value = clientBlocks ?? defaultClientBlocks;
|
|
|
+
|
|
|
+ workingDays.value = wd ?? [];
|
|
|
+ } catch {
|
|
|
+ blockedDays.value = [];
|
|
|
+
|
|
|
+ providerClientBlocks.value = { existing_schedules: [], fully_blocked_weeks: [] };
|
|
|
+
|
|
|
+ workingDays.value = [];
|
|
|
+ } finally {
|
|
|
+ loadingAvailability.value = false;
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
+const loadReviews = async () => {
|
|
|
+ loadingReviews.value = true;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const all = await getProviderReceivedReviews(props.provider.provider_id);
|
|
|
+
|
|
|
+ reviews.value = (all ?? []).slice(0, 10);
|
|
|
+ } catch {
|
|
|
+ reviews.value = [];
|
|
|
+ } finally {
|
|
|
+ loadingReviews.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const normalizeDate = (dateStr) => (dateStr ?? '').replace(/\//g, '-');
|
|
|
|
|
|
const onDateSelected = (val) => {
|
|
|
if (!val) return;
|
|
|
|
|
|
selectedDate.value = null;
|
|
|
- const valFormatted = normalizeDate(val);
|
|
|
|
|
|
+ const valFormatted = normalizeDate(val);
|
|
|
|
|
|
const blocksOfDate = blockedDays.value.filter(
|
|
|
(bd) => bd.date === valFormatted && bd.period !== 'all'
|
|
|
);
|
|
|
|
|
|
-
|
|
|
const dayOfWeek = new Date(`${valFormatted}T12:00:00`).getDay();
|
|
|
|
|
|
const dayPeriods = workingDays.value
|
|
|
@@ -271,103 +390,79 @@ const onDateSelected = (val) => {
|
|
|
workingDayBlocks.push({ init_hour: '07:00:00', end_hour: '13:00:00' });
|
|
|
}
|
|
|
|
|
|
-
|
|
|
const localBookingBlocks = bookings.value
|
|
|
- .filter(b => b.date.replace(/\//g, '-') === valFormatted)
|
|
|
- .map(b => ({
|
|
|
- init_hour: `${b.slot.startHour}:00:00`,
|
|
|
- end_hour: `${b.slot.endHour}:00:00`
|
|
|
+ .filter((booking) => booking.date.replace(/\//g, '-') === valFormatted)
|
|
|
+ .map((booking) => ({
|
|
|
+ end_hour: `${booking.slot.endHour}:00:00`,
|
|
|
+ init_hour: `${booking.slot.startHour}:00:00`,
|
|
|
+ }));
|
|
|
+
|
|
|
+ const cartBookingBlocks = scheduleCart.items
|
|
|
+ .filter((item) =>
|
|
|
+ Number(item.provider_id) === Number(props.provider.provider_id) &&
|
|
|
+ normalizeDate(item.date) === valFormatted
|
|
|
+ )
|
|
|
+ .map((item) => ({
|
|
|
+ end_hour: item.end_time,
|
|
|
+ init_hour: item.start_time,
|
|
|
}));
|
|
|
|
|
|
const serverBookingBlocks = (providerClientBlocks.value.existing_schedules ?? [])
|
|
|
.filter((schedule) => normalizeDate(schedule.date) === valFormatted)
|
|
|
.map((schedule) => ({
|
|
|
+ end_hour: schedule.end_time,
|
|
|
init_hour: schedule.start_time,
|
|
|
- end_hour: schedule.end_time,
|
|
|
}));
|
|
|
|
|
|
-
|
|
|
const partialBlocks = [
|
|
|
...blocksOfDate,
|
|
|
...workingDayBlocks,
|
|
|
...localBookingBlocks,
|
|
|
...serverBookingBlocks,
|
|
|
+ ...cartBookingBlocks,
|
|
|
];
|
|
|
|
|
|
- // fluxo
|
|
|
- $q.dialog({
|
|
|
- component: ServiceSelectionSheet,
|
|
|
- componentProps: {
|
|
|
- provider: props.provider,
|
|
|
- selectedDate: val,
|
|
|
- partialBlocks
|
|
|
- },
|
|
|
-}).onOk(({ serviceType, date: date_, provider: prov }) => {
|
|
|
-
|
|
|
$q.dialog({
|
|
|
- component: ServiceTimeSelectionDialog,
|
|
|
- componentProps: {
|
|
|
- serviceType,
|
|
|
- selectedDate: date_,
|
|
|
- provider: prov,
|
|
|
- partialBlocks
|
|
|
- },
|
|
|
- }).onOk((booking) => {
|
|
|
-
|
|
|
- bookings.value.push(booking);
|
|
|
+ component: ServiceSelectionSheet, componentProps: { partialBlocks, provider: props.provider, selectedDate: val },
|
|
|
+ }).onOk(({ action, serviceType, date: date_, provider: prov }) => {
|
|
|
$q.dialog({
|
|
|
- component: OrderSummaryDialog,
|
|
|
- componentProps: {
|
|
|
- provider: props.provider,
|
|
|
- initialBooking: booking
|
|
|
+ component: ServiceTimeSelectionDialog, componentProps: {partialBlocks, provider: prov, selectedDate: date_, serviceType },
|
|
|
+ }).onOk((booking) => {
|
|
|
+ if (action === 'cart') {
|
|
|
+ scheduleCart.addItem({
|
|
|
+ date: normalizeDate(booking.date),
|
|
|
+ end_time: formatHour(booking.slot.endHour),
|
|
|
+ local_id: `${prov.provider_id}-${booking.date}-${booking.slot.value}-${Date.now()}`,
|
|
|
+ offers_meal: booking.meal === 'offer' ? true : booking.meal === 'no_offer' ? false : null,
|
|
|
+ period_type: booking.serviceType.hoursCount,
|
|
|
+ provider_id: prov.provider_id,
|
|
|
+ provider_name: prov.provider_name,
|
|
|
+ start_time: formatHour(booking.slot.startHour),
|
|
|
+ total_amount: booking.serviceType.price,
|
|
|
+ });
|
|
|
+
|
|
|
+ $q.notify({ message: t('schedule_cart.add_success'), type: 'positive' });
|
|
|
+
|
|
|
+ return;
|
|
|
}
|
|
|
- }).onOk(() => {
|
|
|
- dialogRef.value.hide();
|
|
|
- })
|
|
|
- });
|
|
|
-});
|
|
|
-};
|
|
|
|
|
|
-const loadAvailability = async () => {
|
|
|
- loadingAvailability.value = true;
|
|
|
-
|
|
|
- try {
|
|
|
- const clientId = store.user?.client?.id;
|
|
|
- const defaultClientBlocks = { existing_schedules: [], fully_blocked_weeks: [] };
|
|
|
+ bookings.value.push(booking);
|
|
|
|
|
|
- const [wd, bd, clientBlocks] = await Promise.all([
|
|
|
- getProviderWorkingDays(props.provider.provider_id),
|
|
|
- getProviderBlockedDays(props.provider.provider_id),
|
|
|
- clientId
|
|
|
- ? getClientProviderBlocks(clientId, props.provider.provider_id)
|
|
|
- : Promise.resolve(defaultClientBlocks),
|
|
|
- ]);
|
|
|
-
|
|
|
- workingDays.value = wd ?? [];
|
|
|
- blockedDays.value = bd ?? [];
|
|
|
- providerClientBlocks.value = clientBlocks ?? defaultClientBlocks;
|
|
|
-
|
|
|
- } catch {
|
|
|
- workingDays.value = [];
|
|
|
- blockedDays.value = [];
|
|
|
- providerClientBlocks.value = { existing_schedules: [], fully_blocked_weeks: [] };
|
|
|
-
|
|
|
- } finally {
|
|
|
- loadingAvailability.value = false;
|
|
|
- }
|
|
|
+ $q.dialog({
|
|
|
+ component: OrderSummaryDialog, componentProps: { initialBooking: booking, provider: props.provider },
|
|
|
+ }).onOk(() => {
|
|
|
+ dialogRef.value.hide();
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
};
|
|
|
|
|
|
+const wouldExceedWeekLimit = (selectedDate) => {
|
|
|
+ const cartCount = getCartWeekCount(selectedDate);
|
|
|
+ const localCount = getLocalWeekCount(selectedDate);
|
|
|
+ const serverCount = getServerWeekCount(selectedDate);
|
|
|
|
|
|
-const loadReviews = async () => {
|
|
|
- loadingReviews.value = true;
|
|
|
- try {
|
|
|
- const all = await getProviderReceivedReviews(props.provider.provider_id);
|
|
|
- reviews.value = (all ?? []).slice(0, 10);
|
|
|
- } catch {
|
|
|
- reviews.value = [];
|
|
|
- } finally {
|
|
|
- loadingReviews.value = false;
|
|
|
- }
|
|
|
+ return (serverCount + localCount + cartCount) >= 2;
|
|
|
};
|
|
|
|
|
|
onMounted(() => {
|