awaiting_payment set
This commit is contained in:
@@ -5,8 +5,11 @@
|
|||||||
<h2 class="mb-3 text-sm font-bold text-text sm:mb-4 sm:text-base">خلاصه سفارش</h2>
|
<h2 class="mb-3 text-sm font-bold text-text sm:mb-4 sm:text-base">خلاصه سفارش</h2>
|
||||||
|
|
||||||
<div v-if="items.length" class="space-y-3 sm:space-y-4">
|
<div v-if="items.length" class="space-y-3 sm:space-y-4">
|
||||||
<p v-if="classTitle" class="text-xs font-medium text-brand-600">
|
<p
|
||||||
کلاس {{ classTitle }}
|
v-if="classTitle"
|
||||||
|
class="rounded-lg bg-brand-50 px-3 py-2 text-xs font-medium text-brand-700 dark:bg-brand-500/10 dark:text-brand-500"
|
||||||
|
>
|
||||||
|
کلاس خدمات: {{ classTitle }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -22,12 +22,43 @@
|
|||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<BookingStepper :current="currentStep" />
|
<BookingStepper :current="currentStep" />
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="showSelectionRecap"
|
||||||
|
class="rounded-xl border border-brand-500/25 bg-brand-50 px-4 py-3 text-sm dark:bg-brand-500/10"
|
||||||
|
>
|
||||||
|
<p class="mb-2 text-xs font-semibold text-brand-700 dark:text-brand-500">انتخابهای شما</p>
|
||||||
|
<dl class="space-y-1.5">
|
||||||
|
<div v-if="selectedClassTitle" class="flex justify-between gap-3">
|
||||||
|
<dt class="text-muted">کلاس خدمات</dt>
|
||||||
|
<dd class="font-medium text-text">{{ selectedClassTitle }}</dd>
|
||||||
|
</div>
|
||||||
|
<div v-if="selectedServices.length" class="flex justify-between gap-3">
|
||||||
|
<dt class="shrink-0 text-muted">خدمات</dt>
|
||||||
|
<dd class="max-w-[65%] text-left font-medium text-text">{{ selectedServiceTitle }}</dd>
|
||||||
|
</div>
|
||||||
|
<div v-if="scheduledAt && currentStep >= 3" class="flex justify-between gap-3">
|
||||||
|
<dt class="text-muted">زمان</dt>
|
||||||
|
<dd class="font-medium text-text">{{ scheduledLabel }}</dd>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="selectedServices.length"
|
||||||
|
class="flex justify-between gap-3 border-t border-brand-500/20 pt-1.5"
|
||||||
|
>
|
||||||
|
<dt class="text-muted">مبلغ</dt>
|
||||||
|
<dd class="font-semibold text-brand-600">
|
||||||
|
{{ formatPriceToman(selectedPrice) }} تومان
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p class="text-center text-sm font-semibold text-brand-600 lg:hidden">
|
<p class="text-center text-sm font-semibold text-brand-600 lg:hidden">
|
||||||
{{ currentStepLabel }}
|
{{ currentStepLabel }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<BookingServiceClassStep
|
<BookingServiceClassStep
|
||||||
v-if="currentStep === 1"
|
v-if="currentStep === 1 && classStepRequired"
|
||||||
v-model="selectedClassId"
|
v-model="selectedClassId"
|
||||||
:classes="serviceClasses"
|
:classes="serviceClasses"
|
||||||
:loading="loadingClasses"
|
:loading="loadingClasses"
|
||||||
@@ -134,7 +165,10 @@
|
|||||||
>
|
>
|
||||||
<h3 class="mb-4 font-semibold text-text">بررسی نهایی</h3>
|
<h3 class="mb-4 font-semibold text-text">بررسی نهایی</h3>
|
||||||
<dl class="space-y-3 text-sm">
|
<dl class="space-y-3 text-sm">
|
||||||
<div v-if="selectedClassTitle" class="flex justify-between gap-4">
|
<div
|
||||||
|
v-if="classesEnabled && selectedClassTitle"
|
||||||
|
class="flex justify-between gap-4"
|
||||||
|
>
|
||||||
<dt class="text-muted">کلاس</dt>
|
<dt class="text-muted">کلاس</dt>
|
||||||
<dd class="font-medium text-text">{{ selectedClassTitle }}</dd>
|
<dd class="font-medium text-text">{{ selectedClassTitle }}</dd>
|
||||||
</div>
|
</div>
|
||||||
@@ -169,7 +203,7 @@
|
|||||||
class="hidden flex-wrap items-center justify-between gap-3 lg:flex"
|
class="hidden flex-wrap items-center justify-between gap-3 lg:flex"
|
||||||
>
|
>
|
||||||
<AppButton
|
<AppButton
|
||||||
v-if="currentStep > 1"
|
v-if="currentStep > firstBookingStep"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
class="!w-auto"
|
class="!w-auto"
|
||||||
@click="goBack"
|
@click="goBack"
|
||||||
@@ -193,7 +227,7 @@
|
|||||||
>
|
>
|
||||||
<div class="mx-auto flex w-full max-w-app gap-2 px-4 py-3">
|
<div class="mx-auto flex w-full max-w-app gap-2 px-4 py-3">
|
||||||
<AppButton
|
<AppButton
|
||||||
v-if="currentStep > 1"
|
v-if="currentStep > firstBookingStep"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
class="!w-auto shrink-0 px-4"
|
class="!w-auto shrink-0 px-4"
|
||||||
@click="goBack"
|
@click="goBack"
|
||||||
@@ -303,6 +337,20 @@ const classStepRequired = computed(
|
|||||||
() => Boolean(props.business.serviceClassesEnabled) && serviceClasses.value.length > 0,
|
() => Boolean(props.business.serviceClassesEnabled) && serviceClasses.value.length > 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const firstBookingStep = computed(() => {
|
||||||
|
if (!classStepRequired.value) return 2;
|
||||||
|
if (serviceClasses.value.length <= 1) return 2;
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
const showSelectionRecap = computed(
|
||||||
|
() =>
|
||||||
|
currentStep.value >= 2 &&
|
||||||
|
(Boolean(selectedClassTitle.value) ||
|
||||||
|
selectedServices.value.length > 0 ||
|
||||||
|
Boolean(scheduledAt.value)),
|
||||||
|
);
|
||||||
|
|
||||||
const classesEnabled = computed(() => Boolean(props.business.serviceClassesEnabled));
|
const classesEnabled = computed(() => Boolean(props.business.serviceClassesEnabled));
|
||||||
|
|
||||||
const perClass = computed(
|
const perClass = computed(
|
||||||
@@ -503,6 +551,9 @@ async function loadClasses() {
|
|||||||
if (serviceClasses.value.length === 1) {
|
if (serviceClasses.value.length === 1) {
|
||||||
selectedClassId.value = serviceClasses.value[0].id;
|
selectedClassId.value = serviceClasses.value[0].id;
|
||||||
}
|
}
|
||||||
|
if (currentStep.value < firstBookingStep.value) {
|
||||||
|
currentStep.value = firstBookingStep.value;
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
classesError.value =
|
classesError.value =
|
||||||
e instanceof ApiError ? e.message : 'بارگذاری کلاسهای خدمات ناموفق بود';
|
e instanceof ApiError ? e.message : 'بارگذاری کلاسهای خدمات ناموفق بود';
|
||||||
@@ -542,7 +593,7 @@ function applyEarliestSlot() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function goBack() {
|
function goBack() {
|
||||||
if (currentStep.value > 1) {
|
if (currentStep.value > firstBookingStep.value) {
|
||||||
currentStep.value -= 1;
|
currentStep.value -= 1;
|
||||||
bookingError.value = '';
|
bookingError.value = '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@
|
|||||||
type="button"
|
type="button"
|
||||||
class="flex w-full items-center justify-between gap-3 rounded-2xl border border-border bg-surface-2 px-4 py-3 text-start transition hover:border-brand-500/30"
|
class="flex w-full items-center justify-between gap-3 rounded-2xl border border-border bg-surface-2 px-4 py-3 text-start transition hover:border-brand-500/30"
|
||||||
:aria-expanded="bookingExpanded"
|
:aria-expanded="bookingExpanded"
|
||||||
@click="bookingExpanded = !bookingExpanded"
|
@click="bookingExpanded = !bookingExpanded; bookingMessage = ''; bookingError = ''"
|
||||||
>
|
>
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
@@ -108,6 +108,19 @@
|
|||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<p
|
||||||
|
v-if="bookingMessage"
|
||||||
|
class="mt-3 rounded-xl border border-brand-500/40 bg-brand-500/10 px-4 py-3 text-sm text-brand-700 dark:text-brand-500"
|
||||||
|
>
|
||||||
|
{{ bookingMessage }}
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
v-if="bookingError"
|
||||||
|
class="mt-3 rounded-xl border border-red-500/30 bg-red-500/10 px-4 py-3 text-sm text-red-600"
|
||||||
|
>
|
||||||
|
{{ bookingError }}
|
||||||
|
</p>
|
||||||
|
|
||||||
<div v-show="bookingExpanded" class="mt-3 space-y-4">
|
<div v-show="bookingExpanded" class="mt-3 space-y-4">
|
||||||
<AppInput
|
<AppInput
|
||||||
id="ownerConcurrentCapacity"
|
id="ownerConcurrentCapacity"
|
||||||
@@ -533,6 +546,8 @@ const bookingForm = ref({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const bookingExpanded = ref(false);
|
const bookingExpanded = ref(false);
|
||||||
|
const bookingMessage = ref('');
|
||||||
|
const bookingError = ref('');
|
||||||
|
|
||||||
const serviceForm = ref({
|
const serviceForm = ref({
|
||||||
serviceTemplateId: '',
|
serviceTemplateId: '',
|
||||||
@@ -778,15 +793,19 @@ async function onSaveBookingSettings() {
|
|||||||
if (!business.value) return;
|
if (!business.value) return;
|
||||||
const concurrentCapacity = Number.parseInt(bookingForm.value.concurrentCapacity, 10);
|
const concurrentCapacity = Number.parseInt(bookingForm.value.concurrentCapacity, 10);
|
||||||
if (!Number.isFinite(concurrentCapacity) || concurrentCapacity < 1 || concurrentCapacity > 20) {
|
if (!Number.isFinite(concurrentCapacity) || concurrentCapacity < 1 || concurrentCapacity > 20) {
|
||||||
error.value = 'پذیرش همزمان باید عددی بین ۱ تا ۲۰ باشد.';
|
bookingError.value = 'پذیرش همزمان باید عددی بین ۱ تا ۲۰ باشد.';
|
||||||
|
bookingMessage.value = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const slotStepMinutes = Number.parseInt(bookingForm.value.slotStepMinutes, 10);
|
const slotStepMinutes = Number.parseInt(bookingForm.value.slotStepMinutes, 10);
|
||||||
if (!Number.isFinite(slotStepMinutes) || slotStepMinutes < 5 || slotStepMinutes > 120) {
|
if (!Number.isFinite(slotStepMinutes) || slotStepMinutes < 5 || slotStepMinutes > 120) {
|
||||||
error.value = 'گام نوبتدهی باید عددی بین ۵ تا ۱۲۰ دقیقه باشد.';
|
bookingError.value = 'گام نوبتدهی باید عددی بین ۵ تا ۱۲۰ دقیقه باشد.';
|
||||||
|
bookingMessage.value = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
savingBooking.value = true;
|
savingBooking.value = true;
|
||||||
|
bookingError.value = '';
|
||||||
|
bookingMessage.value = '';
|
||||||
error.value = '';
|
error.value = '';
|
||||||
message.value = '';
|
message.value = '';
|
||||||
try {
|
try {
|
||||||
@@ -796,9 +815,11 @@ async function onSaveBookingSettings() {
|
|||||||
autoApproveBookings: bookingForm.value.autoApproveBookings,
|
autoApproveBookings: bookingForm.value.autoApproveBookings,
|
||||||
});
|
});
|
||||||
tenant.syncSingleBusiness(business.value);
|
tenant.syncSingleBusiness(business.value);
|
||||||
|
bookingMessage.value = 'تنظیمات نوبتدهی ذخیره شد.';
|
||||||
|
bookingExpanded.value = false;
|
||||||
message.value = 'تنظیمات نوبتدهی ذخیره شد.';
|
message.value = 'تنظیمات نوبتدهی ذخیره شد.';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error.value = e instanceof ApiError ? e.message : 'خطا در ذخیره';
|
bookingError.value = e instanceof ApiError ? e.message : 'خطا در ذخیره';
|
||||||
} finally {
|
} finally {
|
||||||
savingBooking.value = false;
|
savingBooking.value = false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user