﻿import { Meta, Story, ArgsTable } from '@storybook/addon-docs/blocks';
import groupBy from './index.js';

<Meta
  title='Filters/GroupBy'
  argTypes={{
    items: { control: { type: 'object' } },
    criteria: { control: { type: 'select', options: ['age','firstname','lastname','gender','ageGroups'] } }
  }}
/>

export const Template = (args, {argTypes}) => ({
  props: {
    items: {
      type: Array,
      default: []
    },
    criteria: {
      type: String,
      default: 'age'
    }
  },
  computed: {
    groups() {
      if(this.items) {
        if(this.criteria==='ageGroups')
          return groupBy(this.items, this.ageGroups);
        else
          return groupBy(this.items, this.criteria);
      }
    }
  },
  methods: {
    ageGroups(person) {
      if(person.age<12)
        return 'children'
      else if(person.age<20)
        return 'adolescents'
      else
        return 'adults'
    }
  },
  template: `
  <div class="container-md p-sm-5 p-4 bg-white" :items="items">
    <div class="row align-items-center">
      <div class="col-sm-4 d-sm-flex justify-content-sm-center">
        <div class="input-group">
          <div class="input-group-prepend">
            <span class="input-group-text">Criteria</span>
          </div>
          <select v-model="criteria" class="custom-select">
            <option value="age">Age</option>
            <option value="firstname">Firstname</option>
            <option value="lastname">Lastname</option>
            <option value="gender">Gender</option>
            <option value="ageGroups">Age Groups (Function Criteria)</option>
          </select>
        </div>
      </div>
      <div class="col-sm-6 d-sm-flex">
        <ul class="list-group">
          <li v-for="groupKey in Object.keys(groups)" class="list-group-item p-0 my-1 rounded overflow-hidden">
            <span class="d-block px-3 py-1 bg-secondary text-white">{{ criteria }}: {{ groupKey }}</span>
            <ul class="unstyled-list p-3 bg-light">
              <li
                v-for="(item,itemIndex) in groups[groupKey]"
                class="badge badge-info text-white d-block"
                :class="{'mt-2': itemIndex!=0}">
                {{ item }}
              </li>
            </ul>
          </li>
        </ul>
      </div>
    </div>
  </div>`
});

# GroupBy Filter

Filters array items into groups by property key or function group logic.

### Example
<Story
  name='Example'
  args={{
    items: [
      { firstname: 'John', lastname: 'Smith', age: 30, gender: 'm' },
      { firstname: 'Alice', lastname: 'Smith', age: 9, gender: 'f' },
      { firstname: 'Edgar', lastname: 'Brown', age: 9, gender: 'm' },
      { firstname: 'John', lastname: 'Trump', age: 45, gender: 'm' },
      { firstname: 'Louis', lastname: 'Bush', age: 30, gender: 'm' },
      { firstname: 'Audrie', lastname: 'Brown', age: 45, gender: 'f' },
      { firstname: 'Mary', lastname: 'Johnson', age: 17, gender: 'f' },
    ],
    criteria: 'age'
  }}
  parameters={{
    storysource: { disabled: true }
  }}>
  {Template.bind({})}
</Story>

<ArgsTable story="Example" />

### Usage

1.- Import the filter

```javascript
import { groupBy } from '@modyo/financial-commons';
```

2.- We will use the preview example so our data, computed properties and methods looks like:

```javascript
...
data() {
  return {
    items: [
      { firstname: 'John', lastname: 'Smith', age: 30, gender: 'm' },
      { firstname: 'Alice', lastname: 'Smith', age: 9, gender: 'f' },
      { firstname: 'Edgar', lastname: 'Brown', age: 9, gender: 'm' },
      { firstname: 'John', lastname: 'Trump', age: 45, gender: 'm' },
      { firstname: 'Louis', lastname: 'Bush', age: 30, gender: 'm' },
      { firstname: 'Audrie', lastname: 'Brown', age: 45, gender: 'f' },
      { firstname: 'Mary', lastname: 'Johnson', age: 17, gender: 'f' },
    ],
    criteria: 'age'
  }
},
computed: {
  groups() {
    if(this.items) {
      if(this.criteria==='ageGroups')
        return groupBy(this.items, this.ageGroups);
      else
        return groupBy(this.items, this.criteria);
    }
  }
},
methods: {
  ageGroups(person) {
    if(person.age<12)
      return 'children'
    else if(person.age<20)
      return 'adolescents'
    else
      return 'adults'
  }
}
...
```

The magic occurs in the computed property `groups` where items are reduced by the groupBy function and the given criteria.

The criteria can be the item property key or a function that groups by some logic as in `ageGroups`.

3.- The computed property `groups` returns an object with keys for groups, each group is populated as an array of items.

Example for `gender` criteria, `groups` object will look like:

```javascript
{
  f: [
    { firstname: 'Alice', lastname: 'Smith', age: 9, gender: 'f' },
    { firstname: 'Audrie', lastname: 'Brown', age: 45, gender: 'f' },
    { firstname: 'Mary', lastname: 'Johnson', age: 17, gender: 'f' }
  ],
  m: [
    { firstname: 'John', lastname: 'Smith', age: 30, gender: 'm' },
    { firstname: 'Edgar', lastname: 'Brown', age: 9, gender: 'm' },
    { firstname: 'John', lastname: 'Trump', age: 45, gender: 'm' },
    { firstname: 'Louis', lastname: 'Bush', age: 30, gender: 'm' }
  ]
}
```

Example for `ageGroups` function criteria, `groups` object will look like:

```javascript
{
  children: [
    { firstname: 'Alice', lastname: 'Smith', age: 9, gender: 'f' },
    { firstname: 'Edgar', lastname: 'Brown', age: 9, gender: 'm' },
  ],
  adolescents: [
    { firstname: 'Mary', lastname: 'Johnson', age: 17, gender: 'f' },
  ],
  adults: [
    { firstname: 'John', lastname: 'Smith', age: 30, gender: 'm' },
    { firstname: 'John', lastname: 'Trump', age: 45, gender: 'm' },
    { firstname: 'Louis', lastname: 'Bush', age: 30, gender: 'm' },
    { firstname: 'Audrie', lastname: 'Brown', age: 45, gender: 'f' },
  ],
}
```