Untitled

mail@pastecode.io avatar
unknown
javascript
3 years ago
29 kB
2
Indexable
Never
import React, { useMemo, useState, useRef, useEffect, forwardRef } from 'react'
import { useTable, useRowSelect } from 'react-table'
import { Link } from 'react-router-dom'
import _uniq from 'lodash/uniq'
import { FormattedMessage } from 'react-intl'
import OutsideClicker from '_common/outside-click'

import { ARCHIVE_SELECTED, DELETE_SELECTED } from '_data/action-types'
import {
  LOCALSTORAGE_KEY,
  DATA_TABLE_IDS,
  CONTACT_TABLE_COLUMN_IDS,
  ESTIMATES_TABLE_COLUMN_IDS,
  ITEMS_TABLE_COLUMN_IDS,
} from '_data/constants'

import IconGearFill from 'bootstrap-icons/icons/gear-fill.svg'
import IconArrowUpDown from 'bootstrap-icons/icons/chevron-expand.svg'
import IconArrowUp from 'bootstrap-icons/icons/chevron-up.svg'
import IconArrowDown from 'bootstrap-icons/icons/chevron-down.svg'
import IconList from 'bootstrap-icons/icons/list.svg'

function getSortLink(location, columnID, sortOrder) {
  const searchParams = new URLSearchParams(location.search)

  // Delete existing sort queries if any
  if (searchParams.has('sortBy')) {
    searchParams.delete('sortBy')
  }
  if (searchParams.has('sortOrder')) {
    searchParams.delete('sortOrder')
  }

  // Set the sort query
  searchParams.set('sortBy', columnID)
  searchParams.set('sortOrder', sortOrder)

  return location.pathname + '?' + searchParams.toString()
}

const RowCheckbox = forwardRef(({ indeterminate, ...rest }, ref) => {
  const defaultRef = useRef()
  const resolvedRef = ref || defaultRef

  useEffect(() => {
    resolvedRef.current.indeterminate = indeterminate
  }, [resolvedRef, indeterminate])

  return (
    <label className="d-flex justify-content-center mb-0">
      <input type="checkbox" ref={resolvedRef} {...rest} />
    </label>
  )
})

const ColumnTogglerMenus = ({ tableID, toggleColumnVisibility, hiddenColumns }) => {
  if (tableID === DATA_TABLE_IDS.contacts) {
    return (
      <>
        <small className="font-weight-light font-weight-bolder text-black-50 pl-2 pb-2 d-block">Display Columns</small>
        <div className="custom-control custom-checkbox">
          <input
            id="contacts-list.table-header.name"
            name={CONTACT_TABLE_COLUMN_IDS.name}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(CONTACT_TABLE_COLUMN_IDS.name)}
          />
          <label
            className="custom-control-label-sm text-body font-weight-light"
            htmlFor="contacts-list.table-header.name">
            <FormattedMessage id="contacts-list.table-header.name" defaultMessage="Name" />
          </label>
        </div>
        <div className="custom-control custom-checkbox">
          <input
            id="contacts-list.table-header.type"
            name={CONTACT_TABLE_COLUMN_IDS.types}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(CONTACT_TABLE_COLUMN_IDS.types)}
          />
          <label
            className="custom-control-label-sm text-body font-weight-light"
            htmlFor="contacts-list.table-header.type">
            <FormattedMessage id="contacts-list.table-header.type" defaultMessage="Types" />
          </label>
        </div>
        <div className="custom-control custom-checkbox">
          <input
            id="contacts-list.table-header.they-owe-you"
            name={CONTACT_TABLE_COLUMN_IDS.theyOweYou}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(CONTACT_TABLE_COLUMN_IDS.theyOweYou)}
          />
          <label
            className="custom-control-label-sm text-body font-weight-light"
            htmlFor="contacts-list.table-header.they-owe-you">
            <FormattedMessage id="contacts-list.table-header.they-owe-you" defaultMessage="They owe you" />
          </label>
        </div>
        <div className="custom-control custom-checkbox">
          <input
            id="contacts-list.table-header.you-owe-them"
            name={CONTACT_TABLE_COLUMN_IDS.youOweThem}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(CONTACT_TABLE_COLUMN_IDS.youOweThem)}
          />
          <label
            className="custom-control-label-sm text-body font-weight-light"
            htmlFor="contacts-list.table-header.you-owe-them">
            <FormattedMessage id="contacts-list.table-header.you-owe-them" defaultMessage="You owe them" />
          </label>
        </div>
      </>
    )
  } else if (tableID === DATA_TABLE_IDS.estimates) {
    return (
      <>
        <small className="font-weight-light font-weight-bolder text-black-50 pl-2 pb-2 d-block">Display Columns</small>
        <div className="custom-control custom-checkbox">
          <input
            id="estimates-list.table-header.estimates-name"
            name={ESTIMATES_TABLE_COLUMN_IDS.estimateRef}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(ESTIMATES_TABLE_COLUMN_IDS.estimateRef)}
          />
          <label
            className="custom-control-label-sm text-body font-weight-light"
            htmlFor="estimates-list.table-header.estimates-name">
            <FormattedMessage id="estimate-list.table-header.ref" defaultMessage="Reference" />
          </label>
        </div>
        <div className="custom-control custom-checkbox">
          <input
            id="estimates-list.table-header.status"
            name={ESTIMATES_TABLE_COLUMN_IDS.status}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(ESTIMATES_TABLE_COLUMN_IDS.status)}
          />
          <label
            className="custom-control-label-sm text-body font-weight-light"
            htmlFor="estimates-list.table-header.status">
            <FormattedMessage id="estimates-list.table-header.status" defaultMessage="Status" />
          </label>
        </div>
        <div className="custom-control custom-checkbox">
          <input
            id="estimates-list.table-header.client"
            name={ESTIMATES_TABLE_COLUMN_IDS.client}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(ESTIMATES_TABLE_COLUMN_IDS.client)}
          />
          <label
            className="custom-control-label-sm text-body font-weight-light"
            htmlFor="estimates-list.table-header.client">
            <FormattedMessage id="estimates-list.table-header.client" defaultMessage="Client" />
          </label>
        </div>
        <div className="custom-control custom-checkbox">
          <input
            id="estimates-list.table-header.net_amount"
            name={ESTIMATES_TABLE_COLUMN_IDS.amount}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(ESTIMATES_TABLE_COLUMN_IDS.amount)}
          />
          <label
            className="custom-control-label-sm text-body font-weight-light"
            htmlFor="estimates-list.table-header.net_amount">
            <FormattedMessage id="estimates-list.table-header.net_amount" defaultMessage="Amount" />
          </label>
        </div>
        <div className="custom-control custom-checkbox">
          <input
            id="estimates-list.table-header.invoice"
            name={ESTIMATES_TABLE_COLUMN_IDS.invoice}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(ESTIMATES_TABLE_COLUMN_IDS.invoice)}
          />
          <label
            className="custom-control-label-sm text-body font-weight-light"
            htmlFor="estimates-list.table-header.invoice">
            <FormattedMessage id="estimates-list.table-header.invoice" defaultMessage="Invoice" />
          </label>
        </div>
      </>
    )
  } else if (tableID === DATA_TABLE_IDS.items) {
    return (
      <>
        <small className="font-weight-light font-weight-bolder text-black-50 pl-2 pb-2 d-block">Display Columns</small>
        <div className="custom-control custom-checkbox">
          <input
            id="items-list.table-header.name"
            name={ITEMS_TABLE_COLUMN_IDS.name}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(ITEMS_TABLE_COLUMN_IDS.name)}
          />
          <label className="custom-control-label-sm text-body font-weight-light" htmlFor="items-list.table-header.name">
            <FormattedMessage id="items-list.table-header.name" defaultMessage="Name" />
          </label>
        </div>
        <div className="custom-control custom-checkbox">
          <input
            id="items-list.table-header.type"
            name={ITEMS_TABLE_COLUMN_IDS.type}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(ITEMS_TABLE_COLUMN_IDS.type)}
          />
          <label className="custom-control-label-sm text-body font-weight-light" htmlFor="items-list.table-header.type">
            <FormattedMessage id="items-list.table-header.type" defaultMessage="Type" />
          </label>
        </div>
        <div className="custom-control custom-checkbox">
          <input
            id="items-list.table-header.category"
            name={ITEMS_TABLE_COLUMN_IDS.category}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(ITEMS_TABLE_COLUMN_IDS.category)}
          />
          <label
            className="custom-control-label-sm text-body font-weight-light"
            htmlFor="items-list.table-header.category">
            <FormattedMessage id="items-list.table-header.category" defaultMessage="Category" />
          </label>
        </div>
        <div className="custom-control custom-checkbox">
          <input
            id="items-list.table-header.supplier"
            name={ITEMS_TABLE_COLUMN_IDS.supplier}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(ITEMS_TABLE_COLUMN_IDS.supplier)}
          />
          <label
            className="custom-control-label-sm text-body font-weight-light"
            htmlFor="items-list.table-header.supplier">
            <FormattedMessage id="items-list.table-header.supplier" defaultMessage="Supplier" />
          </label>
        </div>
        <div className="custom-control custom-checkbox">
          <input
            id="items-list.table-header.buying-price"
            name={ITEMS_TABLE_COLUMN_IDS.we_buy_it}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(ITEMS_TABLE_COLUMN_IDS.we_buy_it)}
          />
          <label
            className="custom-control-label-sm text-body font-weight-light"
            htmlFor="items-list.table-header.buying-price">
            <FormattedMessage id="items-list.table-header.buying-price" defaultMessage="We buy it at" />
          </label>
        </div>
        <div className="custom-control custom-checkbox">
          <input
            id="items-list.table-header.selling-price"
            name={ITEMS_TABLE_COLUMN_IDS.we_sell_it}
            type="checkbox"
            className="custom-control-input"
            onChange={toggleColumnVisibility}
            checked={!hiddenColumns.includes(ITEMS_TABLE_COLUMN_IDS.we_sell_it)}
          />
          <label
            className="custom-control-label-sm text-body font-weight-light"
            htmlFor="items-list.table-header.selling-price">
            <FormattedMessage id="items-list.table-header.selling-price" defaultMessage="We sell it at" />
          </label>
        </div>
      </>
    )
  }
}

const ColumnToggler = ({ tableID, setHiddenColumns, defaultHiddenColumns }) => {
  const [isDropdownOpen, toggleDropdown] = useState(false)
  const [hiddenColumns, setHiddenColumnsList] = useState(defaultHiddenColumns)

  const toggleColumnVisibility = (event) => {
    const {
      target: { name },
    } = event

    let filteredColumns = ''
    if (hiddenColumns.includes(name)) {
      filteredColumns = hiddenColumns.filter((column) => column !== name)
      setHiddenColumnsList(filteredColumns)
    } else {
      filteredColumns = [...hiddenColumns, name]
    }

    // This updates the react states for checked unchecked of checkbox
    setHiddenColumnsList(filteredColumns)
    // Set preference in LC
    localStorage.setItem(`${LOCALSTORAGE_KEY.userPrefTableHiddenCols}-${tableID}`, JSON.stringify(filteredColumns))
    // This func update hidden list of react table
    setHiddenColumns(filteredColumns)
  }

  return (
    <OutsideClicker onClick={() => toggleDropdown(false)}>
      <div
        className="dropdown cursor-pointer d-flex align-items-center justify-content-center"
        aria-haspopup="true"
        aria-expanded={`${isDropdownOpen}`}
        onClick={() => toggleDropdown(!isDropdownOpen)}>
        <IconGearFill />
        <div className={`dropdown-menu ${isDropdownOpen ? 'show' : ''} px-2 py-3 shadow-lg right-0 left-inherit`}>
          <ColumnTogglerMenus
            tableID={tableID}
            toggleColumnVisibility={toggleColumnVisibility}
            hiddenColumns={hiddenColumns}
          />
        </div>
      </div>
    </OutsideClicker>
  )
}

const RowOptionsMenus = ({ tableID, rowProperties, handleRowOptionsMenu }) => {
  if (tableID === DATA_TABLE_IDS.contacts) {
    const contactApiID = rowProperties.apiID
    return (
      <>
        <Link className="dropdown-item" to={`/contacts/${contactApiID}`}>
          <FormattedMessage id="row-options.contact-view" defaultMessage="View contact" />
        </Link>
        <Link className="dropdown-item" to={`/contacts/${contactApiID}/edit`}>
          <FormattedMessage id="row-options.contact-update" defaultMessage="Update contact" />
        </Link>
        <Link className="dropdown-item" to={`/invoices/new/?contact=${contactApiID}`}>
          <FormattedMessage id="row-options.contact-invoice" defaultMessage="Create invoice" />
        </Link>
        <Link className="dropdown-item" to={`/estimates/new/?contact=${contactApiID}`}>
          <FormattedMessage id="row-options.contact-estimate" defaultMessage="Create estimate" />
        </Link>
        <button className="dropdown-item" onClick={() => handleRowOptionsMenu(ARCHIVE_SELECTED, contactApiID)}>
          <FormattedMessage id="row-options.contact-archive" defaultMessage="Archive contact" />
        </button>
        <button className="dropdown-item" onClick={() => handleRowOptionsMenu(DELETE_SELECTED, contactApiID)}>
          <FormattedMessage id="row-options.contact-delete" defaultMessage="Delete contact" />
        </button>
      </>
    )
  } else if (tableID === DATA_TABLE_IDS.estimates) {
    const estimateID = rowProperties.apiID
    return (
      <>
        <Link className="dropdown-item" to={`/estimates/${estimateID}`}>
          <FormattedMessage id="row-options.estimate-view" defaultMessage="View estimate" />
        </Link>
        <Link className="dropdown-item" to={`/estimates/${estimateID}/edit`}>
          <FormattedMessage id="row-options.estimate-update" defaultMessage="Update estimate" />
        </Link>
        <Link className="dropdown-item" to={`/invoices/new/?estimate=${estimateID}`}>
          <FormattedMessage id="row-options.estimate-convert-invoice" defaultMessage="Convert to invoice" />
        </Link>
        <Link className="dropdown-item" to={`/email/?estimate=${estimateID}`}>
          <FormattedMessage id="row-options.estimate-send-email" defaultMessage="Send as email" />
        </Link>
        <button className="dropdown-item" onClick={() => handleRowOptionsMenu(ARCHIVE_SELECTED, estimateID)}>
          <FormattedMessage id="row-options.estimate-archive" defaultMessage="Archive estimate" />
        </button>
        <button className="dropdown-item" onClick={() => handleRowOptionsMenu(DELETE_SELECTED, estimateID)}>
          <FormattedMessage id="row-options.estimate-delete" defaultMessage="Delete estimate" />
        </button>
      </>
    )
  } else if (tableID === DATA_TABLE_IDS.items) {
    const itemID = rowProperties.apiID
    return (
      <>
        <Link className="dropdown-item" to={`/inventory/products-and-services/${itemID}`}>
          <FormattedMessage id="row-options.item-view-edit" defaultMessage="View/edit item" />
        </Link>
        <button className="dropdown-item" onClick={() => handleRowOptionsMenu(DELETE_SELECTED, itemID)}>
          <FormattedMessage id="row-options.item-delete" defaultMessage="Delete item" />
        </button>
      </>
    )
  } else if (tableID === DATA_TABLE_IDS.categories) {
    const categoryApiID = rowProperties.apiID
    return (
      <>
        <Link className="dropdown-item" to={`/inventory/categories/${categoryApiID}`}>
          <FormattedMessage id="row-options.item-category-view-edit" defaultMessage="View/Edit category" />
        </Link>
        <button className="dropdown-item" onClick={() => handleRowOptionsMenu(DELETE_SELECTED, categoryApiID)}>
          <FormattedMessage id="row-options.item-category-delete" defaultMessage="Delete category" />
        </button>
      </>
    )
  } else if (tableID === DATA_TABLE_IDS.units) {
    const unitApiID = rowProperties.apiID
    return (
      <>
        <Link className="dropdown-item" to={`/inventory/units/${unitApiID}/edit`}>
          <FormattedMessage id="row-options.inventory-unit-view" defaultMessage="View/edit unit" />
        </Link>
        <button className="dropdown-item" onClick={() => handleRowOptionsMenu(DELETE_SELECTED, unitApiID)}>
          <FormattedMessage id="row-options.inventory-unit-delete" defaultMessage="Delete unit" />
        </button>
      </>
    )
  }
}

const RowOptionsDropdown = ({ tableID, cell, handleRowOptionsMenu }) => {
  const [isDropdownOpen, toggleDropdown] = useState(false)
  const rowProperties = cell.row.original

  const areRowOptionsHidden = rowProperties?.areRowOptionsHidden ?? false

  if (areRowOptionsHidden) {
    return null
  }

  return (
    <OutsideClicker onClick={() => toggleDropdown(false)}>
      <div
        className="dropdown cursor-pointer d-flex align-items-center justify-content-center"
        aria-haspopup="true"
        aria-expanded={`${isDropdownOpen}`}
        onClick={() => toggleDropdown(!isDropdownOpen)}>
        <IconList />
        <div className={`dropdown-menu ${isDropdownOpen ? 'show' : ''} px-2 py-3 shadow-lg right-0 left-inherit`}>
          <RowOptionsMenus
            tableID={tableID}
            handleRowOptionsMenu={handleRowOptionsMenu}
            rowProperties={rowProperties}
          />
        </div>
      </div>
    </OutsideClicker>
  )
}

const BulkActionMenus = ({ tableID, rowsIDs, handleBulkActionSelect }) => {
  if (tableID === DATA_TABLE_IDS.contacts) {
    return (
      <>
        <button className="dropdown-item" onClick={() => handleBulkActionSelect(ARCHIVE_SELECTED, rowsIDs)}>
          <FormattedMessage id="bulk-action.contact-archive" defaultMessage="Archive selected contact(s)" />
        </button>
        <button className="dropdown-item" onClick={() => handleBulkActionSelect(DELETE_SELECTED, rowsIDs)}>
          <FormattedMessage id="bulk-action.contact-delete" defaultMessage="Delete selected contact(s)" />
        </button>
      </>
    )
  } else if (tableID === DATA_TABLE_IDS.items) {
    return (
      <>
        <button className="dropdown-item" onClick={() => handleBulkActionSelect(DELETE_SELECTED, rowsIDs)}>
          <FormattedMessage id="bulk-action.item-delete" defaultMessage="Delete selected item(s)" />
        </button>
      </>
    )
  } else if (tableID === DATA_TABLE_IDS.categories) {
    return (
      <button className="dropdown-item" onClick={() => handleBulkActionSelect(DELETE_SELECTED, rowsIDs)}>
        <FormattedMessage id="bulk-action.item-category-delete" defaultMessage="Delete selected category(ies)" />
      </button>
    )
  } else if (tableID === DATA_TABLE_IDS.units) {
    return (
      <button className="dropdown-item" onClick={() => handleBulkActionSelect(DELETE_SELECTED, rowsIDs)}>
        <FormattedMessage id="bulk-action.inventory-unit-delete" defaultMessage="Delete selected unit(s)" />
      </button>
    )
  }
}

const BulkActionsDropdown = ({ selectedRowIds, handleBulkActionSelect, tableID }) => {
  const [isDropdownOpen, toggleDropdown] = useState(false)

  // The format of selected row is {id1:true,id2:false ...}
  const rowsIDs = Object.keys(selectedRowIds).filter((selectedRowID) => selectedRowIds[selectedRowID] === true)

  let shouldDisableBulkAction = true
  if (rowsIDs.length !== 0) {
    shouldDisableBulkAction = false
  }

  return (
    <OutsideClicker onClick={() => toggleDropdown(false)}>
      <div className="btn-group">
        <button
          type="button"
          className="btn btn-light border-info"
          disabled={shouldDisableBulkAction}
          onClick={() => toggleDropdown(!isDropdownOpen)}>
          <FormattedMessage id="more-actions-button.title" defaultMessage="Bulk action" />
        </button>
        <button
          id="dropdown-toggle"
          type="button"
          className="btn btn-light border-info dropdown-toggle dropdown-toggle-split"
          disabled={shouldDisableBulkAction}
          onClick={() => toggleDropdown(!isDropdownOpen)}>
          <span className="sr-only sr-only-focusable" aria-haspopup="true" aria-expanded="false">
            Toggle Bulk action menu
          </span>
        </button>
        <div className={`dropdown-menu ${isDropdownOpen ? 'show' : ''}`} aria-labelledby="Bulk action list">
          <BulkActionMenus tableID={tableID} rowsIDs={rowsIDs} handleBulkActionSelect={handleBulkActionSelect} />
        </div>
      </div>
    </OutsideClicker>
  )
}

export default ({
  tableID,
  tableColumns,
  tableData,
  location = {},
  handleBulkActionSelect,
  handleRowOptionsMenu,
  defaultHiddenColumns = [],
  enableColumnHide = false,
  enableRowOptions = false,
  enableRowSelection = false,
  enableColumnSort = false,
}) => {
  let rowSelectionColumn = null
  let rowOptionsColumn = null

  const userPreferedHiddenColums =
    JSON.parse(localStorage.getItem(`${LOCALSTORAGE_KEY.userPrefTableHiddenCols}-${tableID}`)) ?? []
  const hiddenColumns = _uniq([...userPreferedHiddenColums, ...defaultHiddenColumns])

  if (enableRowSelection) {
    rowSelectionColumn = {
      id: 'table.selection',
      Header: ({ getToggleAllRowsSelectedProps }) => <RowCheckbox {...getToggleAllRowsSelectedProps()} />,
      Cell: ({ row }) => <RowCheckbox {...row.getToggleRowSelectedProps()} />,
      headerClassName: 'w-2rem',
      rowClassName: 'w-2rem',
    }
  }

  if (enableColumnHide || enableRowOptions) {
    rowOptionsColumn = {
      id: 'table.properties',
      Header: ({ setHiddenColumns }) =>
        enableColumnHide && (
          <ColumnToggler tableID={tableID} setHiddenColumns={setHiddenColumns} defaultHiddenColumns={hiddenColumns} />
        ),
      Cell: ({ cell }) =>
        enableRowOptions && (
          <RowOptionsDropdown tableID={tableID} handleRowOptionsMenu={handleRowOptionsMenu} cell={cell} />
        ),
      headerClassName: 'w-2rem',
      rowClassName: 'w-2rem',
    }
  }

  const columns = useMemo(() => tableColumns, [...tableColumns])
  const data = useMemo(() => tableData)

  const searchInURL = location?.search ?? ''
  const searchParams = new URLSearchParams(searchInURL)
  let sortBy = ''
  let sortOrder = ''
  if (searchParams.has('sortBy')) {
    sortBy = searchParams.get('sortBy')
  }
  if (searchParams.has('sortOrder')) {
    sortOrder = searchParams.get('sortOrder')
  }

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    state: { selectedRowIds },
  } = useTable(
    {
      columns,
      data,
      initialState: {
        hiddenColumns,
      },
      autoResetPage: false,
      autoResetSelectedRows: false,
    },
    useRowSelect,
    (hooks) => {
      hooks.visibleColumns.push((columns) =>
        [rowSelectionColumn, ...columns, rowOptionsColumn].filter((column) => column !== null),
      )
    },
  )

  return (
    <>
      <table {...getTableProps()} className="mb-4">
        <thead>
          {headerGroups.map((headerGroup) => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((column) => {
                if (column.id !== 'table.properties' && column.id !== 'table.selection') {
                  const isRowSortedIncreasing =
                    column.isSortable && column.id === sortBy && sortOrder === 'inc' && enableColumnSort
                  const isRowSortedDecreasingly =
                    column.isSortable && column.id === sortBy && sortOrder === 'dec' && enableColumnSort
                  const isRowNotSorted = column.isSortable && column.id !== sortBy && enableColumnSort

                  return (
                    <th {...column.getHeaderProps()} key={column.id} className={column.headerClassName}>
                      <small className="text-uppercase font-weight-bold">{column.render('Header')} </small>
                      {isRowSortedIncreasing && (
                        <Link to={getSortLink(location, column.id, 'dec')}>
                          <IconArrowUp className="text-primary" />
                        </Link>
                      )}
                      {isRowSortedDecreasingly && (
                        <Link to={getSortLink(location, column.id, 'inc')}>
                          <IconArrowDown className="text-primary" />
                        </Link>
                      )}
                      {isRowNotSorted && (
                        <Link to={getSortLink(location, column.id, 'inc')}>
                          <IconArrowUpDown />
                        </Link>
                      )}
                    </th>
                  )
                }

                // For anyother type of column render a normal column header
                return (
                  <th {...column.getHeaderProps()} key={column.id} className={column.headerClassName}>
                    {column.render('Header')}
                  </th>
                )
              })}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {rows.map((row) => {
            prepareRow(row)

            return (
              <tr {...row.getRowProps()}>
                {row.cells.map((cell) => {
                  // Render bs pills if value is array
                  if (Array.isArray(cell.value)) {
                    return (
                      <td {...cell.getCellProps()} className={cell.column.rowClassName}>
                        {cell.value.map((cellOfArray, index) => {
                          return (
                            <span
                              key={`_pill-${index}`}
                              className="badge badge-pill mr-2 text-uppercase"
                              style={{ backgroundColor: cellOfArray.color, color: cellOfArray.textColor }}>
                              {cellOfArray.value}
                            </span>
                          )
                        })}
                      </td>
                    )
                  }

                  return (
                    <td {...cell.getCellProps()} className={cell.column.rowClassName}>
                      {cell.render('Cell')}
                    </td>
                  )
                })}
              </tr>
            )
          })}
        </tbody>
      </table>
      {tableID.length !== 0 && enableRowSelection && (
        <BulkActionsDropdown
          selectedRowIds={selectedRowIds}
          handleBulkActionSelect={handleBulkActionSelect}
          tableID={tableID}
        />
      )}
    </>
  )
}