Bruno Predot

Gestion des events search et clear de la searchBar

... ... @@ -6,7 +6,7 @@ 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'
import { useDateFormat } from "@vueuse/core";
//#endregion
//#region --Declaration--.
... ... @@ -26,7 +26,7 @@ const observer = ref<IntersectionObserver | null>(null);
//#region --Computed--.
const movies = computed(() => {
return useRepo(Movie).query().orderBy("popularity", 'desc').get() as unknown as MovieInterface[];
return useRepo(Movie).query().orderBy("popularity", "desc").get() as unknown as MovieInterface[];
});
//#endregion
... ... @@ -40,7 +40,11 @@ const fetchMovies = async (page: number) => {
isLoadingMore.value = true;
const data = await fetchPopularMovies(page);
// Save in Movie model.
isInitialLoading.value ? useRepo(Movie).fresh(data.results) : useRepo(Movie).save(data.results);
if (isInitialLoading.value) {
useRepo(Movie).fresh(data.results);
} else {
useRepo(Movie).save(data.results);
}
totalPages.value = data.total_pages;
currentPage.value = page;
... ... @@ -63,6 +67,15 @@ function createIntersectionObserver() {
{ threshold: 1.0 },
);
}
function handleSearchEvent(event: string) {
console.log(event);
}
function handleClearSearchEvent() {
console.log("clear event");
}
//#endregion
//#region --Global event--.
... ... @@ -94,7 +107,11 @@ onBeforeUnmount(() => {
<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..." />
<search-bar
placeholder="Rechercher un film..."
@event:search="handleSearchEvent"
@event:clear_search="handleClearSearchEvent"
/>
<!-- Loading Skeleton -->
<skeleton-movies-loader v-if="isInitialLoading" :is-initial-loading="isInitialLoading" :skeleton-number="20" />
<!-- Liste des films -->
... ... @@ -108,10 +125,10 @@ onBeforeUnmount(() => {
<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"
:src="`https://image.tmdb.org/t/p/w500${movie.poster_path}`"
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>
... ... @@ -123,13 +140,13 @@ onBeforeUnmount(() => {
</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>
<p class="text-sm text-gray-400">{{ useDateFormat(movie.release_date, "DD-MM-YYYY") }}</p>
</div>
</div>
</div>
<!-- Élément observé pour le défilement infini -->
<div ref="loadMoreTrigger" class="h-10 mt-4"/>
<div ref="loadMoreTrigger" class="h-10 mt-4" />
</section>
</template>
... ...
... ... @@ -2,10 +2,11 @@
//#region --import--.
import { SearchIcon, XIcon } from "lucide-vue-next";
import { ref } from "vue";
import { useDebounceFn } from "@vueuse/core";
//#endregion
//#region --Emits--.
// const emit = defineEmits([]);
const emit = defineEmits(['event:search', 'event:clear_search']);
//#endregion
//#region --Props--.
... ... @@ -22,6 +23,20 @@ defineProps({
//#region --Data/refs--.
const searchQuery = ref("");
//#endregion
//#region --Function--.
/**
* Debounced function
*/
const handleSearchEvent = useDebounceFn(() => {
emit('event:search', searchQuery.value);
}, 500);
function handleClearSearchEvent() {
searchQuery.value = '';
emit('event:clear_search')
}
//#endregion
</script>
<template>
... ... @@ -33,12 +48,12 @@ const searchQuery = ref("");
:placeholder="placeholder"
class="w-full px-4 py-3 bg-gray-800 rounded-full text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-primary"
type="text"
@input="console.log('debouncedSearch à prévoir')"
@input="handleSearchEvent"
/>
<button
v-if="searchQuery"
class="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-white"
@click="console.log('clearSearch à prévoir')"
@click="handleClearSearchEvent"
>
<XIcon :size="20" />
</button>
... ...