import * as ko from "knockout"; import * as Constants from "../../../../../src/constants"; import template from "./subscription-list.html"; import { Component, RuntimeComponent, OnMounted, Param } from "@paperbits/common/ko/decorators"; import { Product } from "../../../../../src/models/product"; import { ProductService } from "../../../../../src/services/productService"; import { UsersService } from "../../../../../src/services/usersService"; import { SearchQuery } from "../../../../../src/contracts/searchQuery"; import { RouteHelper } from "../../../../../src/routing/routeHelper"; import { Router } from "@paperbits/common/routing/router"; @RuntimeComponent({ selector: "subscription-list-runtime" }) @Component({ selector: "subscription-list-runtime", template: template }) export class SubscriptionList { public readonly products: ko.ObservableArray; public readonly selectedProductName: ko.Observable; public readonly showDetails: ko.Observable; public readonly working: ko.Observable; public readonly pattern: ko.Observable; public readonly page: ko.Observable; public readonly hasPager: ko.Computed; public readonly hasPrevPage: ko.Observable; public readonly hasNextPage: ko.Observable; constructor( private readonly usersService: UsersService, private readonly productService: ProductService, private readonly router: Router, private readonly routeHelper: RouteHelper ) { this.detailsPageUrl = ko.observable(); this.allowSelection = ko.observable(false); this.products = ko.observableArray(); this.selectedProductName = ko.observable().extend({ acceptChange: this.allowSelection }); this.working = ko.observable(true); this.pattern = ko.observable(); this.page = ko.observable(1); this.hasPrevPage = ko.observable(false); this.hasNextPage = ko.observable(false); this.hasPager = ko.computed(() => this.hasPrevPage() || this.hasNextPage()); } @Param() public allowSelection: ko.Observable; @Param() public detailsPageUrl: ko.Observable; @OnMounted() public async initialize(): Promise { await this.resetSearch(); this.pattern .extend({ rateLimit: { timeout: Constants.defaultInputDelayMs, method: "notifyWhenChangesStop" } }) .subscribe(this.resetSearch); } public async loadPageOfProducts(): Promise { const pageNumber = this.page() - 1; const query: SearchQuery = { pattern: this.pattern(), skip: pageNumber * Constants.defaultPageSize, take: Constants.defaultPageSize }; try { this.working(true); const itemsPage = await this.productService.getProductsPage(query); this.hasPrevPage(pageNumber > 0); this.hasNextPage(!!itemsPage.nextLink); this.products(itemsPage.value); if (this.allowSelection() && !this.selectedProductName()) { this.selectFirstProduct(); } } catch (error) { if (error.code === "Unauthorized") { this.usersService.navigateToSignin(); return; } throw new Error(`Unable to load products. Error: ${error.message}`); } finally { this.working(false); } } public selectFirstProduct(): void { let productName; const products = this.products(); productName = products[0].name; this.selectedProductName(productName); const productUrl = this.routeHelper.getProductReferenceUrl(productName, this.detailsPageUrl()); this.router.navigateTo(productUrl); } public getProductUrl(product: Product): string { return this.routeHelper.getProductReferenceUrl(product.name, this.detailsPageUrl()); } public prevPage(): void { this.page(this.page() - 1); this.loadPageOfProducts(); } public nextPage(): void { this.page(this.page() + 1); this.loadPageOfProducts(); } public async resetSearch(): Promise { this.page(1); this.loadPageOfProducts(); } }