import { Controls, Canvas, Meta, Source } from '@storybook/blocks';
import * as SyServerTable from './SyServerTable.stories';
import '@/stories/styles/shared.css';

<Meta of={SyServerTable} />

<div className="header">
  <h1>SyServerTable</h1>
  <p>Le composant `SyServerTable` est utilisé pour afficher des données tabulaires chargées depuis un serveur. Il s'appuie sur le composant `VDataTableServer` de Vuetify et offre des fonctionnalités supplémentaires comme le stockage local des options de tableau et des améliorations d'accessibilité.</p>
</div>

<Canvas story={{height: '550px'}} of={SyServerTable.Default} />

## API

<Controls story={{height: '550px'}} of={SyServerTable.Default} />

## Fonctionnalités

### Chargement côté serveur

Le composant `SyServerTable` est spécialement conçu pour gérer les données chargées depuis un serveur. Il permet de:
- Paginer les données côté serveur
- Trier les données côté serveur
- Afficher un état de chargement pendant les requêtes

### Stockage local des options

Le composant enregistre automatiquement les options du tableau (tri, pagination, etc.) dans le localStorage du navigateur. Ces options sont restaurées lorsque l'utilisateur revient sur la page.

Pour gérer individuellement le stockage des options pour différents tableaux, utilisez la prop `suffix`.

### Tri côté serveur

Le composant permet de trier les données par colonne en déléguant le tri au serveur.

Le multi-tri est également supporté. Vous pouvez activer cette fonctionnalité en utilisant la prop `multi-sort`.

### Filtres des colonnes

Le composant permet d'appliquer des filtres sur les colonnes. Vous pouvez définir des filtres personnalisés pour chaque colonne en utilisant la prop `show-filters`. Voir d'autres exemples de filtres dans les stories.

### Resize des colonnes

Le composant peut permettre de redimensionner les colonnes en utilisant la prop `resizable-columns`. Vous pouvez activer ou désactiver cette fonctionnalité selon vos besoins.

### Réorganisation des colonnes

Le composant permet de cacher ou réorganiser l'ordre des colonnes en utilisant la prop `enable-column-controls`. Vous pouvez activer ou désactiver cette fonctionnalité selon vos besoins.

### Selection des lignes

Le composant permet de sélectionner des lignes individuellement ou en masse. Vous pouvez activer la sélection en utilisant la prop `show-select`.

Par défaut, la clé utilisée pour identifier chaque ligne lors de la sélection est `id`. Si vos éléments ne possèdent pas de propriété `id`, la valeur sélectionnée correspondra à l'objet complet de la ligne.

Vous pouvez personnaliser cette clé avec la prop `selection-key` pour indiquer quel champ utiliser (ex: `userId`).

Exemple d'utilisation :
<Source dark code={`
<SyServerTable
  v-model="selected"
  :items="users"
  :headers="headers"
  show-select
  selection-key="userId"
/>
`}/>

### Click des lignes

La prop `clickableRow` active le clic sur toute la ligne du tableau. Quand cette prop vaut `true`, un clic sur une ligne émet l'événement `row-click` avec l'item correspondant.

Les lignes deviennent également focusables au clavier afin de pouvoir être activées avec <kbd>Entrée</kbd> ou <kbd>Espace</kbd>.

Les éléments interactifs déjà présents dans la ligne, comme les cases à cocher, liens ou boutons, conservent leur comportement propre et ne déclenchent pas `row-click`.

L'événement `row-click` est  lorsqu'une ligne est activée alors que `clickableRow` est à `true`.

- Payload : l'objet de la ligne cliquée
- Cas pris en charge : clic souris sur la ligne, activation clavier via <kbd>Entrée</kbd> ou <kbd>Espace</kbd>
- Cas exclus : interaction avec un élément interactif imbriqué dans la ligne

Exemple :
<Source dark code={`
<SyServerTable
  :items="items"
  :headers="headers"
  :server-items-length="totalItems"
  clickable-row
  @row-click="handleRowClick"
/>
`}/>

### Slot item
Le composant permet de personnaliser l'affichage des contenus en utilisant le slot `item`. Vous pouvez définir la structure de chaque contenu en fonction de vos besoins.

### Slot headers
Le composant permet de personnaliser l'affichage des en-têtes de colonnes en utilisant le slot `headers`. Vous pouvez définir la structure de chaque en-tête en fonction de vos besoins.

### Items par page options
Le composant permet de personnaliser le nombre possible d'éléments par page en utilisant la prop `items-per-page-options`. Vous pouvez spécifier un tableau d'options pour permettre de choisir le nombre d'éléments affichés par page.

<div className="header">
  <h1>Accessibilité</h1>
</div>

Le composant améliore l'accessibilité en ajoutant automatiquement:
- Une légende (caption) pour le tableau
- Des attributs ARIA appropriés
- Des attributs scope pour les en-têtes de colonnes

## Exemples d'utilisation

### Tableau avec chargement côté serveur

<Source dark code={`
<template>
  <SyServerTable
    v-model:options="options"
    :items="users"
    :headers="headers"
    :server-items-length="totalUsers"
    :loading="state === StateEnum.PENDING"
    suffix="api-example"
    @update:options="fetchData"
  />
</template>

<script setup lang="ts">
  import { ref, watch } from 'vue'
  import { SyServerTable } from '@cnamts/synapse'
  import { StateEnum } from '@cnamts/synapse/src/components/Tables/common/constants/StateEnum'
  import type { DataOptions } from '@cnamts/synapse/src/components/Tables/common/types'
  
  interface User {
    [key: string]: string
    firstname: string
    lastname: string
    email: string
  }

  interface DataObj {
    items: User[]
    total: number
  }

  const totalUsers = ref(0)
import '../../../stories/styles/shared.css';
  const users = ref<User[]>([])
  const state = ref(StateEnum.IDLE)

  const options = ref({
    itemsPerPage: 5,
    sortBy: [{ key: 'lastname', order: 'asc' }],
    page: 1,
  })

  const headers = [
    { title: 'Nom', key: 'lastname' },
    { title: 'Prénom', key: 'firstname' },
    { title: 'Email', key: 'email' },
  ]

  const fetchData = async (): Promise<void> => {
    const { items, total } = await getDataFromApi(options.value)
    users.value = items
    totalUsers.value = total
  }

  // Simulation d'une API
  const getDataFromApi = async ({ sortBy, page, itemsPerPage }: DataOptions): Promise<DataObj> => {
    state.value = StateEnum.PENDING
    
    // Simuler un délai réseau
    await new Promise(resolve => setTimeout(resolve, 1000))

    return new Promise((resolve) => {
      let items: User[] = [
        { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' },
        { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com' },
        // ... autres utilisateurs
      ]
      
      const total = items.length

      // Appliquer le tri côté serveur
      if (sortBy && sortBy.length > 0) {
        items = items.sort((a, b) => {
          const key = sortBy[0].key
          const order = sortBy[0].order === 'asc' ? 1 : -1
          return a[key] > b[key] ? order : -order
        })
      }

      // Appliquer la pagination côté serveur
      if (itemsPerPage > 0) {
        items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
      }

      resolve({ items, total })
      state.value = StateEnum.RESOLVED
    })
  }
</script>
`} />

### Plusieurs tableaux serveur sur une même page

Pour utiliser plusieurs tableaux serveur sur une même page avec des options indépendantes, utilisez la prop `suffix` pour chaque tableau.

## Bonnes pratiques

- Utilisez la prop `serverItemsLength` pour indiquer le nombre total d'éléments disponibles côté serveur
- Implémentez un état de chargement pendant les requêtes avec la prop `loading`
- Utilisez la prop `suffix` lorsque vous avez plusieurs tableaux sur une même page
- Optimisez les requêtes serveur en utilisant les options de pagination et de tri
- Gérez correctement les erreurs de chargement des données
