UNPKG

@spartacus/cart

Version:

`@spartacus/cart` is a package that you can include in your application, which allows you to use various cart features.

401 lines (394 loc) 15.7 kB
import * as i0 from '@angular/core'; import { Injectable, NgModule } from '@angular/core'; import * as i1$1 from '@spartacus/cart/quick-order/root'; import { defaultQuickOrderConfig, QuickOrderFacade } from '@spartacus/cart/quick-order/root'; import * as i1 from '@spartacus/core'; import { CartAddEntrySuccessEvent, CartAddEntryFailEvent, HttpErrorModel, BASE_SITE_CONTEXT_ID, StorageSyncType } from '@spartacus/core'; import { Subject, BehaviorSubject, of, timer, Subscription } from 'rxjs'; import { map, take, first, switchMap, filter, tap } from 'rxjs/operators'; class QuickOrderService { constructor(activeCartService, productAdapter, // TODO(#14059): Remove this service eventService, productSearchConnector //TODO(#14059): Make it required ) { this.activeCartService = activeCartService; this.productAdapter = productAdapter; this.eventService = eventService; this.productSearchConnector = productSearchConnector; this.productAdded$ = new Subject(); this.entries$ = new BehaviorSubject([]); this.softDeletedEntries$ = new BehaviorSubject({}); this.nonPurchasableProductError$ = new BehaviorSubject(null); this.hardDeleteTimeout = 5000; this.quickOrderListLimit = 0; this.clearDeleteTimeouts = {}; } ngOnDestroy() { this.clearDeletedEntries(); } /** * Get entries */ getEntries() { return this.entries$; } /** * @deprecated since 4.2 - use searchProducts instead * Search product using SKU */ search(productCode) { return this.productAdapter.load(productCode); } /** * Search products using query */ searchProducts(query, maxProducts) { var _a, _b; // TODO(#14059): Remove condition if (this.productSearchConnector) { const searchConfig = { pageSize: maxProducts || ((_b = (_a = defaultQuickOrderConfig.quickOrder) === null || _a === void 0 ? void 0 : _a.searchForm) === null || _b === void 0 ? void 0 : _b.maxProducts), }; return this.productSearchConnector .search(query, searchConfig) .pipe(map((searchPage) => searchPage.products || [])); } else { return of([]); } } /** * Clear a list of added entries */ clearList() { this.entries$.next([]); } /** * Get information about the possibility to add the next product */ canAdd(code) { if (code) { return of(this.isProductOnTheList(code) || !this.isLimitExceeded()); } else { return of(!this.isLimitExceeded()); } } /** * Set quick order list limit property */ setListLimit(limit) { this.quickOrderListLimit = limit; } /** * Load a list of entries */ loadEntries(entries = []) { this.entries$.next(entries); } /** * Load a list of entries */ updateEntryQuantity(entryIndex, quantity) { const entries = this.entries$.getValue() || []; entries[entryIndex].quantity = quantity; this.entries$.next(entries); } /** * Delete single entry from the list */ softDeleteEntry(index) { this.entries$.pipe(take(1)).subscribe((entries) => { const entriesList = entries; this.addSoftEntryDeletion(entriesList[index], true); entriesList.splice(index, 1); this.entries$.next(entriesList); }); } /** * @deprecated since 4.2 - use softDeleteEntry instead */ removeEntry(index) { this.softDeleteEntry(index); } /** * Add product to the quick order list */ addProduct(product, quantity = 1) { const entry = this.generateOrderEntry(product, quantity); this.addEntry(entry); } /** * Return product added subject */ getProductAdded() { return this.productAdded$; } /** * Set product added subject */ setProductAdded(productCode) { this.productAdded$.next(productCode); } /** * Adding to cart all products from the list */ addToCart() { let entries = []; const events = []; const subscription = this.eventService .get(CartAddEntrySuccessEvent) .subscribe((cartEvent) => { if (cartEvent.quantityAdded === 0 || (!!cartEvent.quantityAdded && cartEvent.quantityAdded < cartEvent.quantity)) { events.push(this.createQuickOrderResultEvent(cartEvent)); } }); subscription.add(this.eventService .get(CartAddEntryFailEvent) .subscribe((cartEvent) => { events.push(this.createQuickOrderResultEvent(cartEvent)); })); return this.getEntries().pipe(first(), switchMap((elements) => { entries = elements; this.activeCartService.addEntries(elements); this.clearList(); return this.activeCartService.isStable(); }), filter((isStable) => isStable), map(() => [entries, events]), tap(() => subscription.unsubscribe())); } /** * Return soft deleted entries */ getSoftDeletedEntries() { return this.softDeletedEntries$; } /** * Restore soft deleted entry */ restoreSoftDeletedEntry(productCode) { const entry = this.getSoftDeletedEntry(productCode); this.addEntry(entry); this.hardDeleteEntry(productCode); } /** * Clear deleted entry from the list */ hardDeleteEntry(productCode) { const entry = this.getSoftDeletedEntry(productCode); const deletedEntries = this.softDeletedEntries$.getValue(); if (entry) { delete deletedEntries[productCode]; this.softDeletedEntries$.next(deletedEntries); } this.clearDeleteTimeout(productCode); } /** * Clear all deleted entries and timeout subscriptions */ clearDeletedEntries() { Object.values(this.clearDeleteTimeouts).forEach((subscription) => subscription.unsubscribe()); this.softDeletedEntries$.next({}); this.clearDeleteTimeouts = {}; } /** * Return non purchasable product error */ getNonPurchasableProductError() { return this.nonPurchasableProductError$; } /** * Set error that selected product is not purchasable */ setNonPurchasableProductError(product) { this.nonPurchasableProductError$.next(product); } /** * Clear not purchasable product error */ clearNonPurchasableProductError() { this.nonPurchasableProductError$.next(null); } /** * Add soft deleted entry to the cached list */ addSoftEntryDeletion(entry, clearTimeout = true) { var _a; const deletedEntries = this.softDeletedEntries$.getValue(); const productCode = (_a = entry === null || entry === void 0 ? void 0 : entry.product) === null || _a === void 0 ? void 0 : _a.code; if (productCode) { deletedEntries[productCode] = entry; this.softDeletedEntries$.next(deletedEntries); if (clearTimeout) { const subscription = timer(this.hardDeleteTimeout).subscribe(() => { this.hardDeleteEntry(productCode); }); this.clearDeleteTimeouts[productCode] = subscription; } } } /** * Get soft deletion entry */ getSoftDeletedEntry(productCode) { const deletedEntries = this.softDeletedEntries$.getValue(); return deletedEntries[productCode]; } /** * Generate Order Entry from Product */ generateOrderEntry(product, quantity) { return { basePrice: product.price, product, quantity, totalPrice: product.price, }; } /** * Add single entry to the list */ addEntry(entry) { var _a, _b, _c, _d, _e; if (((_a = entry === null || entry === void 0 ? void 0 : entry.product) === null || _a === void 0 ? void 0 : _a.code) && !this.isProductOnTheList(entry.product.code) && this.isLimitExceeded()) { return; } const entries = this.entries$.getValue() || []; const entryStockLevel = (_c = (_b = entry.product) === null || _b === void 0 ? void 0 : _b.stock) === null || _c === void 0 ? void 0 : _c.stockLevel; if (entryStockLevel && entry.quantity && entry.quantity > entryStockLevel) { entry.quantity = entryStockLevel; } if (((_d = entry.product) === null || _d === void 0 ? void 0 : _d.code) && this.isProductOnTheList(entry.product.code)) { const entryIndex = entries.findIndex((item) => { var _a, _b; return ((_a = item.product) === null || _a === void 0 ? void 0 : _a.code) === ((_b = entry.product) === null || _b === void 0 ? void 0 : _b.code); }); let quantity = entries[entryIndex].quantity; if (quantity && entry.quantity) { entries[entryIndex].quantity = quantity + (entry === null || entry === void 0 ? void 0 : entry.quantity); let newQuantity = entries[entryIndex].quantity; if (newQuantity && entryStockLevel && newQuantity > entryStockLevel) { entries[entryIndex].quantity = entryStockLevel; } this.entries$.next([...entries]); } } else { this.entries$.next([...entries, ...[entry]]); } this.productAdded$.next((_e = entry.product) === null || _e === void 0 ? void 0 : _e.code); } /** * Verify if product is already on the list */ isProductOnTheList(productCode) { const entries = this.entries$.getValue() || []; return !!entries.find((item) => { var _a; return ((_a = item.product) === null || _a === void 0 ? void 0 : _a.code) === productCode; }); } isLimitExceeded() { const entries = this.entries$.getValue() || []; return entries.length >= this.quickOrderListLimit; } createQuickOrderResultEvent(cartEvent) { var _a, _b, _c; const evt = { productCode: cartEvent.productCode, quantity: cartEvent.quantity, }; if ('entry' in cartEvent) { evt.entry = cartEvent.entry; } if ('quantityAdded' in cartEvent) { evt.quantityAdded = cartEvent.quantityAdded; } if ('error' in cartEvent && cartEvent.error instanceof HttpErrorModel) { evt.error = cartEvent.error; } if ((_b = (_a = evt.error) === null || _a === void 0 ? void 0 : _a.details) === null || _b === void 0 ? void 0 : _b.length) { const isOutOfStock = (_c = evt.error) === null || _c === void 0 ? void 0 : _c.details.some((e) => e.type === 'InsufficientStockError'); evt.quantityAdded = isOutOfStock ? 0 : evt.quantity; } return evt; } clearDeleteTimeout(productCode) { const clearMessageTimout = this.clearDeleteTimeouts[productCode]; if (clearMessageTimout) { clearMessageTimout.unsubscribe(); delete this.clearDeleteTimeouts[productCode]; } } } QuickOrderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: QuickOrderService, deps: [{ token: i1.ActiveCartService }, { token: i1.ProductAdapter }, { token: i1.EventService }, { token: i1.ProductSearchConnector }], target: i0.ɵɵFactoryTarget.Injectable }); QuickOrderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: QuickOrderService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: QuickOrderService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i1.ActiveCartService }, { type: i1.ProductAdapter }, { type: i1.EventService }, { type: i1.ProductSearchConnector }]; } }); const facadeProviders = [ QuickOrderService, { provide: QuickOrderFacade, useExisting: QuickOrderService, }, ]; class QuickOrderStatePersistenceService { constructor(quickOrderService, siteContextParamsService, statePersistenceService) { this.quickOrderService = quickOrderService; this.siteContextParamsService = siteContextParamsService; this.statePersistenceService = statePersistenceService; this.subscription = new Subscription(); /** * Identifier used for storage key. */ this.key = 'quick-order'; } /** * Initializes the synchronization between state and browser storage. */ initSync() { this.subscription.add(this.statePersistenceService.syncWithStorage({ key: this.key, state$: this.quickOrderService.getEntries(), context$: this.siteContextParamsService.getValues([ BASE_SITE_CONTEXT_ID, ]), storageType: StorageSyncType.SESSION_STORAGE, onRead: (state) => this.onRead(state), })); } onRead(state) { if (state) { this.quickOrderService.loadEntries(state); } } ngOnDestroy() { this.subscription.unsubscribe(); } } QuickOrderStatePersistenceService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: QuickOrderStatePersistenceService, deps: [{ token: i1$1.QuickOrderFacade }, { token: i1.SiteContextParamsService }, { token: i1.StatePersistenceService }], target: i0.ɵɵFactoryTarget.Injectable }); QuickOrderStatePersistenceService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: QuickOrderStatePersistenceService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: QuickOrderStatePersistenceService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: function () { return [{ type: i1$1.QuickOrderFacade }, { type: i1.SiteContextParamsService }, { type: i1.StatePersistenceService }]; } }); class QuickOrderCoreModule { static forRoot() { return { ngModule: QuickOrderCoreModule, }; } } QuickOrderCoreModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: QuickOrderCoreModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); QuickOrderCoreModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: QuickOrderCoreModule }); QuickOrderCoreModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: QuickOrderCoreModule, providers: [...facadeProviders, QuickOrderStatePersistenceService] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.0.5", ngImport: i0, type: QuickOrderCoreModule, decorators: [{ type: NgModule, args: [{ providers: [...facadeProviders, QuickOrderStatePersistenceService], }] }] }); /** * Generated bundle index. Do not edit. */ export { QuickOrderCoreModule, QuickOrderService, QuickOrderStatePersistenceService }; //# sourceMappingURL=spartacus-cart-quick-order-core.js.map