iurynogueira/ion

View on GitHub
projects/ion/src/core/bn-table/bn-table.ts

Summary

Maintainability
A
1 hr
Test Coverage
import { forkJoin, of } from 'rxjs';
import { finalize, take } from 'rxjs/operators';
import { LIST_OF_PAGE_OPTIONS } from '../../lib/pagination/pagination.component';
import { ConfigTable, EventTable } from '../../lib/table/utilsTable';
import {
  ConfigSmartTable,
  OrderTableEvent,
  PageEvent,
  SmartTableEvent,
} from '../../public-api';
import { BnService, IPayload, IResponse } from '../api/http.interfaces';
import { clearObject } from '../utils/clearObject';

export interface SmartPayload {
  offset?: number;
  total?: boolean;
  limit?: number;
  order?: string;
  sort?: string;
}

export interface IBnTable<DataType> {
  service: BnService<DataType>;
  tableConfig: Pick<ConfigTable<DataType>, 'columns' | 'actions'>;
  formatData?: (data: DataType[]) => DataType[];
}

export default class BnTable<DataType> {
  public configTable: ConfigSmartTable<DataType> = {
    data: [],
    columns: [],
    actions: [],
    pagination: {
      total: 0,
      itemsPerPage: LIST_OF_PAGE_OPTIONS[0],
      pageSizeOptions: LIST_OF_PAGE_OPTIONS,
    },
    loading: false,
  };

  public payload: IPayload = {
    total: true,
    offset: this.configTable.pagination.offset || 0,
    limit: this.configTable.pagination.itemsPerPage,
  };

  private service: BnService<DataType>;
  private formatData: (data: DataType[]) => DataType[];
  private firstLoad = true;

  constructor(config: IBnTable<DataType>) {
    this.service = config.service;

    // set configs
    this.configTable.columns = config.tableConfig.columns;
    this.configTable.actions = config.tableConfig.actions;

    this.formatData = config.formatData;
    this.onInit();
  }

  filter<T = DataType>(filter: T): void {
    this.payload = {
      ...this.payload,
      ...filter,
    };
    clearObject(this.payload);
    this.resetTablePagination();
    this.smartData();
  }

  smartData(): void {
    this.configTable.loading = true;

    if (this.firstLoad) {
      const firstOrderedColumn = this.configTable.columns.filter(
        (column) => column.desc !== undefined
      )[0];

      if (firstOrderedColumn) {
        this.handleSort({
          column: firstOrderedColumn.key,
          desc: firstOrderedColumn.desc,
        });
      }

      this.firstLoad = false;
    }

    const totalRequest$ = this.payload.total
      ? this.service.list(this.payload).pipe(take(1))
      : of(null);

    const dataRequest$ = this.service
      .list({ ...this.payload, total: false })
      .pipe(take(1));

    forkJoin([totalRequest$, dataRequest$])
      .pipe(finalize(() => (this.configTable.loading = false)))
      .subscribe(
        (response) => {
          const [totalResponse, dataResponse]: [
            IResponse<DataType>,
            IResponse<DataType>
          ] = response;

          if (totalResponse && totalResponse.total !== null) {
            this.configTable.pagination = {
              ...this.configTable.pagination,
              total: totalResponse.total || 0,
            };
          }

          this.configTable.data = dataResponse.dados || dataResponse.data || [];

          if (this.formatData) {
            this.configTable.data = this.formatData(this.configTable.data);
          }
        },
        () => {
          // TODO: add notification service
          // const msg: string = error.msg || error.error.msg;
          // this.notify.error('Erro', msg);
        }
      );
  }

  events(event: SmartTableEvent): void {
    const eventHandlers = {
      [EventTable.CHANGE_PAGE]: () => this.handlePageChange(event.change_page),
      [EventTable.SORT]: () => event.order && this.handleSort(event.order),
      [EventTable.REFRESH_FILTER]: () => this.filter(event.data),
    };

    const handler = eventHandlers[event.event];
    if (handler) {
      handler();
    }

    if (event.event !== EventTable.REFRESH_FILTER) {
      this.smartData();
    }
  }

  handlePageChange(changePage: PageEvent): void {
    this.payload.limit = changePage.itemsPerPage;
    this.payload.offset = changePage.offset;
    this.configTable.pagination.page = changePage.actual;
  }

  handleSort(order: OrderTableEvent): void {
    this.payload.order = order.column;
    this.payload.sort = order.desc ? 'desc' : 'asc';

    this.resetTablePagination();
  }

  private resetTablePagination(): void {
    this.configTable.pagination.offset = 0;
    this.configTable.pagination.total = 0;
    this.configTable.pagination.page = 1;

    this.payload.offset = 0;
  }

  private onInit(): void {
    this.smartData();
  }
}