Skip to content

Étape 14 – Créer une fiche de détail complète

🎯 Objectifs de l’étape

Dans cette étape, vous allez construire une fiche de détail enrichie pour chaque Pokémon à partir de son identifiant.

Vous apprendrez à :

  • récupérer les données du Pokémon depuis le store,
  • créer deux composants réutilisables (PokemonTypesChips et PokemonStats),
  • afficher une fiche responsive et lisible avec Vuetify.

🧩 Chapitre 1 – Afficher les informations de base

1. Récupérer le Pokémon

Dans src/pages/pokemons/[id]/index.vue :

vue
<script setup>
import { useRoute } from 'vue-router'
import { usePokemonStore } from '@/stores/pokemonStore'

const route = useRoute()
const pokemonStore = usePokemonStore()
const pokemon = pokemonStore.getPokemonById(route.params.id)
</script>

2. Afficher la fiche

Dans le bloc <template> :

vue
<template>
  <v-container v-if="pokemon">
    <v-row class="align-start">
      <v-col cols="12" md="4">
        <v-img
          :src="`/images/${pokemon.img}`"
          :alt="pokemon.name"
          height="300"
          class="rounded"
          contain
        />
      </v-col>

      <v-col cols="12" md="8">
        <h1 class="text-h4 mb-2">{{ pokemon.name }}</h1>
        <p class="text-subtitle-1 mb-2">Niveau : {{ pokemon.level }}</p>

        <!-- Les types et stats seront ajoutés dans les chapitres suivants -->

        <p class="mt-6 text-body-1">{{ pokemon.description }}</p>

        <v-btn
          to="/"
          prepend-icon="mdi-arrow-left"
          class="mt-8"
          color="primary"
          variant="tonal"
        >
          Retour
        </v-btn>
      </v-col>
    </v-row>
  </v-container>

  <v-container v-else>
    <v-alert type="error" class="text-center">
      Pokémon introuvable.
    </v-alert>
  </v-container>
</template>

🧩 Chapitre 2 – Composant PokemonTypesChips

1. Créer le fichier src/components/PokemonTypesChips.vue

vue
<template>
  <!-- Conteneur principal affichant les types d'un Pokémon -->
  <div>
    <!--
    Puce pour chaque type de Pokémon
      * v-for : Parcourt le tableau des types associés au Pokémon pour afficher chaque type sous forme de puce.
      * :key="type.id" : Utilise `type.id` comme clé unique pour optimiser le rendu.
      * class="ma-1" : Ajoute une marge uniforme autour de chaque puce (1 unité).
      * :color : Définit dynamiquement la couleur de la puce à partir de la propriété `color` du type (valeur par défaut : 'grey').
        type?.color : Utilise l'opérateur de coalescence nulle (?) pour fournir une couleur par défaut si `type.color` est indéfini.
        https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing
      * text-color="white" : Rend le texte des puces blanc pour un meilleur contraste.
    -->
    <v-chip
        v-for="type in pokemonTypes"
        :key="type.id"
        class="ma-1"
        :color="type?.color || 'grey'"
        text-color="white"
    >
      <!-- Affiche le nom du type ou "Inconnu" si le type est introuvable -->
      {{ type?.name || 'Inconnu' }}
    </v-chip>
  </div>
</template>

<script setup>
  /*
  Importation des dépendances nécessaires :
  - defineProps : Permet de définir les propriétés reçues par le composant.
  - usePokemonStore : Fournit l'accès au magasin Pinia pour récupérer les données des types.
  */
  import { computed, defineProps } from 'vue'
  import { usePokemonStore } from '@/stores/pokemonStore'

  // Définition des propriétés du composant
  const props = defineProps({
    pokemon: {
      // Objet représentant un Pokémon. Contient un tableau `types` listant les identifiants des types associés.
      type: Object,
      required: true, // Cette propriété est obligatoire pour le bon fonctionnement du composant.
    },
  })

  // Initialisation du magasin Pinia
  const pokemonStore = usePokemonStore()

  /*
Récupération des types associés au Pokémon
  - Utilise computed pour créer une propriété réactive.
    Ainsi, si les types du Pokémon changent, cette propriété sera mise à jour automatiquement.
  - Parcourt les identifiants des types (`props.pokemon.types`) et récupère leurs données depuis le magasin.
  - Fournit un tableau de types avec leurs propriétés (`name`, `color`, etc.).
*/
  const pokemonTypes = computed(() =>
      props.pokemon.types.map(typeId => pokemonStore.getTypeById(typeId))
  )
</script>

2. Intégrer dans la fiche de détail

vue
<script setup>
import PokemonTypesChips from '@/components/PokemonTypesChips.vue'
</script>

Et dans le <template> :

vue
<PokemonTypesChips :pokemon="pokemon" class="mt-4" />

🧩 Chapitre 3 – Composant PokemonStats

1. Créer le fichier src/components/PokemonStats.vue

vue
<template>
  <!-- Conteneur principal des statistiques -->
  <div class="pokemon-stats">
    <!-- Boucle pour afficher chaque statistique avec son titre et sa barre de progression -->
    <v-list-item v-for="(value, key) in stats" :key="key">
      <!-- Affichage du nom de la statistique et de sa valeur -->
      <v-list-item-title>{{ key.toUpperCase() }}: {{ value }}</v-list-item-title>

      <!-- Barre de progression avec couleur directement liée à la statistique -->
      <v-progress-linear
          :color="statColors[key] || 'grey'"
          height="25"
          :model-value="value"
      >
        <strong>{{ value }}</strong>
      </v-progress-linear>
    </v-list-item>
  </div>
</template>

<script setup>
  /**
   * Composant `PokemonStats`
   * Gère l'affichage des statistiques des Pokémon avec des barres de progression colorées.
   */

  // Propriétés (props) du composant
  defineProps({
    stats: {
      type: Object, // Objet contenant les statistiques (par ex. : { hp: 45, attack: 60 }).
      required: true, // Les statistiques sont nécessaires pour ce composant.
    },
  })

  /**
   * Couleurs associées aux statistiques des Pokémon.
   * Ces couleurs sont utilisées directement dans le template.
   */
  const statColors = {
    hp: '#FF5959', // Rouge doux pour la santé.
    attack: '#C03028', // Rouge sombre pour l'attaque.
    defense: '#6890F0', // Bleu clair pour la défense.
    speed: '#F08030', // Orange vif pour la vitesse.
  }
</script>

<style scoped>
  /* Styles locaux pour améliorer la présentation */
  .pokemon-stats {
    margin-top: 1rem; /* Ajout d'espace au-dessus du conteneur */
  }

  .v-list-item {
    margin-bottom: 1rem; /* Ajout d'espace entre les statistiques */
  }
</style>

2. Intégrer dans la fiche de détail

vue
<script setup>
import PokemonStats from '@/components/PokemonStats.vue'
</script>

Et dans le <template> :

vue
<PokemonStats :stats="pokemon.stats" class="mt-6" />

✅ Résultat final

Vous avez maintenant une fiche de détail complète avec :

  • image, nom, niveau, description,
  • les types sous forme de chips,
  • les statistiques avec barres de progression.

✅ Résultat final

Vous avez maintenant une fiche de détail complète avec :

  • l’image du Pokémon,
  • son nom, son niveau et sa description,
  • ses types affichés sous forme de chips colorées,
  • ses statistiques illustrées avec des barres de progression.

Cette fiche est responsive et lisible sur mobile comme sur ordinateur.

📦 Composants Vuetify utilisés

ComposantRôle
v-imgAffiche l’image du Pokémon
v-containerStructure générale de la page
v-row, v-colGrille responsive pour organiser les colonnes
v-alertAffiche un message si le Pokémon est introuvable
v-btnBouton pour revenir à l’accueil
v-chipAffiche les types du Pokémon
v-progress-linearReprésente visuellement les statistiques numériques

🧪 Tests à effectuer

  1. Naviguez vers différentes URLs de type /pokemons/:id dans le navigateur.
  2. Vérifiez que l’image, le nom, le niveau, la description, les types et les stats s’affichent correctement.
  3. Essayez une URL invalide (ex. /pokemons/xyz) et assurez-vous que le message d’erreur s’affiche.
  4. Cliquez sur le bouton Retour pour revenir à la page d’accueil sans erreur.

📘 Documentation utile