From 64103218958c84ba279fd5f9d9cb2a770ff17897 Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Sat, 20 Jun 2026 15:16:25 +0400 Subject: [PATCH] price --- src/app/models/item.model.ts | 2 ++ src/app/pages/cart/cart.component.html | 18 ++++++++--- src/app/pages/cart/cart.component.scss | 9 +++++- src/app/pages/cart/cart.component.ts | 8 ++++- src/app/services/api.service.ts | 31 +++++++++++++++++++ src/app/services/cart.service.ts | 43 ++++++++++++++++++++++---- 6 files changed, 98 insertions(+), 13 deletions(-) diff --git a/src/app/models/item.model.ts b/src/app/models/item.model.ts index a7ed2b8..1d123ed 100644 --- a/src/app/models/item.model.ts +++ b/src/app/models/item.model.ts @@ -68,6 +68,7 @@ export interface ItemDetail { colour?: string; size?: string; price: number; + deliveryPrice?: number; currency: string; remaining: number; } @@ -80,6 +81,7 @@ export interface Item { description: string; currency: string; price: number; + deliveryPrice?: number; discount: number; remainings?: string; rating: number; diff --git a/src/app/pages/cart/cart.component.html b/src/app/pages/cart/cart.component.html index f54270a..76d9f74 100644 --- a/src/app/pages/cart/cart.component.html +++ b/src/app/pages/cart/cart.component.html @@ -78,6 +78,12 @@ } @else { {{ item.price }} {{ item.currency }} } + + @if (item.deliveryPrice != null) { + + {{ 'cart.deliveryLabel' | translate }}: {{ item.deliveryPrice | number:'1.2-2' }} {{ item.currency }} + + }
@@ -116,14 +122,16 @@ {{ totalPrice() | number:'1.2-2' }} {{ currentCurrency }}
-
- {{ 'cart.deliveryLabel' | translate }} - 0 {{ currentCurrency }} -
+ @if (hasDeliveryPrice()) { +
+ {{ 'cart.deliveryLabel' | translate }} + {{ totalDeliveryPrice() | number:'1.2-2' }} {{ currentCurrency }} +
+ }
{{ 'cart.toPay' | translate }} - {{ totalPrice() | number:'1.2-2' }} {{ currentCurrency }} + {{ totalWithDelivery() | number:'1.2-2' }} {{ currentCurrency }}
diff --git a/src/app/pages/cart/cart.component.scss b/src/app/pages/cart/cart.component.scss index 422ceb7..190df66 100644 --- a/src/app/pages/cart/cart.component.scss +++ b/src/app/pages/cart/cart.component.scss @@ -555,6 +555,12 @@ font-weight: 700; color: #497671; } + + .delivery-price { + font-size: 0.85rem; + font-weight: 500; + color: #697777; + } } // Dexar quantity controls @@ -838,7 +844,7 @@ color: #6b7280; &.delivery { - display: none; // Hide delivery in Novo + display: flex; } &.total { @@ -1830,6 +1836,7 @@ margin: 0; line-height: 1.5; display: -webkit-box; + line-clamp: 2; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; diff --git a/src/app/pages/cart/cart.component.ts b/src/app/pages/cart/cart.component.ts index ba787c4..3662533 100644 --- a/src/app/pages/cart/cart.component.ts +++ b/src/app/pages/cart/cart.component.ts @@ -26,6 +26,9 @@ export class CartComponent implements OnDestroy { items; itemCount; totalPrice; + totalDeliveryPrice; + totalWithDelivery; + hasDeliveryPrice; termsAccepted = false; isnovo = environment.theme === 'novo'; @@ -68,6 +71,9 @@ export class CartComponent implements OnDestroy { this.items = this.cartService.items; this.itemCount = this.cartService.itemCount; this.totalPrice = this.cartService.totalPrice; + this.totalDeliveryPrice = this.cartService.totalDeliveryPrice; + this.totalWithDelivery = this.cartService.totalWithDelivery; + this.hasDeliveryPrice = this.cartService.hasDeliveryPrice; } requestLogin(): void { @@ -195,7 +201,7 @@ export class CartComponent implements OnDestroy { createPayment(): void { const orderId = this.generateOrderId(); const paymentPayload = { - amount: Number(this.totalPrice()), + amount: Number(this.totalWithDelivery()), currency: 'RUB' as const, siteuserID: this.getPaymentUserId(), siteorderID: orderId, diff --git a/src/app/services/api.service.ts b/src/app/services/api.service.ts index 167d618..1ed10e1 100644 --- a/src/app/services/api.service.ts +++ b/src/app/services/api.service.ts @@ -86,6 +86,18 @@ export class ApiService { return c.startsWith('0x') ? '#' + c.slice(2) : c; } + private normalizeOptionalNumber(value: unknown): number | undefined { + if (value === null || value === undefined || value === '') { + return undefined; + } + + const normalized = typeof value === 'number' + ? value + : Number(String(value).replace(',', '.')); + + return Number.isFinite(normalized) ? normalized : undefined; + } + /** Resolve relative image URLs (e.g. ./images/x.webp) against site origin */ private resolveImageUrl(url: string): string { if (!url) return ''; @@ -102,6 +114,13 @@ export class ApiService { private normalizeItem(raw: any): Item { const { partnerID, ...rest } = raw; const item: Item = { ...rest }; + const topLevelDeliveryPrice = this.normalizeOptionalNumber( + raw.deliveryPrice ?? raw.delivery_price ?? raw.deliveryprice + ); + + if (topLevelDeliveryPrice !== undefined) { + item.deliveryPrice = topLevelDeliveryPrice; + } // Extract price/currency/remaining/colour/size from itemDetails[] // Note: Go struct tag is "itemdetails" but actual API may send "itemDetails" @@ -112,11 +131,23 @@ export class ApiService { ...d, colour: this.normalizeColor(d.colour || d.color || ''), color: undefined, + deliveryPrice: this.normalizeOptionalNumber( + d.deliveryPrice ?? d.delivery_price ?? d.deliveryprice + ), })); if (item.price == null || item.price === 0) item.price = detail.price; if (!item.currency) item.currency = detail.currency; if (!item.colour) item.colour = this.normalizeColor(detail.colour || detail.color || ''); if (!item.size) item.size = detail.size || ''; + if (item.deliveryPrice == null) { + const detailDeliveryPrice = this.normalizeOptionalNumber( + detail.deliveryPrice ?? detail.delivery_price ?? detail.deliveryprice + ); + + if (detailDeliveryPrice !== undefined) { + item.deliveryPrice = detailDeliveryPrice; + } + } // Use remaining from detail for stock level if (raw.remaining == null && detail.remaining != null) { (raw as any).remaining = detail.remaining; diff --git a/src/app/services/cart.service.ts b/src/app/services/cart.service.ts index aef8878..12e641c 100644 --- a/src/app/services/cart.service.ts +++ b/src/app/services/cart.service.ts @@ -28,6 +28,17 @@ export class CartService { return total + (getDiscountedPrice(item) * item.quantity); }, 0); }); + totalDeliveryPrice = computed(() => { + const items = this.cartItems(); + if (!Array.isArray(items)) return 0; + return items.reduce((total, item) => total + ((item.deliveryPrice ?? 0) * item.quantity), 0); + }); + totalWithDelivery = computed(() => this.totalPrice() + this.totalDeliveryPrice()); + hasDeliveryPrice = computed(() => { + const items = this.cartItems(); + if (!Array.isArray(items)) return false; + return items.some(item => item.deliveryPrice !== undefined && item.deliveryPrice !== null); + }); constructor(private apiService: ApiService) { this.loadCart(); @@ -41,6 +52,29 @@ export class CartService { }); } + private normalizeOptionalNumber(value: unknown): number | undefined { + if (value === null || value === undefined || value === '') { + return undefined; + } + + const normalized = typeof value === 'number' + ? value + : Number(String(value).replace(',', '.')); + + return Number.isFinite(normalized) ? normalized : undefined; + } + + private normalizeCartItem(item: CartItem): CartItem { + const { deliveryPrice, ...rest } = item; + const normalizedDeliveryPrice = this.normalizeOptionalNumber(deliveryPrice); + + return { + ...rest, + quantity: item.quantity || 1, + ...(normalizedDeliveryPrice !== undefined ? { deliveryPrice: normalizedDeliveryPrice } : {}), + }; + } + private saveToStorage(items: CartItem[]): void { const data = JSON.stringify(items); @@ -90,10 +124,7 @@ export class CartService { try { const items = JSON.parse(json); if (Array.isArray(items)) { - this.cartItems.set(items.map(item => ({ - ...item, - quantity: item.quantity || 1 - }))); + this.cartItems.set(items.map(item => this.normalizeCartItem(item))); return true; } } catch (err) { @@ -118,14 +149,14 @@ export class CartService { this.addingItems.add(itemID); this.apiService.getItem(itemID).subscribe({ next: (item) => { - const cartItem: CartItem = { + const cartItem = this.normalizeCartItem({ ...item, quantity, ...(variant?.colour != null && { colour: variant.colour }), ...(variant?.size != null && { size: variant.size }), ...(variant?.price != null && { price: variant.price }), ...(variant?.currency != null && { currency: variant.currency }), - }; + }); this.cartItems.set([...this.cartItems(), cartItem]); this.addingItems.delete(itemID); },