From ceafb24f1b18686446e99a3600712f97152b0e75 Mon Sep 17 00:00:00 2001 From: R0m1k3 Date: Tue, 21 Apr 2026 09:45:27 +0200 Subject: [PATCH 1/3] style: remove premium labels + fix LU badge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove all visible "premium" text labels across the app: Navigation sidebar: "Premium Audio" → "Your audio space" Header: "Premium Member" → "Membre" Login page badge: "Expérience Audio Premium" → "Votre espace audio" Dashboard hero badge: "Podcastic Premium" → "Podcastic" EpisodeCard fallback author: "Artiste Premium" → empty string - LU badge: remove Check icon (was rendering as "?" in some envs), now shows clean "LU" text only Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/components/EpisodeCard.tsx | 5 ++--- frontend/src/components/Header.tsx | 2 +- frontend/src/components/Navigation.tsx | 2 +- frontend/src/pages/Dashboard.tsx | 2 +- frontend/src/pages/Login.tsx | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/EpisodeCard.tsx b/frontend/src/components/EpisodeCard.tsx index 7dd3196..6ce6655 100644 --- a/frontend/src/components/EpisodeCard.tsx +++ b/frontend/src/components/EpisodeCard.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Episode } from '../services/episodeService'; -import { Play, Pause, Calendar, Activity, Check, CheckCircle2, Circle } from 'lucide-react'; +import { Play, Pause, Calendar, Activity, CheckCircle2, Circle } from 'lucide-react'; import { useAudio } from '../context/AudioContext'; interface EpisodeCardProps { @@ -75,7 +75,6 @@ export default function EpisodeCard({ episode, onPlay, onDetails, onToggleRead }
{isCompleted && (
- LU
)} @@ -112,7 +111,7 @@ export default function EpisodeCard({ episode, onPlay, onDetails, onToggleRead }
- {podcast?.author || 'Artiste Premium'} + {podcast?.author || ''}
diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx index 5997c64..54e058e 100644 --- a/frontend/src/components/Header.tsx +++ b/frontend/src/components/Header.tsx @@ -40,7 +40,7 @@ export default function Header({ title, subtitle, user, onLogout }: HeaderProps)
{user.username} - Premium Member + Membre
diff --git a/frontend/src/components/Navigation.tsx b/frontend/src/components/Navigation.tsx index aa5d385..69d3cd7 100644 --- a/frontend/src/components/Navigation.tsx +++ b/frontend/src/components/Navigation.tsx @@ -26,7 +26,7 @@ export default function Navigation() {
PODCASTIC - Premium Audio + Your audio space
diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index 23eb70d..1853ef4 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -163,7 +163,7 @@ export default function Dashboard() {
- Podcastic Premium + Podcastic

Découvrez les nouveautés de votre univers audio. diff --git a/frontend/src/pages/Login.tsx b/frontend/src/pages/Login.tsx index c3048c8..8b764d2 100644 --- a/frontend/src/pages/Login.tsx +++ b/frontend/src/pages/Login.tsx @@ -61,7 +61,7 @@ export default function Login() {

PODCASTIC

- Expérience Audio Premium + Votre espace audio
From 454d8517fbbc746cd754ea871d1f33a3ef561629 Mon Sep 17 00:00:00 2001 From: R0m1k3 Date: Tue, 21 Apr 2026 09:55:03 +0200 Subject: [PATCH 2/3] ci: add GitHub Actions auto-build + fix Unraid update - Add .github/workflows/docker-publish.yml: builds Docker image on every push to main and publishes to ghcr.io/r0m1k3/podcastic:latest automatically - docker-compose.yml: replace local `build:` with `image: ghcr.io/r0m1k3/podcastic:latest` so Unraid's "Update" button can pull the image directly from the registry instead of failing with "no service selected" - Remove deprecated `version: '3.8'` field Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/docker-publish.yml | 49 ++++++++++++++++++++++++++++ docker-compose.yml | 6 +--- 2 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/docker-publish.yml diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..f573c55 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,49 @@ +name: Build & Publish Docker Image + +on: + push: + branches: [main] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest + type=sha,prefix=sha- + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/docker-compose.yml b/docker-compose.yml index aede5f0..2aa5f52 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: mongodb: image: mongo:8 @@ -31,9 +29,7 @@ services: retries: 5 app: - build: - context: . - dockerfile: Dockerfile + image: ghcr.io/r0m1k3/podcastic:latest container_name: podcastic-app restart: unless-stopped ports: From e06f342c8ee70dab12ecb82982a24f58f2497321 Mon Sep 17 00:00:00 2001 From: R0m1k3 Date: Tue, 21 Apr 2026 10:06:09 +0200 Subject: [PATCH 3/3] fix: lu badge persistence + remove ? + fix duplicate buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- frontend/src/components/EpisodeCard.tsx | 2 +- frontend/src/pages/Dashboard.tsx | 39 +++++++++++++++---------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/frontend/src/components/EpisodeCard.tsx b/frontend/src/components/EpisodeCard.tsx index 6ce6655..b805a2e 100644 --- a/frontend/src/components/EpisodeCard.tsx +++ b/frontend/src/components/EpisodeCard.tsx @@ -139,7 +139,7 @@ export default function EpisodeCard({ episode, onPlay, onDetails, onToggleRead } ? : } - {isCompleted ? 'Lu' : 'Lu ?'} + {isCompleted ? 'Lu' : 'Marquer'} )}
diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index 1853ef4..e232be9 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -1,5 +1,5 @@ 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 { episodeService, Episode } from '../services/episodeService'; import { authService } from '../services/authService'; @@ -13,6 +13,7 @@ import { Sparkles, Play, Clock, TrendingUp, Loader, RefreshCcw } from 'lucide-re export default function Dashboard() { const { playEpisode, currentEpisode, closePlayer, setUserId } = useAudio(); + const queryClient = useQueryClient(); const [user, setUser] = useState(null); const [detailsEpisode, setDetailsEpisode] = useState(null); const [isDetailsOpen, setIsDetailsOpen] = useState(false); @@ -41,21 +42,29 @@ export default function Dashboard() { }; const handleToggleRead = async (episode: Episode, completed: boolean) => { + const newProgress = { position: completed ? episode.duration : 0, isCompleted: completed }; + // Optimistic update: local state + all cached query pages + setEpisodes(prev => + prev.map(ep => ep._id === episode._id ? { ...ep, progress: newProgress } : ep) + ); + queryClient.setQueriesData( + { 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, - completed ? episode.duration : 0, - completed - ); - setEpisodes(prev => - prev.map(ep => - ep._id === episode._id - ? { ...ep, progress: { position: completed ? ep.duration : 0, isCompleted: completed } } - : ep - ) - ); + await episodeService.saveProgress(episode._id, newProgress.position, completed); } catch (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)}... ) : ( - + - Découvrir + Découvrir des podcasts )}