Showing
7 changed files
with
75 additions
and
145 deletions
@@ -38,20 +38,13 @@ async function fetchMovies(page: number) { | @@ -38,20 +38,13 @@ async function fetchMovies(page: number) { | ||
38 | try { | 38 | try { |
39 | isLoadingMore.value = true; | 39 | isLoadingMore.value = true; |
40 | const data = await fetchPopularMovies(page); | 40 | const data = await fetchPopularMovies(page); |
41 | - // Save in Movie model. | 41 | + // Save in Movie model. If first fetch, erase old data before save or, add to store collection. |
42 | - if (isInitialLoading.value) { | 42 | + isInitialLoading.value ? useRepo(Movie).fresh(data.results) : useRepo(Movie).save(data.results); |
43 | - // First fetch, erase old data before save. | ||
44 | - useRepo(Movie).fresh(data.results); | ||
45 | - } | ||
46 | - else { | ||
47 | - // Add to store collection. | ||
48 | - useRepo(Movie).save(data.results); | ||
49 | - } | ||
50 | totalPages.value = data.total_pages; | 43 | totalPages.value = data.total_pages; |
51 | currentPage.value = page; | 44 | currentPage.value = page; |
52 | } | 45 | } |
53 | catch (error) { | 46 | catch (error) { |
54 | - console.error("Error fetching popular movies:", error); | 47 | + throw new Error(`Error fetching popular movies: ${error}`); |
55 | } | 48 | } |
56 | finally { | 49 | finally { |
57 | isInitialLoading.value = false; | 50 | isInitialLoading.value = false; |
@@ -72,24 +65,16 @@ async function search(query: string, page: number) { | @@ -72,24 +65,16 @@ async function search(query: string, page: number) { | ||
72 | } | 65 | } |
73 | try { | 66 | try { |
74 | isLoadingMore.value = true; | 67 | isLoadingMore.value = true; |
75 | - if (page === 1) { | 68 | + if (page === 1) isInitialLoading.value = true; |
76 | - isInitialLoading.value = true; | ||
77 | - } | ||
78 | const data = await searchMovies(query, page); | 69 | const data = await searchMovies(query, page); |
79 | - // Save in Movie model. | 70 | + |
80 | - if (isInitialLoading.value) { | 71 | + // Save in Movie model. If first fetch, erase old data before save or, add to store collection. |
81 | - // First fetch, erase old data before save. | 72 | + isInitialLoading.value ? useRepo(Movie).fresh(data.results) : useRepo(Movie).save(data.results); |
82 | - useRepo(Movie).fresh(data.results); | ||
83 | - } | ||
84 | - else { | ||
85 | - // Add to store collection. | ||
86 | - useRepo(Movie).save(data.results); | ||
87 | - } | ||
88 | totalPages.value = data.total_pages; | 73 | totalPages.value = data.total_pages; |
89 | currentPage.value = page; | 74 | currentPage.value = page; |
90 | } | 75 | } |
91 | catch (error) { | 76 | catch (error) { |
92 | - console.error("Error searching movies:", error); | 77 | + throw new Error(`Error searching movies: ${error}`); |
93 | } | 78 | } |
94 | finally { | 79 | finally { |
95 | isInitialLoading.value = false; | 80 | isInitialLoading.value = false; |
@@ -101,16 +86,8 @@ function createIntersectionObserver() { | @@ -101,16 +86,8 @@ function createIntersectionObserver() { | ||
101 | return new IntersectionObserver( | 86 | return new IntersectionObserver( |
102 | (entries) => { | 87 | (entries) => { |
103 | const [entry] = entries; | 88 | const [entry] = entries; |
104 | - if (entry.isIntersecting && !isLoadingMore.value && currentPage.value < totalPages.value) { | 89 | + // Continue searching query if already active or, continue fetching popular movies. |
105 | - if (searchQuery.value) { | 90 | + if (entry.isIntersecting && !isLoadingMore.value && currentPage.value < totalPages.value) searchQuery.value ? search(searchQuery.value, currentPage.value + 1) : fetchMovies(currentPage.value + 1); |
106 | - // Continue searching query if already active. | ||
107 | - search(searchQuery.value, currentPage.value + 1); | ||
108 | - } | ||
109 | - else { | ||
110 | - // Continue fetching popular movies. | ||
111 | - fetchMovies(currentPage.value + 1); | ||
112 | - } | ||
113 | - } | ||
114 | }, | 91 | }, |
115 | { threshold: 1.0 }, | 92 | { threshold: 1.0 }, |
116 | ); | 93 | ); |
@@ -137,21 +114,15 @@ onMounted(() => { | @@ -137,21 +114,15 @@ onMounted(() => { | ||
137 | fetchMovies(1); | 114 | fetchMovies(1); |
138 | // Création et stockage dans la ref de l'instance IntersectionObserver. | 115 | // Création et stockage dans la ref de l'instance IntersectionObserver. |
139 | observer.value = createIntersectionObserver(); | 116 | observer.value = createIntersectionObserver(); |
140 | - if (loadMoreTrigger.value) { | 117 | + // Début d'observation de la div pour le défilement infini. |
141 | - // Début d'observation de la div pour le défilement infini. | 118 | + if (loadMoreTrigger.value) observer.value.observe(loadMoreTrigger.value); |
142 | - observer.value.observe(loadMoreTrigger.value); | ||
143 | - } | ||
144 | 119 | ||
145 | - if (loadMoreTrigger.value) { | 120 | + if (loadMoreTrigger.value) observer.value.observe(loadMoreTrigger.value); |
146 | - observer.value.observe(loadMoreTrigger.value); | ||
147 | - } | ||
148 | }); | 121 | }); |
149 | 122 | ||
150 | onBeforeUnmount(() => { | 123 | onBeforeUnmount(() => { |
151 | // Disconnect the observer when the component is unmounted. | 124 | // Disconnect the observer when the component is unmounted. |
152 | - if (observer.value) { | 125 | + if (observer.value) observer.value.disconnect(); |
153 | - observer.value.disconnect(); | ||
154 | - } | ||
155 | }); | 126 | }); |
156 | // #endregion | 127 | // #endregion |
157 | </script> | 128 | </script> |
@@ -13,9 +13,7 @@ defineProps<{ | @@ -13,9 +13,7 @@ defineProps<{ | ||
13 | * @param count | 13 | * @param count |
14 | */ | 14 | */ |
15 | function formatVoteCount(count: number) { | 15 | function formatVoteCount(count: number) { |
16 | - if (count >= 1000) { | 16 | + if (count >= 1000) return `${(count / 1000).toFixed(1)}k votes`; |
17 | - return `${(count / 1000).toFixed(1)}k votes`; | ||
18 | - } | ||
19 | return `${count} votes`; | 17 | return `${count} votes`; |
20 | } | 18 | } |
21 | // #endregion | 19 | // #endregion |
@@ -117,9 +117,7 @@ function handleMessageEvent(event: string) { | @@ -117,9 +117,7 @@ function handleMessageEvent(event: string) { | ||
117 | @click=" | 117 | @click=" |
118 | async () => { | 118 | async () => { |
119 | const validForm = await v$.$validate(); | 119 | const validForm = await v$.$validate(); |
120 | - if (validForm) { | 120 | + if (validForm) submitComment(); |
121 | - submitComment(); | ||
122 | - } | ||
123 | } | 121 | } |
124 | " | 122 | " |
125 | > | 123 | > |
@@ -69,9 +69,7 @@ watch(content, (newValue) => { | @@ -69,9 +69,7 @@ watch(content, (newValue) => { | ||
69 | watch( | 69 | watch( |
70 | () => props.modelValue, | 70 | () => props.modelValue, |
71 | (newValue) => { | 71 | (newValue) => { |
72 | - if (newValue !== content.value) { | 72 | + if (newValue !== content.value) content.value = newValue; |
73 | - content.value = newValue; | ||
74 | - } | ||
75 | }, | 73 | }, |
76 | ); | 74 | ); |
77 | // #endregion | 75 | // #endregion |
@@ -12,15 +12,11 @@ export function useTMDB() { | @@ -12,15 +12,11 @@ export function useTMDB() { | ||
12 | const fetchPopularMovies = async (page: number) => { | 12 | const fetchPopularMovies = async (page: number) => { |
13 | try { | 13 | try { |
14 | const response = await fetch(`${apiUrl}/movie/popular?api_key=${apiKey}&language=fr-FR&page=${page}`); | 14 | const response = await fetch(`${apiUrl}/movie/popular?api_key=${apiKey}&language=fr-FR&page=${page}`); |
15 | - if (!response.ok) { | 15 | + if (!response.ok) throw new Error("An error occurred when fetching popular movies"); |
16 | - console.error("An error occurred when fetching popular movies:"); | 16 | + return await response.json(); |
17 | - } | ||
18 | - else { | ||
19 | - return await response.json(); | ||
20 | - } | ||
21 | } | 17 | } |
22 | catch (error) { | 18 | catch (error) { |
23 | - console.error("Error fetching popular movies:", error); | 19 | + throw new Error(`Error fetching popular movies: ${error}`); |
24 | } | 20 | } |
25 | }; | 21 | }; |
26 | 22 | ||
@@ -34,15 +30,11 @@ export function useTMDB() { | @@ -34,15 +30,11 @@ export function useTMDB() { | ||
34 | const response = await fetch( | 30 | const response = await fetch( |
35 | `${apiUrl}/search/movie?api_key=${apiKey}&language=fr-FR&query=${encodeURIComponent(query)}&page=${page}`, | 31 | `${apiUrl}/search/movie?api_key=${apiKey}&language=fr-FR&query=${encodeURIComponent(query)}&page=${page}`, |
36 | ); | 32 | ); |
37 | - if (!response.ok) { | 33 | + if (!response.ok) throw new Error("An error occurred when searching movies"); |
38 | - console.error("An error occurred when searching movies:"); | 34 | + return await response.json(); |
39 | - } | ||
40 | - else { | ||
41 | - return await response.json(); | ||
42 | - } | ||
43 | } | 35 | } |
44 | catch (error) { | 36 | catch (error) { |
45 | - console.error("Error searching movies:", error); | 37 | + throw new Error(`Error searching movies: ${error}`); |
46 | } | 38 | } |
47 | }; | 39 | }; |
48 | 40 | ||
@@ -53,15 +45,11 @@ export function useTMDB() { | @@ -53,15 +45,11 @@ export function useTMDB() { | ||
53 | const fetchMovieDetails = async (id: number | string) => { | 45 | const fetchMovieDetails = async (id: number | string) => { |
54 | try { | 46 | try { |
55 | const response = await fetch(`${apiUrl}/movie/${id}?api_key=${apiKey}&language=fr-FR`); | 47 | const response = await fetch(`${apiUrl}/movie/${id}?api_key=${apiKey}&language=fr-FR`); |
56 | - if (!response.ok) { | 48 | + if (!response.ok) throw new Error("An error occurred when fetching movie details"); |
57 | - console.error("An error occurred when fetching movie details:"); | 49 | + return await response.json(); |
58 | - } | ||
59 | - else { | ||
60 | - return await response.json(); | ||
61 | - } | ||
62 | } | 50 | } |
63 | catch (error) { | 51 | catch (error) { |
64 | - console.error("Error fetching details:", error); | 52 | + throw new Error(`Error fetching details: ${error}`); |
65 | } | 53 | } |
66 | }; | 54 | }; |
67 | 55 | ||
@@ -71,15 +59,11 @@ export function useTMDB() { | @@ -71,15 +59,11 @@ export function useTMDB() { | ||
71 | const fetchMovieCredits = async (id: number | string) => { | 59 | const fetchMovieCredits = async (id: number | string) => { |
72 | try { | 60 | try { |
73 | const response = await fetch(`${apiUrl}/movie/${id}/credits?api_key=${apiKey}&language=fr-FR`); | 61 | const response = await fetch(`${apiUrl}/movie/${id}/credits?api_key=${apiKey}&language=fr-FR`); |
74 | - if (!response.ok) { | 62 | + if (!response.ok) throw new Error("An error occurred when fetching movie credits"); |
75 | - console.error("An error occurred when fetching movie credits:"); | 63 | + return await response.json(); |
76 | - } | ||
77 | - else { | ||
78 | - return await response.json(); | ||
79 | - } | ||
80 | } | 64 | } |
81 | catch (error) { | 65 | catch (error) { |
82 | - console.error("Error fetching movie credits:", error); | 66 | + throw new Error(`Error fetching movie credits: ${error}`); |
83 | } | 67 | } |
84 | }; | 68 | }; |
85 | 69 |
1 | import antfu from "@antfu/eslint-config"; | 1 | import antfu from "@antfu/eslint-config"; |
2 | 2 | ||
3 | export default antfu({ | 3 | export default antfu({ |
4 | -// Type of the project. 'lib' for libraries, the default is 'app' | 4 | + // `.eslintignore` is no longer supported in Flat config, use `ignores` instead. |
5 | - type: "app", | 5 | + ignores: [ |
6 | + "**/fixtures", | ||
7 | + "**/.cache", | ||
8 | + "**/.data", | ||
9 | + "**/.gitignore", | ||
10 | + "**/.env", | ||
11 | + "**/.env.dist", | ||
12 | + "**/.output", | ||
13 | + "**/.nitro", | ||
14 | + "**/.nuxt", | ||
15 | + "**/assets", | ||
16 | + "**/dist", | ||
17 | + "**/logs", | ||
18 | + "**/node_modules", | ||
19 | + "**/public", | ||
20 | + "**/server", | ||
21 | + ], | ||
6 | 22 | ||
23 | + // Disable jsonc and yaml support. | ||
24 | + jsonc: false, | ||
25 | + markdown: false, | ||
26 | + | ||
27 | + // personnal rules. | ||
7 | rules: { | 28 | rules: { |
8 | "antfu/if-newline": 0, | 29 | "antfu/if-newline": 0, |
9 | "antfu/curly": 0, | 30 | "antfu/curly": 0, |
10 | }, | 31 | }, |
11 | 32 | ||
12 | - // Enable stylistic formatting rules | 33 | + // Enable stylistic formatting rules. |
13 | // stylistic: true, | 34 | // stylistic: true, |
14 | - | 35 | + // Or customize the stylistic rules. |
15 | - // Or customize the stylistic rules | ||
16 | stylistic: { | 36 | stylistic: { |
17 | indent: 2, // 4, or 'tab' | 37 | indent: 2, // 4, or 'tab' |
18 | semi: true, | 38 | semi: true, |
19 | stylistic: true, | 39 | stylistic: true, |
20 | - quotes: "double", // 'single' or 'double' | 40 | + quotes: "double", // 'single' or 'double'. |
21 | }, | 41 | }, |
22 | 42 | ||
43 | + // Type of the project. 'lib' for libraries, the default is 'app'. | ||
44 | + type: "app", | ||
45 | + | ||
23 | // TypeScript and Vue are autodetected, you can also explicitly enable them: | 46 | // TypeScript and Vue are autodetected, you can also explicitly enable them: |
24 | typescript: true, | 47 | typescript: true, |
25 | vue: true, | 48 | vue: true, |
26 | 49 | ||
27 | - // Disable jsonc and yaml support | ||
28 | - jsonc: false, | ||
29 | - markdown: false, | ||
30 | yaml: false, | 50 | yaml: false, |
31 | - | ||
32 | - // `.eslintignore` is no longer supported in Flat config, use `ignores` instead | ||
33 | - ignores: [ | ||
34 | - "**/fixtures", | ||
35 | - "**/.cache", | ||
36 | - "**/.data", | ||
37 | - "**/.gitignore", | ||
38 | - "**/.env", | ||
39 | - "**/.env.dist", | ||
40 | - "**/.output", | ||
41 | - "**/.nitro", | ||
42 | - "**/.nuxt", | ||
43 | - "**/assets", | ||
44 | - "**/dist", | ||
45 | - "**/logs", | ||
46 | - "**/node_modules", | ||
47 | - "**/public", | ||
48 | - "**/server", | ||
49 | - ], | ||
50 | }); | 51 | }); |
51 | 52 | ||
52 | -// Ancienne config eslint. | 53 | +// Last eslint config. |
53 | // import withNuxt from "./.nuxt/eslint.config.mjs"; | 54 | // import withNuxt from "./.nuxt/eslint.config.mjs"; |
54 | // import js from "@eslint/js"; | 55 | // import js from "@eslint/js"; |
55 | // import eslintPluginVue from "eslint-plugin-vue"; | 56 | // import eslintPluginVue from "eslint-plugin-vue"; |
@@ -27,47 +27,28 @@ const isSubmitting = ref(false); | @@ -27,47 +27,28 @@ const isSubmitting = ref(false); | ||
27 | 27 | ||
28 | // #region --Computed--. | 28 | // #region --Computed--. |
29 | const movieId = computed(() => { | 29 | const movieId = computed(() => { |
30 | - if (currentRoute.value.params.id) { | 30 | + if (!currentRoute.value.params.id) return null; |
31 | - if (typeof currentRoute.value.params.id === "string") { | 31 | + if (typeof currentRoute.value.params.id !== "string") return null; |
32 | - if (typeof Number(+currentRoute.value.params.id) === "number") { | 32 | + |
33 | - return +currentRoute.value.params.id as number; | 33 | + if (typeof Number(+currentRoute.value.params.id) === "number") return +currentRoute.value.params.id as number; |
34 | - } | 34 | + return currentRoute.value.params.id as string; |
35 | - else { | ||
36 | - return currentRoute.value.params.id as string; | ||
37 | - } | ||
38 | - } | ||
39 | - else { | ||
40 | - return null; | ||
41 | - } | ||
42 | - } | ||
43 | - else { | ||
44 | - return null; | ||
45 | - } | ||
46 | }); | 35 | }); |
47 | 36 | ||
48 | const movie = computed(() => { | 37 | const movie = computed(() => { |
49 | - if (unref(movieId)) { | 38 | + if (!unref(movieId)) return null; |
50 | - return useRepo(Movie) | 39 | + return useRepo(Movie) |
51 | - .query() | 40 | + .query() |
52 | - .where("id", movieId.value as WhereSecondaryClosure<never> | null | undefined) | 41 | + .where("id", movieId.value as WhereSecondaryClosure<never> | null | undefined) |
53 | - .withAll() | 42 | + .withAll() |
54 | - .first() as unknown as MovieInterface; | 43 | + .first() as unknown as MovieInterface; |
55 | - } | ||
56 | - else { | ||
57 | - return null; | ||
58 | - } | ||
59 | }); | 44 | }); |
60 | 45 | ||
61 | /** | 46 | /** |
62 | * Computed property for director | 47 | * Computed property for director |
63 | */ | 48 | */ |
64 | const director = computed(() => { | 49 | const director = computed(() => { |
65 | - if (unref(movie)?.credit?.crew) { | 50 | + if (!unref(movie)?.credit?.crew) return null; |
66 | - return movie.value?.credit.crew.find(person => person.job === "Director"); | 51 | + return movie.value?.credit.crew.find(person => person.job === "Director"); |
67 | - } | ||
68 | - else { | ||
69 | - return null; | ||
70 | - } | ||
71 | }); | 52 | }); |
72 | 53 | ||
73 | /** | 54 | /** |
@@ -98,7 +79,7 @@ async function fetchDetails(id: number | string) { | @@ -98,7 +79,7 @@ async function fetchDetails(id: number | string) { | ||
98 | useRepo(Movie).save(data); | 79 | useRepo(Movie).save(data); |
99 | } | 80 | } |
100 | catch (error) { | 81 | catch (error) { |
101 | - console.error("Error fetching movie details:", error); | 82 | + throw new Error(`Error fetching movie details: ${error}`); |
102 | } | 83 | } |
103 | finally { | 84 | finally { |
104 | isLoading.value = false; | 85 | isLoading.value = false; |
@@ -110,8 +91,7 @@ async function fetchDetails(id: number | string) { | @@ -110,8 +91,7 @@ async function fetchDetails(id: number | string) { | ||
110 | * @param minutes | 91 | * @param minutes |
111 | */ | 92 | */ |
112 | function formatRuntime(minutes: number) { | 93 | function formatRuntime(minutes: number) { |
113 | - if (!minutes) | 94 | + if (!minutes) return "Durée inconnue"; |
114 | - return "Durée inconnue"; | ||
115 | // Find nb hours. | 95 | // Find nb hours. |
116 | const hours = Math.floor(minutes / 60); | 96 | const hours = Math.floor(minutes / 60); |
117 | // Find last minutes. | 97 | // Find last minutes. |
@@ -128,7 +108,7 @@ async function fetchCredits(id: number | string) { | @@ -128,7 +108,7 @@ async function fetchCredits(id: number | string) { | ||
128 | useRepo(Credit).save(data); | 108 | useRepo(Credit).save(data); |
129 | } | 109 | } |
130 | catch (error) { | 110 | catch (error) { |
131 | - console.error("Error fetching movie credits:", error); | 111 | + throw new Error(`Error fetching movie credits: ${error}`); |
132 | } | 112 | } |
133 | } | 113 | } |
134 | 114 |
-
Please register or login to post a comment