From 3d2d71be2ad04a9e0f12ab4c19bffb6ac66440d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lara=20Mi=C3=B1ones=20Rodr=C3=ADguez?= Date: Mon, 15 Dec 2025 10:54:32 +0100 Subject: [PATCH 1/2] FIX search pagination cache --- src/app/pages/search/search.component.ts | 77 ++++++++++++++++--- src/app/services/app-init.service.ts | 2 +- src/app/services/search-state.service.spec.ts | 16 ++++ src/app/services/search-state.service.ts | 26 +++++++ 4 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 src/app/services/search-state.service.spec.ts create mode 100644 src/app/services/search-state.service.ts diff --git a/src/app/pages/search/search.component.ts b/src/app/pages/search/search.component.ts index 886f16d2..b08c67b7 100644 --- a/src/app/pages/search/search.component.ts +++ b/src/app/pages/search/search.component.ts @@ -8,9 +8,10 @@ import { PaginationService } from 'src/app/services/pagination.service' import {LocalStorageService} from "../../services/local-storage.service"; import {Category} from "../../models/interfaces"; import {EventMessageService} from "../../services/event-message.service"; +import { SearchStateService } from "../../services/search-state.service" import { LoginServiceService } from "src/app/services/login-service.service" import { environment } from 'src/environments/environment'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, NavigationStart } from '@angular/router'; import { FormControl } from '@angular/forms'; import { Router } from '@angular/router'; import { LoginInfo, FeedbackInfo } from 'src/app/models/interfaces'; @@ -38,6 +39,7 @@ export class SearchComponent implements OnInit, OnDestroy { showPanel = false; feedback:boolean=false; providerThemeName=environment.providerThemeName; + private navigatingToDetail = false; constructor( private api: ApiServiceService, @@ -47,9 +49,13 @@ export class SearchComponent implements OnInit, OnDestroy { private localStorage: LocalStorageService, private eventMessage: EventMessageService, private loginService: LoginServiceService, - private paginationService: PaginationService) { - this.eventMessage.messages$.subscribe(ev => { + private paginationService: PaginationService, + private state: SearchStateService + ) { + this.eventMessage.messages$.subscribe(async ev => { if(ev.type === 'AddedFilter' || ev.type === 'RemovedFilter') { + console.log('event filter') + await this.getProducts(false); this.checkPanel(); } }) @@ -61,6 +67,17 @@ export class SearchComponent implements OnInit, OnDestroy { } async ngOnInit() { + + this.router.events.subscribe(event => { + if (event instanceof NavigationStart) { + // Detecta navegación al detalle del producto + if (event.url.startsWith('/search/urn:ngsi-ld:product-offering')) { + this.navigatingToDetail = true; + } else { + this.navigatingToDetail = false; + } + } + }); this.products=[]; this.nextProducts=[]; @@ -73,13 +90,33 @@ export class SearchComponent implements OnInit, OnDestroy { this.searchField.setValue(this.keywords); } console.log('INIT') + + // 1. Restaurar estado + if (this.state.hasState()) { + console.log("Restoring state…"); + + this.products = this.state.products; + this.nextProducts = this.state.nextProducts; + this.page = this.state.page; + this.page_check = this.state.page_check; + this.keywords = this.state.keywords; + + // restaurar campo de búsqueda + this.searchField.setValue(this.keywords); + + return; // <-- IMPORTANTE: evitar volver a cargar desde cero + } + + // Si no hay estado, entonces sí iniciar búsqueda normal await this.getProducts(false); - await this.eventMessage.messages$.subscribe(async ev => { + + + /*await this.eventMessage.messages$.subscribe(async ev => { if(ev.type === 'AddedFilter' || ev.type === 'RemovedFilter') { console.log('event filter') await this.getProducts(false); } - }) + })*/ let input = document.querySelector('[type=search]') if(input!=undefined){ @@ -160,6 +197,10 @@ export class SearchComponent implements OnInit, OnDestroy { } ngOnDestroy(){ + if (this.navigatingToDetail) { + return; + } + let storedFilters = this.localStorage.getObject('selected_categories') as Category[] || []; for(let i=0;i { - this.products=await this.api.getProductsDetails(data.items); - this.page_check=data.page_check; - this.nextProducts=await this.api.getProductsDetails(data.nextItems); - this.page=data.page; - this.loading=false; - this.loading_more=false; + this.products = await this.api.getProductsDetails(data.items); + this.nextProducts = await this.api.getProductsDetails(data.nextItems); + + this.page = data.page; + this.page_check = data.page_check; + + this.loading = false; + this.loading_more = false; + + // SAVE STATE 🔥🔥🔥 + this.state.save({ + products: this.products, + nextProducts: this.nextProducts, + page: this.page, + page_check: this.page_check, + keywords: this.keywords + }); }) } diff --git a/src/app/services/app-init.service.ts b/src/app/services/app-init.service.ts index e9f9e7bd..5cf0ddba 100644 --- a/src/app/services/app-init.service.ts +++ b/src/app/services/app-init.service.ts @@ -21,7 +21,7 @@ export class AppInitService { environment.MATOMO_TRACKER_URL = config.matomoUrl; environment.KNOWLEDGE_BASE_URL = config.knowledgeBaseUrl; environment.TICKETING_SYSTEM_URL = config.ticketingUrl; - environment.SEARCH_ENABLED = config.searchEnabled; + environment.SEARCH_ENABLED = true; environment.DOME_TRUST_LINK = config.domeTrust; environment.DOME_ABOUT_LINK = config.domeAbout; environment.PURCHASE_ENABLED = config.purchaseEnabled ?? true; diff --git a/src/app/services/search-state.service.spec.ts b/src/app/services/search-state.service.spec.ts new file mode 100644 index 00000000..2a6493f0 --- /dev/null +++ b/src/app/services/search-state.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { SearchStateService } from './search-state.service'; + +describe('SearchStateService', () => { + let service: SearchStateService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(SearchStateService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/services/search-state.service.ts b/src/app/services/search-state.service.ts new file mode 100644 index 00000000..75a108f6 --- /dev/null +++ b/src/app/services/search-state.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ providedIn: 'root' }) +export class SearchStateService { + products: any[] = []; + nextProducts: any[] = []; + page: number = 0; + page_check: boolean = true; + keywords: string | undefined = undefined; + + hasState(): boolean { + return this.products.length > 0; + } + + save(state: Partial) { + Object.assign(this, state); + } + + clear() { + this.products = []; + this.nextProducts = []; + this.page = 0; + this.page_check = true; + this.keywords = undefined; + } +} From 4c968e3e58a645a99c2955d5629477c83a5830c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lara=20Mi=C3=B1ones=20Rodr=C3=ADguez?= Date: Wed, 17 Dec 2025 10:04:05 +0100 Subject: [PATCH 2/2] FIX pagination's cache on catalog search + close every subscription when components are destroyed --- .../offerings/gallery/gallery.component.ts | 17 +++-- src/app/pages/admin/admin.component.ts | 16 ++++- .../admin/categories/categories.component.ts | 16 ++++- .../create-category.component.ts | 16 ++++- .../update-category.component.ts | 16 ++++- .../billing-address.component.ts | 16 ++++- src/app/pages/checkout/checkout.component.ts | 16 ++++- .../contact-us/contact-us-form.component.ts | 17 +++-- .../pages/dashboard/dashboard.component.ts | 13 +++- .../pages/dome-blog/dome-blog.component.ts | 13 +++- .../product-details.component.ts | 17 +++-- .../inventory-products.component.ts | 16 ++++- .../inventory-resources.component.ts | 16 ++++- .../inventory-services.component.ts | 16 ++++- .../product-inventory.component.ts | 16 ++++- .../product-orders.component.ts | 16 ++++- .../invoices-info/invoices-info.component.ts | 16 ++++- .../order-info/order-info.component.ts | 17 +++-- .../search-catalog.component.ts | 66 +++++++++++++++++-- src/app/pages/search/search.component.ts | 25 +++++-- .../create-catalog.component.ts | 16 ++++- .../seller-catalogs.component.ts | 16 ++++- .../update-catalog.component.ts | 16 ++++- .../create-offer/create-offer.component.ts | 18 +++-- .../new-price-plan.component.ts | 16 ++++- .../seller-offer/seller-offer.component.ts | 18 ++++- .../update-offer/update-offer.component.ts | 18 +++-- .../update-price-plan.component.ts | 16 ++++- .../create-product-spec.component.ts | 16 ++++- .../seller-product-spec.component.ts | 16 ++++- .../update-product-spec.component.ts | 16 ++++- .../create-resource-spec.component.ts | 16 ++++- .../seller-resource-spec.component.ts | 16 ++++- .../update-resource-spec.component.ts | 16 ++++- .../create-service-spec.component.ts | 16 ++++- .../seller-service-spec.component.ts | 16 ++++- .../update-service-spec.component.ts | 16 ++++- .../seller-offerings.component.ts | 16 ++++- .../usage-specs/usage-specs.component.ts | 16 ++++- .../billing-info/billing-info.component.ts | 17 ++++- .../order-info/order-info.component.ts | 17 ++++- .../org-info/org-info.component.ts | 16 ++++- .../user-info/user-info.component.ts | 17 ++++- .../user-profile/user-profile.component.ts | 16 ++++- src/app/services/pagination.service.ts | 7 +- .../billing-account-form.component.ts | 18 ++++- src/app/shared/card/card.component.ts | 9 ++- .../cart-drawer/cart-drawer.component.ts | 17 ++++- .../categories-filter.component.ts | 16 ++++- .../categories-panel.component.ts | 16 ++++- .../category-item/category-item.component.ts | 16 ++++- src/app/shared/footer/footer.component.ts | 9 ++- .../general-info/general-info.component.ts | 8 ++- .../forms/offer/license/license.component.ts | 13 +++- src/app/shared/forms/offer/offer.component.ts | 13 +++- .../price-plan-drawer.component.ts | 20 ++++-- .../price-plans/price-plans.component.ts | 12 +++- .../procurement-mode.component.ts | 14 +++- .../usage-spec-general-info.component.ts | 10 ++- .../forms/usage-spec/usage-spec.component.ts | 15 ++++- src/app/shared/header/header.component.ts | 9 ++- 61 files changed, 804 insertions(+), 188 deletions(-) diff --git a/src/app/offerings/gallery/gallery.component.ts b/src/app/offerings/gallery/gallery.component.ts index 1bcac2d3..1073566b 100644 --- a/src/app/offerings/gallery/gallery.component.ts +++ b/src/app/offerings/gallery/gallery.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { CommonModule } from '@angular/common'; import {CardComponent} from "../../shared/card/card.component"; import {components} from "../../models/product-catalog"; @@ -6,18 +6,20 @@ type ProductOffering = components["schemas"]["ProductOffering"]; import { ApiServiceService } from 'src/app/services/product-service.service'; import {ThemeService} from "../../services/theme.service"; import {ThemeConfig} from "../../themes"; -import { Subscription } from 'rxjs'; +import { Subscription, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'bae-off-gallery', templateUrl: './gallery.component.html', styleUrl: './gallery.component.css' }) -export class GalleryComponent implements OnInit { +export class GalleryComponent implements OnInit, OnDestroy { products: ProductOffering[]=[]; private themeSubscription: Subscription = new Subscription(); currentTheme: ThemeConfig | null = null; + private destroy$ = new Subject(); constructor( private api: ApiServiceService, @@ -29,7 +31,9 @@ export class GalleryComponent implements OnInit { gallery_limit=4; ngOnInit() { - this.themeSubscription = this.themeService.currentTheme$.subscribe(theme => { + this.themeSubscription = this.themeService.currentTheme$ + .pipe(takeUntil(this.destroy$)) + .subscribe(theme => { this.currentTheme = theme; }); console.log('API RESPONSE:') @@ -107,4 +111,9 @@ export class GalleryComponent implements OnInit { console.log(this.products) } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + } diff --git a/src/app/pages/admin/admin.component.ts b/src/app/pages/admin/admin.component.ts index c09d8260..7b3d7201 100644 --- a/src/app/pages/admin/admin.component.ts +++ b/src/app/pages/admin/admin.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { FormControl } from '@angular/forms'; import {faIdCard, faSort, faSwatchbook} from "@fortawesome/pro-solid-svg-icons"; @@ -10,18 +10,21 @@ import {LocalStorageService} from "src/app/services/local-storage.service"; import { LoginInfo } from 'src/app/models/interfaces'; import { initFlowbite } from 'flowbite'; import {EventMessageService} from "../../services/event-message.service"; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-admin', templateUrl: './admin.component.html', styleUrl: './admin.component.css' }) -export class AdminComponent implements OnInit { +export class AdminComponent implements OnInit, OnDestroy { show_categories:boolean = true; show_create_categories:boolean = false; show_update_categories:boolean = false; show_verification:boolean = false; show_revenue:boolean = false; + private destroy$ = new Subject(); category_to_update:any; constructor( @@ -29,7 +32,9 @@ export class AdminComponent implements OnInit { private cdr: ChangeDetectorRef, private eventMessage: EventMessageService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'AdminCategories' && ev.value == true) { this.goToCategories(); } @@ -47,6 +52,11 @@ export class AdminComponent implements OnInit { console.log('init') } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + goToCategories(){ this.selectCategories(); this.show_categories = true; diff --git a/src/app/pages/admin/categories/categories.component.ts b/src/app/pages/admin/categories/categories.component.ts index df61c696..d98a129a 100644 --- a/src/app/pages/admin/categories/categories.component.ts +++ b/src/app/pages/admin/categories/categories.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { FormControl } from '@angular/forms'; import {faIdCard, faSort, faSwatchbook} from "@fortawesome/pro-solid-svg-icons"; @@ -10,13 +10,15 @@ import {LocalStorageService} from "src/app/services/local-storage.service"; import { LoginInfo } from 'src/app/models/interfaces'; import {EventMessageService} from "src/app/services/event-message.service"; import { initFlowbite } from 'flowbite'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'admin-categories', templateUrl: './categories.component.html', styleUrl: './categories.component.css' }) -export class CategoriesComponent { +export class CategoriesComponent implements OnDestroy { protected readonly faIdCard = faIdCard; protected readonly faSort = faSort; protected readonly faSwatchbook = faSwatchbook; @@ -29,6 +31,7 @@ export class CategoriesComponent { loading: boolean = false; partyId:any; status:any[]=['Active','Launched']; + private destroy$ = new Subject(); constructor( private router: Router, @@ -37,7 +40,9 @@ export class CategoriesComponent { private localStorage: LocalStorageService, private eventMessage: EventMessageService, ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initCatalogs(); } @@ -48,6 +53,11 @@ export class CategoriesComponent { this.initCatalogs(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initCatalogs(){ this.loading=true; this.categories=[]; diff --git a/src/app/pages/admin/categories/create-category/create-category.component.ts b/src/app/pages/admin/categories/create-category/create-category.component.ts index 4b084a68..e0f8c204 100644 --- a/src/app/pages/admin/categories/create-category/create-category.component.ts +++ b/src/app/pages/admin/categories/create-category/create-category.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { ApiServiceService } from 'src/app/services/product-service.service'; import {LocalStorageService} from "src/app/services/local-storage.service"; @@ -7,6 +7,8 @@ import { LoginInfo } from 'src/app/models/interfaces'; import { initFlowbite } from 'flowbite'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import * as moment from 'moment'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import {components} from "src/app/models/product-catalog"; type Category_Create = components["schemas"]["Category_Create"]; @@ -16,7 +18,7 @@ type Category_Create = components["schemas"]["Category_Create"]; templateUrl: './create-category.component.html', styleUrl: './create-category.component.css' }) -export class CreateCategoryComponent implements OnInit { +export class CreateCategoryComponent implements OnInit, OnDestroy { partyId:any=''; categoryToCreate:Category_Create | undefined; @@ -50,6 +52,7 @@ export class CreateCategoryComponent implements OnInit { errorMessage:any=''; showError:boolean=false; + private destroy$ = new Subject(); constructor( private router: Router, @@ -59,7 +62,9 @@ export class CreateCategoryComponent implements OnInit { private elementRef: ElementRef, private api: ApiServiceService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -81,6 +86,11 @@ export class CreateCategoryComponent implements OnInit { this.initPartyInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/admin/categories/update-category/update-category.component.ts b/src/app/pages/admin/categories/update-category/update-category.component.ts index eb626417..34ba301a 100644 --- a/src/app/pages/admin/categories/update-category/update-category.component.ts +++ b/src/app/pages/admin/categories/update-category/update-category.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, Input } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, Input, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { ApiServiceService } from 'src/app/services/product-service.service'; import {LocalStorageService} from "src/app/services/local-storage.service"; @@ -7,6 +7,8 @@ import { LoginInfo } from 'src/app/models/interfaces'; import { initFlowbite } from 'flowbite'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import * as moment from 'moment'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import {components} from "src/app/models/product-catalog"; type Category_Update = components["schemas"]["Category_Update"]; @@ -16,7 +18,7 @@ type Category_Update = components["schemas"]["Category_Update"]; templateUrl: './update-category.component.html', styleUrl: './update-category.component.css' }) -export class UpdateCategoryComponent implements OnInit { +export class UpdateCategoryComponent implements OnInit, OnDestroy { @Input() category: any; partyId:any=''; @@ -55,6 +57,7 @@ export class UpdateCategoryComponent implements OnInit { errorMessage:any=''; showError:boolean=false; + private destroy$ = new Subject(); constructor( private router: Router, @@ -64,7 +67,9 @@ export class UpdateCategoryComponent implements OnInit { private elementRef: ElementRef, private api: ApiServiceService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -86,6 +91,11 @@ export class UpdateCategoryComponent implements OnInit { this.initPartyInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/checkout/billing-address/billing-address.component.ts b/src/app/pages/checkout/billing-address/billing-address.component.ts index 1660f8f3..67aa2064 100644 --- a/src/app/pages/checkout/billing-address/billing-address.component.ts +++ b/src/app/pages/checkout/billing-address/billing-address.component.ts @@ -1,4 +1,4 @@ -import {Component, EventEmitter, HostListener, Input, OnInit, Output} from '@angular/core'; +import {Component, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output} from '@angular/core'; import {billingAccountCart} from "../../../models/interfaces"; import {TranslateModule} from "@ngx-translate/core"; import {NgClass} from "@angular/common"; @@ -6,13 +6,15 @@ import {BillingAccountFormComponent} from "../../../shared/billing-account-form/ import { AccountServiceService } from 'src/app/services/account-service.service'; import { LocalStorageService } from 'src/app/services/local-storage.service'; import {EventMessageService} from "../../../services/event-message.service"; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-billing-address', templateUrl: './billing-address.component.html', styleUrl: './billing-address.component.css' }) -export class BillingAddressComponent { +export class BillingAddressComponent implements OnDestroy { @Input() position: number = 0; @Input() data: billingAccountCart = { id: '', @@ -32,13 +34,16 @@ export class BillingAddressComponent { }; @Output() selectedEvent= new EventEmitter(); @Output() deletedEvent= new EventEmitter(); + private destroy$ = new Subject(); constructor( private localStorage: LocalStorageService, private accountService: AccountServiceService, private eventMessage: EventMessageService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.value == false){ this.editBill=false; } @@ -84,4 +89,9 @@ export class BillingAddressComponent { return false } } + + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } } diff --git a/src/app/pages/checkout/checkout.component.ts b/src/app/pages/checkout/checkout.component.ts index cb112fa0..964ed3b2 100644 --- a/src/app/pages/checkout/checkout.component.ts +++ b/src/app/pages/checkout/checkout.component.ts @@ -1,4 +1,4 @@ -import {ChangeDetectorRef, Component, HostListener, OnInit} from '@angular/core'; +import {ChangeDetectorRef, Component, HostListener, OnDestroy, OnInit} from '@angular/core'; import {firstValueFrom, lastValueFrom} from 'rxjs'; import {TranslateModule} from "@ngx-translate/core"; import {LocalStorageService} from "../../services/local-storage.service"; @@ -20,6 +20,8 @@ import {BillingAccountFormComponent} from "../../shared/billing-account-form/bil import { PaymentService } from 'src/app/services/payment.service'; import { v4 as uuidv4 } from 'uuid'; import { data } from 'jquery'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ @@ -27,7 +29,7 @@ import { data } from 'jquery'; templateUrl: './checkout.component.html', styleUrl: './checkout.component.css' }) -export class CheckoutComponent implements OnInit { +export class CheckoutComponent implements OnInit, OnDestroy { protected readonly faCartShopping = faCartShopping; public static BASE_URL: String = environment.BASE_URL; PURCHASE_ENABLED: boolean = environment.PURCHASE_ENABLED; @@ -52,6 +54,7 @@ export class CheckoutComponent implements OnInit { providerId:any = null; loadingItems:boolean=false; orderNote: string = ''; + private destroy$ = new Subject(); constructor( private localStorage: LocalStorageService, @@ -67,7 +70,9 @@ export class CheckoutComponent implements OnInit { private route: ActivatedRoute) { // Bind the method to preserve context this.orderProduct = this.orderProduct.bind(this); - this.eventMessage.messages$.subscribe(async ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(async ev => { if (ev.type === 'BillAccChanged') { this.getBilling(); } @@ -363,6 +368,11 @@ export class CheckoutComponent implements OnInit { } } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + async initCheckoutData() { this.providerId = this.route.snapshot.paramMap.get('id'); let aux = this.localStorage.getObject('login_items') as LoginInfo; diff --git a/src/app/pages/contact-us/contact-us-form.component.ts b/src/app/pages/contact-us/contact-us-form.component.ts index 8f90ad9e..fb0c6fde 100644 --- a/src/app/pages/contact-us/contact-us-form.component.ts +++ b/src/app/pages/contact-us/contact-us-form.component.ts @@ -1,10 +1,11 @@ -import {Component, HostListener, OnInit, ChangeDetectorRef} from '@angular/core'; +import {Component, HostListener, OnInit, ChangeDetectorRef, OnDestroy} from '@angular/core'; import { FormGroup, FormControl, Validators, FormArray } from '@angular/forms'; import {faHandsHoldingHeart} from "@fortawesome/pro-solid-svg-icons"; import { environment } from 'src/environments/environment'; import {ThemeService} from "../../services/theme.service"; import {ThemeConfig} from "../../themes"; -import { Subscription } from 'rxjs'; +import { Subscription, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-contact-us-form', @@ -12,7 +13,7 @@ import { Subscription } from 'rxjs'; styleUrl: './contact-us-form.component.css' }) -export class ContactUsFormComponent implements OnInit { +export class ContactUsFormComponent implements OnInit, OnDestroy { contactForm = new FormGroup({ email: new FormControl('', [Validators.required, Validators.email, Validators.pattern('^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$'), Validators.maxLength(320)]), name: new FormControl('', [Validators.required, Validators.maxLength(100)]), @@ -34,13 +35,21 @@ export class ContactUsFormComponent implements OnInit { showThanksMessage:boolean=false; currentTheme: ThemeConfig | null = null; private themeSubscription: Subscription = new Subscription(); + private destroy$ = new Subject(); ngOnInit() { - this.themeSubscription = this.themeService.currentTheme$.subscribe(theme => { + this.themeSubscription = this.themeService.currentTheme$ + .pipe(takeUntil(this.destroy$)) + .subscribe(theme => { this.currentTheme = theme; }); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + sendMail() { let message = 'First name: '+this.contactForm.value.name+ '%0A' + 'Last name: '+this.contactForm.value.lastname+ '%0A' + diff --git a/src/app/pages/dashboard/dashboard.component.ts b/src/app/pages/dashboard/dashboard.component.ts index 7eaeaaa4..e21c1483 100644 --- a/src/app/pages/dashboard/dashboard.component.ts +++ b/src/app/pages/dashboard/dashboard.component.ts @@ -6,7 +6,7 @@ import { ActivatedRoute } from '@angular/router'; import { Router } from '@angular/router'; import { LoginInfo } from 'src/app/models/interfaces'; import * as moment from 'moment'; -import { interval, Subscription} from 'rxjs'; +import { interval, Subscription, Subject} from 'rxjs'; import { RefreshLoginServiceService } from "src/app/services/refresh-login-service.service" import { StatsServiceService } from "src/app/services/stats-service.service" import { LoginServiceService } from "src/app/services/login-service.service" @@ -15,6 +15,7 @@ import { initFlowbite } from 'flowbite'; import { environment } from 'src/environments/environment'; import {ThemeService} from "../../services/theme.service"; import {ThemeConfig} from "../../themes"; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-dashboard', @@ -37,6 +38,7 @@ export class DashboardComponent implements OnInit, OnDestroy { currentTheme: ThemeConfig | null = null; private themeSubscription: Subscription = new Subscription(); providerThemeName=environment.providerThemeName; + private destroy$ = new Subject(); //loginSubscription: Subscription = new Subscription();; constructor(private localStorage: LocalStorageService, @@ -49,7 +51,9 @@ export class DashboardComponent implements OnInit, OnDestroy { private cdr: ChangeDetectorRef, private themeService: ThemeService, private refreshApi: RefreshLoginServiceService) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'FilterShown') { this.isFilterPanelShown = ev.value as boolean; } @@ -75,9 +79,12 @@ export class DashboardComponent implements OnInit, OnDestroy { } async ngOnInit() { - this.themeSubscription = this.themeService.currentTheme$.subscribe(theme => { + this.themeSubscription = this.themeService.currentTheme$ + .subscribe(theme => { this.currentTheme = theme; }); + this.destroy$.next(); + this.destroy$.complete(); this.statsService.getStats().then(data=> { this.services=data?.services || []; diff --git a/src/app/pages/dome-blog/dome-blog.component.ts b/src/app/pages/dome-blog/dome-blog.component.ts index 01e95c59..3cc71ac7 100644 --- a/src/app/pages/dome-blog/dome-blog.component.ts +++ b/src/app/pages/dome-blog/dome-blog.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { Router } from '@angular/router'; import {EventMessageService} from "src/app/services/event-message.service"; @@ -6,8 +6,9 @@ import {LocalStorageService} from "src/app/services/local-storage.service"; import { DomeBlogServiceService } from "src/app/services/dome-blog-service.service" import { LoginInfo } from 'src/app/models/interfaces'; import * as moment from 'moment'; -import { lastValueFrom } from 'rxjs'; +import { lastValueFrom, Subject } from 'rxjs'; import { MarkdownComponent } from "ngx-markdown"; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-dome-blog', @@ -16,7 +17,7 @@ import { MarkdownComponent } from "ngx-markdown"; templateUrl: './dome-blog.component.html', styleUrl: './dome-blog.component.css' }) -export class DomeBlogComponent implements OnInit { +export class DomeBlogComponent implements OnInit, OnDestroy { constructor( private router: Router, private eventMessage: EventMessageService, @@ -32,6 +33,7 @@ export class DomeBlogComponent implements OnInit { partyId:any=''; checkAdmin:boolean=false; + private destroy$ = new Subject(); entries:any[]=[ ] @@ -41,6 +43,11 @@ export class DomeBlogComponent implements OnInit { this.entries=entries; } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/product-details/product-details.component.ts b/src/app/pages/product-details/product-details.component.ts index 287ff808..219ccfa7 100644 --- a/src/app/pages/product-details/product-details.component.ts +++ b/src/app/pages/product-details/product-details.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ElementRef, ViewChild,ChangeDetectorRef, HostListener } from '@angular/core'; +import { Component, OnInit, ElementRef, ViewChild,ChangeDetectorRef, HostListener, OnDestroy } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { ApiServiceService } from 'src/app/services/product-service.service'; import {components} from "../../models/product-catalog"; @@ -18,14 +18,15 @@ import {EventMessageService} from "../../services/event-message.service"; import * as moment from 'moment'; import { environment } from 'src/environments/environment'; import { Location } from '@angular/common'; -import {firstValueFrom} from "rxjs"; +import {firstValueFrom, Subject} from "rxjs"; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-product-details', templateUrl: './product-details.component.html', styleUrl: './product-details.component.css' }) -export class ProductDetailsComponent implements OnInit { +export class ProductDetailsComponent implements OnInit, OnDestroy { @ViewChild('relationshipsContent') relationshipsContent: ElementRef | undefined; @@ -104,6 +105,7 @@ export class ProductDetailsComponent implements OnInit { isLoaded = false; private isManualScroll = false; private scrollTimeout: any; + private destroy$ = new Subject(); constructor( private cdr: ChangeDetectorRef, @@ -119,7 +121,9 @@ export class ProductDetailsComponent implements OnInit { private location: Location ) { this.showTermsMore=false; - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'CloseCartCard') { this.hideCartSelection(); //TOGGLE TOAST @@ -167,6 +171,11 @@ export class ProductDetailsComponent implements OnInit { }) } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + @HostListener('window:scroll', ['$event']) updateTabs(event:any) { // Skip if user manually clicked a tab and scroll is in progress diff --git a/src/app/pages/product-inventory/inventory-items/inventory-products/inventory-products.component.ts b/src/app/pages/product-inventory/inventory-items/inventory-products/inventory-products.component.ts index c9422627..aae1914c 100644 --- a/src/app/pages/product-inventory/inventory-items/inventory-products/inventory-products.component.ts +++ b/src/app/pages/product-inventory/inventory-items/inventory-products/inventory-products.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, Input } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, Input, OnDestroy } from '@angular/core'; import { LoginInfo } from 'src/app/models/interfaces'; import { ProductInventoryServiceService } from 'src/app/services/product-inventory-service.service'; import { ApiServiceService } from 'src/app/services/product-service.service'; @@ -16,13 +16,15 @@ import * as moment from 'moment'; import { FormControl } from '@angular/forms'; import { LocalStorageService } from 'src/app/services/local-storage.service'; import {faIdCard, faSort, faSwatchbook} from "@fortawesome/pro-solid-svg-icons"; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'inventory-products', templateUrl: './inventory-products.component.html', styleUrl: './inventory-products.component.css' }) -export class InventoryProductsComponent implements OnInit { +export class InventoryProductsComponent implements OnInit, OnDestroy { protected readonly faIdCard = faIdCard; protected readonly faSort = faSort; @@ -59,6 +61,7 @@ export class InventoryProductsComponent implements OnInit { showDetails:boolean=false; checkCustom:boolean=false; checkFrom:boolean=true; + private destroy$ = new Subject(); constructor( private inventoryService: ProductInventoryServiceService, @@ -71,7 +74,9 @@ export class InventoryProductsComponent implements OnInit { private eventMessage: EventMessageService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initInventory(); } @@ -85,6 +90,11 @@ export class InventoryProductsComponent implements OnInit { this.initInventory(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initInventory(){ this.loading = true; diff --git a/src/app/pages/product-inventory/inventory-resources/inventory-resources.component.ts b/src/app/pages/product-inventory/inventory-resources/inventory-resources.component.ts index 04f4c9c6..498f5c51 100644 --- a/src/app/pages/product-inventory/inventory-resources/inventory-resources.component.ts +++ b/src/app/pages/product-inventory/inventory-resources/inventory-resources.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, Input } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, Input, OnDestroy } from '@angular/core'; import { LoginInfo } from 'src/app/models/interfaces'; import { ProductInventoryServiceService } from 'src/app/services/product-inventory-service.service'; import { LocalStorageService } from 'src/app/services/local-storage.service'; @@ -10,13 +10,15 @@ import {faIdCard, faSort, faSwatchbook} from "@fortawesome/pro-solid-svg-icons"; import { initFlowbite } from 'flowbite'; import { environment } from 'src/environments/environment'; import * as moment from 'moment'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'inventory-resources', templateUrl: './inventory-resources.component.html', styleUrl: './inventory-resources.component.css' }) -export class InventoryResourcesComponent implements OnInit { +export class InventoryResourcesComponent implements OnInit, OnDestroy { protected readonly faIdCard = faIdCard; protected readonly faSort = faSort; @@ -36,6 +38,7 @@ export class InventoryResourcesComponent implements OnInit { INVENTORY_LIMIT: number = environment.INVENTORY_RES_LIMIT; showDetails:boolean=false; selectedRes:any; + private destroy$ = new Subject(); constructor( private inventoryService: ProductInventoryServiceService, @@ -46,7 +49,9 @@ export class InventoryResourcesComponent implements OnInit { private eventMessage: EventMessageService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initInventory(); } @@ -64,6 +69,11 @@ export class InventoryResourcesComponent implements OnInit { this.initInventory(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initInventory(){ this.loading=true; diff --git a/src/app/pages/product-inventory/inventory-services/inventory-services.component.ts b/src/app/pages/product-inventory/inventory-services/inventory-services.component.ts index 68a0958e..860c425c 100644 --- a/src/app/pages/product-inventory/inventory-services/inventory-services.component.ts +++ b/src/app/pages/product-inventory/inventory-services/inventory-services.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, Input } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, Input, OnDestroy } from '@angular/core'; import { LoginInfo } from 'src/app/models/interfaces'; import { ProductInventoryServiceService } from 'src/app/services/product-inventory-service.service'; import { LocalStorageService } from 'src/app/services/local-storage.service'; @@ -10,13 +10,15 @@ import {faIdCard, faSort, faSwatchbook} from "@fortawesome/pro-solid-svg-icons"; import { initFlowbite } from 'flowbite'; import { environment } from 'src/environments/environment'; import * as moment from 'moment'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'inventory-services', templateUrl: './inventory-services.component.html', styleUrl: './inventory-services.component.css' }) -export class InventoryServicesComponent implements OnInit { +export class InventoryServicesComponent implements OnInit, OnDestroy { protected readonly faIdCard = faIdCard; protected readonly faSort = faSort; @@ -36,6 +38,7 @@ export class InventoryServicesComponent implements OnInit { INVENTORY_LIMIT: number = environment.INVENTORY_SERV_LIMIT; showDetails:boolean=false; selectedServ:any; + private destroy$ = new Subject(); constructor( private inventoryService: ProductInventoryServiceService, @@ -46,7 +49,9 @@ export class InventoryServicesComponent implements OnInit { private eventMessage: EventMessageService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initInventory(); } @@ -62,6 +67,11 @@ export class InventoryServicesComponent implements OnInit { this.initInventory(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initInventory(){ this.loading=true; diff --git a/src/app/pages/product-inventory/product-inventory.component.ts b/src/app/pages/product-inventory/product-inventory.component.ts index 4ee0f84b..03284cdc 100644 --- a/src/app/pages/product-inventory/product-inventory.component.ts +++ b/src/app/pages/product-inventory/product-inventory.component.ts @@ -1,15 +1,17 @@ -import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, OnDestroy } from '@angular/core'; import {components} from "../../models/product-catalog"; import { initFlowbite } from 'flowbite'; type ProductOffering = components["schemas"]["ProductOffering"]; import {EventMessageService} from "../../services/event-message.service"; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-product-inventory', templateUrl: './product-inventory.component.html', styleUrl: './product-inventory.component.css' }) -export class ProductInventoryComponent implements OnInit, AfterViewInit { +export class ProductInventoryComponent implements OnInit, AfterViewInit, OnDestroy { show_prods:boolean = true; show_serv:boolean = false; show_res:boolean = false; @@ -17,12 +19,15 @@ export class ProductInventoryComponent implements OnInit, AfterViewInit { openServiceId:any=undefined; openResourceId:any=undefined; openProdId:any=undefined; + private destroy$ = new Subject(); constructor( private cdr: ChangeDetectorRef, private eventMessage: EventMessageService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'OpenServiceDetails') { this.openServiceId=(ev.value as any)?.serviceId; this.openProdId=(ev.value as any)?.prodId; @@ -44,6 +49,11 @@ export class ProductInventoryComponent implements OnInit, AfterViewInit { initFlowbite(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + ngAfterViewInit() { initFlowbite(); } diff --git a/src/app/pages/product-orders/product-orders.component.ts b/src/app/pages/product-orders/product-orders.component.ts index 95858f94..069c7a02 100644 --- a/src/app/pages/product-orders/product-orders.component.ts +++ b/src/app/pages/product-orders/product-orders.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, OnDestroy } from '@angular/core'; import { CommonModule, DatePipe } from '@angular/common'; import { LoginInfo, billingAccountCart } from 'src/app/models/interfaces'; import { ApiServiceService } from 'src/app/services/product-service.service'; @@ -21,6 +21,8 @@ import { TranslateModule } from '@ngx-translate/core'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { OrderInfoComponent } from "./sections/order-info/order-info.component"; import { InvoicesInfoComponent } from "./sections/invoices-info/invoices-info.component"; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-product-orders', @@ -30,7 +32,7 @@ import { InvoicesInfoComponent } from "./sections/invoices-info/invoices-info.co templateUrl: './product-orders.component.html', styleUrl: './product-orders.component.css' }) -export class ProductOrdersComponent implements OnInit { +export class ProductOrdersComponent implements OnInit, OnDestroy { loading: boolean = false; orders:any[]=[]; nextOrders:any[]=[]; @@ -57,6 +59,7 @@ export class ProductOrdersComponent implements OnInit { protected readonly faIdCard = faIdCard; protected readonly faSort = faSort; protected readonly faSwatchbook = faSwatchbook; + private destroy$ = new Subject(); constructor( private localStorage: LocalStorageService, @@ -67,7 +70,9 @@ export class ProductOrdersComponent implements OnInit { private eventMessage: EventMessageService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -99,6 +104,11 @@ export class ProductOrdersComponent implements OnInit { this.initPartyInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/product-orders/sections/invoices-info/invoices-info.component.ts b/src/app/pages/product-orders/sections/invoices-info/invoices-info.component.ts index 7669491e..c842cabb 100644 --- a/src/app/pages/product-orders/sections/invoices-info/invoices-info.component.ts +++ b/src/app/pages/product-orders/sections/invoices-info/invoices-info.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, NgModule } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, NgModule, OnDestroy } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { CommonModule, DatePipe } from '@angular/common'; import { LoginInfo, billingAccountCart } from 'src/app/models/interfaces'; @@ -20,6 +20,8 @@ import { environment } from 'src/environments/environment'; import {faIdCard, faSort, faSwatchbook, faEdit, faSave} from "@fortawesome/pro-solid-svg-icons"; import { TranslateModule } from '@ngx-translate/core'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-invoices-info', @@ -29,7 +31,7 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; templateUrl: './invoices-info.component.html', styleUrl: './invoices-info.component.css' }) -export class InvoicesInfoComponent implements OnInit { +export class InvoicesInfoComponent implements OnInit, OnDestroy { loading: boolean = false; invoices:any[]=[]; nextInvoices:any[]=[]; @@ -63,6 +65,7 @@ export class InvoicesInfoComponent implements OnInit { protected readonly faSwatchbook = faSwatchbook; protected readonly faEdit = faEdit; protected readonly faSave = faSave; + private destroy$ = new Subject(); constructor( private localStorage: LocalStorageService, @@ -74,7 +77,9 @@ export class InvoicesInfoComponent implements OnInit { private paginationService: PaginationService, private router: Router ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -99,6 +104,11 @@ export class InvoicesInfoComponent implements OnInit { this.initPartyInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/product-orders/sections/order-info/order-info.component.ts b/src/app/pages/product-orders/sections/order-info/order-info.component.ts index 84a55eb0..7db1e930 100644 --- a/src/app/pages/product-orders/sections/order-info/order-info.component.ts +++ b/src/app/pages/product-orders/sections/order-info/order-info.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, OnDestroy } from '@angular/core'; import { CommonModule, DatePipe } from '@angular/common'; import { LoginInfo, billingAccountCart } from 'src/app/models/interfaces'; import { ApiServiceService } from 'src/app/services/product-service.service'; @@ -21,7 +21,8 @@ import { TranslateModule } from '@ngx-translate/core'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import {SharedModule} from "../../../../shared/shared.module"; import { v4 as uuidv4 } from 'uuid'; -import { from, Observable } from 'rxjs'; +import { from, Observable, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-order-info', @@ -31,7 +32,7 @@ import { from, Observable } from 'rxjs'; templateUrl: './order-info.component.html', styleUrl: './order-info.component.css' }) -export class OrderInfoComponent implements OnInit, AfterViewInit { +export class OrderInfoComponent implements OnInit, AfterViewInit, OnDestroy { loading: boolean = false; orders:any[]=[]; nextOrders:any[]=[]; @@ -79,6 +80,7 @@ export class OrderInfoComponent implements OnInit, AfterViewInit { protected readonly faIdCard = faIdCard; protected readonly faSort = faSort; protected readonly faSwatchbook = faSwatchbook; + private destroy$ = new Subject(); constructor( private localStorage: LocalStorageService, @@ -90,7 +92,9 @@ export class OrderInfoComponent implements OnInit, AfterViewInit { private eventMessage: EventMessageService, private paginationService: PaginationService, ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -204,6 +208,11 @@ export class OrderInfoComponent implements OnInit, AfterViewInit { this.initPartyInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/search-catalog/search-catalog.component.ts b/src/app/pages/search-catalog/search-catalog.component.ts index d7c86920..deac41ec 100644 --- a/src/app/pages/search-catalog/search-catalog.component.ts +++ b/src/app/pages/search-catalog/search-catalog.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit, ChangeDetectorRef, HostListener, OnDestroy } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, NavigationStart } from '@angular/router'; import { ApiServiceService } from 'src/app/services/product-service.service'; import { PriceServiceService } from 'src/app/services/price-service.service'; import { PaginationService } from 'src/app/services/pagination.service'; @@ -13,6 +13,9 @@ import {Category, LoginInfo} from "../../models/interfaces"; import { environment } from 'src/environments/environment'; import { Router } from '@angular/router'; import * as moment from 'moment'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { SearchStateService } from "../../services/search-state.service" @Component({ selector: 'app-search-catalog', @@ -29,19 +32,26 @@ export class SearchCatalogComponent implements OnInit, OnDestroy{ private eventMessage: EventMessageService, private localStorage: LocalStorageService, private router: Router, - private paginationService: PaginationService + private paginationService: PaginationService, + private state: SearchStateService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'AddedFilter' || ev.type === 'RemovedFilter') { this.checkPanel(); } }) - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'CloseFeedback') { this.feedback = false; } }) - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'AddedFilter' || ev.type === 'RemovedFilter') { this.getProducts(false); } @@ -65,6 +75,8 @@ export class SearchCatalogComponent implements OnInit, OnDestroy{ feedback:boolean=false; providerThemeName=environment.providerThemeName; logo=''; + private destroy$ = new Subject(); + private navigatingToDetail = false; async ngOnInit() { @@ -111,6 +123,19 @@ export class SearchCatalogComponent implements OnInit, OnDestroy{ console.log(this.catalog) }) + // 1. Restaurar estado + if (this.state.hasState()) { + console.log("Restoring state…"); + + this.products = this.state.products; + this.nextProducts = this.state.nextProducts; + this.page = this.state.page; + this.page_check = this.state.page_check; + + return; // <-- IMPORTANTE: evitar volver a cargar desde cero + } + + // Si no hay estado, entonces sí iniciar búsqueda normal await this.getProducts(false); @@ -122,6 +147,19 @@ export class SearchCatalogComponent implements OnInit, OnDestroy{ if ((JSON.stringify(userInfo) != '{}' && (((userInfo.expire - moment().unix())-4) > 0))) { this.feedback=true; } + + this.router.events + .pipe(takeUntil(this.destroy$)) + .subscribe(event => { + if (event instanceof NavigationStart) { + // Detecta navegación al detalle del producto + if (event.url.startsWith('/search/urn:ngsi-ld:product-offering')) { + this.navigatingToDetail = true; + } else { + this.navigatingToDetail = false; + } + } + }); } @HostListener('document:click') @@ -136,12 +174,22 @@ export class SearchCatalogComponent implements OnInit, OnDestroy{ this.router.navigate([path]); } + ngOnDestroy(){ + if (this.navigatingToDetail) { + return; + } + let storedFilters = this.localStorage.getObject('selected_categories') as Category[] || []; for(let i=0;i(); constructor( private api: ApiServiceService, @@ -52,14 +56,18 @@ export class SearchComponent implements OnInit, OnDestroy { private paginationService: PaginationService, private state: SearchStateService ) { - this.eventMessage.messages$.subscribe(async ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(async ev => { if(ev.type === 'AddedFilter' || ev.type === 'RemovedFilter') { console.log('event filter') await this.getProducts(false); - this.checkPanel(); + this.checkPanel(); } }) - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'CloseFeedback') { this.feedback = false; } @@ -68,7 +76,9 @@ export class SearchComponent implements OnInit, OnDestroy { async ngOnInit() { - this.router.events.subscribe(event => { + this.router.events + .pipe(takeUntil(this.destroy$)) + .subscribe(event => { if (event instanceof NavigationStart) { // Detecta navegación al detalle del producto if (event.url.startsWith('/search/urn:ngsi-ld:product-offering')) { @@ -206,6 +216,11 @@ export class SearchComponent implements OnInit, OnDestroy { this.localStorage.removeCategoryFilter(storedFilters[i]); this.eventMessage.emitRemovedFilter(storedFilters[i]); } + + this.state.clear(); + + this.destroy$.next(); + this.destroy$.complete(); } async getProducts(next:boolean){ @@ -233,7 +248,7 @@ export class SearchComponent implements OnInit, OnDestroy { this.loading = false; this.loading_more = false; - // SAVE STATE 🔥🔥🔥 + // SAVE STATE this.state.save({ products: this.products, nextProducts: this.nextProducts, diff --git a/src/app/pages/seller-offerings/offerings/seller-catalogs/create-catalog/create-catalog.component.ts b/src/app/pages/seller-offerings/offerings/seller-catalogs/create-catalog/create-catalog.component.ts index ce758c38..19d5a924 100644 --- a/src/app/pages/seller-offerings/offerings/seller-catalogs/create-catalog/create-catalog.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-catalogs/create-catalog/create-catalog.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { ApiServiceService } from 'src/app/services/product-service.service'; import {LocalStorageService} from "src/app/services/local-storage.service"; @@ -7,6 +7,8 @@ import { LoginInfo } from 'src/app/models/interfaces'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import * as moment from 'moment'; import { noWhitespaceValidator } from 'src/app/validators/validators'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import {components} from "src/app/models/product-catalog"; type Catalog_Create = components["schemas"]["Catalog_Create"]; @@ -16,7 +18,7 @@ type Catalog_Create = components["schemas"]["Catalog_Create"]; templateUrl: './create-catalog.component.html', styleUrl: './create-catalog.component.css' }) -export class CreateCatalogComponent implements OnInit { +export class CreateCatalogComponent implements OnInit, OnDestroy { partyId:any=''; catalogToCreate:Catalog_Create | undefined; @@ -51,6 +53,7 @@ export class CreateCatalogComponent implements OnInit { errorMessage:any=''; showError:boolean=false; + private destroy$ = new Subject(); constructor( private router: Router, @@ -60,7 +63,9 @@ export class CreateCatalogComponent implements OnInit { private elementRef: ElementRef, private api: ApiServiceService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -79,6 +84,11 @@ export class CreateCatalogComponent implements OnInit { this.initPartyInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/seller-offerings/offerings/seller-catalogs/seller-catalogs.component.ts b/src/app/pages/seller-offerings/offerings/seller-catalogs/seller-catalogs.component.ts index 8bea053f..e594df35 100644 --- a/src/app/pages/seller-offerings/offerings/seller-catalogs/seller-catalogs.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-catalogs/seller-catalogs.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { FormControl } from '@angular/forms'; import {faIdCard, faSort, faSwatchbook} from "@fortawesome/pro-solid-svg-icons"; @@ -11,13 +11,15 @@ import { LoginInfo } from 'src/app/models/interfaces'; import {EventMessageService} from "src/app/services/event-message.service"; import { PaginationService } from 'src/app/services/pagination.service'; import { initFlowbite } from 'flowbite'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'seller-catalogs', templateUrl: './seller-catalogs.component.html', styleUrl: './seller-catalogs.component.css' }) -export class SellerCatalogsComponent { +export class SellerCatalogsComponent implements OnInit, OnDestroy { protected readonly faIdCard = faIdCard; protected readonly faSort = faSort; @@ -34,6 +36,7 @@ export class SellerCatalogsComponent { filter:any=undefined; partyId:any; status:any[]=['Active','Launched']; + private destroy$ = new Subject(); constructor( private router: Router, @@ -43,7 +46,9 @@ export class SellerCatalogsComponent { private eventMessage: EventMessageService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initCatalogs(); } @@ -54,6 +59,11 @@ export class SellerCatalogsComponent { this.initCatalogs(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + goToCreate(){ this.eventMessage.emitSellerCreateCatalog(true); } diff --git a/src/app/pages/seller-offerings/offerings/seller-catalogs/update-catalog/update-catalog.component.ts b/src/app/pages/seller-offerings/offerings/seller-catalogs/update-catalog/update-catalog.component.ts index e955317e..2e8ba3fb 100644 --- a/src/app/pages/seller-offerings/offerings/seller-catalogs/update-catalog/update-catalog.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-catalogs/update-catalog/update-catalog.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, Input } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, Input, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { ApiServiceService } from 'src/app/services/product-service.service'; import {LocalStorageService} from "src/app/services/local-storage.service"; @@ -7,6 +7,8 @@ import { LoginInfo } from 'src/app/models/interfaces'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import * as moment from 'moment'; import { noWhitespaceValidator } from 'src/app/validators/validators'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import {components} from "src/app/models/product-catalog"; type Catalog_Update = components["schemas"]["Catalog_Update"]; @@ -16,7 +18,7 @@ type Catalog_Update = components["schemas"]["Catalog_Update"]; templateUrl: './update-catalog.component.html', styleUrl: './update-catalog.component.css' }) -export class UpdateCatalogComponent implements OnInit { +export class UpdateCatalogComponent implements OnInit, OnDestroy { @Input() cat: any; partyId:any=''; @@ -53,6 +55,7 @@ export class UpdateCatalogComponent implements OnInit { errorMessage:any=''; showError:boolean=false; loading:boolean=false; + private destroy$ = new Subject(); constructor( private router: Router, @@ -62,7 +65,9 @@ export class UpdateCatalogComponent implements OnInit { private elementRef: ElementRef, private api: ApiServiceService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -82,6 +87,11 @@ export class UpdateCatalogComponent implements OnInit { this.populateCatInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + populateCatInfo(){ //GENERAL INFORMATION this.generalForm.controls['name'].setValue(this.cat.name); diff --git a/src/app/pages/seller-offerings/offerings/seller-offer/create-offer/create-offer.component.ts b/src/app/pages/seller-offerings/offerings/seller-offer/create-offer/create-offer.component.ts index 9dfb07ee..7c65e293 100644 --- a/src/app/pages/seller-offerings/offerings/seller-offer/create-offer/create-offer.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-offer/create-offer/create-offer.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import {components} from "src/app/models/product-catalog"; import { environment } from 'src/environments/environment'; @@ -18,7 +18,8 @@ import { v4 as uuidv4 } from 'uuid'; import { currencies } from 'currencies.json'; import { certifications } from 'src/app/models/certification-standards.const'; import {ProductOfferingPrice_DTO} from 'src/app/models/interfaces'; -import { lastValueFrom } from 'rxjs'; +import { lastValueFrom, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; type ProductOffering_Create = components["schemas"]["ProductOffering_Create"]; type BundledProductOffering = components["schemas"]["BundledProductOffering"]; @@ -31,7 +32,7 @@ type ProductOfferingPrice = components["schemas"]["ProductOfferingPrice"] templateUrl: './create-offer.component.html', styleUrl: './create-offer.component.css' }) -export class CreateOfferComponent implements OnInit { +export class CreateOfferComponent implements OnInit, OnDestroy { //PAGE SIZES: PROD_SPEC_LIMIT: number = environment.PROD_SPEC_LIMIT; @@ -204,6 +205,8 @@ export class CreateOfferComponent implements OnInit { //FINAL OFFER USING API CALL STRUCTURE offerToCreate:ProductOffering_Create | undefined; + private destroy$ = new Subject(); + @ViewChild('updatemetric') updatemetric!: ElementRef; @ViewChild('responsemetric') responsemetric!: ElementRef; @ViewChild('delaymetric') delaymetric!: ElementRef; @@ -224,7 +227,9 @@ export class CreateOfferComponent implements OnInit { private resSpecService: ResourceSpecServiceService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'CategoryAdded') { this.addCategory(ev.value); } @@ -274,6 +279,11 @@ export class CreateOfferComponent implements OnInit { this.initPartyInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/seller-offerings/offerings/seller-offer/new-price-plan/new-price-plan.component.ts b/src/app/pages/seller-offerings/offerings/seller-offer/new-price-plan/new-price-plan.component.ts index 764e1cd5..38acca22 100644 --- a/src/app/pages/seller-offerings/offerings/seller-offer/new-price-plan/new-price-plan.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-offer/new-price-plan/new-price-plan.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, Input } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, Input, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import {components} from "src/app/models/product-catalog"; import { environment } from 'src/environments/environment'; @@ -18,6 +18,8 @@ import { v4 as uuidv4 } from 'uuid'; import { currencies } from 'currencies.json'; import { certifications } from 'src/app/models/certification-standards.const'; import {ProductOfferingPrice_DTO} from 'src/app/models/interfaces'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; //type ProductOffering_Create = components["schemas"]["ProductOffering_Create"]; //type ProductOfferingPrice = components["schemas"]["ProductOfferingPrice"] @@ -27,7 +29,7 @@ import {ProductOfferingPrice_DTO} from 'src/app/models/interfaces'; templateUrl: './new-price-plan.component.html', styleUrl: './new-price-plan.component.css' }) -export class NewPricePlanComponent implements OnInit { +export class NewPricePlanComponent implements OnInit, OnDestroy { //currencies=currencies; //Only allowing EUR for the moment @@ -81,6 +83,7 @@ export class NewPricePlanComponent implements OnInit { showPreview:boolean=false; showEmoji:boolean=false; + private destroy$ = new Subject(); @Input() selectedProdSpec: any | {id:''}; //@Input() priceToUpdate: ProductOfferingPrice_DTO | undefined; @@ -98,7 +101,9 @@ export class NewPricePlanComponent implements OnInit { private resSpecService: ResourceSpecServiceService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -131,6 +136,11 @@ export class NewPricePlanComponent implements OnInit { }, 100); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + checkPriceInfo(){ for(let i=0;i certification.name === this.selectedProdSpec.productSpecCharacteristic[i].name)) { diff --git a/src/app/pages/seller-offerings/offerings/seller-offer/seller-offer.component.ts b/src/app/pages/seller-offerings/offerings/seller-offer/seller-offer.component.ts index 1cb5b7ac..a0bba27e 100644 --- a/src/app/pages/seller-offerings/offerings/seller-offer/seller-offer.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-offer/seller-offer.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { FormControl } from '@angular/forms'; import {faIdCard, faSort, faSwatchbook, faSparkles} from "@fortawesome/pro-solid-svg-icons"; @@ -10,13 +10,15 @@ import {LocalStorageService} from "src/app/services/local-storage.service"; import { LoginInfo } from 'src/app/models/interfaces'; import {EventMessageService} from "src/app/services/event-message.service"; import { initFlowbite } from 'flowbite'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'seller-offer', templateUrl: './seller-offer.component.html', styleUrl: './seller-offer.component.css' }) -export class SellerOfferComponent implements OnInit{ +export class SellerOfferComponent implements OnInit, OnDestroy { protected readonly faIdCard = faIdCard; protected readonly faSort = faSort; protected readonly faSwatchbook = faSwatchbook; @@ -36,6 +38,7 @@ export class SellerOfferComponent implements OnInit{ partyId:any; sort:any=undefined; isBundle:any=undefined; + private destroy$ = new Subject(); constructor( private router: Router, @@ -45,7 +48,9 @@ export class SellerOfferComponent implements OnInit{ private eventMessage: EventMessageService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initOffers(); } @@ -56,6 +61,11 @@ export class SellerOfferComponent implements OnInit{ this.initOffers(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initOffers(){ this.loading=true; let aux = this.localStorage.getObject('login_items') as LoginInfo; @@ -114,6 +124,8 @@ export class SellerOfferComponent implements OnInit{ this.page=data.page; this.loading=false; this.loading_more=false; + console.log('--- offerss ---') + console.log(data) }) } diff --git a/src/app/pages/seller-offerings/offerings/seller-offer/update-offer/update-offer.component.ts b/src/app/pages/seller-offerings/offerings/seller-offer/update-offer/update-offer.component.ts index ffa12411..5fe4e25c 100644 --- a/src/app/pages/seller-offerings/offerings/seller-offer/update-offer/update-offer.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-offer/update-offer/update-offer.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, Input } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, Input, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import {components} from "src/app/models/product-catalog"; import { environment } from 'src/environments/environment'; @@ -16,7 +16,8 @@ import { FormGroup, FormControl, Validators, AbstractControl, ValidationErrors, import * as moment from 'moment'; import { v4 as uuidv4 } from 'uuid'; import { currencies } from 'currencies.json'; -import { lastValueFrom } from 'rxjs'; +import { lastValueFrom, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; type ProductOffering_Update = components["schemas"]["ProductOffering_Update"]; type BundledProductOffering = components["schemas"]["BundledProductOffering"]; @@ -28,7 +29,7 @@ type ProductOfferingPrice = components["schemas"]["ProductOfferingPrice"] templateUrl: './update-offer.component.html', styleUrl: './update-offer.component.css' }) -export class UpdateOfferComponent implements OnInit{ +export class UpdateOfferComponent implements OnInit, OnDestroy { @Input() offer: any; //PAGE SIZES: @@ -194,6 +195,8 @@ export class UpdateOfferComponent implements OnInit{ availableCountries:any[]=['Austria','Belgium','Germany','Hungary','Luxembourg','Poland','Romania','Spain'] availableMarketplaces:any[]=['BEIA Software Services','CloudFerro','CSI Piemonte','digitanimal','Digitel TS','DOME'] + private destroy$ = new Subject(); + @ViewChild('updatemetric') updatemetric!: ElementRef; @ViewChild('responsemetric') responsemetric!: ElementRef; @ViewChild('delaymetric') delaymetric!: ElementRef; @@ -214,7 +217,9 @@ export class UpdateOfferComponent implements OnInit{ private resSpecService: ResourceSpecServiceService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'CategoryAdded') { this.addCategory(ev.value); } @@ -263,6 +268,11 @@ export class UpdateOfferComponent implements OnInit{ this.showCreatePrice=false; } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/seller-offerings/offerings/seller-offer/update-price-plan/update-price-plan.component.ts b/src/app/pages/seller-offerings/offerings/seller-offer/update-price-plan/update-price-plan.component.ts index f73fe17a..27cf8586 100644 --- a/src/app/pages/seller-offerings/offerings/seller-offer/update-price-plan/update-price-plan.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-offer/update-price-plan/update-price-plan.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, Input } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, Input, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import {components} from "src/app/models/product-catalog"; import { environment } from 'src/environments/environment'; @@ -18,13 +18,15 @@ import { v4 as uuidv4 } from 'uuid'; import { currencies } from 'currencies.json'; import { certifications } from 'src/app/models/certification-standards.const'; import {ProductOfferingPrice_DTO} from 'src/app/models/interfaces'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'update-price-plan', templateUrl: './update-price-plan.component.html', styleUrl: './update-price-plan.component.css' }) -export class UpdatePricePlanComponent implements OnInit { +export class UpdatePricePlanComponent implements OnInit, OnDestroy { //currencies=currencies; //Only allowing EUR for the moment @@ -81,6 +83,7 @@ export class UpdatePricePlanComponent implements OnInit { @Input() selectedProdSpec: any | {id:''}; @Input() priceToUpdate: ProductOfferingPrice_DTO | undefined; + private destroy$ = new Subject(); constructor( private router: Router, @@ -95,7 +98,9 @@ export class UpdatePricePlanComponent implements OnInit { private resSpecService: ResourceSpecServiceService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -118,6 +123,11 @@ export class UpdatePricePlanComponent implements OnInit { this.checkPriceInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + checkPriceInfo(){ for(let i=0;i certification.name === this.selectedProdSpec.productSpecCharacteristic[i].name)) { diff --git a/src/app/pages/seller-offerings/offerings/seller-product-spec/create-product-spec/create-product-spec.component.ts b/src/app/pages/seller-offerings/offerings/seller-product-spec/create-product-spec/create-product-spec.component.ts index a29636a8..033f9e38 100644 --- a/src/app/pages/seller-offerings/offerings/seller-product-spec/create-product-spec/create-product-spec.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-product-spec/create-product-spec/create-product-spec.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import {components} from "src/app/models/product-catalog"; import { environment } from 'src/environments/environment'; @@ -18,6 +18,8 @@ import { certifications } from 'src/app/models/certification-standards.const' import * as moment from 'moment'; import { v4 as uuidv4 } from 'uuid'; import { noWhitespaceValidator } from 'src/app/validators/validators'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; type CharacteristicValueSpecification = components["schemas"]["CharacteristicValueSpecification"]; type ProductSpecification_Create = components["schemas"]["ProductSpecification_Create"]; @@ -33,7 +35,7 @@ type AttachmentRefOrValue = components["schemas"]["AttachmentRefOrValue"]; templateUrl: './create-product-spec.component.html', styleUrl: './create-product-spec.component.css' }) -export class CreateProductSpecComponent implements OnInit { +export class CreateProductSpecComponent implements OnInit, OnDestroy { //PAGE SIZES: PROD_SPEC_LIMIT: number = environment.PROD_SPEC_LIMIT; @@ -177,6 +179,7 @@ export class CreateProductSpecComponent implements OnInit { rangeUnit: string = ''; filenameRegex = /^[A-Za-z0-9_.-]+$/; + private destroy$ = new Subject(); constructor( private router: Router, @@ -194,7 +197,9 @@ export class CreateProductSpecComponent implements OnInit { for(let i=0; i { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -248,6 +253,11 @@ export class CreateProductSpecComponent implements OnInit { this.initPartyInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/seller-offerings/offerings/seller-product-spec/seller-product-spec.component.ts b/src/app/pages/seller-offerings/offerings/seller-product-spec/seller-product-spec.component.ts index bac99853..c64b7862 100644 --- a/src/app/pages/seller-offerings/offerings/seller-product-spec/seller-product-spec.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-product-spec/seller-product-spec.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { FormControl } from '@angular/forms'; import {faIdCard, faSort, faSwatchbook, faSparkles} from "@fortawesome/pro-solid-svg-icons"; @@ -11,13 +11,15 @@ import {LocalStorageService} from "src/app/services/local-storage.service"; import {EventMessageService} from "src/app/services/event-message.service"; import { LoginInfo } from 'src/app/models/interfaces'; import { initFlowbite } from 'flowbite'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'seller-product-spec', templateUrl: './seller-product-spec.component.html', styleUrl: './seller-product-spec.component.css' }) -export class SellerProductSpecComponent implements OnInit{ +export class SellerProductSpecComponent implements OnInit, OnDestroy { protected readonly faIdCard = faIdCard; protected readonly faSort = faSort; protected readonly faSwatchbook = faSwatchbook; @@ -37,6 +39,7 @@ export class SellerProductSpecComponent implements OnInit{ partyId:any; sort:any=undefined; isBundle:any=undefined; + private destroy$ = new Subject(); constructor( private router: Router, @@ -47,7 +50,9 @@ export class SellerProductSpecComponent implements OnInit{ private eventMessage: EventMessageService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initProdSpecs(); } @@ -58,6 +63,11 @@ export class SellerProductSpecComponent implements OnInit{ this.initProdSpecs(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initProdSpecs(){ this.loading=true; this.prodSpecs=[]; diff --git a/src/app/pages/seller-offerings/offerings/seller-product-spec/update-product-spec/update-product-spec.component.ts b/src/app/pages/seller-offerings/offerings/seller-product-spec/update-product-spec/update-product-spec.component.ts index c6a91443..05dce3e4 100644 --- a/src/app/pages/seller-offerings/offerings/seller-product-spec/update-product-spec/update-product-spec.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-product-spec/update-product-spec/update-product-spec.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, Input, AfterViewInit } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, Input, AfterViewInit, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import {components} from "src/app/models/product-catalog"; import { environment } from 'src/environments/environment'; @@ -20,6 +20,8 @@ import { v4 as uuidv4 } from 'uuid'; import { QrVerifierService } from 'src/app/services/qr-verifier.service'; import { jwtDecode } from "jwt-decode"; import { noWhitespaceValidator } from 'src/app/validators/validators'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; type CharacteristicValueSpecification = components["schemas"]["CharacteristicValueSpecification"]; @@ -36,7 +38,7 @@ type AttachmentRefOrValue = components["schemas"]["AttachmentRefOrValue"]; templateUrl: './update-product-spec.component.html', styleUrl: './update-product-spec.component.css' }) -export class UpdateProductSpecComponent implements OnInit { +export class UpdateProductSpecComponent implements OnInit, OnDestroy { @Input() prod: any; //PAGE SIZES: @@ -175,6 +177,7 @@ export class UpdateProductSpecComponent implements OnInit { rangeUnit: string = ''; filenameRegex = /^[A-Za-z0-9_.-]+$/; + private destroy$ = new Subject(); constructor( private router: Router, @@ -193,7 +196,9 @@ export class UpdateProductSpecComponent implements OnInit { for(let i=0; i { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -248,6 +253,11 @@ export class UpdateProductSpecComponent implements OnInit { initFlowbite(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/seller-offerings/offerings/seller-resource-spec/create-resource-spec/create-resource-spec.component.ts b/src/app/pages/seller-offerings/offerings/seller-resource-spec/create-resource-spec/create-resource-spec.component.ts index b97f1e9c..116a8f2b 100644 --- a/src/app/pages/seller-offerings/offerings/seller-resource-spec/create-resource-spec/create-resource-spec.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-resource-spec/create-resource-spec/create-resource-spec.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import {LocalStorageService} from "src/app/services/local-storage.service"; import {EventMessageService} from "src/app/services/event-message.service"; @@ -8,6 +8,8 @@ import { FormGroup, FormControl, Validators } from '@angular/forms'; import * as moment from 'moment'; import { v4 as uuidv4 } from 'uuid'; import { noWhitespaceValidator } from 'src/app/validators/validators'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import {components} from "src/app/models/resource-catalog"; type ResourceSpecification_Create = components["schemas"]["ResourceSpecification_Create"]; @@ -19,7 +21,7 @@ type ResourceSpecificationCharacteristic = components["schemas"]["ResourceSpecif templateUrl: './create-resource-spec.component.html', styleUrl: './create-resource-spec.component.css' }) -export class CreateResourceSpecComponent implements OnInit { +export class CreateResourceSpecComponent implements OnInit, OnDestroy { partyId:any=''; @@ -78,6 +80,7 @@ export class CreateResourceSpecComponent implements OnInit { fromValue: string = ''; toValue: string = ''; rangeUnit: string = ''; + private destroy$ = new Subject(); constructor( private router: Router, @@ -87,7 +90,9 @@ export class CreateResourceSpecComponent implements OnInit { private elementRef: ElementRef, private resSpecService: ResourceSpecServiceService, ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -106,6 +111,11 @@ export class CreateResourceSpecComponent implements OnInit { this.initPartyInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/seller-offerings/offerings/seller-resource-spec/seller-resource-spec.component.ts b/src/app/pages/seller-offerings/offerings/seller-resource-spec/seller-resource-spec.component.ts index 9735047d..c285ec64 100644 --- a/src/app/pages/seller-offerings/offerings/seller-resource-spec/seller-resource-spec.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-resource-spec/seller-resource-spec.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { FormControl } from '@angular/forms'; import {faIdCard, faSort, faSwatchbook} from "@fortawesome/pro-solid-svg-icons"; @@ -11,13 +11,15 @@ import {LocalStorageService} from "src/app/services/local-storage.service"; import { LoginInfo } from 'src/app/models/interfaces'; import {EventMessageService} from "src/app/services/event-message.service"; import { initFlowbite } from 'flowbite'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'seller-resource-spec', templateUrl: './seller-resource-spec.component.html', styleUrl: './seller-resource-spec.component.css' }) -export class SellerResourceSpecComponent implements OnInit { +export class SellerResourceSpecComponent implements OnInit, OnDestroy { protected readonly faIdCard = faIdCard; protected readonly faSort = faSort; protected readonly faSwatchbook = faSwatchbook; @@ -35,6 +37,7 @@ export class SellerResourceSpecComponent implements OnInit { status:any[]=['Active','Launched']; partyId:any; sort:any=undefined; + private destroy$ = new Subject(); constructor( private router: Router, @@ -45,7 +48,9 @@ export class SellerResourceSpecComponent implements OnInit { private eventMessage: EventMessageService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initResources(); } @@ -56,6 +61,11 @@ export class SellerResourceSpecComponent implements OnInit { this.initResources(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initResources(){ this.loading=true; this.resSpecs=[]; diff --git a/src/app/pages/seller-offerings/offerings/seller-resource-spec/update-resource-spec/update-resource-spec.component.ts b/src/app/pages/seller-offerings/offerings/seller-resource-spec/update-resource-spec/update-resource-spec.component.ts index a1bb2b75..13803a0b 100644 --- a/src/app/pages/seller-offerings/offerings/seller-resource-spec/update-resource-spec/update-resource-spec.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-resource-spec/update-resource-spec/update-resource-spec.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild } from '@angular/core'; +import { Component, Input, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import {LocalStorageService} from "src/app/services/local-storage.service"; import {EventMessageService} from "src/app/services/event-message.service"; @@ -8,6 +8,8 @@ import { FormGroup, FormControl, Validators } from '@angular/forms'; import * as moment from 'moment'; import { v4 as uuidv4 } from 'uuid'; import { noWhitespaceValidator } from 'src/app/validators/validators'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import {components} from "src/app/models/resource-catalog"; import { initFlowbite } from 'flowbite'; @@ -20,7 +22,7 @@ type ResourceSpecificationCharacteristic = components["schemas"]["ResourceSpecif templateUrl: './update-resource-spec.component.html', styleUrl: './update-resource-spec.component.css' }) -export class UpdateResourceSpecComponent implements OnInit { +export class UpdateResourceSpecComponent implements OnInit, OnDestroy { @Input() res: any; partyId:any=''; @@ -77,6 +79,7 @@ export class UpdateResourceSpecComponent implements OnInit { fromValue: string = ''; toValue: string = ''; rangeUnit: string = ''; + private destroy$ = new Subject(); constructor( private router: Router, @@ -86,7 +89,9 @@ export class UpdateResourceSpecComponent implements OnInit { private elementRef: ElementRef, private resSpecService: ResourceSpecServiceService, ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -108,6 +113,11 @@ export class UpdateResourceSpecComponent implements OnInit { initFlowbite(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/seller-offerings/offerings/seller-service-spec/create-service-spec/create-service-spec.component.ts b/src/app/pages/seller-offerings/offerings/seller-service-spec/create-service-spec/create-service-spec.component.ts index 931eccf1..33b8349d 100644 --- a/src/app/pages/seller-offerings/offerings/seller-service-spec/create-service-spec/create-service-spec.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-service-spec/create-service-spec/create-service-spec.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import {LocalStorageService} from "src/app/services/local-storage.service"; import {EventMessageService} from "src/app/services/event-message.service"; @@ -8,6 +8,8 @@ import { FormGroup, FormControl, Validators } from '@angular/forms'; import * as moment from 'moment'; import { v4 as uuidv4 } from 'uuid'; import { noWhitespaceValidator } from 'src/app/validators/validators'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import {components} from "src/app/models/service-catalog"; type ServiceSpecification_Create = components["schemas"]["ServiceSpecification_Create"]; @@ -19,7 +21,7 @@ type ProductSpecificationCharacteristic = components["schemas"]["CharacteristicS templateUrl: './create-service-spec.component.html', styleUrl: './create-service-spec.component.css' }) -export class CreateServiceSpecComponent implements OnInit { +export class CreateServiceSpecComponent implements OnInit, OnDestroy { partyId:any=''; @@ -78,6 +80,7 @@ export class CreateServiceSpecComponent implements OnInit { fromValue: string = ''; toValue: string = ''; rangeUnit: string = ''; + private destroy$ = new Subject(); constructor( private router: Router, @@ -87,7 +90,9 @@ export class CreateServiceSpecComponent implements OnInit { private elementRef: ElementRef, private servSpecService: ServiceSpecServiceService, ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -106,6 +111,11 @@ export class CreateServiceSpecComponent implements OnInit { this.initPartyInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/seller-offerings/offerings/seller-service-spec/seller-service-spec.component.ts b/src/app/pages/seller-offerings/offerings/seller-service-spec/seller-service-spec.component.ts index fd5592af..47765d18 100644 --- a/src/app/pages/seller-offerings/offerings/seller-service-spec/seller-service-spec.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-service-spec/seller-service-spec.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { FormControl } from '@angular/forms'; import {faIdCard, faSort, faSwatchbook} from "@fortawesome/pro-solid-svg-icons"; @@ -11,13 +11,15 @@ import {LocalStorageService} from "src/app/services/local-storage.service"; import {EventMessageService} from "src/app/services/event-message.service"; import { LoginInfo } from 'src/app/models/interfaces'; import { initFlowbite } from 'flowbite'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'seller-service-spec', templateUrl: './seller-service-spec.component.html', styleUrl: './seller-service-spec.component.css' }) -export class SellerServiceSpecComponent implements OnInit { +export class SellerServiceSpecComponent implements OnInit, OnDestroy { protected readonly faIdCard = faIdCard; protected readonly faSort = faSort; protected readonly faSwatchbook = faSwatchbook; @@ -35,6 +37,7 @@ export class SellerServiceSpecComponent implements OnInit { status:any[]=['Active','Launched']; partyId:any; sort:any=undefined; + private destroy$ = new Subject(); constructor( private router: Router, @@ -45,7 +48,9 @@ export class SellerServiceSpecComponent implements OnInit { private eventMessage: EventMessageService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initServices(); } @@ -56,6 +61,11 @@ export class SellerServiceSpecComponent implements OnInit { this.initServices(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initServices(){ this.loading=true; this.servSpecs=[]; diff --git a/src/app/pages/seller-offerings/offerings/seller-service-spec/update-service-spec/update-service-spec.component.ts b/src/app/pages/seller-offerings/offerings/seller-service-spec/update-service-spec/update-service-spec.component.ts index 38a6ce54..63cf380c 100644 --- a/src/app/pages/seller-offerings/offerings/seller-service-spec/update-service-spec/update-service-spec.component.ts +++ b/src/app/pages/seller-offerings/offerings/seller-service-spec/update-service-spec/update-service-spec.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild } from '@angular/core'; +import { Component, Input, OnInit, ChangeDetectorRef, HostListener, ElementRef, ViewChild, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import {LocalStorageService} from "src/app/services/local-storage.service"; import {EventMessageService} from "src/app/services/event-message.service"; @@ -9,6 +9,8 @@ import { FormGroup, FormControl, Validators } from '@angular/forms'; import * as moment from 'moment'; import { v4 as uuidv4 } from 'uuid'; import { noWhitespaceValidator } from 'src/app/validators/validators'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import {components} from "src/app/models/service-catalog"; type ServiceSpecification_Update = components["schemas"]["ServiceSpecification_Update"]; @@ -20,7 +22,7 @@ type ProductSpecificationCharacteristic = components["schemas"]["CharacteristicS templateUrl: './update-service-spec.component.html', styleUrl: './update-service-spec.component.css' }) -export class UpdateServiceSpecComponent implements OnInit { +export class UpdateServiceSpecComponent implements OnInit, OnDestroy { @Input() serv: any; partyId:any=''; @@ -77,6 +79,7 @@ export class UpdateServiceSpecComponent implements OnInit { fromValue: string = ''; toValue: string = ''; rangeUnit: string = ''; + private destroy$ = new Subject(); constructor( private router: Router, @@ -86,7 +89,9 @@ export class UpdateServiceSpecComponent implements OnInit { private elementRef: ElementRef, private servSpecService: ServiceSpecServiceService, ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -107,6 +112,11 @@ export class UpdateServiceSpecComponent implements OnInit { this.populateResInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/seller-offerings/seller-offerings.component.ts b/src/app/pages/seller-offerings/seller-offerings.component.ts index ac4d9f03..32f8baff 100644 --- a/src/app/pages/seller-offerings/seller-offerings.component.ts +++ b/src/app/pages/seller-offerings/seller-offerings.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { FormControl } from '@angular/forms'; import {faIdCard, faSort, faSwatchbook} from "@fortawesome/pro-solid-svg-icons"; @@ -11,13 +11,15 @@ import { LoginInfo } from 'src/app/models/interfaces'; import { initFlowbite } from 'flowbite'; import {EventMessageService} from "../../services/event-message.service"; import * as moment from 'moment'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-seller-offerings', templateUrl: './seller-offerings.component.html', styleUrl: './seller-offerings.component.css' }) -export class SellerOfferingsComponent implements OnInit { +export class SellerOfferingsComponent implements OnInit, OnDestroy { show_catalogs: boolean = true; show_prod_specs: boolean = false; @@ -49,13 +51,16 @@ export class SellerOfferingsComponent implements OnInit { servicespec: this.goToServiceSpec, resourcespec: this.goToResourceSpec }; + private destroy$ = new Subject(); constructor( private localStorage: LocalStorageService, private cdr: ChangeDetectorRef, private eventMessage: EventMessageService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'SellerProductSpec') { if(ev.value == true && (JSON.stringify(this.userInfo) != '{}' && (((this.userInfo.expire - moment().unix())-4) > 0))) { this.feedback=true; @@ -125,6 +130,11 @@ export class SellerOfferingsComponent implements OnInit { } } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + setActiveSection(section: string) { this.activeSection = section; localStorage.setItem('activeSection', section); diff --git a/src/app/pages/usage-specs/usage-specs.component.ts b/src/app/pages/usage-specs/usage-specs.component.ts index da0b8c14..49cccad4 100644 --- a/src/app/pages/usage-specs/usage-specs.component.ts +++ b/src/app/pages/usage-specs/usage-specs.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, OnDestroy } from '@angular/core'; import { CommonModule, DatePipe } from '@angular/common'; import { LoginInfo, billingAccountCart } from 'src/app/models/interfaces'; import { ApiServiceService } from 'src/app/services/product-service.service'; @@ -22,6 +22,8 @@ import { UsageListComponent } from "src/app/pages/usage-specs/usage-sections/usa import { UsageSpecComponent } from "src/app/shared/forms/usage-spec/usage-spec.component" import { CreateUsageSpecComponent } from "./usage-sections/create-usage-spec/create-usage-spec.component" import { UpdateUsageSpecComponent } from './usage-sections/update-usage-spec/update-usage-spec.component' +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-usage-specs', @@ -39,20 +41,23 @@ import { UpdateUsageSpecComponent } from './usage-sections/update-usage-spec/upd templateUrl: './usage-specs.component.html', styleUrl: './usage-specs.component.css' }) -export class UsageSpecsComponent implements OnInit { +export class UsageSpecsComponent implements OnInit, OnDestroy { userInfo:any; show_usage_specs:boolean=true; show_create_usage:boolean=false; show_update_usage:boolean=false; usageSpecToUpdate:any; + private destroy$ = new Subject(); constructor( private localStorage: LocalStorageService, private cdr: ChangeDetectorRef, private eventMessage: EventMessageService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'UsageSpecList' && ev.value == true) { this.goToUsageSpec(); } else if(ev.type === 'UpdateUsageSpec' && ev.value) { @@ -72,6 +77,11 @@ export class UsageSpecsComponent implements OnInit { this.userInfo = this.localStorage.getObject('login_items') as LoginInfo; } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + goToUsageSpec(){ this.show_update_usage=false; this.show_usage_specs=true; diff --git a/src/app/pages/user-profile/profile-sections/billing-info/billing-info.component.ts b/src/app/pages/user-profile/profile-sections/billing-info/billing-info.component.ts index affcbe12..3613b7cd 100644 --- a/src/app/pages/user-profile/profile-sections/billing-info/billing-info.component.ts +++ b/src/app/pages/user-profile/profile-sections/billing-info/billing-info.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, OnDestroy } from '@angular/core'; import { LoginInfo, billingAccountCart } from 'src/app/models/interfaces'; import { ApiServiceService } from 'src/app/services/product-service.service'; import { AccountServiceService } from 'src/app/services/account-service.service'; @@ -13,13 +13,15 @@ import { initFlowbite } from 'flowbite'; import {EventMessageService} from "src/app/services/event-message.service"; import * as moment from 'moment'; import { environment } from 'src/environments/environment'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'billing-info', templateUrl: './billing-info.component.html', styleUrl: './billing-info.component.css' }) -export class BillingInfoComponent implements OnInit{ +export class BillingInfoComponent implements OnInit, OnDestroy { loading: boolean = false; orders:any[]=[]; profile:any; @@ -46,6 +48,8 @@ export class BillingInfoComponent implements OnInit{ errorMessage:any=''; showError:boolean=false; + private destroy$ = new Subject(); + constructor( private localStorage: LocalStorageService, private api: ApiServiceService, @@ -55,7 +59,9 @@ export class BillingInfoComponent implements OnInit{ private orderService: ProductOrderService, private eventMessage: EventMessageService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'BillAccChanged') { this.getBilling(); } @@ -92,6 +98,11 @@ export class BillingInfoComponent implements OnInit{ this.initPartyInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/user-profile/profile-sections/order-info/order-info.component.ts b/src/app/pages/user-profile/profile-sections/order-info/order-info.component.ts index 8db60151..b46436f9 100644 --- a/src/app/pages/user-profile/profile-sections/order-info/order-info.component.ts +++ b/src/app/pages/user-profile/profile-sections/order-info/order-info.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, OnDestroy } from '@angular/core'; import { LoginInfo, billingAccountCart } from 'src/app/models/interfaces'; import { ApiServiceService } from 'src/app/services/product-service.service'; import { AccountServiceService } from 'src/app/services/account-service.service'; @@ -16,6 +16,8 @@ import {EventMessageService} from "src/app/services/event-message.service"; import * as moment from 'moment'; import { environment } from 'src/environments/environment'; import {faIdCard, faSort, faSwatchbook} from "@fortawesome/pro-solid-svg-icons"; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'order-info', @@ -23,7 +25,7 @@ import {faIdCard, faSort, faSwatchbook} from "@fortawesome/pro-solid-svg-icons"; styleUrl: './order-info.component.css' }) -export class OrderInfoComponent implements OnInit { +export class OrderInfoComponent implements OnInit, OnDestroy { loading: boolean = false; orders:any[]=[]; nextOrders:any[]=[]; @@ -48,6 +50,8 @@ export class OrderInfoComponent implements OnInit { protected readonly faSort = faSort; protected readonly faSwatchbook = faSwatchbook; + private destroy$ = new Subject(); + constructor( private localStorage: LocalStorageService, private api: ApiServiceService, @@ -57,7 +61,9 @@ export class OrderInfoComponent implements OnInit { private eventMessage: EventMessageService, private paginationService: PaginationService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -82,6 +88,11 @@ export class OrderInfoComponent implements OnInit { this.initPartyInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/user-profile/profile-sections/org-info/org-info.component.ts b/src/app/pages/user-profile/profile-sections/org-info/org-info.component.ts index 522e53dd..7075b4b0 100644 --- a/src/app/pages/user-profile/profile-sections/org-info/org-info.component.ts +++ b/src/app/pages/user-profile/profile-sections/org-info/org-info.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, OnChanges } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, OnChanges, OnDestroy } from '@angular/core'; import { LoginInfo } from 'src/app/models/interfaces'; import { ApiServiceService } from 'src/app/services/product-service.service'; import { AccountServiceService } from 'src/app/services/account-service.service'; @@ -15,6 +15,8 @@ import {parsePhoneNumber} from 'libphonenumber-js/max' import {AttachmentServiceService} from "src/app/services/attachment-service.service"; import { NgxFileDropEntry, FileSystemFileEntry, FileSystemDirectoryEntry } from 'ngx-file-drop'; import { environment } from 'src/environments/environment'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; type OrganizationUpdate = components["schemas"]["Organization_Update"]; @@ -23,7 +25,7 @@ type OrganizationUpdate = components["schemas"]["Organization_Update"]; templateUrl: './org-info.component.html', styleUrl: './org-info.component.css' }) -export class OrgInfoComponent implements OnInit { +export class OrgInfoComponent implements OnInit, OnDestroy { loading: boolean = false; orders:any[]=[]; profile:any; @@ -109,6 +111,7 @@ export class OrgInfoComponent implements OnInit { @ViewChild('imgURL') imgURL!: ElementRef; public files: NgxFileDropEntry[] = []; + private destroy$ = new Subject(); constructor( private localStorage: LocalStorageService, @@ -118,7 +121,9 @@ export class OrgInfoComponent implements OnInit { private eventMessage: EventMessageService, private attachmentService: AttachmentServiceService, ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -139,6 +144,11 @@ export class OrgInfoComponent implements OnInit { }, 500); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/user-profile/profile-sections/user-info/user-info.component.ts b/src/app/pages/user-profile/profile-sections/user-info/user-info.component.ts index e96dbfcc..cc3c6544 100644 --- a/src/app/pages/user-profile/profile-sections/user-info/user-info.component.ts +++ b/src/app/pages/user-profile/profile-sections/user-info/user-info.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, OnDestroy } from '@angular/core'; import { LoginInfo } from 'src/app/models/interfaces'; import { ApiServiceService } from 'src/app/services/product-service.service'; import { AccountServiceService } from 'src/app/services/account-service.service'; @@ -8,13 +8,15 @@ import { phoneNumbers, countries } from 'src/app/models/country.const' import {EventMessageService} from "src/app/services/event-message.service"; import { initFlowbite } from 'flowbite'; import * as moment from 'moment'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'user-info', templateUrl: './user-info.component.html', styleUrl: './user-info.component.css' }) -export class UserInfoComponent implements OnInit { +export class UserInfoComponent implements OnInit, OnDestroy { loading: boolean = false; orders:any[]=[]; profile:any; @@ -41,6 +43,8 @@ export class UserInfoComponent implements OnInit { showError:boolean=false; successVisibility:boolean=false; + private destroy$ = new Subject(); + constructor( private localStorage: LocalStorageService, private api: ApiServiceService, @@ -48,7 +52,9 @@ export class UserInfoComponent implements OnInit { private accountService: AccountServiceService, private eventMessage: EventMessageService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -63,6 +69,11 @@ export class UserInfoComponent implements OnInit { this.initPartyInfo(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/pages/user-profile/user-profile.component.ts b/src/app/pages/user-profile/user-profile.component.ts index 4ad23bad..208c4bdc 100644 --- a/src/app/pages/user-profile/user-profile.component.ts +++ b/src/app/pages/user-profile/user-profile.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, ElementRef, ViewChild, AfterViewInit, HostListener, OnDestroy } from '@angular/core'; import { LoginInfo, billingAccountCart } from 'src/app/models/interfaces'; import { ApiServiceService } from 'src/app/services/product-service.service'; import { AccountServiceService } from 'src/app/services/account-service.service'; @@ -13,13 +13,15 @@ import { initFlowbite } from 'flowbite'; import {EventMessageService} from "../../services/event-message.service"; import * as moment from 'moment'; import { environment } from 'src/environments/environment'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-user-profile', templateUrl: './user-profile.component.html', styleUrl: './user-profile.component.css' }) -export class UserProfileComponent implements OnInit{ +export class UserProfileComponent implements OnInit, OnDestroy { show_profile: boolean = true; show_org_profile:boolean=false; show_orders: boolean = false; @@ -30,13 +32,16 @@ export class UserProfileComponent implements OnInit{ partyId:any=''; token:string=''; email:string=''; + private destroy$ = new Subject(); constructor( private localStorage: LocalStorageService, private cdr: ChangeDetectorRef, private eventMessage: EventMessageService ) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initPartyInfo(); } @@ -52,6 +57,11 @@ export class UserProfileComponent implements OnInit{ }, 100); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initPartyInfo(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) { diff --git a/src/app/services/pagination.service.ts b/src/app/services/pagination.service.ts index 56b72aff..d90fd5d3 100644 --- a/src/app/services/pagination.service.ts +++ b/src/app/services/pagination.service.ts @@ -88,12 +88,7 @@ export class PaginationService { } catch(err) { console.log(err) } finally { - let page_check=true; - if(nextItems.length>0){ - page_check=true; - } else { - page_check=false; - } + let page_check = nextItems.some(item => item != null); let info = { "page": page, diff --git a/src/app/shared/billing-account-form/billing-account-form.component.ts b/src/app/shared/billing-account-form/billing-account-form.component.ts index 5a260870..acde475e 100644 --- a/src/app/shared/billing-account-form/billing-account-form.component.ts +++ b/src/app/shared/billing-account-form/billing-account-form.component.ts @@ -6,7 +6,8 @@ import { ViewChild, AfterViewInit, HostListener, - Input + Input, + OnDestroy } from '@angular/core'; import {FormGroup, FormControl, Validators, ReactiveFormsModule} from '@angular/forms'; import {AccountServiceService} from 'src/app/services/account-service.service'; @@ -24,6 +25,8 @@ import {getCountries, getCountryCallingCode, CountryCode} from 'libphonenumber-j import {parsePhoneNumber} from 'libphonenumber-js/max' import {TranslateModule} from "@ngx-translate/core"; import { getLocaleId } from '@angular/common'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ @@ -31,7 +34,7 @@ import { getLocaleId } from '@angular/common'; templateUrl: './billing-account-form.component.html', styleUrl: './billing-account-form.component.css' }) -export class BillingAccountFormComponent implements OnInit { +export class BillingAccountFormComponent implements OnInit, OnDestroy { @Input() billAcc: billingAccountCart | undefined; @Input() preferred: boolean | undefined; @@ -97,6 +100,8 @@ export class BillingAccountFormComponent implements OnInit { { code: 'SE', name: 'Sweden' } ]; + private destroy$ = new Subject(); + constructor( private localStorage: LocalStorageService, private cdr: ChangeDetectorRef, @@ -105,7 +110,9 @@ export class BillingAccountFormComponent implements OnInit { private eventMessage: EventMessageService ) { getLocaleId; - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'ChangedSession') { this.initUserData(); } @@ -128,6 +135,11 @@ export class BillingAccountFormComponent implements OnInit { } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + initUserData(){ let aux = this.localStorage.getObject('login_items') as LoginInfo; if (JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix()) - 4) > 0)) { diff --git a/src/app/shared/card/card.component.ts b/src/app/shared/card/card.component.ts index 83e1cc34..7bbf3ab8 100644 --- a/src/app/shared/card/card.component.ts +++ b/src/app/shared/card/card.component.ts @@ -30,6 +30,8 @@ import { environment } from 'src/environments/environment'; import {ThemeConfig} from "../../themes"; import {Subscription} from "rxjs"; import {ThemeService} from "../../services/theme.service"; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'bae-off-card', @@ -86,6 +88,7 @@ export class CardComponent implements OnInit, OnDestroy, AfterViewInit { currentTheme: ThemeConfig | null = null; private themeSubscription: Subscription = new Subscription(); + private destroy$ = new Subject(); productAlreadyInCart:boolean=false; @@ -107,7 +110,9 @@ export class CardComponent implements OnInit, OnDestroy, AfterViewInit { this.targetModal = document.getElementById('details-modal'); this.modal = new Modal(this.targetModal); - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'CloseCartCard') { this.hideCartSelection(); //TOGGLE TOAST @@ -209,6 +214,8 @@ export class CardComponent implements OnInit, OnDestroy, AfterViewInit { if (this.themeSubscription) { this.themeSubscription.unsubscribe(); } + this.destroy$.next(); + this.destroy$.complete(); } async ngOnInit() { diff --git a/src/app/shared/cart-drawer/cart-drawer.component.ts b/src/app/shared/cart-drawer/cart-drawer.component.ts index 283cb98c..f5e744d1 100644 --- a/src/app/shared/cart-drawer/cart-drawer.component.ts +++ b/src/app/shared/cart-drawer/cart-drawer.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ChangeDetectorRef, HostListener } from '@angular/core'; +import { Component, OnInit, ChangeDetectorRef, HostListener, OnDestroy } from '@angular/core'; import { faCartShopping } from "@fortawesome/sharp-solid-svg-icons"; @@ -13,13 +13,15 @@ import { AccountServiceService } from 'src/app/services/account-service.service' import { cartProduct } from '../../models/interfaces'; import { TYPES } from 'src/app/models/types.const'; import { Router } from '@angular/router'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-cart-drawer', templateUrl: './cart-drawer.component.html', styleUrl: './cart-drawer.component.css' }) -export class CartDrawerComponent implements OnInit{ +export class CartDrawerComponent implements OnInit, OnDestroy { protected readonly faCartShopping = faCartShopping; items: any[] = []; totalPrice:any; @@ -29,6 +31,8 @@ export class CartDrawerComponent implements OnInit{ errorMessage:string=''; showError:boolean=false; + private destroy$ = new Subject(); + constructor( private localStorage: LocalStorageService, private eventMessage: EventMessageService, @@ -50,7 +54,9 @@ export class CartDrawerComponent implements OnInit{ this.showBackDrop=true; this.getCart(); - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'AddedCartItem') { console.log('Elemento añadido') this.loading=true; @@ -64,6 +70,11 @@ export class CartDrawerComponent implements OnInit{ console.log(this.items) } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + get objectKeys() { return Object.keys; } diff --git a/src/app/shared/categories-filter/categories-filter.component.ts b/src/app/shared/categories-filter/categories-filter.component.ts index 4eec1704..613a653c 100644 --- a/src/app/shared/categories-filter/categories-filter.component.ts +++ b/src/app/shared/categories-filter/categories-filter.component.ts @@ -1,4 +1,4 @@ -import {Component, EventEmitter, OnInit, Output, ChangeDetectorRef, Input} from '@angular/core'; +import {Component, EventEmitter, OnInit, Output, ChangeDetectorRef, Input, OnDestroy} from '@angular/core'; import {Category} from "../../models/interfaces"; import {Subject} from "rxjs"; import {LocalStorageService} from "../../services/local-storage.service"; @@ -7,13 +7,14 @@ import { ApiServiceService } from 'src/app/services/product-service.service'; import { initFlowbite } from 'flowbite'; import {faCircleCheck} from "@fortawesome/pro-solid-svg-icons"; import {faCircle} from "@fortawesome/pro-regular-svg-icons"; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'bae-categories-filter', templateUrl: './categories-filter.component.html', styleUrl: './categories-filter.component.css' }) -export class CategoriesFilterComponent implements OnInit { +export class CategoriesFilterComponent implements OnInit, OnDestroy { classListFirst = 'flex items-center justify-between w-full p-5 font-medium rtl:text-right text-gray-500 border border-b-0 border-gray-200 rounded-t-xl focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-800 dark:border-gray-700 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-tertiary-100 gap-3'; classListLast = 'flex items-center justify-between w-full p-5 font-medium rtl:text-right text-gray-500 border border-gray-200 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-800 dark:border-gray-700 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-tertiary-100 gap-3'; @@ -36,6 +37,8 @@ export class CategoriesFilterComponent implements OnInit { protected readonly faCircleCheck = faCircleCheck; protected readonly faCircle = faCircle; + private destroy$ = new Subject(); + constructor( private localStorage: LocalStorageService, private eventMessage: EventMessageService, @@ -43,7 +46,9 @@ export class CategoriesFilterComponent implements OnInit { private cdr: ChangeDetectorRef ) { this.categories = []; - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { const cat = ev.value as Category; if(ev.type === 'AddedFilter' && !this.isCheckedCategory(cat)){ this.checkedCategories.push(cat.id); @@ -100,6 +105,11 @@ export class CategoriesFilterComponent implements OnInit { initFlowbite(); } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + findChildren(parent:any,data:any[]){ let childs = data.filter((p => p.parentId === parent.id)); parent["children"] = childs; diff --git a/src/app/shared/categories-panel/categories-panel.component.ts b/src/app/shared/categories-panel/categories-panel.component.ts index 5601841b..232fc566 100644 --- a/src/app/shared/categories-panel/categories-panel.component.ts +++ b/src/app/shared/categories-panel/categories-panel.component.ts @@ -1,4 +1,4 @@ -import {Component, OnInit} from '@angular/core'; +import {Component, OnDestroy, OnInit} from '@angular/core'; import { NgClass } from '@angular/common'; import {TranslateModule} from "@ngx-translate/core"; import {LocalStorageService} from "../../services/local-storage.service"; @@ -8,6 +8,8 @@ import {faAddressCard} from "@fortawesome/sharp-solid-svg-icons"; import {FaIconComponent} from "@fortawesome/angular-fontawesome"; import {faFilterList} from "@fortawesome/pro-regular-svg-icons"; import {faTag} from "@fortawesome/pro-solid-svg-icons"; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'bae-categories-panel', @@ -20,12 +22,15 @@ import {faTag} from "@fortawesome/pro-solid-svg-icons"; templateUrl: './categories-panel.component.html', styleUrl: './categories-panel.component.css' }) -export class CategoriesPanelComponent implements OnInit { +export class CategoriesPanelComponent implements OnInit, OnDestroy { selected: Category[] = []; + private destroy$ = new Subject(); constructor(private localStorage: LocalStorageService, private eventMessage: EventMessageService) { this.selected = []; - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'AddedFilter') { const cat = ev.value as Category; const index = this.selected.findIndex(item => item.id === cat.id); @@ -46,6 +51,11 @@ export class CategoriesPanelComponent implements OnInit { this.selected = Array.isArray(stored) ? stored as Category[] : [] } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + notifyDismiss(cat: Category) { console.log('Category dismissed: '+ JSON.stringify(cat)); this.localStorage.removeCategoryFilter(cat); diff --git a/src/app/shared/category-item/category-item.component.ts b/src/app/shared/category-item/category-item.component.ts index 514f71db..6bf02e8e 100644 --- a/src/app/shared/category-item/category-item.component.ts +++ b/src/app/shared/category-item/category-item.component.ts @@ -1,17 +1,18 @@ -import {Component, EventEmitter, Input, OnInit, Output, ChangeDetectorRef} from '@angular/core'; +import {Component, EventEmitter, Input, OnInit, Output, ChangeDetectorRef, OnDestroy} from '@angular/core'; import {faCircleCheck} from "@fortawesome/pro-solid-svg-icons"; import {faCircle} from "@fortawesome/pro-regular-svg-icons"; import {Category} from "../../models/interfaces"; import {Subject} from "rxjs"; import {EventMessageService} from "../../services/event-message.service"; import {LocalStorageService} from "../../services/local-storage.service"; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'bae-category-item', templateUrl: './category-item.component.html', styleUrl: './category-item.component.css' }) -export class CategoryItemComponent implements OnInit { +export class CategoryItemComponent implements OnInit, OnDestroy { protected readonly faCircleCheck = faCircleCheck; protected readonly faCircle = faCircle; @@ -37,8 +38,12 @@ export class CategoryItemComponent implements OnInit { @Input() isFirst = false; @Input() isLast = false; + private destroy$ = new Subject(); + constructor(private localStorage: LocalStorageService, private eventMessage: EventMessageService, private cdr: ChangeDetectorRef) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { const cat = ev.value as Category; if(ev.type === 'AddedFilter' && cat?.id === this.data?.id) { this.checked = true; @@ -80,6 +85,11 @@ export class CategoryItemComponent implements OnInit { this.labelClass = 'flex items-center justify-between w-full px-5 py-3 font-medium rtl:text-right text-gray-500 border border-gray-200 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-800 dark:border-gray-700 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 gap-3 peer-checked:border-primary-50 dark:peer-checked:bg-primary-50 dark:peer-checked:text-secondary-100 peer-checked:text-gray-600'; } + ngOnDestroy(){ + this.destroy$.next(); + this.destroy$.complete(); + } + onClick(checked:boolean){ if(!checked) { this.checkedCategories.push((this.data as Category).id); diff --git a/src/app/shared/footer/footer.component.ts b/src/app/shared/footer/footer.component.ts index 0e1715e8..21a20add 100644 --- a/src/app/shared/footer/footer.component.ts +++ b/src/app/shared/footer/footer.component.ts @@ -8,6 +8,8 @@ import {EventMessageService} from "../../services/event-message.service"; import {LocalStorageService} from "../../services/local-storage.service"; import { LoginInfo } from 'src/app/models/interfaces'; import * as moment from 'moment'; +import {Subject} from "rxjs"; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'bae-footer', @@ -19,6 +21,7 @@ export class FooterComponent implements OnInit, OnDestroy { protected readonly faLinkedin = faLinkedin; protected readonly faYoutube = faYoutube; protected readonly faXTwitter = faXTwitter; + private destroy$ = new Subject(); // Propiedades dinámicas del tema public footerLinks: NavLink[] = []; @@ -32,7 +35,9 @@ export class FooterComponent implements OnInit, OnDestroy { private eventMessage: EventMessageService, private localStorage: LocalStorageService, private themeService: ThemeService) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'CloseFeedback') { this.feedback = false; } @@ -71,6 +76,8 @@ export class FooterComponent implements OnInit, OnDestroy { if (this.themeSubscription) { this.themeSubscription.unsubscribe(); } + this.destroy$.next(); + this.destroy$.complete(); } diff --git a/src/app/shared/forms/offer/general-info/general-info.component.ts b/src/app/shared/forms/offer/general-info/general-info.component.ts index 1de04643..a0988e7b 100644 --- a/src/app/shared/forms/offer/general-info/general-info.component.ts +++ b/src/app/shared/forms/offer/general-info/general-info.component.ts @@ -8,6 +8,8 @@ import {FormChangeState} from "../../../../models/interfaces"; import {Subscription} from "rxjs"; import {debounceTime} from "rxjs/operators"; import { noWhitespaceValidator } from 'src/app/validators/validators'; +import {Subject} from "rxjs"; +import { takeUntil } from 'rxjs/operators'; interface GeneralInfo { name: string; @@ -37,6 +39,7 @@ export class GeneralInfoComponent implements OnInit, OnDestroy { private originalValue: GeneralInfo; private hasBeenModified: boolean = false; private isEditMode: boolean = false; + private destroy$ = new Subject(); constructor(private eventMessage: EventMessageService) { console.log('🔄 Initializing GeneralInfoComponent'); @@ -96,7 +99,8 @@ export class GeneralInfoComponent implements OnInit, OnDestroy { // Subscribe to form changes only in edit mode if (this.isEditMode) { this.formGroup.valueChanges.pipe( - debounceTime(500) // Esperar 500ms después del último cambio antes de emitir + debounceTime(500), // Esperar 500ms después del último cambio antes de emitir + takeUntil(this.destroy$) ).subscribe((newValue) => { console.log('📝 Form value changed:', newValue); const dirtyFields = this.getDirtyFields(newValue); @@ -121,6 +125,8 @@ export class GeneralInfoComponent implements OnInit, OnDestroy { ngOnDestroy() { console.log('🗑️ Destroying GeneralInfoComponent'); + this.destroy$.next(); + this.destroy$.complete(); } private getDirtyFields(currentValue: GeneralInfo): string[] { diff --git a/src/app/shared/forms/offer/license/license.component.ts b/src/app/shared/forms/offer/license/license.component.ts index 63d012e3..ab29bad5 100644 --- a/src/app/shared/forms/offer/license/license.component.ts +++ b/src/app/shared/forms/offer/license/license.component.ts @@ -5,6 +5,8 @@ import {EventMessageService} from "src/app/services/event-message.service"; import {StatusSelectorComponent} from "../../status-selector/status-selector.component"; import {TranslateModule} from "@ngx-translate/core"; import {FormChangeState} from "../../../../models/interfaces"; +import {Subject} from "rxjs"; +import { takeUntil } from 'rxjs/operators'; interface License { treatment: string; @@ -27,10 +29,13 @@ export class LicenseComponent implements OnInit, OnDestroy { @Input() formType!: string; @Input() data: any; @Output() formChange = new EventEmitter(); + private destroy$ = new Subject(); constructor( private eventMessage: EventMessageService) { - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'UpdateOffer') { if (this.isEditMode && this.hasBeenModified && this.originalValue) { const currentValue = { @@ -108,7 +113,9 @@ export class LicenseComponent implements OnInit, OnDestroy { // Subscribe to form changes only in edit mode if (this.isEditMode) { - this.formGroup.valueChanges.subscribe(() => { + this.formGroup.valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe(() => { this.hasBeenModified = true; }); } @@ -143,6 +150,8 @@ export class LicenseComponent implements OnInit, OnDestroy { } else if (!this.isEditMode) { console.log('📝 Not in edit mode, skipping change detection'); } + this.destroy$.next(); + this.destroy$.complete(); } private getDirtyFields(currentValue: License): string[] { diff --git a/src/app/shared/forms/offer/offer.component.ts b/src/app/shared/forms/offer/offer.component.ts index 0ed95f13..8bf2685f 100644 --- a/src/app/shared/forms/offer/offer.component.ts +++ b/src/app/shared/forms/offer/offer.component.ts @@ -19,6 +19,8 @@ import {FormChangeState, PricePlanChangeState} from "../../../models/interfaces" import {Subscription} from "rxjs"; import * as moment from 'moment'; import { certifications } from 'src/app/models/certification-standards.const'; +import {Subject} from "rxjs"; +import { takeUntil } from 'rxjs/operators'; type ProductOffering_Create = components["schemas"]["ProductOffering_Create"]; type ProductOfferingPrice = components["schemas"]["ProductOfferingPrice"] @@ -77,6 +79,7 @@ export class OfferComponent implements OnInit, OnDestroy{ private formChanges: { [key: string]: FormChangeState } = {}; private formSubscription: Subscription | null = null; + private destroy$ = new Subject(); hasChanges: boolean = false; constructor(private api: ApiServiceService, @@ -95,7 +98,9 @@ export class OfferComponent implements OnInit, OnDestroy{ }); // Subscribe to form validation changes - this.productOfferForm.statusChanges.subscribe(status => { + this.productOfferForm.statusChanges + .pipe(takeUntil(this.destroy$)) + .subscribe(status => { if(!this.productOfferForm.controls['generalInfo'].valid || !this.productOfferForm.get('procurementMode')?.valid){ this.isFormValid = false } else { @@ -104,7 +109,9 @@ export class OfferComponent implements OnInit, OnDestroy{ }); // Subscribe to subform changes - this.formSubscription = this.eventMessage.messages$.subscribe(message => { + this.formSubscription = this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(message => { console.log('subform changed-----') if (message.type === 'SubformChange') { const changeState = message.value as FormChangeState; @@ -126,6 +133,8 @@ export class OfferComponent implements OnInit, OnDestroy{ if (this.formSubscription) { this.formSubscription.unsubscribe(); } + this.destroy$.next(); + this.destroy$.complete(); } goToStep(index: number) { diff --git a/src/app/shared/forms/offer/price-plans/price-plan-drawer/price-plan-drawer.component.ts b/src/app/shared/forms/offer/price-plans/price-plan-drawer/price-plan-drawer.component.ts index b5fb4e6b..07ea6a3c 100644 --- a/src/app/shared/forms/offer/price-plans/price-plan-drawer/price-plan-drawer.component.ts +++ b/src/app/shared/forms/offer/price-plans/price-plan-drawer/price-plan-drawer.component.ts @@ -1,4 +1,4 @@ -import {Component, EventEmitter, Input, Output, OnInit, HostListener, SimpleChanges, OnChanges} from '@angular/core'; +import {Component, EventEmitter, Input, Output, OnInit, HostListener, SimpleChanges, OnChanges, OnDestroy} from '@angular/core'; import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms'; import {MarkdownTextareaComponent} from "../../../markdown-textarea/markdown-textarea.component"; import {TranslateModule} from "@ngx-translate/core"; @@ -9,6 +9,8 @@ import {currencies} from "currencies.json"; import { ConfigurationProfileDrawerComponent } from "../configuration-profile-drawer/configuration-profile-drawer.component"; +import {Subject} from "rxjs"; +import { takeUntil } from 'rxjs/operators'; @Component({ @@ -28,7 +30,7 @@ import { ], styleUrl: './price-plan-drawer.component.css' }) -export class PricePlanDrawerComponent implements OnInit { +export class PricePlanDrawerComponent implements OnInit, OnDestroy { @Input() formGroup!: FormGroup; // Receive the parent form @Input() prodSpec: any | null = null; // Access to prodSpec @@ -44,6 +46,7 @@ export class PricePlanDrawerComponent implements OnInit { //protected readonly currencies = currencies; //Only allowing EUR for the moment protected readonly currencies=[currencies[2]]; + private destroy$ = new Subject(); constructor(private fb: FormBuilder) {} @@ -64,7 +67,9 @@ export class PricePlanDrawerComponent implements OnInit { } // 🔹 Ensure dynamic updates work - this.formGroup.get('paymentOnline')?.valueChanges.subscribe(value => { + this.formGroup.get('paymentOnline')?.valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe(value => { if (!value) { this.formGroup.get('priceType')?.setValue('custom'); } else { @@ -73,7 +78,9 @@ export class PricePlanDrawerComponent implements OnInit { }); // 🔹 Mark the form as touched when changes occur - this.formGroup.valueChanges.subscribe(() => { + this.formGroup.valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe(() => { this.formGroup.markAsTouched(); }); @@ -84,6 +91,11 @@ export class PricePlanDrawerComponent implements OnInit { } } + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } + savePricePlan() { if (this.formGroup.invalid) return; this.save.emit(this.formGroup.getRawValue()); diff --git a/src/app/shared/forms/offer/price-plans/price-plans.component.ts b/src/app/shared/forms/offer/price-plans/price-plans.component.ts index 20c9c26f..6b493c1a 100644 --- a/src/app/shared/forms/offer/price-plans/price-plans.component.ts +++ b/src/app/shared/forms/offer/price-plans/price-plans.component.ts @@ -16,7 +16,8 @@ import { ReactiveFormsModule } from '@angular/forms'; import { NgClass } from "@angular/common"; import { EventMessageService } from "src/app/services/event-message.service"; import { FormChangeState, PricePlanChangeState } from "src/app/models/interfaces"; -import { Subscription, debounceTime, distinctUntilChanged, filter } from "rxjs"; +import { Subscription, debounceTime, distinctUntilChanged, filter, Subject } from "rxjs"; +import { takeUntil } from 'rxjs/operators'; interface PriceComponent { id: string; @@ -108,6 +109,7 @@ export class PricePlansComponent implements OnInit, OnDestroy, ControlValueAcces private originalPricePlans: PricePlan[] = []; private originalPriceComponents: { [key: string]: any[] } = {}; private lastKnownState: PricePlan[] = []; + private destroy$ = new Subject(); constructor(private fb: FormBuilder, private cdr: ChangeDetectorRef, private eventMessage: EventMessageService) {} @@ -199,7 +201,8 @@ export class PricePlansComponent implements OnInit, OnDestroy, ControlValueAcces .pipe( debounceTime(500), distinctUntilChanged(), - filter(() => this.pricePlansForm.dirty) + filter(() => this.pricePlansForm.dirty), + takeUntil(this.destroy$) ) .subscribe((newValue) => { console.log('📊 Form array value changed:', newValue); @@ -211,7 +214,8 @@ export class PricePlansComponent implements OnInit, OnDestroy, ControlValueAcces control.valueChanges .pipe( debounceTime(500), - distinctUntilChanged() + distinctUntilChanged(), + takeUntil(this.destroy$) ) .subscribe((newValue) => { console.log(`📈 Price plan ${index} changed:`, newValue); @@ -224,6 +228,8 @@ export class PricePlansComponent implements OnInit, OnDestroy, ControlValueAcces if (this.formSubscription) { this.formSubscription.unsubscribe(); } + this.destroy$.next(); + this.destroy$.complete(); } private checkChanges() { diff --git a/src/app/shared/forms/offer/procurement-mode/procurement-mode.component.ts b/src/app/shared/forms/offer/procurement-mode/procurement-mode.component.ts index 4cec2f1f..1880b8e2 100644 --- a/src/app/shared/forms/offer/procurement-mode/procurement-mode.component.ts +++ b/src/app/shared/forms/offer/procurement-mode/procurement-mode.component.ts @@ -8,7 +8,8 @@ import {FormChangeState} from "../../../../models/interfaces"; import {EventMessageService} from "src/app/services/event-message.service"; import { HttpClient, HttpClientModule } from '@angular/common/http'; import { environment } from 'src/environments/environment'; -import { lastValueFrom, Subscription } from 'rxjs'; +import { lastValueFrom, Subscription, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; interface ProcurementMode { id: string; @@ -54,6 +55,7 @@ export class ProcurementModeComponent implements ControlValueAccessor, AfterView private hasBeenModified: boolean = false; private isEditMode: boolean = false; private formSub?: Subscription; + private destroy$ = new Subject(); showProcurementError:boolean=false; errorMessage:string = ''; @@ -62,7 +64,9 @@ export class ProcurementModeComponent implements ControlValueAccessor, AfterView constructor(private cdr: ChangeDetectorRef, private eventMessage: EventMessageService, private http: HttpClient) { console.log('🔄 Initializing ProcurementModeComponent'); - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(ev => { if(ev.type === 'UpdateOffer') { if (this.isEditMode && this.hasBeenModified && this.originalValue) { const currentValue = { @@ -160,7 +164,9 @@ export class ProcurementModeComponent implements ControlValueAccessor, AfterView } // Suscribirse a los cambios del formulario - this.formSub = this.form.valueChanges.subscribe(value => { + this.formSub = this.form.valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe(value => { console.log('📝 Form value changed in subscription:', value); if (value && value.mode) { @@ -246,5 +252,7 @@ export class ProcurementModeComponent implements ControlValueAccessor, AfterView }); } } + this.destroy$.next(); + this.destroy$.complete(); } } diff --git a/src/app/shared/forms/usage-spec/usage-spec-general-info/usage-spec-general-info.component.ts b/src/app/shared/forms/usage-spec/usage-spec-general-info/usage-spec-general-info.component.ts index 5665105f..7812e097 100644 --- a/src/app/shared/forms/usage-spec/usage-spec-general-info/usage-spec-general-info.component.ts +++ b/src/app/shared/forms/usage-spec/usage-spec-general-info/usage-spec-general-info.component.ts @@ -5,8 +5,8 @@ import {MarkdownTextareaComponent} from "../../markdown-textarea/markdown-textar import {StatusSelectorComponent} from "../../status-selector/status-selector.component"; import {EventMessageService} from "../../../../services/event-message.service"; import {FormChangeState} from "../../../../models/interfaces"; -import {Subscription} from "rxjs"; -import {debounceTime} from "rxjs/operators"; +import {Subject, Subscription} from "rxjs"; +import {debounceTime, takeUntil} from "rxjs/operators"; import { noWhitespaceValidator } from 'src/app/validators/validators'; interface GeneralInfo { @@ -35,6 +35,7 @@ export class UsageSpecGeneralInfoComponent implements OnInit, OnDestroy { private originalValue: GeneralInfo; private hasBeenModified: boolean = false; private isEditMode: boolean = false; + private destroy$ = new Subject(); constructor(private eventMessage: EventMessageService) { console.log('🔄 Initializing GeneralInfoComponent'); @@ -78,7 +79,8 @@ export class UsageSpecGeneralInfoComponent implements OnInit, OnDestroy { // Subscribe to form changes only in edit mode if (this.isEditMode) { this.formGroup.valueChanges.pipe( - debounceTime(500) // Esperar 500ms después del último cambio antes de emitir + debounceTime(500), // Esperar 500ms después del último cambio antes de emitir + takeUntil(this.destroy$) ).subscribe((newValue) => { console.log('📝 Form value changed:', newValue); const dirtyFields = this.getDirtyFields(newValue); @@ -103,6 +105,8 @@ export class UsageSpecGeneralInfoComponent implements OnInit, OnDestroy { ngOnDestroy() { console.log('🗑️ Destroying GeneralInfoComponent'); + this.destroy$.next(); + this.destroy$.complete(); } private getDirtyFields(currentValue: GeneralInfo): string[] { diff --git a/src/app/shared/forms/usage-spec/usage-spec.component.ts b/src/app/shared/forms/usage-spec/usage-spec.component.ts index e733eb35..aa74d4dd 100644 --- a/src/app/shared/forms/usage-spec/usage-spec.component.ts +++ b/src/app/shared/forms/usage-spec/usage-spec.component.ts @@ -16,6 +16,8 @@ import { UsageSpecSummaryComponent } from './usage-spec-summary/usage-spec-summa import { AccountServiceService } from 'src/app/services/account-service.service' import { UsageServiceService } from 'src/app/services/usage-service.service' import { v4 as uuidv4 } from 'uuid'; +import {Subject} from "rxjs"; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'usage-spec-form', @@ -31,7 +33,7 @@ import { v4 as uuidv4 } from 'uuid'; templateUrl: './usage-spec.component.html', styleUrl: './usage-spec.component.css' }) -export class UsageSpecComponent implements OnInit { +export class UsageSpecComponent implements OnInit, OnDestroy { @Input() formType: 'create' | 'update' = 'create'; @Input() usageSpec: any = {}; @@ -53,6 +55,7 @@ export class UsageSpecComponent implements OnInit { private formChanges: { [key: string]: FormChangeState } = {}; private formSubscription: Subscription | null = null; + private destroy$ = new Subject(); hasChanges: boolean = false; constructor(private api: ApiServiceService, @@ -67,12 +70,16 @@ export class UsageSpecComponent implements OnInit { }); // Subscribe to form validation changes - this.usageSpecForm.statusChanges.subscribe(status => { + this.usageSpecForm.statusChanges + .pipe(takeUntil(this.destroy$)) + .subscribe(status => { this.isFormValid = status === 'VALID'; }); // Subscribe to subform changes - this.formSubscription = this.eventMessage.messages$.subscribe(message => { + this.formSubscription = this.eventMessage.messages$ + .pipe(takeUntil(this.destroy$)) + .subscribe(message => { if (message.type === 'SubformChange') { const changeState = message.value as FormChangeState; console.log('Received subform change:', changeState); @@ -93,6 +100,8 @@ export class UsageSpecComponent implements OnInit { if (this.formSubscription) { this.formSubscription.unsubscribe(); } + this.destroy$.next(); + this.destroy$.complete(); } goToStep(index: number) { diff --git a/src/app/shared/header/header.component.ts b/src/app/shared/header/header.component.ts index 40ed522a..adbc14b8 100644 --- a/src/app/shared/header/header.component.ts +++ b/src/app/shared/header/header.component.ts @@ -32,6 +32,8 @@ import { TranslateService } from '@ngx-translate/core'; import {ShoppingCartServiceService} from "../../services/shopping-cart-service.service"; import {ThemeService} from "../../services/theme.service"; import {NavLink, ThemeAuthUrlsConfig, ThemeConfig, ThemeLinkConfig} from "../../themes"; +import {Subject} from "rxjs"; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'bae-header', @@ -98,6 +100,7 @@ export class HeaderComponent implements OnInit, AfterViewInit, DoCheck, OnDestro private themeSubscription: Subscription = new Subscription(); public headerLinks: NavLink[] = []; public themeAuthUrls: ThemeAuthUrlsConfig | undefined; + private destroy$ = new Subject(); @@ -107,6 +110,8 @@ export class HeaderComponent implements OnInit, AfterViewInit, DoCheck, OnDestro if (this.themeSubscription) { this.themeSubscription.unsubscribe(); } + this.destroy$.next(); + this.destroy$.complete(); } ngDoCheck(): void { @@ -214,7 +219,7 @@ export class HeaderComponent implements OnInit, AfterViewInit, DoCheck, OnDestro this.cdr.detectChanges(); } - this.sc.cart$.subscribe(cart => { + this.sc.cart$.pipe(takeUntil(this.destroy$)).subscribe(cart => { this.cartCount = cart.length; // Updates counter on icon }); @@ -225,7 +230,7 @@ export class HeaderComponent implements OnInit, AfterViewInit, DoCheck, OnDestro } }) - this.eventMessage.messages$.subscribe(ev => { + this.eventMessage.messages$.pipe(takeUntil(this.destroy$)).subscribe(ev => { if(ev.type === 'LoginProcess') { let aux = this.localStorage.getObject('login_items') as LoginInfo; if(JSON.stringify(aux) != '{}' && (((aux.expire - moment().unix())-4) > 0)) {