import { ChangeDetectionStrategy, Component, computed, DestroyRef, inject, signal } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { Router } from '@angular/router'; import { ToastrService } from 'ngx-toastr'; import { catchError, finalize, of } from 'rxjs'; import { OnboardingStep, OnboardingStepper } from './components/onboarding-stepper/onboarding-stepper'; import { OrganizationBasicsStepComponent } from './steps/organization-basics/organization-basics'; import { OrganizationOnboardingStateService } from './services/organization-onboarding-state.service'; import { OrganizationOnboardingService } from './services/organization-onboarding.service'; @Component({ selector: 'app-organization-onboarding', standalone: true, imports: [OnboardingStepper, OrganizationBasicsStepComponent], templateUrl: './organization-onboarding.html', styleUrl: './organization-onboarding.scss', changeDetection: ChangeDetectionStrategy.OnPush, providers: [OrganizationOnboardingStateService, OrganizationOnboardingService] }) export class OrganizationOnboarding { private readonly destroyRef = inject(DestroyRef); private readonly router = inject(Router); private readonly toastr = inject(ToastrService); private readonly stateService = inject(OrganizationOnboardingStateService); private readonly onboardingService = inject(OrganizationOnboardingService); readonly steps: readonly OnboardingStep[] = this.stateService.createStepDefinitions(); readonly savingDraft = signal(false); readonly finishing = signal(false); private basicsStep?: OrganizationBasicsStepComponent; readonly currentStepIndex = this.stateService.currentStepIndex; readonly completedStepIndexes = this.stateService.completedStepIndexes; readonly currentStep = computed( () => this.steps[this.currentStepIndex()] ); readonly navigationDisabled = computed( () => this.savingDraft() || this.finishing() ); constructor() { this.onboardingService.loadDraft() .pipe( catchError(() => { this.toastr.error('Unable to restore the onboarding draft.', 'Draft restore failed'); return of(null); }), takeUntilDestroyed(this.destroyRef) ) .subscribe(draft => { if (!draft) { return; } this.stateService.restoreDraft(draft); }); } registerBasicsStep(component: OrganizationBasicsStepComponent): void { this.basicsStep = component; const basicsDraft = this.stateService.onboardingDraft().basics; if (basicsDraft) { component.patchValue(basicsDraft); } } onStepSelected(index: number): void { if (!this.stateService.canOpenStep(index)) { return; } this.stateService.setCurrentStepIndex(index); } onBack(): void { const currentIndex = this.currentStepIndex(); if (currentIndex <= 0) { return; } this.stateService.setCurrentStepIndex(currentIndex - 1); } onNext(): void { const currentIndex = this.currentStepIndex(); if (currentIndex >= this.steps.length - 1) { return; } if (currentIndex === 0) { if (!this.basicsStep?.validate()) { this.stateService.unmarkStepCompleted(currentIndex); return; } this.stateService.updateBasics(this.basicsStep.getValue()); } this.stateService.markStepCompleted(currentIndex); this.stateService.setCurrentStepIndex(currentIndex + 1); } onSaveDraft(): void { if (this.savingDraft()) { return; } if (this.currentStepIndex() === 0 && this.basicsStep) { this.stateService.updateBasicsDraft(this.basicsStep.getDraftValue()); } this.savingDraft.set(true); this.onboardingService.saveDraft(this.stateService.buildDraft()) .pipe( finalize(() => { this.savingDraft.set(false); }), takeUntilDestroyed(this.destroyRef) ) .subscribe({ next: () => { this.toastr.success('Onboarding draft saved successfully.', 'Draft saved'); }, error: () => { this.toastr.error('Unable to save the onboarding draft.', 'Draft save failed'); } }); } onFinish(): void { if (this.finishing()) { return; } this.finishing.set(true); queueMicrotask(() => { this.finishing.set(false); }); } onCancel(): void { this.stateService.clear(); void this.router.navigate(['/configuration/organizations']); } }