All files / src/app/core/directives product-context.directive.ts

36.58% Statements 15/41
33.33% Branches 6/18
22.72% Functions 5/22
38.23% Lines 13/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 11925x 25x   25x         25x                 25x 13x 13x 13x   13x   13x 13x                                                                                                     13x                                                                             13x      
import { Directive, Input, OnInit, Optional, Output, SkipSelf } from '@angular/core';
import { ReplaySubject, combineLatest, debounceTime, distinctUntilChanged, pairwise, startWith } from 'rxjs';
 
import {
  ProductContext,
  ProductContextDisplayProperties,
  ProductContextFacade,
} from 'ish-core/facades/product-context.facade';
import { ProductCompletenessLevel, SkuQuantityType } from 'ish-core/models/product/product.model';
 
declare type IdType = number | string;
 
@Directive({
  selector: '[ishProductContext]',
  providers: [ProductContextFacade],
  exportAs: 'ishProductContext',
})
export class ProductContextDirective implements OnInit {
  @Input() completeness: ProductCompletenessLevel = ProductCompletenessLevel.List;
  @Output() skuChange = this.context.select('sku');
  @Output() quantityChange = this.context.select('quantity');
 
  private propIndex$ = new ReplaySubject<IdType>(1);
 
  constructor(@SkipSelf() @Optional() parentContext: ProductContextFacade, private context: ProductContextFacade) {
    Iif (parentContext) {
      function removeFromParent(parent: ProductContext['children'], id: IdType) {
        delete parent[id];
      }
 
      function addToParent(parent: ProductContext['children'], id: IdType, context: ProductContext) {
        parent[id] = context;
      }
 
      function isId(id: IdType): boolean {
        return id !== undefined;
      }
 
      parentContext.connect(
        'children',
        combineLatest([
          this.propIndex$.pipe(startWith(undefined), distinctUntilChanged(), pairwise()),
          this.context.select().pipe(debounceTime(0)),
        ]),
        (parent, [[prevId, currId], context]) => {
          let newChildren: ProductContext['children'];
 
          // remove previous entry if ID changed
          Iif (context.propagateActive && isId(prevId) && prevId !== currId) {
            newChildren = { ...parent.children };
            removeFromParent(newChildren, prevId);
          }
 
          // propagate current entry
          Iif (isId(currId)) {
            newChildren ??= { ...parent.children };
            if (context.propagateActive) {
              addToParent(newChildren, currId, context);
            } else {
              removeFromParent(newChildren, currId);
            }
          }
 
          return newChildren ?? parent.children;
        }
      );
    }
  }
 
  @Input()
  set log(log: boolean) {
    this.context.log(log);
  }
 
  @Input()
  set sku(sku: string) {
    this.context.set('sku', () => sku);
  }
 
  @Input()
  set categoryId(categoryId: string) {
    this.context.set('categoryId', () => categoryId);
  }
 
  @Input()
  set quantity(quantity: number) {
    this.context.set('quantity', () => quantity);
  }
 
  @Input()
  set allowZeroQuantity(allowZeroQuantity: boolean) {
    this.context.set('allowZeroQuantity', () => allowZeroQuantity);
  }
 
  @Input()
  set propagateActive(propagateActive: boolean) {
    this.context.set('propagateActive', () => propagateActive);
  }
 
  @Input()
  set propagateIndex(index: number | string) {
    this.propIndex$.next(index);
  }
 
  @Input()
  set parts(parts: SkuQuantityType[]) {
    this.context.set('parts', () => parts);
  }
 
  @Input()
  set configuration(config: Partial<ProductContextDisplayProperties>) {
    this.context.config = config;
  }
 
  ngOnInit() {
    this.context.set('requiredCompletenessLevel', () => this.completeness);
  }
}