Bruno Predot

lintfix selon les règles de @antfu/eslint-config.

1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -//#region --Props--. 2 +import type { MovieInterface } from "~/interfaces/movie";
  3 +// #region --Props--.
3 import { useDateFormat } from "@vueuse/core"; 4 import { useDateFormat } from "@vueuse/core";
4 import { FilmIcon } from "lucide-vue-next"; 5 import { FilmIcon } from "lucide-vue-next";
5 -import type { MovieInterface } from "~/interfaces/movie"; 6 +// #endregion
6 -//#endregion  
7 7
8 -//#region --Props--. 8 +// #region --Props--.
9 /** Typescript typage */ 9 /** Typescript typage */
10 defineProps<{ 10 defineProps<{
11 movie: MovieInterface; 11 movie: MovieInterface;
@@ -18,7 +18,7 @@ defineProps<{ @@ -18,7 +18,7 @@ defineProps<{
18 // nullable: false, 18 // nullable: false,
19 // }, 19 // },
20 // }); 20 // });
21 -//#endregion 21 +// #endregion
22 </script> 22 </script>
23 23
24 <template> 24 <template>
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -//#region --Import--. 2 +// #region --Import--.
3 import type { MovieCommentInterface } from "~/interfaces/movieComment"; 3 import type { MovieCommentInterface } from "~/interfaces/movieComment";
4 import { MessageSquareIcon } from "lucide-vue-next"; 4 import { MessageSquareIcon } from "lucide-vue-next";
5 -//#endregion 5 +// #endregion
6 6
7 -//#region --Props--. 7 +// #region --Props--.
8 /** Typescript typage */ 8 /** Typescript typage */
9 const props = defineProps<{ 9 const props = defineProps<{
10 comments: Array<MovieCommentInterface>; 10 comments: Array<MovieCommentInterface>;
@@ -17,9 +17,9 @@ const props = defineProps<{ @@ -17,9 +17,9 @@ const props = defineProps<{
17 // nullable: false, 17 // nullable: false,
18 // }, 18 // },
19 // }); 19 // });
20 -//#endregion 20 +// #endregion
21 21
22 -//#region --Watch--. 22 +// #region --Watch--.
23 watch( 23 watch(
24 () => props.comments, 24 () => props.comments,
25 (comments) => { 25 (comments) => {
@@ -34,7 +34,7 @@ watch( @@ -34,7 +34,7 @@ watch(
34 }, 34 },
35 { immediate: true }, 35 { immediate: true },
36 ); 36 );
37 -//#endregion 37 +// #endregion
38 </script> 38 </script>
39 39
40 <template> 40 <template>
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -//#region --import--. 2 +import type { MovieInterface } from "~/interfaces/movie";
  3 +import { SearchXIcon } from "lucide-vue-next";
  4 +// #region --import--.
3 import { onBeforeUnmount, ref } from "vue"; 5 import { onBeforeUnmount, ref } from "vue";
4 import { useTMDB } from "~/composables/tMDB"; 6 import { useTMDB } from "~/composables/tMDB";
5 import { Movie } from "~/models/movie"; 7 import { Movie } from "~/models/movie";
6 -import { SearchXIcon } from "lucide-vue-next"; 8 +// #endregion
7 -import type { MovieInterface } from "~/interfaces/movie";  
8 -//#endregion  
9 9
10 -//#region --Declaration--. 10 +// #region --Declaration--.
11 const { fetchPopularMovies, searchMovies } = useTMDB(); 11 const { fetchPopularMovies, searchMovies } = useTMDB();
12 -//#endregion 12 +// #endregion
13 13
14 -//#region --Data/refs--. 14 +// #region --Data/refs--.
15 const isInitialLoading = ref(true); 15 const isInitialLoading = ref(true);
16 const isLoadingMore = ref(false); 16 const isLoadingMore = ref(false);
17 const currentPage = ref(1); 17 const currentPage = ref(1);
@@ -21,20 +21,20 @@ const searchQuery = ref(""); @@ -21,20 +21,20 @@ const searchQuery = ref("");
21 const loadMoreTrigger = ref<HTMLElement | null>(null); 21 const loadMoreTrigger = ref<HTMLElement | null>(null);
22 /** Instance de IntersectionObserver */ 22 /** Instance de IntersectionObserver */
23 const observer = ref<IntersectionObserver | null>(null); 23 const observer = ref<IntersectionObserver | null>(null);
24 -//#endregion 24 +// #endregion
25 25
26 -//#region --Computed--. 26 +// #region --Computed--.
27 const movies = computed(() => { 27 const movies = computed(() => {
28 return useRepo(Movie).query().orderBy("popularity", "desc").get() as unknown as MovieInterface[]; 28 return useRepo(Movie).query().orderBy("popularity", "desc").get() as unknown as MovieInterface[];
29 }); 29 });
30 -//#endregion 30 +// #endregion
31 31
32 -//#region --Function--. 32 +// #region --Function--.
33 /** 33 /**
34 * Fetch popular movies 34 * Fetch popular movies
35 * @param page 35 * @param page
36 */ 36 */
37 -const fetchMovies = async (page: number) => { 37 +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);
@@ -42,26 +42,29 @@ const fetchMovies = async (page: number) => { @@ -42,26 +42,29 @@ const fetchMovies = async (page: number) => {
42 if (isInitialLoading.value) { 42 if (isInitialLoading.value) {
43 // First fetch, erase old data before save. 43 // First fetch, erase old data before save.
44 useRepo(Movie).fresh(data.results); 44 useRepo(Movie).fresh(data.results);
45 - } else { 45 + }
  46 + else {
46 // Add to store collection. 47 // Add to store collection.
47 useRepo(Movie).save(data.results); 48 useRepo(Movie).save(data.results);
48 } 49 }
49 totalPages.value = data.total_pages; 50 totalPages.value = data.total_pages;
50 currentPage.value = page; 51 currentPage.value = page;
51 - } catch (error) { 52 + }
  53 + catch (error) {
52 console.error("Error fetching popular movies:", error); 54 console.error("Error fetching popular movies:", error);
53 - } finally { 55 + }
  56 + finally {
54 isInitialLoading.value = false; 57 isInitialLoading.value = false;
55 isLoadingMore.value = false; 58 isLoadingMore.value = false;
56 } 59 }
57 -}; 60 +}
58 61
59 /** 62 /**
60 * Search movies 63 * Search movies
61 * @param query 64 * @param query
62 * @param page 65 * @param page
63 */ 66 */
64 -const search = async (query: string, page: number) => { 67 +async function search(query: string, page: number) {
65 // If empty search, fetch popular movies. 68 // If empty search, fetch popular movies.
66 if (!query.trim()) { 69 if (!query.trim()) {
67 await fetchMovies(1); 70 await fetchMovies(1);
@@ -77,19 +80,22 @@ const search = async (query: string, page: number) => { @@ -77,19 +80,22 @@ const search = async (query: string, page: number) => {
77 if (isInitialLoading.value) { 80 if (isInitialLoading.value) {
78 // First fetch, erase old data before save. 81 // First fetch, erase old data before save.
79 useRepo(Movie).fresh(data.results); 82 useRepo(Movie).fresh(data.results);
80 - } else { 83 + }
  84 + else {
81 // Add to store collection. 85 // Add to store collection.
82 useRepo(Movie).save(data.results); 86 useRepo(Movie).save(data.results);
83 } 87 }
84 totalPages.value = data.total_pages; 88 totalPages.value = data.total_pages;
85 currentPage.value = page; 89 currentPage.value = page;
86 - } catch (error) { 90 + }
  91 + catch (error) {
87 console.error("Error searching movies:", error); 92 console.error("Error searching movies:", error);
88 - } finally { 93 + }
  94 + finally {
89 isInitialLoading.value = false; 95 isInitialLoading.value = false;
90 isLoadingMore.value = false; 96 isLoadingMore.value = false;
91 } 97 }
92 -}; 98 +}
93 99
94 function createIntersectionObserver() { 100 function createIntersectionObserver() {
95 return new IntersectionObserver( 101 return new IntersectionObserver(
@@ -99,7 +105,8 @@ function createIntersectionObserver() { @@ -99,7 +105,8 @@ function createIntersectionObserver() {
99 if (searchQuery.value) { 105 if (searchQuery.value) {
100 // Continue searching query if already active. 106 // Continue searching query if already active.
101 search(searchQuery.value, currentPage.value + 1); 107 search(searchQuery.value, currentPage.value + 1);
102 - } else { 108 + }
  109 + else {
103 // Continue fetching popular movies. 110 // Continue fetching popular movies.
104 fetchMovies(currentPage.value + 1); 111 fetchMovies(currentPage.value + 1);
105 } 112 }
@@ -122,9 +129,9 @@ function handleClearSearchEvent() { @@ -122,9 +129,9 @@ function handleClearSearchEvent() {
122 fetchMovies(1); 129 fetchMovies(1);
123 } 130 }
124 131
125 -//#endregion 132 +// #endregion
126 133
127 -//#region --Global event--. 134 +// #region --Global event--.
128 onMounted(() => { 135 onMounted(() => {
129 // First loading. 136 // First loading.
130 fetchMovies(1); 137 fetchMovies(1);
@@ -146,7 +153,7 @@ onBeforeUnmount(() => { @@ -146,7 +153,7 @@ onBeforeUnmount(() => {
146 observer.value.disconnect(); 153 observer.value.disconnect();
147 } 154 }
148 }); 155 });
149 -//#endregion 156 +// #endregion
150 </script> 157 </script>
151 158
152 <template> 159 <template>
@@ -157,8 +164,8 @@ onBeforeUnmount(() => { @@ -157,8 +164,8 @@ onBeforeUnmount(() => {
157 <!-- Barre de recherche --> 164 <!-- Barre de recherche -->
158 <ui-components-search-bar 165 <ui-components-search-bar
159 placeholder="Rechercher un film..." 166 placeholder="Rechercher un film..."
160 - @event:search="handleSearchEvent" 167 + @event-search="handleSearchEvent"
161 - @event:clear_search="handleClearSearchEvent" 168 + @event-clear-search="handleClearSearchEvent"
162 /> 169 />
163 170
164 <!-- Loading Skeleton --> 171 <!-- Loading Skeleton -->
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -//#region --Import--. 2 +// #region --Import--.
3 import type { Genre } from "~/interfaces/movie"; 3 import type { Genre } from "~/interfaces/movie";
4 -//#endregion 4 +// #endregion
5 5
6 -//#region --Props--. 6 +// #region --Props--.
7 defineProps({ 7 defineProps({
8 genres: { 8 genres: {
9 type: Array<Genre>, 9 type: Array<Genre>,
@@ -11,7 +11,7 @@ defineProps({ @@ -11,7 +11,7 @@ defineProps({
11 nullable: false, 11 nullable: false,
12 }, 12 },
13 }); 13 });
14 -//#endregion 14 +// #endregion
15 </script> 15 </script>
16 16
17 <template> 17 <template>
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -//#region --Props--. 2 +// #region --Props--.
3 /** Typescript typage */ 3 /** Typescript typage */
4 defineProps<{ 4 defineProps<{
5 score: number; 5 score: number;
@@ -18,20 +18,20 @@ defineProps<{ @@ -18,20 +18,20 @@ defineProps<{
18 // nullable: false, 18 // nullable: false,
19 // }, 19 // },
20 // }); 20 // });
21 -//#endregion 21 +// #endregion
22 22
23 -//#region --Function--. 23 +// #region --Function--.
24 /** 24 /**
25 * Format vote count if > 1000. 25 * Format vote count if > 1000.
26 * @param count 26 * @param count
27 */ 27 */
28 -const formatVoteCount = (count: number) => { 28 +function formatVoteCount(count: number) {
29 if (count >= 1000) { 29 if (count >= 1000) {
30 return `${(count / 1000).toFixed(1)}k votes`; 30 return `${(count / 1000).toFixed(1)}k votes`;
31 } 31 }
32 return `${count} votes`; 32 return `${count} votes`;
33 -}; 33 +}
34 -//#endregion 34 +// #endregion
35 </script> 35 </script>
36 36
37 <template> 37 <template>
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -//#region --Import--. 2 +import type { Comment } from "~/type/commentForm";
  3 +// #region --Import--.
3 import { useVuelidate } from "@vuelidate/core"; 4 import { useVuelidate } from "@vuelidate/core";
4 import { helpers, maxLength, maxValue, minLength, minValue, required } from "@vuelidate/validators"; 5 import { helpers, maxLength, maxValue, minLength, minValue, required } from "@vuelidate/validators";
5 -import type { Comment } from "~/type/commentForm"; 6 +// #endregion
6 -//#endregion  
7 7
8 -//#region --Emit--. 8 +// #region --Props--.
9 -const emit = defineEmits(["event:submit"]);  
10 -//#endregion  
11 -  
12 -//#region --Props--.  
13 defineProps({ 9 defineProps({
14 isSubmitting: { 10 isSubmitting: {
15 type: Boolean, 11 type: Boolean,
@@ -18,9 +14,13 @@ defineProps({ @@ -18,9 +14,13 @@ defineProps({
18 default: false, 14 default: false,
19 }, 15 },
20 }); 16 });
21 -//#endregion 17 +// #endregion
  18 +
  19 +// #region --Emit--.
  20 +const emit = defineEmits(["eventSubmit"]);
  21 +// #endregion
22 22
23 -//#region --Data/ref--. 23 +// #region --Data/ref--.
24 const initialState: Comment = { 24 const initialState: Comment = {
25 username: "", 25 username: "",
26 message: "", 26 message: "",
@@ -35,6 +35,7 @@ const rules = { @@ -35,6 +35,7 @@ const rules = {
35 maxLength: helpers.withMessage("Le nom d'utilisateur ne peut pas dépasser 50 caractères", maxLength(50)), 35 maxLength: helpers.withMessage("Le nom d'utilisateur ne peut pas dépasser 50 caractères", maxLength(50)),
36 alpha: helpers.withMessage( 36 alpha: helpers.withMessage(
37 "Le nom d'utilisateur ne peut contenir que des lettres", 37 "Le nom d'utilisateur ne peut contenir que des lettres",
  38 + // eslint-disable-next-line regexp/no-obscure-range
38 helpers.regex(/^[a-zA-ZÀ-ÿ\s]+$/), 39 helpers.regex(/^[a-zA-ZÀ-ÿ\s]+$/),
39 ), 40 ),
40 }, 41 },
@@ -54,15 +55,15 @@ const formData = reactive({ @@ -54,15 +55,15 @@ const formData = reactive({
54 ...initialState, 55 ...initialState,
55 }); 56 });
56 const v$ = useVuelidate(rules, formData); 57 const v$ = useVuelidate(rules, formData);
57 -//#endregion 58 +// #endregion
58 59
59 // const errormessages = computed(() => { 60 // const errormessages = computed(() => {
60 // return v$.value.message.$errors.map((e) => e.$message); 61 // return v$.value.message.$errors.map((e) => e.$message);
61 // }); 62 // });
62 63
63 -//#region --Function--. 64 +// #region --Function--.
64 async function submitComment() { 65 async function submitComment() {
65 - emit("event:submit", formData); 66 + emit("eventSubmit", formData);
66 } 67 }
67 68
68 function clear() { 69 function clear() {
@@ -80,7 +81,7 @@ function handleMessageEvent(event: string) { @@ -80,7 +81,7 @@ function handleMessageEvent(event: string) {
80 // console.log(formData.message.replace(/(&lt;([^&gt;]+)&gt;)/ig, '')); 81 // console.log(formData.message.replace(/(&lt;([^&gt;]+)&gt;)/ig, ''));
81 } 82 }
82 83
83 -//#endregion 84 +// #endregion
84 </script> 85 </script>
85 86
86 <template> 87 <template>
@@ -105,7 +106,7 @@ function handleMessageEvent(event: string) { @@ -105,7 +106,7 @@ function handleMessageEvent(event: string) {
105 @blur="v$.rating.$touch" 106 @blur="v$.rating.$touch"
106 @input="v$.rating.$touch" 107 @input="v$.rating.$touch"
107 /> 108 />
108 - <!-- <pre>{{ errormessages }}</pre>--> 109 + <!-- <pre>{{ errormessages }}</pre> -->
109 <ui-components-tiny-mce-field-editor 110 <ui-components-tiny-mce-field-editor
110 :error-message="v$?.message?.$errors[0]?.$message ? (v$.message.$errors[0].$message as string) : ''" 111 :error-message="v$?.message?.$errors[0]?.$message ? (v$.message.$errors[0].$message as string) : ''"
111 :model-value="formData.message" 112 :model-value="formData.message"
1 -import { describe, expect, it } from "vitest";  
2 import { mount } from "@vue/test-utils"; 1 import { mount } from "@vue/test-utils";
  2 +import { describe, expect, it } from "vitest";
3 3
4 import HelloWorld from "./HelloWorld.vue"; 4 import HelloWorld from "./HelloWorld.vue";
5 5
6 -describe("HelloWorld", () => { 6 +describe("helloWorld", () => {
7 it("component renders Hello world properly", () => { 7 it("component renders Hello world properly", () => {
8 const wrapper = mount(HelloWorld); 8 const wrapper = mount(HelloWorld);
9 expect(wrapper.text()).toContain("Hello world"); 9 expect(wrapper.text()).toContain("Hello world");
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -//#region --Props--. 2 +// #region --Props--.
3 defineProps({ 3 defineProps({
4 src: { 4 src: {
5 type: String, 5 type: String,
@@ -12,11 +12,11 @@ defineProps({ @@ -12,11 +12,11 @@ defineProps({
12 nullable: false, 12 nullable: false,
13 }, 13 },
14 }); 14 });
15 -//#endregion 15 +// #endregion
16 16
17 -//#region --Declaration--. 17 +// #region --Declaration--.
18 const w: Window = window; 18 const w: Window = window;
19 -//#endregion 19 +// #endregion
20 </script> 20 </script>
21 21
22 <template> 22 <template>
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -//#region --Props--. 2 +// #region --Props--.
3 defineProps({ 3 defineProps({
4 isLoading: { 4 isLoading: {
5 type: Boolean, 5 type: Boolean,
@@ -13,7 +13,7 @@ defineProps({ @@ -13,7 +13,7 @@ defineProps({
13 default: false, 13 default: false,
14 }, 14 },
15 }); 15 });
16 -//#endregion 16 +// #endregion
17 </script> 17 </script>
18 18
19 <template> 19 <template>
1 <script setup lang="ts"> 1 <script setup lang="ts">
2 -//#region --Props--. 2 +// #region --Props--.
3 import { FilmIcon } from "lucide-vue-next"; 3 import { FilmIcon } from "lucide-vue-next";
4 4
5 defineProps({ 5 defineProps({
@@ -14,7 +14,7 @@ defineProps({ @@ -14,7 +14,7 @@ defineProps({
14 nullable: false, 14 nullable: false,
15 }, 15 },
16 }); 16 });
17 -//#endregion 17 +// #endregion
18 </script> 18 </script>
19 19
20 <template> 20 <template>
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -//#region --import--. 2 +import { useDebounceFn } from "@vueuse/core";
  3 +// #region --import--.
3 import { SearchIcon, XIcon } from "lucide-vue-next"; 4 import { SearchIcon, XIcon } from "lucide-vue-next";
4 import { ref } from "vue"; 5 import { ref } from "vue";
5 -import { useDebounceFn } from "@vueuse/core"; 6 +// #endregion
6 -//#endregion  
7 7
8 -//#region --Emits--. 8 +// #region --Props--.
9 -const emit = defineEmits(["event:search", "event:clear_search"]);  
10 -//#endregion  
11 -  
12 -//#region --Props--.  
13 defineProps({ 9 defineProps({
14 placeholder: { 10 placeholder: {
15 type: String, 11 type: String,
@@ -18,25 +14,29 @@ defineProps({ @@ -18,25 +14,29 @@ defineProps({
18 default: "", 14 default: "",
19 }, 15 },
20 }); 16 });
21 -//#endregion 17 +// #endregion
  18 +
  19 +// #region --Emits--.
  20 +const emit = defineEmits(["eventSearch", "eventClearSearch"]);
  21 +// #endregion
22 22
23 -//#region --Data/refs--. 23 +// #region --Data/refs--.
24 const searchQuery = ref(""); 24 const searchQuery = ref("");
25 -//#endregion 25 +// #endregion
26 26
27 -//#region --Function--. 27 +// #region --Function--.
28 /** 28 /**
29 * Debounced function 29 * Debounced function
30 */ 30 */
31 const handleSearchEvent = useDebounceFn(() => { 31 const handleSearchEvent = useDebounceFn(() => {
32 - emit("event:search", searchQuery.value); 32 + emit("eventSearch", searchQuery.value);
33 }, 500); 33 }, 500);
34 34
35 function handleClearSearchEvent() { 35 function handleClearSearchEvent() {
36 searchQuery.value = ""; 36 searchQuery.value = "";
37 - emit("event:clear_search"); 37 + emit("eventClearSearch");
38 } 38 }
39 -//#endregion 39 +// #endregion
40 </script> 40 </script>
41 41
42 <template> 42 <template>
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -//#region --Props--. 2 +// #region --Props--.
3 defineProps({ 3 defineProps({
4 isInitialLoading: { 4 isInitialLoading: {
5 type: Boolean, 5 type: Boolean,
@@ -13,7 +13,7 @@ defineProps({ @@ -13,7 +13,7 @@ defineProps({
13 default: 12, 13 default: 12,
14 }, 14 },
15 }); 15 });
16 -//#endregion 16 +// #endregion
17 </script> 17 </script>
18 18
19 <template> 19 <template>
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -//#region --Import--. 2 +// #region --Import--.
3 import Editor from "@tinymce/tinymce-vue"; 3 import Editor from "@tinymce/tinymce-vue";
4 import { ref, watch } from "vue"; 4 import { ref, watch } from "vue";
5 -//#endregion 5 +// #endregion
6 6
7 -//#region --Declaration--. 7 +// #region --Props--.
8 -const runtimeConfig = useRuntimeConfig(); 8 +const props = defineProps<{
9 -//#endregion 9 + modelValue: string;
  10 + errorMessage: string;
  11 +}>();
  12 +// #endregion
10 13
11 -//#region --Emit--. 14 +// #region --Emit--.
12 const emit = defineEmits<{ 15 const emit = defineEmits<{
13 (e: "update:modelValue", value: string): void; 16 (e: "update:modelValue", value: string): void;
14 }>(); 17 }>();
15 -//#endregion 18 +// #endregion
16 19
17 -//#region --Props--. 20 +// #region --Declaration--.
18 -const props = defineProps<{ 21 +const runtimeConfig = useRuntimeConfig();
19 - modelValue: string; 22 +// #endregion
20 - errorMessage: string;  
21 -}>();  
22 -//#endregion  
23 23
24 -//#region --Data/ref--. 24 +// #region --Data/ref--.
25 const content = ref(props.modelValue); 25 const content = ref(props.modelValue);
26 const init = { 26 const init = {
27 height: 300, 27 height: 300,
@@ -48,10 +48,10 @@ const init = { @@ -48,10 +48,10 @@ const init = {
48 "wordcount", 48 "wordcount",
49 ], 49 ],
50 toolbar: 50 toolbar:
51 - "undo redo | blocks | bold italic underline strikethrough |" + 51 + "undo redo | blocks | bold italic underline strikethrough |"
52 - "bold italic forecolor | alignleft aligncenter " + 52 + + "bold italic forecolor | alignleft aligncenter "
53 - "alignright alignjustify | bullist numlist outdent indent | " + 53 + + "alignright alignjustify | bullist numlist outdent indent | "
54 - "removeformat | help", 54 + + "removeformat | help",
55 content_style: "body { font-family:Helvetica,Arial,sans-serif; font-size:14px }", 55 content_style: "body { font-family:Helvetica,Arial,sans-serif; font-size:14px }",
56 skin: "oxide-dark", 56 skin: "oxide-dark",
57 content_css: "dark", 57 content_css: "dark",
@@ -59,9 +59,9 @@ const init = { @@ -59,9 +59,9 @@ const init = {
59 // valid_elements: [], 59 // valid_elements: [],
60 // entity_encoding : "raw", 60 // entity_encoding : "raw",
61 }; 61 };
62 -//#endregion 62 +// #endregion
63 63
64 -//#region --Watch--. 64 +// #region --Watch--.
65 watch(content, (newValue) => { 65 watch(content, (newValue) => {
66 emit("update:modelValue", newValue); 66 emit("update:modelValue", newValue);
67 }); 67 });
@@ -74,12 +74,12 @@ watch( @@ -74,12 +74,12 @@ watch(
74 } 74 }
75 }, 75 },
76 ); 76 );
77 -//#endregion 77 +// #endregion
78 </script> 78 </script>
79 79
80 <template> 80 <template>
81 <div> 81 <div>
82 - <editor 82 + <Editor
83 v-model="content" 83 v-model="content"
84 :api-key="runtimeConfig.public.apiTinyMceSecret" 84 :api-key="runtimeConfig.public.apiTinyMceSecret"
85 :init="init" 85 :init="init"
1 import type { RuntimeConfig } from "nuxt/schema"; 1 import type { RuntimeConfig } from "nuxt/schema";
2 2
3 -export const useTMDB = function () { 3 +export function useTMDB() {
4 const runtimeconfig: RuntimeConfig = useRuntimeConfig(); 4 const runtimeconfig: RuntimeConfig = useRuntimeConfig();
5 const apiUrl = runtimeconfig.public.apiTMDBUrl; 5 const apiUrl = runtimeconfig.public.apiTMDBUrl;
6 const apiKey = runtimeconfig.public.apiTMDBSecret; 6 const apiKey = runtimeconfig.public.apiTMDBSecret;
@@ -14,10 +14,12 @@ export const useTMDB = function () { @@ -14,10 +14,12 @@ export const useTMDB = function () {
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) {
16 console.error("An error occurred when fetching popular movies:"); 16 console.error("An error occurred when fetching popular movies:");
17 - } else { 17 + }
  18 + else {
18 return await response.json(); 19 return await response.json();
19 } 20 }
20 - } catch (error) { 21 + }
  22 + catch (error) {
21 console.error("Error fetching popular movies:", error); 23 console.error("Error fetching popular movies:", error);
22 } 24 }
23 }; 25 };
@@ -34,10 +36,12 @@ export const useTMDB = function () { @@ -34,10 +36,12 @@ export const useTMDB = function () {
34 ); 36 );
35 if (!response.ok) { 37 if (!response.ok) {
36 console.error("An error occurred when searching movies:"); 38 console.error("An error occurred when searching movies:");
37 - } else { 39 + }
  40 + else {
38 return await response.json(); 41 return await response.json();
39 } 42 }
40 - } catch (error) { 43 + }
  44 + catch (error) {
41 console.error("Error searching movies:", error); 45 console.error("Error searching movies:", error);
42 } 46 }
43 }; 47 };
@@ -51,10 +55,12 @@ export const useTMDB = function () { @@ -51,10 +55,12 @@ export const useTMDB = function () {
51 const response = await fetch(`${apiUrl}/movie/${id}?api_key=${apiKey}&language=fr-FR`); 55 const response = await fetch(`${apiUrl}/movie/${id}?api_key=${apiKey}&language=fr-FR`);
52 if (!response.ok) { 56 if (!response.ok) {
53 console.error("An error occurred when fetching movie details:"); 57 console.error("An error occurred when fetching movie details:");
54 - } else { 58 + }
  59 + else {
55 return await response.json(); 60 return await response.json();
56 } 61 }
57 - } catch (error) { 62 + }
  63 + catch (error) {
58 console.error("Error fetching details:", error); 64 console.error("Error fetching details:", error);
59 } 65 }
60 }; 66 };
@@ -67,13 +73,15 @@ export const useTMDB = function () { @@ -67,13 +73,15 @@ export const useTMDB = function () {
67 const response = await fetch(`${apiUrl}/movie/${id}/credits?api_key=${apiKey}&language=fr-FR`); 73 const response = await fetch(`${apiUrl}/movie/${id}/credits?api_key=${apiKey}&language=fr-FR`);
68 if (!response.ok) { 74 if (!response.ok) {
69 console.error("An error occurred when fetching movie credits:"); 75 console.error("An error occurred when fetching movie credits:");
70 - } else { 76 + }
  77 + else {
71 return await response.json(); 78 return await response.json();
72 } 79 }
73 - } catch (error) { 80 + }
  81 + catch (error) {
74 console.error("Error fetching movie credits:", error); 82 console.error("Error fetching movie credits:", error);
75 } 83 }
76 }; 84 };
77 85
78 return { fetchPopularMovies, searchMovies, fetchMovieDetails, fetchMovieCredits }; 86 return { fetchPopularMovies, searchMovies, fetchMovieDetails, fetchMovieCredits };
79 -}; 87 +}
@@ -7,10 +7,10 @@ export interface CreditInterface { @@ -7,10 +7,10 @@ export interface CreditInterface {
7 character?: string; 7 character?: string;
8 } 8 }
9 9
10 -export type CreditsResponse = { 10 +export interface CreditsResponse {
11 id: number; 11 id: number;
12 cast: CreditInterface[]; 12 cast: CreditInterface[];
13 crew: CreditInterface[]; 13 crew: CreditInterface[];
14 movie_id: unknown; 14 movie_id: unknown;
15 movie: MovieInterface; 15 movie: MovieInterface;
16 -}; 16 +}
@@ -20,7 +20,7 @@ export interface MovieInterface { @@ -20,7 +20,7 @@ export interface MovieInterface {
20 credit: CreditsResponse; 20 credit: CreditsResponse;
21 } 21 }
22 22
23 -export type Genre = { 23 +export interface Genre {
24 id: number; 24 id: number;
25 name: string; 25 name: string;
26 -}; 26 +}
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 -//#region --import--. 2 +import type { WhereSecondaryClosure } from "pinia-orm";
  3 +import type { CreditsResponse } from "~/interfaces/credit";
  4 +import type { MovieInterface } from "~/interfaces/movie";
  5 +import type { MovieCommentInterface } from "~/interfaces/movieComment";
  6 +// #region --import--.
3 import { AlertTriangleIcon, ArrowLeftIcon } from "lucide-vue-next"; 7 import { AlertTriangleIcon, ArrowLeftIcon } from "lucide-vue-next";
4 -import { useTMDB } from "~/composables/tMDB";  
5 import { computed, onMounted, ref } from "vue"; 8 import { computed, onMounted, ref } from "vue";
6 -import { Movie } from "~/models/movie"; 9 +import { useTMDB } from "~/composables/tMDB";
7 -import type { MovieInterface } from "~/interfaces/movie";  
8 import { Credit } from "~/models/credit"; 10 import { Credit } from "~/models/credit";
9 -import type { CreditsResponse } from "~/interfaces/credit"; 11 +import { Movie } from "~/models/movie";
10 -import type { MovieCommentInterface } from "~/interfaces/movieComment";  
11 import { MovieComment } from "~/models/movieComment"; 12 import { MovieComment } from "~/models/movieComment";
12 -import type { WhereSecondaryClosure } from "pinia-orm"; 13 +// #endregion
13 -//#endregion  
14 14
15 -//#region --Declaration--. 15 +// #region --Declaration--.
16 const { fetchMovieDetails, fetchMovieCredits } = useTMDB(); 16 const { fetchMovieDetails, fetchMovieCredits } = useTMDB();
17 -//#endregion 17 +// #endregion
18 18
19 -//#region --Declaration--. 19 +// #region --Declaration--.
20 const { currentRoute } = useRouter(); 20 const { currentRoute } = useRouter();
21 -//#endregion 21 +// #endregion
22 22
23 -//#region --Data/ref--. 23 +// #region --Data/ref--.
24 const isLoading = ref(true); 24 const isLoading = ref(true);
25 const isSubmitting = ref(false); 25 const isSubmitting = ref(false);
26 -//#endregion 26 +// #endregion
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) {
31 if (typeof currentRoute.value.params.id === "string") { 31 if (typeof currentRoute.value.params.id === "string") {
32 if (typeof Number(+currentRoute.value.params.id) === "number") { 32 if (typeof Number(+currentRoute.value.params.id) === "number") {
33 return +currentRoute.value.params.id as number; 33 return +currentRoute.value.params.id as number;
34 - } else { 34 + }
  35 + else {
35 return currentRoute.value.params.id as string; 36 return currentRoute.value.params.id as string;
36 } 37 }
37 - } else { 38 + }
  39 + else {
38 return null; 40 return null;
39 } 41 }
40 - } else { 42 + }
  43 + else {
41 return null; 44 return null;
42 } 45 }
43 }); 46 });
@@ -49,7 +52,8 @@ const movie = computed(() => { @@ -49,7 +52,8 @@ const movie = computed(() => {
49 .where("id", movieId.value as WhereSecondaryClosure<never> | null | undefined) 52 .where("id", movieId.value as WhereSecondaryClosure<never> | null | undefined)
50 .withAll() 53 .withAll()
51 .first() as unknown as MovieInterface; 54 .first() as unknown as MovieInterface;
52 - } else { 55 + }
  56 + else {
53 return null; 57 return null;
54 } 58 }
55 }); 59 });
@@ -59,8 +63,9 @@ const movie = computed(() => { @@ -59,8 +63,9 @@ const movie = computed(() => {
59 */ 63 */
60 const director = computed(() => { 64 const director = computed(() => {
61 if (unref(movie)?.credit?.crew) { 65 if (unref(movie)?.credit?.crew) {
62 - return movie.value?.credit.crew.find((person) => person.job === "Director"); 66 + return movie.value?.credit.crew.find(person => person.job === "Director");
63 - } else { 67 + }
  68 + else {
64 return null; 69 return null;
65 } 70 }
66 }); 71 });
@@ -78,39 +83,42 @@ const comments = computed(() => { @@ -78,39 +83,42 @@ const comments = computed(() => {
78 .orderBy("createdAt", "desc") 83 .orderBy("createdAt", "desc")
79 .get(); 84 .get();
80 }); 85 });
81 -//#endregion 86 +// #endregion
82 87
83 -//#region --Function--. 88 +// #region --Function--.
84 /** 89 /**
85 * Fetch movie details 90 * Fetch movie details
86 */ 91 */
87 -const fetchDetails = async (id: number | string) => { 92 +async function fetchDetails(id: number | string) {
88 try { 93 try {
89 isLoading.value = true; 94 isLoading.value = true;
90 95
91 const data = await fetchMovieDetails(id); 96 const data = await fetchMovieDetails(id);
92 // Add to store collection. 97 // Add to store collection.
93 useRepo(Movie).save(data); 98 useRepo(Movie).save(data);
94 - } catch (error) { 99 + }
  100 + catch (error) {
95 console.error("Error fetching movie details:", error); 101 console.error("Error fetching movie details:", error);
96 - } finally { 102 + }
  103 + finally {
97 isLoading.value = false; 104 isLoading.value = false;
98 } 105 }
99 -}; 106 +}
100 107
101 /** 108 /**
102 * Format runtime 109 * Format runtime
103 * @param minutes 110 * @param minutes
104 */ 111 */
105 -const formatRuntime = (minutes: number) => { 112 +function formatRuntime(minutes: number) {
106 - if (!minutes) return "Durée inconnue"; 113 + if (!minutes)
  114 + return "Durée inconnue";
107 // Find nb hours. 115 // Find nb hours.
108 const hours = Math.floor(minutes / 60); 116 const hours = Math.floor(minutes / 60);
109 // Find last minutes. 117 // Find last minutes.
110 const mins = minutes % 60; 118 const mins = minutes % 60;
111 119
112 return `${hours}h ${mins}min`; 120 return `${hours}h ${mins}min`;
113 -}; 121 +}
114 122
115 async function fetchCredits(id: number | string) { 123 async function fetchCredits(id: number | string) {
116 try { 124 try {
@@ -118,12 +126,13 @@ async function fetchCredits(id: number | string) { @@ -118,12 +126,13 @@ async function fetchCredits(id: number | string) {
118 data.movie_id = id; 126 data.movie_id = id;
119 // Add to store collection. 127 // Add to store collection.
120 useRepo(Credit).save(data); 128 useRepo(Credit).save(data);
121 - } catch (error) { 129 + }
  130 + catch (error) {
122 console.error("Error fetching movie credits:", error); 131 console.error("Error fetching movie credits:", error);
123 } 132 }
124 } 133 }
125 134
126 -//Ce n'est pas le film du siècle cependant, il est suffisamment intéressant pour passer une bonne soirée ! 135 +// Ce n'est pas le film du siècle cependant, il est suffisamment intéressant pour passer une bonne soirée !
127 function handleSubmitEvent(event: MovieCommentInterface) { 136 function handleSubmitEvent(event: MovieCommentInterface) {
128 isSubmitting.value = true; 137 isSubmitting.value = true;
129 event.movie_id = unref(movieId); 138 event.movie_id = unref(movieId);
@@ -132,9 +141,9 @@ function handleSubmitEvent(event: MovieCommentInterface) { @@ -132,9 +141,9 @@ function handleSubmitEvent(event: MovieCommentInterface) {
132 isSubmitting.value = false; 141 isSubmitting.value = false;
133 } 142 }
134 143
135 -//#endregion 144 +// #endregion
136 145
137 -//#region --Global event--. 146 +// #region --Global event--.
138 onMounted(() => { 147 onMounted(() => {
139 // Fetch data on component mount. 148 // Fetch data on component mount.
140 if (unref(movieId)) { 149 if (unref(movieId)) {
@@ -144,7 +153,7 @@ onMounted(() => { @@ -144,7 +153,7 @@ onMounted(() => {
144 } 153 }
145 // loadComments() 154 // loadComments()
146 }); 155 });
147 -//#endregion 156 +// #endregion
148 </script> 157 </script>
149 158
150 <template> 159 <template>
@@ -245,7 +254,7 @@ onMounted(() => { @@ -245,7 +254,7 @@ onMounted(() => {
245 <h3 class="text-xl font-bold mt-8 mb-4"> 254 <h3 class="text-xl font-bold mt-8 mb-4">
246 Ajouter un commentaire 255 Ajouter un commentaire
247 </h3> 256 </h3>
248 - <form-movie-comment-form @event:submit="handleSubmitEvent" /> 257 + <form-movie-comment-form @event-submit="handleSubmitEvent" />
249 258
250 <!-- Liste des commentaires --> 259 <!-- Liste des commentaires -->
251 <movie-comment-list :comments="comments as unknown as MovieCommentInterface[]" /> 260 <movie-comment-list :comments="comments as unknown as MovieCommentInterface[]" />
1 -//#region --Import--. 1 +import type { Genre } from "~/interfaces/movie";
2 -import { describe, expect, it } from "vitest";  
3 import { mount } from "@vue/test-utils"; 2 import { mount } from "@vue/test-utils";
  3 +// #region --Import--.
  4 +import { describe, expect, it } from "vitest";
4 import MovieGender from "../../components/details/MovieGender.vue"; 5 import MovieGender from "../../components/details/MovieGender.vue";
5 -import type { Genre } from "~/interfaces/movie"; 6 +// #endregion
6 -//#endregion  
7 7
8 -describe("MovieGender", () => { 8 +describe("movieGender", () => {
9 it("affiche correctement les genres", () => { 9 it("affiche correctement les genres", () => {
10 // Données de test. 10 // Données de test.
11 const genres: Genre[] = [ 11 const genres: Genre[] = [
1 -//#region --Import--.  
2 -import { describe, expect, it } from "vitest";  
3 import { mount } from "@vue/test-utils"; 1 import { mount } from "@vue/test-utils";
  2 +// #region --Import--.
  3 +import { describe, expect, it } from "vitest";
4 import ScoreAndVote from "../../components/details/ScoreAndVote.vue"; 4 import ScoreAndVote from "../../components/details/ScoreAndVote.vue";
5 -//#endregion 5 +// #endregion
6 6
7 -describe("ScoreAndVote", () => { 7 +describe("scoreAndVote", () => {
8 it("affiche correctement le score", () => { 8 it("affiche correctement le score", () => {
9 // Monter le composant avec ses props. 9 // Monter le composant avec ses props.
10 const wrapper = mount(ScoreAndVote, { 10 const wrapper = mount(ScoreAndVote, {
1 -export type Comment = { 1 +export interface Comment {
2 username: string; 2 username: string;
3 message: string; 3 message: string;
4 rating: number; 4 rating: number;
5 -}; 5 +}
1 -import { defineVitestConfig } from "@nuxt/test-utils/config";  
2 import { fileURLToPath } from "node:url"; 1 import { fileURLToPath } from "node:url";
  2 +import { defineVitestConfig } from "@nuxt/test-utils/config";
3 3
4 export default defineVitestConfig({ 4 export default defineVitestConfig({
5 /** 5 /**