delivery
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Injectable, signal, computed, effect } from '@angular/core';
|
||||
import { ApiService } from './api.service';
|
||||
import { Item, CartItem } from '../models';
|
||||
import { DeliveryOption, Item, CartItem } from '../models';
|
||||
import { getDiscountedPrice } from '../utils/item.utils';
|
||||
import { environment } from '../../environments/environment';
|
||||
import type { } from '../types/telegram.types';
|
||||
@@ -31,13 +31,21 @@ export class CartService {
|
||||
totalDeliveryPrice = computed(() => {
|
||||
const items = this.cartItems();
|
||||
if (!Array.isArray(items)) return 0;
|
||||
return items.reduce((total, item) => total + ((item.deliveryPrice ?? 0) * item.quantity), 0);
|
||||
return items.reduce((total, item) => {
|
||||
return total + ((item.selectedDelivery?.deliveryPrice ?? 0) * item.quantity);
|
||||
}, 0);
|
||||
});
|
||||
totalWithDelivery = computed(() => this.totalPrice() + this.totalDeliveryPrice());
|
||||
allRequiredDeliveriesSelected = computed(() => {
|
||||
const items = this.cartItems();
|
||||
if (!Array.isArray(items)) return true;
|
||||
return items.every(item => !this.itemRequiresDeliverySelection(item) || item.selectedDelivery != null);
|
||||
});
|
||||
hasDeliveryPrice = computed(() => {
|
||||
const items = this.cartItems();
|
||||
if (!Array.isArray(items)) return false;
|
||||
return items.some(item => item.deliveryPrice !== undefined && item.deliveryPrice !== null);
|
||||
return this.allRequiredDeliveriesSelected()
|
||||
&& items.some(item => (item.deliveryOptions?.length ?? 0) > 0 || item.selectedDelivery != null);
|
||||
});
|
||||
|
||||
constructor(private apiService: ApiService) {
|
||||
@@ -64,14 +72,110 @@ export class CartService {
|
||||
return Number.isFinite(normalized) ? normalized : undefined;
|
||||
}
|
||||
|
||||
private normalizeOptionalString(value: unknown): string {
|
||||
if (typeof value === 'string') {
|
||||
return value.trim();
|
||||
}
|
||||
|
||||
if (typeof value === 'number' || typeof value === 'bigint') {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private normalizeDeliveryOption(value: unknown): DeliveryOption | null {
|
||||
if (value === null || value === undefined || typeof value !== 'object' || Array.isArray(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const source = value as Record<string, unknown>;
|
||||
const deliveryPlace = this.normalizeOptionalString(
|
||||
source['deliveryPlace'] ?? source['delivery_place'] ?? source['deliveryplace']
|
||||
);
|
||||
const deliveryTime = this.normalizeOptionalString(
|
||||
source['deliveryTime'] ?? source['delivery_time'] ?? source['deliverytime']
|
||||
);
|
||||
const deliveryPrice = this.normalizeOptionalNumber(
|
||||
source['deliveryPrice'] ?? source['delivery_price'] ?? source['deliveryprice']
|
||||
);
|
||||
|
||||
if (deliveryPrice === undefined && !deliveryPlace && !deliveryTime) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
deliveryPrice: deliveryPrice ?? 0,
|
||||
deliveryPlace,
|
||||
deliveryTime,
|
||||
};
|
||||
}
|
||||
|
||||
private sameDeliveryOption(left: DeliveryOption, right: DeliveryOption): boolean {
|
||||
return left.deliveryPrice === right.deliveryPrice
|
||||
&& left.deliveryPlace === right.deliveryPlace
|
||||
&& left.deliveryTime === right.deliveryTime;
|
||||
}
|
||||
|
||||
private itemRequiresDeliverySelection(item: CartItem): boolean {
|
||||
return item.deliveryMode !== 'digital'
|
||||
&& (item.deliveryOptions?.length ?? 0) > 0
|
||||
&& item.deliverySelectionRequired !== false;
|
||||
}
|
||||
|
||||
private normalizeDeliveryState(item: CartItem): {
|
||||
deliveryMode?: CartItem['deliveryMode'];
|
||||
deliveryOptions: DeliveryOption[];
|
||||
deliverySelectionRequired: boolean;
|
||||
selectedDelivery: DeliveryOption | null;
|
||||
} {
|
||||
const normalizedOptions = Array.isArray(item.deliveryOptions)
|
||||
? item.deliveryOptions
|
||||
.map(option => this.normalizeDeliveryOption(option))
|
||||
.filter((option): option is DeliveryOption => option !== null)
|
||||
: [];
|
||||
const legacyDeliveryPrice = this.normalizeOptionalNumber(item.deliveryPrice);
|
||||
const deliveryOptions = normalizedOptions.length > 0
|
||||
? normalizedOptions
|
||||
: legacyDeliveryPrice !== undefined
|
||||
? [{ deliveryPrice: legacyDeliveryPrice, deliveryPlace: '', deliveryTime: '' }]
|
||||
: [];
|
||||
const deliveryMode = item.deliveryMode === 'digital'
|
||||
? 'digital'
|
||||
: deliveryOptions.length > 0
|
||||
? 'selectable'
|
||||
: undefined;
|
||||
const deliverySelectionRequired = deliveryOptions.length > 0
|
||||
? item.deliverySelectionRequired !== false && normalizedOptions.length > 0
|
||||
: false;
|
||||
const selectedDelivery = this.normalizeDeliveryOption(item.selectedDelivery)
|
||||
?? (deliveryOptions.length === 1 && !deliverySelectionRequired ? deliveryOptions[0] : null);
|
||||
const matchedSelection = selectedDelivery && deliveryOptions.length > 0
|
||||
? deliveryOptions.find(option => this.sameDeliveryOption(option, selectedDelivery)) ?? selectedDelivery
|
||||
: selectedDelivery;
|
||||
|
||||
return {
|
||||
deliveryMode,
|
||||
deliveryOptions,
|
||||
deliverySelectionRequired,
|
||||
selectedDelivery: matchedSelection,
|
||||
};
|
||||
}
|
||||
|
||||
private normalizeCartItem(item: CartItem): CartItem {
|
||||
const { deliveryPrice, ...rest } = item;
|
||||
const normalizedDeliveryPrice = this.normalizeOptionalNumber(deliveryPrice);
|
||||
const deliveryState = this.normalizeDeliveryState(item);
|
||||
const hasDeliveryState = !!deliveryState.deliveryMode
|
||||
|| deliveryState.deliveryOptions.length > 0
|
||||
|| deliveryState.selectedDelivery != null;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
quantity: item.quantity || 1,
|
||||
...(normalizedDeliveryPrice !== undefined ? { deliveryPrice: normalizedDeliveryPrice } : {}),
|
||||
...(hasDeliveryState ? { deliverySelectionRequired: deliveryState.deliverySelectionRequired } : {}),
|
||||
...(deliveryState.deliveryMode ? { deliveryMode: deliveryState.deliveryMode } : {}),
|
||||
...(deliveryState.deliveryOptions.length > 0 ? { deliveryOptions: deliveryState.deliveryOptions } : {}),
|
||||
...(deliveryState.selectedDelivery ? { selectedDelivery: deliveryState.selectedDelivery } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -181,6 +285,22 @@ export class CartService {
|
||||
this.cartItems.set(updatedItems);
|
||||
}
|
||||
|
||||
setSelectedDelivery(itemID: number, selectedDelivery: DeliveryOption | null): void {
|
||||
const normalizedSelection = this.normalizeDeliveryOption(selectedDelivery);
|
||||
const updatedItems = this.cartItems().map(item => {
|
||||
if (item.itemID !== itemID) {
|
||||
return item;
|
||||
}
|
||||
|
||||
return this.normalizeCartItem({
|
||||
...item,
|
||||
selectedDelivery: normalizedSelection,
|
||||
});
|
||||
});
|
||||
|
||||
this.cartItems.set(updatedItems);
|
||||
}
|
||||
|
||||
removeItems(itemIDs: number[]): void {
|
||||
const currentItems = this.cartItems();
|
||||
const updatedItems = currentItems.filter(item => !itemIDs.includes(item.itemID));
|
||||
|
||||
Reference in New Issue
Block a user