diff --git a/assets/vue/app/domain/manga/infrastructure/api/apiMangaRepository.js b/assets/vue/app/domain/manga/infrastructure/api/apiMangaRepository.js
index f06dd56..91738f9 100644
--- a/assets/vue/app/domain/manga/infrastructure/api/apiMangaRepository.js
+++ b/assets/vue/app/domain/manga/infrastructure/api/apiMangaRepository.js
@@ -141,4 +141,36 @@ export class ApiMangaRepository {
throw error;
}
}
+
+ async getPreferredSources(mangaId) {
+ try {
+ const response = await fetch(`/api/mangas/${mangaId}/preferred-sources`);
+ if (!response.ok) {
+ throw new Error('Failed to fetch preferred sources');
+ }
+ return await response.json();
+ } catch (error) {
+ console.error('API Error:', error);
+ throw error;
+ }
+ }
+
+ async setPreferredSources(mangaId, sourceIds) {
+ try {
+ const response = await fetch(`/api/mangas/${mangaId}/preferred-sources`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ sourceIds })
+ });
+ if (!response.ok) {
+ throw new Error('Failed to set preferred sources');
+ }
+ return await response.json();
+ } catch (error) {
+ console.error('API Error:', error);
+ throw error;
+ }
+ }
}
diff --git a/assets/vue/app/domain/manga/presentation/components/MangaPreferredSourcesModal.vue b/assets/vue/app/domain/manga/presentation/components/MangaPreferredSourcesModal.vue
new file mode 100644
index 0000000..8666a4a
--- /dev/null
+++ b/assets/vue/app/domain/manga/presentation/components/MangaPreferredSourcesModal.vue
@@ -0,0 +1,191 @@
+
+
+
+
+
+
+
diff --git a/assets/vue/app/domain/manga/presentation/composables/useMangaPreferredSources.js b/assets/vue/app/domain/manga/presentation/composables/useMangaPreferredSources.js
new file mode 100644
index 0000000..fd03502
--- /dev/null
+++ b/assets/vue/app/domain/manga/presentation/composables/useMangaPreferredSources.js
@@ -0,0 +1,52 @@
+import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query';
+import { computed } from 'vue';
+import { ApiMangaRepository } from '../../infrastructure/api/apiMangaRepository';
+
+export function useMangaPreferredSources(mangaId) {
+ const mangaRepository = new ApiMangaRepository();
+ const queryClient = useQueryClient();
+
+ // Query pour récupérer les sources préférées
+ const preferredSourcesQuery = useQuery({
+ queryKey: ['manga', mangaId, 'preferred-sources'],
+ queryFn: () => {
+ if (!mangaId.value) {
+ return Promise.resolve(null);
+ }
+ return mangaRepository.getPreferredSources(mangaId.value);
+ },
+ enabled: computed(() => !!mangaId.value)
+ });
+
+ // Mutation pour sauvegarder les sources préférées
+ const setPreferredSourcesMutation = useMutation({
+ mutationFn: ({ sourceIds }) => {
+ return mangaRepository.setPreferredSources(mangaId.value, sourceIds);
+ },
+ onSuccess: () => {
+ // Invalider le cache pour refaire la requête de récupération
+ queryClient.invalidateQueries({
+ queryKey: ['manga', mangaId.value, 'preferred-sources']
+ });
+ }
+ });
+
+ const sources = computed(() => preferredSourcesQuery.data.value?.sources || []);
+ const hasPreferredSources = computed(() => preferredSourcesQuery.data.value?.hasPreferredSources || false);
+ const isLoading = computed(() => preferredSourcesQuery.isLoading.value);
+ const error = computed(() => preferredSourcesQuery.error.value);
+ const isSaving = computed(() => setPreferredSourcesMutation.isPending.value);
+
+ const savePreferredSources = (sourceIds) => {
+ return setPreferredSourcesMutation.mutate({ sourceIds });
+ };
+
+ return {
+ sources,
+ hasPreferredSources,
+ isLoading,
+ error,
+ isSaving,
+ savePreferredSources
+ };
+}
diff --git a/assets/vue/app/domain/manga/presentation/pages/MangaDetails.vue b/assets/vue/app/domain/manga/presentation/pages/MangaDetails.vue
index 9096af3..5a4a41b 100644
--- a/assets/vue/app/domain/manga/presentation/pages/MangaDetails.vue
+++ b/assets/vue/app/domain/manga/presentation/pages/MangaDetails.vue
@@ -24,6 +24,17 @@
+
+
+
@@ -35,33 +46,38 @@