Commit a28f9eca authored by Merzough Münker's avatar Merzough Münker
Browse files

fix: simplify and generalize the accordion data source

parent f29b8ade
Loading
Loading
Loading
Loading
+45 −41
Original line number Diff line number Diff line
import {
  Inject,
  inject,
  Injectable,
  InjectionToken,
  OnDestroy,
  OnInit,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { BaseDataSource } from '@rxap/data-source';
import { MethodWithParameters } from '@rxap/pattern';
import {
  isDefined,
  ToggleSubject,
} from '@rxap/rxjs';
import { Method } from '@rxap/pattern';
import { ToggleSubject } from '@rxap/rxjs';
import { isPromiseLike } from '@rxap/utilities';
import {
  isObservable,
  Observable,
  ReplaySubject,
  Subject,
  Subscription,
} from 'rxjs';
import {
  map,
  tap,
} from 'rxjs/operators';

export const ACCORDION_DATA_SOURCE_METHOD = new InjectionToken('accordion-data-source-method');
export type AccordionDataSourceMethod<Data = unknown, Parameters = unknown> = Method<Data, Parameters>;

export const ACCORDION_DATA_SOURCE_METHOD = new InjectionToken<AccordionDataSourceMethod>(
  'accordion-data-source-method');

@Injectable()
export abstract class AccordionDataSource<Data = unknown> extends BaseDataSource<Data> implements OnInit {
export abstract class AccordionDataSource<
  Data = unknown,
  Parameters = unknown
> extends BaseDataSource<Data> implements OnInit, OnDestroy {

  public override _data$ = new ReplaySubject<Data>(1);
  public override readonly loading$ = new ToggleSubject(true);

  protected constructor(
    @Inject(ACCORDION_DATA_SOURCE_METHOD)
    protected readonly method: MethodWithParameters<Data, { parameters: { uuid: string } }>,
    protected readonly route: ActivatedRoute,
  ) {
    super();
  }
  protected parameters: Parameters | null = null;

  protected _lastUuid: string | null = null;
  protected readonly _refresh$ = new Subject<void>();

  public get lastUuid(): string {
    if (!this._lastUuid) {
      throw new Error('The last accordion uuid is not yet defined');
    }
    return this._lastUuid;
  }
  protected readonly method = inject<AccordionDataSourceMethod<Data, Parameters>>(ACCORDION_DATA_SOURCE_METHOD);

  protected _refresh$ = new Subject<void>();
  protected _subscription: Subscription | null = null;

  public get refresh$(): Observable<void> {
    return this._refresh$.asObservable();
  }

  public abstract getParameters(): Observable<Parameters> | Promise<Parameters> | Parameters;

  public override ngOnDestroy() {
    super.ngOnDestroy();
    this._subscription?.unsubscribe();
  }

  public ngOnInit() {
    if (!this.route.snapshot.paramMap.has('uuid')) {
      throw new Error('Could not extract the accordion uuid from the route params');
    const parameters = this.getParameters();
    if (isObservable(parameters)) {
      this._subscription = parameters.subscribe((params) => {
        this.parameters = params;
        return this.load();
      });
    } else if (isPromiseLike(parameters)) {
      parameters.then((params) => {
        this.parameters = params;
        return this.load();
      });
    } else {
      this.parameters = parameters;
      this.load();
    }
    this.route.paramMap.pipe(
      map(paramMap => paramMap.get('uuid')),
      isDefined(),
      tap(uuid => this._lastUuid = uuid),
      tap(uuid => this.load(uuid)),
    ).subscribe();
  }

  public override refresh(): any {
    const result = this.load(this.lastUuid);
    const result = this.load();
    if (isPromiseLike(result)) {
      result.then(() => this._refresh$.next());
    } else {
@@ -74,13 +77,14 @@ export abstract class AccordionDataSource<Data = unknown> extends BaseDataSource
    }
  }

  protected async load(uuid: string): Promise<void> {
  protected async load(): Promise<void> {
    if (!this.parameters) {
      throw new Error('The parameters are not set. Ensure the parameters are set before calling the load method.');
    }
    this.loading$.enable();
    this.hasError$.disable();
    try {
      const result = await this.method
                               .call({ parameters: { uuid } });
      this._data$.next(result);
      this._data$.next(await this.method.call(this.parameters));
    } catch (error) {
      console.error(`Fail to load data '${ this.id }' - '${ this.constructor.name }'`);
      this.hasError$.enable();
+11 −21
Original line number Diff line number Diff line
import {
  ACCORDION_DATA_SOURCE_METHOD,
  AccordionDataSource,
} from './accordion.data-source';
import {
  Inject,
  inject,
  Injectable,
  OnDestroy,
  OnInit,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import '@rxap/rxjs';
import { AccordionDataSource } from './accordion.data-source';
import { ACCORDION_DATA_SOURCE } from './tokens';
import {
  Method,
  MethodWithParameters,
} from '@rxap/pattern';

@Injectable()
export abstract class PanelAccordionDataSource<Data> extends AccordionDataSource<Data> implements OnDestroy {
export abstract class PanelAccordionDataSource<
  Data = unknown,
  Parameters = unknown
> extends AccordionDataSource<Data, Parameters> implements OnDestroy, OnInit {

  private _subscription?: Subscription;
  protected readonly accordionDataSource = inject<AccordionDataSource<Data, Parameters>>(ACCORDION_DATA_SOURCE);

  constructor(
    @Inject(ACCORDION_DATA_SOURCE_METHOD)
      method: MethodWithParameters<Data, { parameters: { uuid: string } }>,
    route: ActivatedRoute,
    @Inject(ACCORDION_DATA_SOURCE)
    protected readonly accordionDataSource: AccordionDataSource<unknown>,
  ) {
    super(method, route);
  override getParameters(): Observable<Parameters> | Promise<Parameters> | Parameters {
    return this.accordionDataSource.getParameters();
  }

  override ngOnInit() {