MoviesList.vue 3.07 KB
<script lang="ts" setup>
//#region --import--.
import SearchBar from "~/components/SearchBar.vue";
import { ref } from "vue";
import { useTMDB } from "~/composables/tMDB";
import { Movie } from "~/models/movie";
import { FilmIcon } from "lucide-vue-next";
import type { MovieInterface } from "~/interfaces/movie";
import { useDateFormat } from '@vueuse/core'
//#endregion

//#region --Declaration--.
const { fetchPopularMovies } = useTMDB();
//#endregion

//#region --Data/refs--.
const isInitialLoading = ref(true);
const isLoadingMore = ref(false);
const currentPage = ref(1);
const totalPages = ref(0);
//#endregion

//#region --Computed--.
const movies = computed(() => {
  return useRepo(Movie).all() as unknown as MovieInterface[];
});
//#endregion

//#region --Function--.
/**
 * Fetch popular movies
 * @param page
 */
const fetchMovies = async (page: number) => {
  try {
    isLoadingMore.value = true;
    const data = await fetchPopularMovies(page);
    // Save in Movie model.
    useRepo(Movie).save(data.results);

    totalPages.value = data.total_pages;
    currentPage.value = page;
  } catch (error) {
    console.error("Error fetching popular movies:", error);
  } finally {
    isInitialLoading.value = false;
    isLoadingMore.value = false;
  }
};
//#endregion

//#region --Global event--.
onMounted(() => {
  // Chargement des premiers films.
  fetchMovies(1);
});
//#endregion
</script>

<template>
  <section>
    <h1 class="text-4xl font-bold mb-8 text-center">Découvrez les films populaires</h1>
    <!-- Barre de recherche -->
    <search-bar placeholder="Rechercher un film..." />
    <!-- Loading Skeleton -->
    <skeleton-movies-loader v-if="isInitialLoading" :is-initial-loading="isInitialLoading" :skeleton-number="20" />
    <!-- Liste des films -->
    <div v-else-if="movies.length > 0" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
      <div
        v-for="movie in movies"
        :key="movie.id"
        class="bg-gray-800 rounded-lg overflow-hidden shadow-lg transition-transform duration-300 hover:scale-105 cursor-pointer"
        @click="navigateTo(`/movies/${movie.id}`)"
      >
        <div class="relative pb-[150%]">
          <img
            v-if="movie.poster_path"
            :src="`https://image.tmdb.org/t/p/w500${movie.poster_path}`"
            :alt="movie.title"
            class="absolute inset-0 w-full h-full object-cover"
          >
          <div v-else class="absolute inset-0 w-full h-full bg-gray-700 flex items-center justify-center">
            <FilmIcon :size="48" class="text-gray-500" />
          </div>
          <div
            class="absolute top-2 right-2 bg-primary text-white rounded-full w-10 h-10 flex items-center justify-center font-bold"
          >
            {{ movie.vote_average.toFixed(1) }}
          </div>
        </div>
        <div class="p-4">
          <h2 class="text-lg font-bold mb-1 line-clamp-1">{{ movie.title }}</h2>
          <p class="text-sm text-gray-400">{{ useDateFormat(movie.release_date, 'DD-MM-YYYY') }}</p>
        </div>
      </div>
    </div>
  </section>
</template>

<style scoped></style>