AddServiceLoyalty

This commit is contained in:
2026-07-15 20:42:03 +03:30
parent 0d4158db4e
commit a2d0232113
6 changed files with 137 additions and 5 deletions
+60 -2
View File
@@ -54,6 +54,12 @@
{{ formatPriceToman(selectedPrice) }} تومان
</dd>
</div>
<p
v-if="loyaltyHint"
class="border-t border-brand-500/20 pt-1.5 text-xs leading-6 text-brand-700 dark:text-brand-400"
>
{{ loyaltyHint }}
</p>
</dl>
</div>
@@ -268,10 +274,21 @@
<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import { createBooking, createBookingBatch, fetchAvailableSlots } from '@/api/bookings';
import {
createBooking,
createBookingBatch,
fetchAvailableSlots,
fetchServiceLoyaltyStatus,
} from '@/api/bookings';
import { fetchBusinessServiceClasses } from '@/api/business-service-classes';
import { ApiError } from '@/api/client';
import type { Booking, Business, BusinessService, BusinessServiceClass } from '@/api/types';
import type {
Booking,
Business,
BusinessService,
BusinessServiceClass,
ServiceLoyaltyStatus,
} from '@/api/types';
import BookingOrderSummary from '@/components/booking/BookingOrderSummary.vue';
import BusinessRatingBadge from '@/components/business/BusinessRatingBadge.vue';
import BookingServiceClassStep from '@/components/booking/BookingServiceClassStep.vue';
@@ -343,6 +360,7 @@ const dateTimeRef = ref<InstanceType<typeof DesktopBookingDateTime> | null>(null
const serviceClasses = ref<BusinessServiceClass[]>([]);
const loadingClasses = ref(true);
const classesError = ref('');
const loyaltyByServiceId = ref<Record<string, ServiceLoyaltyStatus>>({});
const classStepRequired = computed(() => {
if (loadingClasses.value && props.business.serviceClassesEnabled) {
@@ -414,6 +432,46 @@ const selectedDurationLabel = computed(() => {
return `${selectedDurationMinutes.value} دقیقه`;
});
const loyaltyHint = computed(() => {
if (!auth.isLoggedIn || !selectedServices.value.length) return '';
const parts: string[] = [];
for (const service of selectedServices.value) {
const status = loyaltyByServiceId.value[service.id];
if (!status?.enabled || !status.everyN) continue;
const title = service.serviceTemplate?.title ?? 'این خدمت';
if (status.nextIsFree) {
parts.push(`«${title}» در نوبت بعدی رایگان می‌شود.`);
} else if (status.remainingPaidVisits != null) {
parts.push(
`«${title}»: ${status.remainingPaidVisits} نوبت تا رایگان بعدی (هر ${status.everyN} بار).`,
);
}
}
return parts.join(' ');
});
watch(
[selectedServiceIds, () => auth.isLoggedIn],
async ([ids, loggedIn]) => {
if (!loggedIn || !ids.length) {
loyaltyByServiceId.value = {};
return;
}
const next: Record<string, ServiceLoyaltyStatus> = {};
await Promise.all(
ids.map(async (id) => {
try {
next[id] = await fetchServiceLoyaltyStatus(id);
} catch {
/* ignore */
}
}),
);
loyaltyByServiceId.value = next;
},
{ immediate: true },
);
const summaryItems = computed(() =>
selectedServices.value.map((service) => ({
id: service.id,