update rezerv
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
import type { BusinessService, BusinessServiceClass } from '@/api/types';
|
||||
import { formatDuration, formatPriceToman } from '@/utils/format';
|
||||
|
||||
export function activeServiceClasses(classes: BusinessServiceClass[]): BusinessServiceClass[] {
|
||||
return [...classes]
|
||||
.filter((item) => item.isActive)
|
||||
.sort((a, b) => a.sortOrder - b.sortOrder || a.title.localeCompare(b.title, 'fa'));
|
||||
}
|
||||
|
||||
export function usesServiceClasses(
|
||||
classesEnabled: boolean,
|
||||
classes: BusinessServiceClass[],
|
||||
): boolean {
|
||||
return classesEnabled && activeServiceClasses(classes).length > 0;
|
||||
}
|
||||
|
||||
export function getClassPriceForService(
|
||||
service: BusinessService,
|
||||
classId: string,
|
||||
) {
|
||||
return service.classPrices?.find(
|
||||
(item) => item.classId === classId && item.isActive,
|
||||
);
|
||||
}
|
||||
|
||||
export function serviceHasActiveClassPrices(
|
||||
service: BusinessService,
|
||||
classes: BusinessServiceClass[],
|
||||
): boolean {
|
||||
const activeIds = new Set(activeServiceClasses(classes).map((item) => item.id));
|
||||
return (service.classPrices ?? []).some(
|
||||
(item) => item.isActive && activeIds.has(item.classId),
|
||||
);
|
||||
}
|
||||
|
||||
export function isServiceBookable(
|
||||
service: BusinessService,
|
||||
classesEnabled: boolean,
|
||||
classes: BusinessServiceClass[],
|
||||
): boolean {
|
||||
if (!service.isActive) return false;
|
||||
if (!usesServiceClasses(classesEnabled, classes)) return true;
|
||||
return serviceHasActiveClassPrices(service, classes);
|
||||
}
|
||||
|
||||
export function servicePriceLabel(
|
||||
service: BusinessService,
|
||||
classesEnabled: boolean,
|
||||
classes: BusinessServiceClass[],
|
||||
): string {
|
||||
if (!usesServiceClasses(classesEnabled, classes)) {
|
||||
return `${formatPriceToman(service.price)} تومان`;
|
||||
}
|
||||
|
||||
const activeClasses = activeServiceClasses(classes);
|
||||
const prices = activeClasses
|
||||
.map((item) => getClassPriceForService(service, item.id))
|
||||
.filter(Boolean)
|
||||
.map((item) => Number.parseFloat(item!.price));
|
||||
|
||||
if (!prices.length) return 'قیمت تعیین نشده';
|
||||
const min = Math.min(...prices);
|
||||
const max = Math.max(...prices);
|
||||
if (min === max) {
|
||||
return `${formatPriceToman(String(min))} تومان`;
|
||||
}
|
||||
return `از ${formatPriceToman(String(min))} تومان`;
|
||||
}
|
||||
|
||||
export function serviceDurationLabel(
|
||||
service: BusinessService,
|
||||
classesEnabled: boolean,
|
||||
classes: BusinessServiceClass[],
|
||||
classId?: string | null,
|
||||
): string {
|
||||
if (classId) {
|
||||
const classPrice = getClassPriceForService(service, classId);
|
||||
return formatDuration(
|
||||
classPrice?.durationMinutes ?? service.durationMinutes,
|
||||
service.serviceTemplate?.defaultDurationMinutes,
|
||||
);
|
||||
}
|
||||
|
||||
if (!usesServiceClasses(classesEnabled, classes)) {
|
||||
return formatDuration(
|
||||
service.durationMinutes,
|
||||
service.serviceTemplate?.defaultDurationMinutes,
|
||||
);
|
||||
}
|
||||
|
||||
const activeClasses = activeServiceClasses(classes);
|
||||
const durations = activeClasses
|
||||
.map((item) => getClassPriceForService(service, item.id))
|
||||
.filter(Boolean)
|
||||
.map((item) =>
|
||||
item!.durationMinutes ?? service.durationMinutes ?? service.serviceTemplate?.defaultDurationMinutes,
|
||||
)
|
||||
.filter((value): value is number => value != null && value > 0);
|
||||
|
||||
if (!durations.length) {
|
||||
return formatDuration(
|
||||
service.durationMinutes,
|
||||
service.serviceTemplate?.defaultDurationMinutes,
|
||||
);
|
||||
}
|
||||
|
||||
const min = Math.min(...durations);
|
||||
const max = Math.max(...durations);
|
||||
if (min === max) return `${min} دقیقه`;
|
||||
return `${min}–${max} دقیقه`;
|
||||
}
|
||||
|
||||
export function resolvedServicePrice(
|
||||
service: BusinessService,
|
||||
classId: string,
|
||||
): string | null {
|
||||
const classPrice = getClassPriceForService(service, classId);
|
||||
return classPrice?.price ?? null;
|
||||
}
|
||||
|
||||
export function resolveServiceDurationMinutes(
|
||||
service: BusinessService,
|
||||
classesEnabled: boolean,
|
||||
classes: BusinessServiceClass[],
|
||||
classId?: string | null,
|
||||
): number {
|
||||
if (classId) {
|
||||
const classPrice = getClassPriceForService(service, classId);
|
||||
const fromClass =
|
||||
classPrice?.durationMinutes ?? service.durationMinutes ?? service.serviceTemplate?.defaultDurationMinutes;
|
||||
if (fromClass != null && fromClass > 0) return fromClass;
|
||||
}
|
||||
|
||||
if (usesServiceClasses(classesEnabled, classes) && classId) {
|
||||
const classPrice = getClassPriceForService(service, classId);
|
||||
const value =
|
||||
classPrice?.durationMinutes ??
|
||||
service.durationMinutes ??
|
||||
service.serviceTemplate?.defaultDurationMinutes;
|
||||
if (value != null && value > 0) return value;
|
||||
}
|
||||
|
||||
const fallback =
|
||||
service.durationMinutes ?? service.serviceTemplate?.defaultDurationMinutes;
|
||||
return fallback != null && fallback > 0 ? fallback : 30;
|
||||
}
|
||||
|
||||
export function totalDurationForServices(
|
||||
services: BusinessService[],
|
||||
classesEnabled: boolean,
|
||||
classes: BusinessServiceClass[],
|
||||
classId?: string | null,
|
||||
): number {
|
||||
return services.reduce(
|
||||
(sum, service) =>
|
||||
sum + resolveServiceDurationMinutes(service, classesEnabled, classes, classId),
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
export function totalPriceForServices(
|
||||
services: BusinessService[],
|
||||
classesEnabled: boolean,
|
||||
classes: BusinessServiceClass[],
|
||||
classId?: string | null,
|
||||
): number | null {
|
||||
if (usesServiceClasses(classesEnabled, classes)) {
|
||||
if (!classId) return null;
|
||||
let total = 0;
|
||||
for (const service of services) {
|
||||
const price = resolvedServicePrice(service, classId);
|
||||
if (!price) return null;
|
||||
total += Number.parseFloat(price);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
return services.reduce((sum, service) => sum + Number.parseFloat(service.price), 0);
|
||||
}
|
||||
Reference in New Issue
Block a user