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

12.19% Statements 5/41
30% Branches 6/20
0% Functions 0/22
14.28% Lines 5/35

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 119 120 12120x 20x   20x         20x                 20x                                                                                                                                                                                                              
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: 'List' | 'Detail' = '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 === 'List' ? ProductCompletenessLevel.List : ProductCompletenessLevel.Detail
    );
  }
}