npm package: @mailstep/dashboard
Description: Customizable dashboard inspired by Jira dashboard. Allows you to add, remove and configure _built-in_ or custom widgets.
Author: Jan Jarcik
Latest version: 0.8.16

# Keep Dashboard

Customizable dashboard inspired by Jira dashboard. Allows you to add, remove and configure _built-in_ or custom widgets.

Key points:

- Easy integration
- Supports multiple languages
- Supports color schemes (TODO)

Requirements:

- Redux, React
- node 16.x

## Getting started

1. Install deps

```js
yarn add @inventi/dashboard react-grid-layout styled-components

yarn add @nivo/pie @nivo/bar @nivo/core
```

- Note: `@nivo/pie @nivo/bar @nivo/core` - are optional and only required if you want to use specific built-in widgets which use @nivo packages

---

2. Add reducer to createReducers

```js
import { reducer as dashboardReducer } from '@inventi/dashboard'

export default (history: History) =>
  combineReducers({
    // ... your other reducers
    dashboard: dashboardReducer,
  })
```

---

3. Copy static css file
Copy this file: `node_modules/react-grid-layout/css/styles.css` to your public folder in your app. It should be available by `http://your-app.nx/react-grid-layout/css/styles.css`

---
4. Use Dashboard

- Note: all types can be imported from index - `@inventi/dashboard'`

```ts
import Dashboard, { PieChart, NumberBox, WidgetConfig, LayoutWidgetItem, WidgetDefinition, CustomComponents } from '@inventi/dashboard'

// Define language to use
const language: 'cs' | 'en' = 'en'
// Define widgets you want to use in your dashboard
const widgets: WidgetDefinition[] = [NumberBox, PieChart]
// Define initial (persisted) widgets to display
const initialWidgets: LayoutWidgetItem[] = [{ ...layoutItem1 }, { ...layoutItem2 }]
// Custom components that override default ones to provide extra customization 
const components: CustomComponents = {
  Button, // Buttons
  Picker, // Element responsible form adding new widget, located top right
  ItemConfigControls, // Bottom of item (widget) config with controls. 
  ItemHeader, // header if item (widget) with name, drag icon 
}

// Define onChange handler
const onChange = (widgetList: LayoutWidgetItem[]) => {
  // ... persistDashboard(widgetList)
}

const MyPage = () => {
  return <Dashboard lang={language} widgetDefinitions={widgets} initialWidgets={initialWidgets} onChange={onChange} components={component} />
}
```

---

4. Confuguring built-in widgets - HoC

Each widget takes in common base props:

- `data` - depends on widget, but is generally an array
- `isLoading` - boolean value, if true, displays loader
- `error` - boolean, if true, displays error message

The recommended approach is to use **multiple HOC functions** exposed by the Dashboard package. <br />
If the behaviour of exposed functions is not to your liking, you can use your own.

- ### withFetchHOC

Allows to pass in fetch (base) data. <br />
Implementation of `fetch` is called on each widget config change and on first render. <br />
Adds props - `data`, `isLoading` and `error` to widget compoment.

```js
import { withFetchHOC, WidgetConfig } from '@packages/dashboard'

const handleFetch = (cfg?: WidgetConfig) => {
  // fetch logic based on widget config
  // ...
  // payload can specify data only:
  const payloadData = [1, 2, 3]
  // or named data with other props:
  // ...
  const payloadWithProps = { data: [1, 2, 3], otherProp: 'x123' }
  // return promise with data from fetch
  return Promise.resolve(payloadData)
}

const widgets = [ColorBox, withFetchHOC(handleFetch)(PieChart)]
const MyDashboard = () => <Dashboard widgets={widgets} />
```

Promise has to be returned because loading & error is based on it. <br />
Individual widget fetch logic can be further specified in **widget config**.

- ### withConfigHOC

Allows to customize config component of widget. <br />
Config component defines sources, filters & other props in `MultiConfigProps` <br />
This HOC passed spreaded `config` object as props to `configComponent`. <br />
Adds flexibility with each widget source.

```js
import { withConfig } from '@packages/dashboard'

const pieChartConfig = {
  // Define all available widget sources (variants of widget)
  // Can be selected in widget config
  sources: [
    { value: 'source1', label: 'Widget source 1' },
    {
      value: 'source2',
      label: 'Widget source 2',
      // Add filters which can be selected and added to widget config
      filters: [
        {
          // Will be saved as 'status' property in config if selected
          name: 'status',
          label: t({ id: 'homepage.widget.status', message: 'Status' }),
          // Can select multiple values, saved as array if set to true
          isMulti: true,
          options: [
            { value: 'val1', label: 'status option 1' },
            { value: 'val1', label: 'status option 1' },
          ],
        },
      ],
    },
  ],
}

const widgets = [ColorBox, withConfig(pieChartConfig)(PieChart)]
const MyDashboard = () => <Dashboard widgets={widgets} />
```

- #### withPropsHOC

Allows to pass general props - each widget has its own. Eg. title / description of widget etc.

```js
import { withPropsWDefinition as withProps, WidgetConfig } from '@packages/dashboard'

// Pass props based on selected widget variant ~ source
const pieChartProps = ({ config }: WidgetConfig): WidgetConfig =>
  ({
    source1: { title: 'Title od widget based on source 1' },
    source2: { title: 'Title od widget based on source 2', description: 'Desciption of widget ... 2' },
  }[config?.source])

const widgets = [ColorBox, withProps(pieChartProps)(PieChart)]
const MyDashboard = () => <Dashboard widgets={widgets} />
```

---

## Built-in widgets

There are several predefined widgets which can be used in your Dashboard:

### **[NumberBox](/docs/NumberBox.md)**

### **[Table](/docs/Table.md)**

### **[PieChart](/docs/PieChart.md)**

### **[BarChart](/docs/BarChart.md)**

### **[HorizontalBar](/docs/HorizontalBar.md)**

### **[ColorBox](/docs/ColorBox.md)**

<br />
... and you can also create your own widget

### **[YourCustomWidget](/docs/CustomWidget.md)**

---

<br />

Made with ❤️ and support of INVENTI.