import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { BehaviorSubject, map } from 'rxjs'; import { environment } from 'src/environments/environment'; import { Basket, IBasket, IBasketItem, IBasketTotals } from '../shared/models/baskset'; import { IDeliveryMethods } from '../shared/models/deliveryMethods'; import { IProduct } from '../shared/models/product'; @Injectable({ providedIn: 'root' }) export class BasketService { baseUrl = environment.apiUrl; private basketSource = new BehaviorSubject(null); basket$ = this.basketSource.asObservable(); private basketTotalSource = new BehaviorSubject(null); basketTotal$ = this.basketTotalSource.asObservable(); shipping = 0; constructor(private http: HttpClient) { } setShippingPrice(deliveryMethod: IDeliveryMethods){ this.shipping = deliveryMethod.price; this.calculateTotals(); } getBasket(id: string){ return this.http.get(this.baseUrl + 'basket?id=' + id).pipe( map((basket: IBasket) => { this.basketSource.next(basket); this.calculateTotals(); }) ); } setBasket(basket: IBasket){ return this.http.post(this.baseUrl + 'basket', basket).subscribe({ next: (response: IBasket) => { this.basketSource.next(response); this.calculateTotals(); }, error: (e: any) => { console.log(e); }, complete: () => { console.log('complete'); } }); } getCurrentBasketValue(){ return this.basketSource.value; } addItemToBasket(item: IProduct, quantity = 1){ const itemToAdd: IBasketItem = this.mapProductItemToBasketItem(item, quantity); const basket = this.getCurrentBasketValue() ?? this.createBasket(); basket.items = this.addOrUpdateItem(basket.items, itemToAdd, quantity); this.setBasket(basket); } incrementItemQuantity(item: IBasketItem){ const basket = this.getCurrentBasketValue(); const foundItemIndex = basket.items.findIndex(x => x.id === item.id); basket.items[foundItemIndex].quantity++; this.setBasket(basket); } decrementItemQuantity(item: IBasketItem){ const basket = this.getCurrentBasketValue(); const foundItemIndex = basket.items.findIndex(x => x.id === item.id); if (basket.items[foundItemIndex].quantity > 1){ basket.items[foundItemIndex].quantity--; this.setBasket(basket); } else { this.removeItemFromBasket(item); } } removeItemFromBasket(item: IBasketItem) { const basket = this.getCurrentBasketValue(); if(basket.items.some(x => x.id === item.id)) { basket.items = basket.items.filter(i => i.id !== item.id); if (basket.items.length > 0){ this.setBasket(basket); } else { this.deleteBasket(basket); } } } deleteBasket(basket: IBasket) { return this.http.delete(this.baseUrl + 'basket?id=' + basket.id).subscribe({ next: () => { this.basketSource.next(null); this.basketTotalSource.next(null); localStorage.removeItem('basket_id'); }, error: (e: any) => { console.log(e) }, complete: () => { console.log('Complete') } }); } private calculateTotals(){ const basket = this.getCurrentBasketValue(); const shipping = this.shipping; const subtotal = basket.items.reduce((a, b) => (b.price * b.quantity) + a, 0); const total = subtotal + shipping; this.basketTotalSource.next({ shipping, total, subtotal }); } private addOrUpdateItem(items: IBasketItem[], itemToAdd: IBasketItem, quantity: number): IBasketItem[] { const index = items.findIndex(i => i.id === itemToAdd.id); if(index === -1){ itemToAdd.quantity = quantity; items.push(itemToAdd); } else { items[index].quantity += quantity; } return items; } private createBasket(): IBasket { const basket = new Basket(); localStorage.setItem('basket_id', basket.id); return basket; } private mapProductItemToBasketItem(item: IProduct, quantity: number): IBasketItem { return { id: item.id, productName: item.name, price: item.price, pictureUrl: item.pictureUrl, quantity, brand: item.productBrand, type: item.productType } } }