import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import {
ActiveCartService,
Cart,
OrderEntry,
PromotionLocation,
} from '@spartacus/core';
import { Observable } from 'rxjs';
import {
filter,
map,
shareReplay,
startWith,
switchMap,
switchMapTo,
tap,
} from 'rxjs/operators';
import { ICON_TYPE } from '../../../../cms-components/misc/icon/icon.model';
import { ModalService } from '../../../../shared/components/modal/modal.service';
@Component({
selector: 'cx-added-to-cart-dialog',
templateUrl: './added-to-cart-dialog.component.html',
})
export class AddedToCartDialogComponent implements OnInit {
iconTypes = ICON_TYPE;
entry$: Observable<OrderEntry>;
cart$: Observable<Cart>;
loaded$: Observable<boolean>;
addedEntryWasMerged$: Observable<boolean>;
numberOfEntriesBeforeAdd: number;
promotionLocation: PromotionLocation = PromotionLocation.ActiveCart;
quantity = 0;
modalIsOpen = false;
@ViewChild('dialog', { read: ElementRef })
dialog: ElementRef;
form: FormGroup = new FormGroup({});
protected quantityControl$: Observable<FormControl>;
constructor(
protected modalService: ModalService,
protected cartService: ActiveCartService
) {}
/**
* Returns an observable formControl with the quantity of the cartEntry,
* but also updates the entry in case of a changed value.
* The quantity can be set to zero in order to remove the entry.
*/
getQuantityControl(): Observable<FormControl> {
if (!this.quantityControl$) {
this.quantityControl$ = this.entry$.pipe(
filter((e) => !!e),
map((entry) => this.getQuantityFormControl(entry)),
switchMap(() =>
this.form.valueChanges.pipe(
// eslint-disable-next-line import/no-deprecated
startWith(null),
tap((valueChange) => {
if (valueChange) {
this.cartService.updateEntry(
valueChange.entryNumber,
valueChange.quantity
);
if (valueChange.quantity === 0) {
this.dismissModal('Removed');
}
} else {
this.form.markAsPristine();
}
})
)
),
map(() => <FormControl>this.form.get('quantity')),
shareReplay({ bufferSize: 1, refCount: true })
);
}
return this.quantityControl$;
}
ngOnInit() {
this.addedEntryWasMerged$ = this.loaded$.pipe(
filter((loaded) => loaded),
switchMapTo(this.cartService.getEntries()),
map((entries) => entries.length === this.numberOfEntriesBeforeAdd)
);
}
/**
* Adds quantity and entryNumber form controls to the FormGroup.
* Returns quantity form control.
*/
protected getQuantityFormControl(entry: OrderEntry): FormControl {
if (!this.form.get('quantity')) {
const quantity = new FormControl(entry.quantity, { updateOn: 'blur' });
this.form.addControl('quantity', quantity);
const entryNumber = new FormControl(entry.entryNumber);
this.form.addControl('entryNumber', entryNumber);
}
return <FormControl>this.form.get('quantity');
}
dismissModal(reason?: any): void {
this.modalService.dismissActiveModal(reason);
}
}
<div #dialog>
<!-- Modal Header -->
<ng-container *ngIf="(loaded$ | async) || modalIsOpen; else loading">
<div class="cx-dialog-header modal-header">
<div
class="cx-dialog-title modal-title"
aria-live="polite"
aria-atomic="true"
>
{{
(addedEntryWasMerged$ | async)
? ('addToCart.itemsIncrementedInYourCart' | cxTranslate)
: ('addToCart.itemsAddedToYourCart' | cxTranslate)
}}
</div>
<button
type="button"
class="close"
attr.aria-label="{{ 'addToCart.closeModal' | cxTranslate }}"
cxModal="dismiss"
cxModalReason="Cross click"
>
<span aria-hidden="true">
<cx-icon [type]="iconTypes.CLOSE"></cx-icon>
</span>
</button>
</div>
<!-- Modal Body -->
<div class="cx-dialog-body modal-body" *ngIf="entry$ | async as entry">
<div class="cx-dialog-row">
<div class="cx-dialog-item col-sm-12 col-md-6">
<cx-cart-item
[item]="entry"
[compact]="true"
[quantityControl]="getQuantityControl() | async"
[promotionLocation]="promotionLocation"
></cx-cart-item>
</div>
<!-- Separator -->
<div
class="cx-dialog-separator col-sm-12 d-xs-block d-sm-block d-md-none"
></div>
<!-- Total container -->
<div
class="cx-dialog-actions col-sm-12 col-md-6"
*ngIf="cart$ | async as cart"
>
<div class="cx-dialog-total">
<div>
{{
'cartItems.cartTotal'
| cxTranslate: { count: cart.deliveryItemsQuantity }
}}
</div>
<div>{{ cart.subTotal?.formattedValue }}</div>
</div>
<!-- Promotions -->
<div class="cx-dialog-promotions">
<cx-promotions
[promotions]="
(cart.appliedOrderPromotions || []).concat(
cart.potentialOrderPromotions || []
)
"
></cx-promotions>
</div>
<!-- Actions -->
<div class="cx-dialog-buttons">
<a
[class.disabled]="form.dirty"
[routerLink]="{ cxRoute: 'cart' } | cxUrl"
cxModal="dismiss"
cxModalReason="View Cart click"
class="btn btn-primary"
autofocus
>{{ 'addToCart.viewCart' | cxTranslate }}</a
>
<a
[class.disabled]="form.dirty"
[routerLink]="{ cxRoute: 'checkout' } | cxUrl"
cxModal="dismiss"
cxModalReason="Proceed To Checkout click"
class="btn btn-secondary"
>{{ 'addToCart.proceedToCheckout' | cxTranslate }}</a
>
</div>
</div>
</div>
</div>
</ng-container>
<ng-template #loading>
<div class="cx-dialog-header modal-header">
<div class="cx-dialog-title modal-title">
{{ 'addToCart.updatingCart' | cxTranslate }}
</div>
<button
type="button"
class="close"
[attr.aria-label]="'common.close' | cxTranslate"
cxModal="dismiss"
cxModalReason="Cross click"
>
<span aria-hidden="true">
<cx-icon [type]="iconTypes.CLOSE"></cx-icon>
</span>
</button>
</div>
<!-- Modal Body -->
<div class="cx-dialog-body modal-body">
<div class="cx-dialog-row">
<div class="col-sm-12"><cx-spinner></cx-spinner></div>
</div>
</div>
</ng-template>
</div>