mirror of
https://github.com/R0m1k3/podcastic.git
synced 2026-10-11 17:26:20 +02:00
fix: lu badge persistence + remove ? + fix duplicate buttons
- EpisodeCard: change 'Lu ?' → 'Marquer' so the toggle button no longer shows a confusing question mark next to completed episodes - Dashboard: fix episodes reappearing in 'Continuer l'écoute' after navigation. handleToggleRead now does an optimistic update on BOTH local state AND all TanStack Query cache pages (setQueriesData), so the 'lu' state survives page navigation without a server roundtrip. On error, cache is invalidated to revert to server truth. - Dashboard: 'Découvrir' button now links to /add (discover new podcasts) instead of /trending — was identical to 'Parcourir les tendances' button Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
454d8517fb
commit
e06f342c8e
2 files changed
+24
-15
No files matched your search
@@ -139,7 +139,7 @@ export default function EpisodeCard({ episode, onPlay, onDetails, onToggleRead }
|
|||||||
? <CheckCircle2 className="w-3.5 h-3.5" />
|
? <CheckCircle2 className="w-3.5 h-3.5" />
|
||||||
: <Circle className="w-3.5 h-3.5" />
|
: <Circle className="w-3.5 h-3.5" />
|
||||||
}
|
}
|
||||||
<span>{isCompleted ? 'Lu' : 'Lu ?'}</span>
|
<span>{isCompleted ? 'Lu' : 'Marquer'}</span>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { episodeService, Episode } from '../services/episodeService';
|
import { episodeService, Episode } from '../services/episodeService';
|
||||||
import { authService } from '../services/authService';
|
import { authService } from '../services/authService';
|
||||||
@@ -13,6 +13,7 @@ import { Sparkles, Play, Clock, TrendingUp, Loader, RefreshCcw } from 'lucide-re
|
|||||||
|
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
const { playEpisode, currentEpisode, closePlayer, setUserId } = useAudio();
|
const { playEpisode, currentEpisode, closePlayer, setUserId } = useAudio();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const [user, setUser] = useState<any>(null);
|
const [user, setUser] = useState<any>(null);
|
||||||
const [detailsEpisode, setDetailsEpisode] = useState<Episode | null>(null);
|
const [detailsEpisode, setDetailsEpisode] = useState<Episode | null>(null);
|
||||||
const [isDetailsOpen, setIsDetailsOpen] = useState(false);
|
const [isDetailsOpen, setIsDetailsOpen] = useState(false);
|
||||||
@@ -41,21 +42,29 @@ export default function Dashboard() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleToggleRead = async (episode: Episode, completed: boolean) => {
|
const handleToggleRead = async (episode: Episode, completed: boolean) => {
|
||||||
try {
|
const newProgress = { position: completed ? episode.duration : 0, isCompleted: completed };
|
||||||
await episodeService.saveProgress(
|
// Optimistic update: local state + all cached query pages
|
||||||
episode._id,
|
|
||||||
completed ? episode.duration : 0,
|
|
||||||
completed
|
|
||||||
);
|
|
||||||
setEpisodes(prev =>
|
setEpisodes(prev =>
|
||||||
prev.map(ep =>
|
prev.map(ep => ep._id === episode._id ? { ...ep, progress: newProgress } : ep)
|
||||||
ep._id === episode._id
|
|
||||||
? { ...ep, progress: { position: completed ? ep.duration : 0, isCompleted: completed } }
|
|
||||||
: ep
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
queryClient.setQueriesData<any>(
|
||||||
|
{ queryKey: ['episodes', 'latest'], exact: false },
|
||||||
|
(old: any) => {
|
||||||
|
if (!old?.episodes) return old;
|
||||||
|
return {
|
||||||
|
...old,
|
||||||
|
episodes: old.episodes.map((ep: Episode) =>
|
||||||
|
ep._id === episode._id ? { ...ep, progress: newProgress } : ep
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await episodeService.saveProgress(episode._id, newProgress.position, completed);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to toggle read state:', error);
|
console.error('Failed to toggle read state:', error);
|
||||||
|
// Revert on error
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['episodes', 'latest'] });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -181,9 +190,9 @@ export default function Dashboard() {
|
|||||||
Reprendre : {episodesInProgress[0].title.substring(0, 20)}...
|
Reprendre : {episodesInProgress[0].title.substring(0, 20)}...
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<Link to="/trending" className="neon-button flex items-center gap-2">
|
<Link to="/add" className="neon-button flex items-center gap-2">
|
||||||
<TrendingUp className="w-4 h-4" />
|
<TrendingUp className="w-4 h-4" />
|
||||||
Découvrir
|
Découvrir des podcasts
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
<Link to="/trending" className="px-6 py-3 rounded-2xl bg-[var(--bg-secondary)] text-[var(--text-secondary)] font-bold text-sm hover:bg-[var(--accent-primary)]/10 transition-all border border-[var(--border-color)] flex items-center justify-center">
|
<Link to="/trending" className="px-6 py-3 rounded-2xl bg-[var(--bg-secondary)] text-[var(--text-secondary)] font-bold text-sm hover:bg-[var(--accent-primary)]/10 transition-all border border-[var(--border-color)] flex items-center justify-center">
|
||||||
|
|||||||
Reference in new issue
Block a user