{# # ============================================================================ # ORGANISM: TREND CHART PANEL # ============================================================================ # # Carte de courbe complète : chart-card + filter-tabs + le câblage du # contrôleur shared--trend-chart. # # C'est un organisme et non une molécule parce qu'il compose deux molécules # (chart-card, filter-tabs), conformément à la règle de niveau atomique. # # Il existe pour une raison précise : le tableau de bord commercial et l'écran # admin affichent EXACTEMENT cette carte, aux mêmes séries et aux mêmes # pastilles. Le laisser en double dans les deux templates, c'était deux endroits # à corriger pour un même défaut, et trois répétitions du bloc de pastilles # dans chacun. # # ============================================================================ # COMPOSITION # ============================================================================ # # - _molecules/chart-card # - _molecules/filter-tabs (mode clientToggle) # - _atoms/icon # - contrôleur Stimulus shared--trend-chart # # ============================================================================ # PARAMÈTRES # ============================================================================ # # | Paramètre | Type | Défaut | Description | # |----------------|--------|------------|------------------------------------| # | title | string | 'Évolution'| Titre de la carte | # | subtitle | string | null | Ligne de contexte | # | labels | array | [] | Libellés d'axe | # | primary | array | [] | Série principale (trait plein) | # | secondary | array | [] | Série secondaire (pointillés) | # | primaryLabel | string | '' | Nom de la série principale | # | secondaryLabel | string | '' | Nom de la série secondaire | # | suffix | string | '' | Suffixe d'unité, ex. ' €' | # | icon | string | 'chart' | Icône de la pastille d'en-tête | # | iconColor | string | 'primary' | Couleur de la pastille | # | height | string | 'md' | sm, md, lg | # | emptyText | string | 'Aucune…' | Texte de l'état vide | # | attr | object | {} | Attributs additionnels, fusionnés | # # ============================================================================ # EXEMPLES D'UTILISATION # ============================================================================ # # {% include '_organisms/trend-chart-panel/trend-chart-panel.html.twig' with { # title: 'Commissions & chiffre d\'affaires', # labels: series.labels, primary: series.commissions, secondary: series.revenue, # primaryLabel: 'Commission acquise', secondaryLabel: 'CA net généré', suffix: ' €' # } only %} # # ============================================================================ #} {% set title = title ?? 'Évolution' %} {% set subtitle = subtitle ?? null %} {% set labels = labels ?? [] %} {% set primary = primary ?? [] %} {% set secondary = secondary ?? [] %} {% set primaryLabel = primaryLabel ?? '' %} {% set secondaryLabel = secondaryLabel ?? '' %} {% set suffix = suffix ?? '' %} {% set icon = icon ?? 'chart' %} {% set iconColor = iconColor ?? 'primary' %} {% set height = height ?? 'md' %} {% set emptyText = emptyText ?? 'Aucune donnée sur la période' %} {% set attr = attr ?? {} %} {# Les douze points partent dans le DOM une seule fois ; le contrôleur les découpe côté client au changement de période, sans requête. #} {# Le câblage du contrôleur gagne en cas de collision : l'appelant ne peut pas l'écraser, y compris par erreur. Il apporte ses propres attributs par-dessus — un attribut de test, par exemple —, jamais à la place. #} {% set chartAttr = attr|merge({ 'data-controller': 'shared--trend-chart', 'data-shared--trend-chart-labels-value': labels|json_encode, 'data-shared--trend-chart-primary-value': primary|json_encode, 'data-shared--trend-chart-primary-label-value': primaryLabel, 'data-shared--trend-chart-suffix-value': suffix }) %} {# Pas de series secondaire vide : le contrôleur ne doit pas dessiner une courbe plate à zéro là où il n'y a qu'une seule grandeur à montrer. #} {% if secondary is not empty %} {% set chartAttr = chartAttr|merge({ 'data-shared--trend-chart-secondary-value': secondary|json_encode, 'data-shared--trend-chart-secondary-label-value': secondaryLabel }) %} {% endif %} {% set heightMap = { 'sm': 'h-40', 'md': 'h-56', 'lg': 'h-72' } %} {% set zoneHeight = heightMap[height] ?? heightMap['md'] %} {% set periodBtnAttr = { 'data-shared--trend-chart-target': 'periodBtn', 'data-action': 'click->shared--trend-chart#switchPeriod' } %} {# `only` retiré : les blocs `actions` et `body` ci-dessous référencent `periodBtnAttr` et `zoneHeight`, qui ne sont pas transmis par le `with`. Un bloc redéfini par `{% embed %}` est compilé dans CE template et garde son contexte ; `only` isole seulement ce que la molécule elle-même reçoit. Les `include` internes gardent `only` : eux n'ont pas besoin du contexte appelant. #} {% embed '_molecules/chart-card/chart-card.html.twig' with { title: title, subtitle: subtitle, icon: icon, iconColor: iconColor, emptyText: emptyText, attr: chartAttr } %} {% block actions %} {% include '_molecules/filter-tabs/filter-tabs.html.twig' with { filters: [ { id: '3', label: '3 mois', attr: periodBtnAttr }, { id: '6', label: '6 mois', attr: periodBtnAttr }, { id: '12', label: '12 mois', attr: periodBtnAttr } ], active: '12', size: 'sm', clientToggle: true } only %} {% endblock %} {% block body %}
{{ emptyText }}