feat: SPA pour les pages existantes
This commit is contained in:
parent
668702b1fb
commit
140cc14316
@@ -1,4 +1,4 @@
|
||||
import React, { createContext, useContext, useReducer, useCallback } from 'react';
|
||||
import React, { createContext, useContext, useReducer, useCallback, useEffect } from 'react';
|
||||
import { ApiMangaRepository } from '../../infrastructure/api/apiMangaRepository';
|
||||
import { GetMangaCollection } from '../../application/useCases/getMangaCollection';
|
||||
import { GetMangaDetail } from '../../application/useCases/getMangaDetail';
|
||||
@@ -13,20 +13,48 @@ const initialState = {
|
||||
collection: null,
|
||||
detailedMangas: {},
|
||||
loading: false,
|
||||
error: null
|
||||
error: null,
|
||||
lastCollectionUpdate: null,
|
||||
isBackgroundLoading: false
|
||||
};
|
||||
|
||||
function mangaReducer(state, action) {
|
||||
switch (action.type) {
|
||||
case 'SET_LOADING':
|
||||
return { ...state, loading: action.payload };
|
||||
case 'SET_BACKGROUND_LOADING':
|
||||
return { ...state, isBackgroundLoading: action.payload };
|
||||
case 'SET_ERROR':
|
||||
return { ...state, error: action.payload, loading: false };
|
||||
case 'SET_COLLECTION':
|
||||
return { ...state, collection: action.payload, loading: false, error: null };
|
||||
case 'SET_MANGA_DETAIL':
|
||||
return {
|
||||
...state,
|
||||
collection: action.payload,
|
||||
loading: false,
|
||||
error: null,
|
||||
lastCollectionUpdate: Date.now()
|
||||
};
|
||||
case 'UPDATE_COLLECTION':
|
||||
return {
|
||||
...state,
|
||||
collection: action.payload,
|
||||
isBackgroundLoading: false,
|
||||
lastCollectionUpdate: Date.now()
|
||||
};
|
||||
case 'SET_MANGA_DETAIL':
|
||||
// Mettre à jour également le manga dans la collection si présent
|
||||
const updatedCollection = state.collection ? {
|
||||
...state.collection,
|
||||
items: state.collection.items.map(manga =>
|
||||
manga.slug === action.payload.slug
|
||||
? { ...manga, ...action.payload }
|
||||
: manga
|
||||
)
|
||||
} : state.collection;
|
||||
|
||||
return {
|
||||
...state,
|
||||
collection: updatedCollection,
|
||||
detailedMangas: {
|
||||
...state.detailedMangas,
|
||||
[action.payload.slug]: action.payload
|
||||
@@ -42,8 +70,43 @@ function mangaReducer(state, action) {
|
||||
export function MangaProvider({ children }) {
|
||||
const [state, dispatch] = useReducer(mangaReducer, initialState);
|
||||
|
||||
// Fonction pour charger la collection en arrière-plan
|
||||
const refreshCollectionInBackground = useCallback(async () => {
|
||||
if (state.isBackgroundLoading) return;
|
||||
|
||||
dispatch({ type: 'SET_BACKGROUND_LOADING', payload: true });
|
||||
try {
|
||||
const collection = await getMangaCollection.execute(1);
|
||||
dispatch({ type: 'UPDATE_COLLECTION', payload: collection });
|
||||
} catch (error) {
|
||||
console.error('Background collection refresh failed:', error);
|
||||
dispatch({ type: 'SET_BACKGROUND_LOADING', payload: false });
|
||||
}
|
||||
}, [state.isBackgroundLoading]);
|
||||
|
||||
// Rafraîchir la collection toutes les 5 minutes si elle est chargée
|
||||
useEffect(() => {
|
||||
if (!state.collection) return;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
refreshCollectionInBackground();
|
||||
}, 5 * 60 * 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [state.collection, refreshCollectionInBackground]);
|
||||
|
||||
const loadCollection = useCallback(async () => {
|
||||
if (state.collection) return; // Return if already loaded
|
||||
// Si nous avons déjà des données, les afficher immédiatement
|
||||
if (state.collection) {
|
||||
// Rafraîchir en arrière-plan si les données sont vieilles de plus de 1 minute
|
||||
const isStale = state.lastCollectionUpdate &&
|
||||
(Date.now() - state.lastCollectionUpdate) > 60 * 1000;
|
||||
|
||||
if (isStale) {
|
||||
refreshCollectionInBackground();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch({ type: 'SET_LOADING', payload: true });
|
||||
try {
|
||||
@@ -53,23 +116,47 @@ export function MangaProvider({ children }) {
|
||||
dispatch({ type: 'SET_ERROR', payload: 'Failed to load manga collection' });
|
||||
console.error(error);
|
||||
}
|
||||
}, []);
|
||||
}, [state.collection, state.lastCollectionUpdate, refreshCollectionInBackground]);
|
||||
|
||||
const loadMangaDetail = useCallback(async (slug) => {
|
||||
// Return cached data if available
|
||||
if (state.detailedMangas[slug]) return state.detailedMangas[slug];
|
||||
// Retourner les données en cache si disponibles
|
||||
if (state.detailedMangas[slug]) {
|
||||
// Rafraîchir en arrière-plan si les données sont vieilles de plus de 5 minutes
|
||||
const cachedManga = state.detailedMangas[slug];
|
||||
const isStale = cachedManga.lastUpdate &&
|
||||
(Date.now() - cachedManga.lastUpdate) > 5 * 60 * 1000;
|
||||
|
||||
if (isStale) {
|
||||
// Charger les nouvelles données en arrière-plan
|
||||
getMangaDetail.execute(slug).then(manga => {
|
||||
dispatch({ type: 'SET_MANGA_DETAIL', payload: { ...manga, lastUpdate: Date.now() } });
|
||||
}).catch(console.error);
|
||||
}
|
||||
|
||||
return state.detailedMangas[slug];
|
||||
}
|
||||
|
||||
// Si le manga est dans la collection, l'utiliser comme données temporaires
|
||||
const collectionManga = getMangaFromCollection(slug);
|
||||
if (collectionManga) {
|
||||
dispatch({
|
||||
type: 'SET_MANGA_DETAIL',
|
||||
payload: { ...collectionManga, isPartial: true, lastUpdate: Date.now() }
|
||||
});
|
||||
}
|
||||
|
||||
// Charger les détails complets
|
||||
dispatch({ type: 'SET_LOADING', payload: true });
|
||||
try {
|
||||
const manga = await getMangaDetail.execute(slug);
|
||||
dispatch({ type: 'SET_MANGA_DETAIL', payload: manga });
|
||||
dispatch({ type: 'SET_MANGA_DETAIL', payload: { ...manga, lastUpdate: Date.now() } });
|
||||
return manga;
|
||||
} catch (error) {
|
||||
dispatch({ type: 'SET_ERROR', payload: 'Failed to load manga details' });
|
||||
console.error(error);
|
||||
return null;
|
||||
}
|
||||
}, []);
|
||||
}, [state.detailedMangas]);
|
||||
|
||||
const getMangaFromCollection = useCallback((slug) => {
|
||||
if (!state.collection) return null;
|
||||
@@ -80,7 +167,8 @@ export function MangaProvider({ children }) {
|
||||
...state,
|
||||
loadCollection,
|
||||
loadMangaDetail,
|
||||
getMangaFromCollection
|
||||
getMangaFromCollection,
|
||||
refreshCollectionInBackground
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user