Files
Mangarr/assets/react/app/presentation/context/MangaContext.jsx
2025-02-17 12:02:56 +01:00

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;
}