Bruno Predot

Factorisation en incluant les guards clauses et ternaires.

@@ -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) {  
141 // Début d'observation de la div pour le défilement infini. 117 // Début d'observation de la div pour le défilement infini.
142 - observer.value.observe(loadMoreTrigger.value); 118 + if (loadMoreTrigger.value) 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:");  
17 - }  
18 - else {  
19 return await response.json(); 16 return await response.json();
20 } 17 }
21 - }  
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:");  
39 - }  
40 - else {  
41 return await response.json(); 34 return await response.json();
42 } 35 }
43 - }  
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:");  
58 - }  
59 - else {  
60 return await response.json(); 49 return await response.json();
61 } 50 }
62 - }  
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:");  
76 - }  
77 - else {  
78 return await response.json(); 63 return await response.json();
79 } 64 }
80 - }  
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 - }  
35 - else {  
36 return currentRoute.value.params.id as string; 34 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