99 lines
2.9 KiB
JavaScript
99 lines
2.9 KiB
JavaScript
import React, { createContext, useContext, useReducer, useCallback } from 'react';
|
|
import { ApiMangaRepository } from '../../infrastructure/api/apiMangaRepository';
|
|
import { GetMangaCollection } from '../../application/useCases/getMangaCollection';
|
|
import { GetMangaDetail } from '../../application/useCases/getMangaDetail';
|
|
|
|
const mangaRepository = new ApiMangaRepository();
|
|
const getMangaCollection = new GetMangaCollection(mangaRepository);
|
|
const getMangaDetail = new GetMangaDetail(mangaRepository);
|
|
|
|
const MangaContext = createContext(null);
|
|
|
|
const initialState = {
|
|
collection: null,
|
|
detailedMangas: {},
|
|
loading: false,
|
|
error: null
|
|
};
|
|
|
|
function mangaReducer(state, action) {
|
|
switch (action.type) {
|
|
case 'SET_LOADING':
|
|
return { ...state, loading: 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,
|
|
detailedMangas: {
|
|
...state.detailedMangas,
|
|
[action.payload.slug]: action.payload
|
|
},
|
|
loading: false,
|
|
error: null
|
|
};
|
|
default:
|
|
return state;
|
|
}
|
|
}
|
|
|
|
export function MangaProvider({ children }) {
|
|
const [state, dispatch] = useReducer(mangaReducer, initialState);
|
|
|
|
const loadCollection = useCallback(async () => {
|
|
if (state.collection) return; // Return if already loaded
|
|
|
|
dispatch({ type: 'SET_LOADING', payload: true });
|
|
try {
|
|
const collection = await getMangaCollection.execute(1);
|
|
dispatch({ type: 'SET_COLLECTION', payload: collection });
|
|
} catch (error) {
|
|
dispatch({ type: 'SET_ERROR', payload: 'Failed to load manga collection' });
|
|
console.error(error);
|
|
}
|
|
}, []);
|
|
|
|
const loadMangaDetail = useCallback(async (slug) => {
|
|
// Return cached data if available
|
|
if (state.detailedMangas[slug]) return state.detailedMangas[slug];
|
|
|
|
dispatch({ type: 'SET_LOADING', payload: true });
|
|
try {
|
|
const manga = await getMangaDetail.execute(slug);
|
|
dispatch({ type: 'SET_MANGA_DETAIL', payload: manga });
|
|
return manga;
|
|
} catch (error) {
|
|
dispatch({ type: 'SET_ERROR', payload: 'Failed to load manga details' });
|
|
console.error(error);
|
|
return null;
|
|
}
|
|
}, []);
|
|
|
|
const getMangaFromCollection = useCallback((slug) => {
|
|
if (!state.collection) return null;
|
|
return state.collection.items.find(manga => manga.slug === slug);
|
|
}, [state.collection]);
|
|
|
|
const value = {
|
|
...state,
|
|
loadCollection,
|
|
loadMangaDetail,
|
|
getMangaFromCollection
|
|
};
|
|
|
|
return (
|
|
<MangaContext.Provider value={value}>
|
|
{children}
|
|
</MangaContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useManga() {
|
|
const context = useContext(MangaContext);
|
|
if (!context) {
|
|
throw new Error('useManga must be used within a MangaProvider');
|
|
}
|
|
return context;
|
|
} |