feat: front update

This commit is contained in:
ext.jeremy.guillot@maxicoffee.domains
2025-03-22 15:38:05 +01:00
parent 7303d63198
commit 4f4f86fb91
5 changed files with 44 additions and 34 deletions

View File

@@ -27,6 +27,9 @@ help: ## Outputs this help screen
build: ## Builds the Docker images
@$(DOCKER_COMP) build --pull --no-cache
up: ## Start the docker hub
@$(DOCKER_COMP) up -d
start: ## Start the docker hub in detached mode (no logs)
@$(DOCKER_COMP) up --pull always -d --wait

View File

@@ -11,7 +11,8 @@ export class Manga {
genres,
status,
rating,
description = ''
description = '',
createdAt = null
) {
this.id = id;
this.title = title;
@@ -23,6 +24,7 @@ export class Manga {
this.status = status;
this.rating = rating;
this.description = description;
this.createdAt = createdAt;
}
}
@@ -49,7 +51,8 @@ export class MangaDetail extends Manga {
manga.genres,
manga.status,
manga.rating,
manga.description
manga.description,
manga.createdAt
);
this.chapters = this.organizeChaptersByVolume(chapters);
}

View File

@@ -23,7 +23,9 @@ export class ApiMangaRepository {
item.publicationYear,
item.genres,
item.status,
item.rating
item.rating,
item.description,
item.createdAt
));
return new MangaCollection(
@@ -55,7 +57,8 @@ export class ApiMangaRepository {
item.genres,
item.status,
item.rating,
item.description
item.description,
item.createdAt
));
} catch (error) {
console.error('Error searching mangas:', error);
@@ -90,7 +93,8 @@ export class ApiMangaRepository {
genres: mangaData.genres,
status: mangaData.status,
rating: mangaData.rating,
description: mangaData.description
description: mangaData.description,
createdAt: mangaData.createdAt
}, chapters);
} catch (error) {
console.error('Error fetching manga details:', error);

View File

@@ -1,7 +1,5 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faStar } from '@fortawesome/free-solid-svg-icons';
export function MangaCard({ manga }) {
const navigate = useNavigate();
@@ -10,39 +8,34 @@ export function MangaCard({ manga }) {
navigate(`/manga/${manga.slug}`);
};
const formatDate = (dateString) => {
const date = new Date(dateString);
return date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric'
});
};
return (
<div
className="bg-white rounded-lg shadow-md overflow-hidden cursor-pointer transition-transform hover:scale-105"
onClick={handleClick}
>
<div className="relative h-64">
<div className="relative pb-[150%]">
<img
src={manga.imageUrl || 'https://via.placeholder.com/300x400'}
alt={manga.title}
className="w-full h-full object-cover"
className="absolute inset-0 w-full h-full object-contain bg-gray-100"
/>
</div>
<div className="p-4">
<h3 className="text-lg font-semibold text-gray-800 mb-2">{manga.title}</h3>
<p className="text-sm text-gray-600 mb-2">By {manga.author}</p>
<div className="flex items-center justify-between">
<div className="p-2">
<h3 className="text-lg font-semibold text-gray-800 mb-1">{manga.title}</h3>
<div className="flex items-center">
<span className="text-sm text-gray-500">{manga.publicationYear}</span>
{manga.rating && (
<span className="flex items-center text-yellow-500">
<FontAwesomeIcon icon={faStar} className="mr-1" />
{manga.rating}
</span>
)}
</div>
<div className="mt-2 flex flex-wrap gap-1">
{manga.genres.map((genre, index) => (
<span
key={index}
className="px-2 py-1 text-xs bg-green-100 text-green-800 rounded-full"
>
{genre}
</span>
))}
<div className="mt-1 text-sm text-gray-500">
Added: {formatDate(manga.createdAt)}
</div>
</div>
</div>

View File

@@ -47,7 +47,11 @@ function mangaReducer(state, action) {
...state.collection,
items: state.collection.items.map(manga =>
manga.slug === action.payload.slug
? { ...manga, ...action.payload }
? {
...manga,
...action.payload,
createdAt: manga.createdAt || action.payload.createdAt
}
: manga
)
} : state.collection;
@@ -57,7 +61,10 @@ function mangaReducer(state, action) {
collection: updatedCollection,
detailedMangas: {
...state.detailedMangas,
[action.payload.slug]: action.payload
[action.payload.slug]: {
...action.payload,
createdAt: state.collection?.items.find(m => m.slug === action.payload.slug)?.createdAt || action.payload.createdAt
}
},
loading: false,
error: null
@@ -98,11 +105,11 @@ export function MangaProvider({ children }) {
const loadCollection = useCallback(async () => {
// 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
// Rafraîchir en arrière-plan si les données sont vieilles de plus de 30 secondes
const isStale = state.lastCollectionUpdate &&
(Date.now() - state.lastCollectionUpdate) > 60 * 1000;
(Date.now() - state.lastCollectionUpdate) > 30 * 1000;
if (isStale) {
if (isStale && !state.isBackgroundLoading) {
refreshCollectionInBackground();
}
return;
@@ -116,7 +123,7 @@ export function MangaProvider({ children }) {
dispatch({ type: 'SET_ERROR', payload: 'Failed to load manga collection' });
console.error(error);
}
}, [state.collection, state.lastCollectionUpdate, refreshCollectionInBackground]);
}, [state.collection, state.lastCollectionUpdate, state.isBackgroundLoading, refreshCollectionInBackground]);
const loadMangaDetail = useCallback(async (slug) => {
// Retourner les données en cache si disponibles