npm package: @joseaburt/mui-v5-react-table-manager
Description: This package is the implementation using [Material UI V5](https://mui.com/material-ui/getting-started/installation/) for [@joseaburt/react-table-manager ](https://www.npmjs.com/package/@joseaburt/react-table-manager) core package.
Author: Jose Aburto
Latest version: 0.1.1

## react-table-manager-mui-v5

This package is the implementation using [Material UI V5](https://mui.com/material-ui/getting-started/installation/) for [@joseaburt/react-table-manager ](https://www.npmjs.com/package/@joseaburt/react-table-manager) core package.

- Content of the documentation:
  - Installation
  - Manager Instance
  - Columns
    - Columns / Basic configs
    - Columns / Custom Render
    - Columns / Custom Query Parser
  - Getting Table Component
    - Getting Table Component / Basic Table
    - Getting Table Component / Responsive one
      - ResponsiveTableViewsBuilder
  - Getting Data / PaginableRepository
    - Contracts
    - Implementing my custom Repository
  - Full Example!!!

## Installation

```cmd
yarn add @mui/material @emotion/react @emotion/styled @mui/icons-material
```

## 1. Manager Instance

The brain of this module is the [@joseaburt/react-table-manager ](https://www.npmjs.com/package/@joseaburt/react-table-manager) and the first think we need
is a fresh instance of that manager and for doing that this package provide and builder for that:

```typescript
import { TableManagerBuilder } from '@joseaburt/mui-v5-react-table-manager';

const manager = TableManagerBuilder // 👈🏼 This Builder
  //
  .fromDataProvider<User>(new UserRepository())
  .addColumn({})
  .get();
```

Maybe you can ask how where table component come from? This is an specific topic but let see a little example. Take in mind
that the following way is just one of two way, but in soon we will discuss about it.

```typescript
import { TableManagerBuilder, createTable } from '@joseaburt/mui-v5-react-table-manager';

const manager = TableManagerBuilder
  //
  .fromDataProvider<User>(new UserRepository())
  .addColumn({})
  .get();

const Table = createTable(manager); // 👈🏼 Here buddy

export default function App() {
  return (
    <div className="container p-4">
      <Table />
    </div>
  );
}
```

## 2. Columns

Columns are important, so let's learn how to define them. ⚠️ The following configurations definitions are just for each column of the table.

| Prop              | Required | Type                | Default             | Description                                                                                                   |
| ----------------- | -------- | ------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------- |
| name              | yes      | keyof T             |                     | Name to be used in the input.                                                                                 |
| label             | yes      | string              |                     | Value to be used in the input label .                                                                         |
| type              | yes      | ColumnType          |                     | Define the type of the column. Important for the searching filters in header.                                 |
| render            | no       | RenderFactory       | StringRenderFactory | By factory will be provided that return an string, so if you need custom children use it.                     |
| width             | no       | string              | undefined           | Define the with of the column                                                                                 |
| isHidden          | no       | boolean             | undefined           | If defined when table render given column will be no render. This can change throw manager commands           |
| align             | no       | ColumnAlign         | left                | Define the orientation of the content of the column cell                                                      |
| queryType         | no       | QueryType           | filter              | Define in with path of the url the filter are placed. Params or Filter/Query string                           |
| queryOperation    | no       | FilterOperationType | equal               | Define the the operation of the column query: like or ilike o equal                                           |
| isSortable        | no       | boolean             | true                | If prop no passed a table header sort controls will be render, if explicit false if given wont be render      |
| isQueryable       | no       | boolean             | true                | If prop no passed a table header filter controls will be render, if explicit false if given wont be render    |
| customQueryParser | no       | QueryParser         | undefined           | There is 3 kind of query operations: "like/ilike/equal" but maybe you required your own, so define this prop. |

Let's setup a couple one for learn. For doing that we will use `BankTransaction` model as example.

```typescript
type BankTransaction = {
  transactionId: string;
  date: Date;
  amount: number;
  description: string;
  accountFrom: string;
  accountTo: string;
  transactionType: 'deposit' | 'withdrawal' | 'transfer';
};
```

### 2.1. Columns / Basic configs

This is all you need for a simple table column. By default you get: sort, filter and render the exact value.

```typescript
import { TableManagerBuilder, createTable } from '@joseaburt/mui-v5-react-table-manager';

const manager = TableManagerBuilder
  //
  .fromDataProvider<User>(new UserRepository())
  .addColumn({
    label: 'ID',
    type: 'text',
    name: 'transactionId',
  })
  .get();

export default createTable(manager);
```

### 2.2. Columns / Custom Render

This is all you need for a simple table column. By default you get: sort, filter and render the exact value.

```typescript
import { TableManagerBuilder, createTable } from '@joseaburt/mui-v5-react-table-manager';

const manager = TableManagerBuilder
  //
  .fromDataProvider<User>(new UserRepository())
  .addColumn({})
  .addColumn({
    label: 'Date',
    type: 'text',
    name: 'date',
    render({ value, record }: RenderProps<User>): JSX.Element {
      // 👈🏼 Here buddy
      return (
        <MomentText variant="body2" format="short-date">
          {value}
        </MomentText>
      );
    },
  })
  .get();

export default createTable(manager);
```

### 2.3. Columns / Custom Query Parser

This is all you need for a simple table column. By default you get: sort, filter and render the exact value.

```typescript
import { TableManagerBuilder, createTable } from '@joseaburt/mui-v5-react-table-manager';

function getDateRange(value: string) {
  const originalDate = moment(date);
  const gte = moment(originalDate).startOf('day').toISOString();
  const lte = moment(originalDate).endOf('day').toISOString();
  return { lte, gte };
}

const manager = TableManagerBuilder
  //
  .fromDataProvider<User>(new UserRepository())
  .addColumn({})
  .addColumn({
    label: 'Date',
    name: 'date',
    type: 'date-range',
    customQueryParser: getDateRange, // 👈🏼 Here buddy
  })
  .get();

export default createTable(manager);
```

And the rest are as easy as that.

## 3. Getting Table Component

We have two options for getting table component: one base way and one for responsive one.

### 3.1. Getting Table Component / Basic Table

The base table help is by using `createTable` this will build that table component.

```typescript
import { TableManagerBuilder, createTable } from '@joseaburt/mui-v5-react-table-manager';

const manager = TableManagerBuilder
  //
  .fromDataProvider<User>(new UserRepository())
  .addColumn({})
  .get();

export default createTable(manager); // 👈🏼 Here buddy
```

### 3.2. Getting Table Component / Responsive one

This helper provides:

- defined breakpoints for hiding columns on a given viewport width.
- Switch to small view on given viewport width

```typescript
import { TableManagerBuilder, createTable, ResponsiveTableViewsBuilder } from '@joseaburt/mui-v5-react-table-manager';

const manager = TableManagerBuilder
  //
  .fromDataProvider<BankTransaction>(new UserRepository())
  .addColumn({})
  .get();

export default ResponsiveTableViewsBuilder.new<BankTransaction>(manager)
  .addBreakpoint('(max-width: 636)', ['date']) // 👈🏼 Here buddy
  .addBreakpoint('(max-width: 519)', ['description']) // 👈🏼 Here buddy
  .registerSmallView(<div className="p-4 text-center">Small Table Not Implemented</div>) // 👈🏼 Here buddy
  .get();
```

#### 3.2.1. **ResponsiveTableViewsBuilder**

This is a builder helper to abstract the complexity of the responsiveness of the table. This builder has two main methods:

- **`addBreakpoint(cssBreakpoint: string, columnNames: (keyof T | 'action')[])`**:
  Use this method for add as many breakpoints for hiding columns base on css media query.

  ```ts
  export default ResponsiveTableViewsBuilder.new<BankTransaction>(manager)
    .addBreakpoint('(max-width: 636)', ['date']) // 👈🏼 Add one
    .addBreakpoint('(max-width: 519)', ['description']); // 👈🏼 And one more
    .addBreakpoint('(max-width: 519)', ['description']); // 👈🏼 More
    .addBreakpoint('(max-width: 519)', ['description']); // 👈🏼 And one more
    // Etc
  ```

- **`registerSmallView(smallTableElement: JSX.Element)`**: This is the setter method for defining small table view.

## 4. **Getting Data / PaginableRepository**

Getting data is important and as you may know we have been using `new UserRepository()`, so let's check how to implement one repository.

```typescript
const manager = TableManagerBuilder.fromDataProvider<BankTransaction>(new UserRepository()); // 👈🏼 This Repository
```

The way you get and process data it is your concern and this module just offer a contract and this module depends on that contract that you
have to implement and provide an implementation.

### 4.1. **Contracts**

```typescript
type BackendResponse<T> = { data: T; meta: Meta };

type Meta = { page: number; total: number; pageSize: number };

interface PaginableRepository<T> {
  getAll(query: Query, signal: AbortSignal): Promise<BackendResponse<T>>;
}
```

### 4.1. **Implementing my custom Repository**

```typescript
export class MyCustomRepository implements PaginableRepository<BankTransaction[]> {
  constructor(private endpoint: string) {}

  public async getAll(query: Query, signal: AbortSignal): Promise<BackendResponse<BankTransaction[]>> {
    const qs = this.parseQuery(query);
    const { data } = axios.get<BackendResponse<BankTransaction[]>>(`${this.endpoint}${q}`);
    return data;
  }

  public parseQuery(query: Query): string {
    // TODO implement this method
  }
}
```

Now you can use your impl!

## 5. **Full Example!!!**

```typescript
import './index.css';
import React from 'react';
import 'react-app-polyfill/ie11';
import 'react-app-polyfill/ie11';
import ReactDOM from 'react-dom/client';
import { User } from './api/entities';
import UserRepository from './api/repository';
import EditorPreview from './components/EditorPreview';
import MoreVertIcon from '@mui/icons-material/MoreVert';
import { Avatar, Box, IconButton, Stack, Typography } from '@mui/material';
import { RenderProps, TableManagerBuilder, ResponsiveTableViewsBuilder } from '../.';

const manager = TableManagerBuilder.fromDataProvider<User>(new UserRepository())
  .addColumn({
    label: 'ID',
    name: 'id',
    type: 'text',
    width: '10%',
  })
  .addColumn({
    type: 'text',
    isSortable: true,
    isQueryable: true,
    label: 'Username',
    name: 'fullName',
    render({ value, record }: RenderProps<User>) {
      return (
        <Stack direction="row" alignItems="center" gap={1}>
          <Avatar sx={{ width: '2rem', height: '2rem' }} src={record.thumbnail} />
          <Box>
            <Typography>{record.fullName}</Typography>
            <Typography variant="caption" color="blue">
              {record.email}
            </Typography>
          </Box>
        </Stack>
      );
    },
  })
  .addColumn({
    label: 'Phone',
    name: 'phone',
    type: 'text',
  })
  .addColumn({
    label: 'Address',
    name: 'address',
    type: 'text',
  })
  .addColumn({
    label: 'Action',
    name: 'action',

    render({ value, record }: RenderProps<User>) {
      return (
        <Box>
          <IconButton>
            <MoreVertIcon />
          </IconButton>
        </Box>
      );
    },
  })
  .get();

const TableResponsive = ResponsiveTableViewsBuilder.new<User>(manager)
  .addBreakpoint('(max-width: 636)', ['date'])
  .addBreakpoint('(max-width: 519)', ['description'])
  .registerSmallView(<Box sx={{ padding: '4rem', textAlign: 'center' }}>Small Table Not Implemented</Box>)
  .get({
    debugWidth: true,
    cardProps: {
      sx: {
        border: 'none',
        borderTopRightRadius: 0,
        borderTopLeftRadius: 0,
      },
    },
  });

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(<TableResponsive />);
```