import { useState } from "react"; import { useQuery } from "@tanstack/react-query"; import { Clock, CheckCircle, XCircle, Calendar, History as HistoryIcon, Eye, Image as ImageIcon, Smartphone, Loader2, Clapperboard } from "lucide-react"; import Sidebar from "@/components/sidebar"; import TopBar from "@/components/topbar"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import type { ScheduledPost, SocialPage, Post, Media } from "@shared/schema"; import { format } from "date-fns"; import { fr } from "date-fns/locale"; import { PreviewModal } from "@/components/preview-modal"; import { useToast } from "@/hooks/use-toast"; type ScheduledPostWithRelations = ScheduledPost & { post?: Post; page?: SocialPage; }; /** Publication dont l'heure est passée mais que le scheduler n'a pas encore traitée. */ function isAwaitingPublication(scheduledPost: ScheduledPostWithRelations): boolean { return ( !!scheduledPost.scheduledAt && new Date(scheduledPost.scheduledAt) <= new Date() && !scheduledPost.publishedAt ); } export default function History() { const [sidebarOpen, setSidebarOpen] = useState(false); const [previewModalOpen, setPreviewModalOpen] = useState(false); const [previewData, setPreviewData] = useState<{ postText: string; mediaIds: string[]; allMedia: Media[]; generationStatus?: string; generationProgress?: number }>({ postText: '', mediaIds: [], allMedia: [] }); const { toast } = useToast(); const { data: scheduledPosts = [], isLoading } = useQuery({ queryKey: ['/api/scheduled-posts'], // Le scheduler publie en tâche de fond : on ne suit à la seconde que ce qui // est réellement en attente. Le reste du temps, une veille lente suffit — // sans quoi la page entière était rechargée 20 fois par minute pour rien. refetchInterval: (query) => (query.state.data ?? []).some(isAwaitingPublication) ? 3000 : 30000, }); // Filter attempted posts (scheduled in the past) const now = new Date(); const publishedPosts = scheduledPosts .filter(sp => sp.scheduledAt && new Date(sp.scheduledAt) <= now) .sort((a, b) => new Date(b.scheduledAt!).getTime() - new Date(a.scheduledAt!).getTime()); const handlePreviewPost = async (scheduledPost: ScheduledPostWithRelations) => { try { const response = await fetch(`/api/posts/${scheduledPost.postId}`, { credentials: "include", }); if (!response.ok) { throw new Error("Failed to fetch post"); } const postWithMedia = await response.json(); const mediaIds = postWithMedia.media?.map((m: Media) => m.id) || []; const allMedia = postWithMedia.media || []; setPreviewData({ postText: postWithMedia.post.content || '', mediaIds: mediaIds, allMedia: allMedia, generationStatus: postWithMedia.post.generationStatus, generationProgress: postWithMedia.post.generationProgress, }); setPreviewModalOpen(true); } catch (error) { toast({ title: "Erreur", description: "Impossible de charger la prévisualisation", variant: "destructive", }); } }; const getPostTypeIcon = (postType: string) => { if (postType === 'feed') { return ; } else if (postType === 'story') { return ; } else if (postType === 'reel') { return ; } else if (postType === 'both') { return (
); } return null; }; return (
{sidebarOpen && (
setSidebarOpen(false)} /> )}
setSidebarOpen(false)} />
setSidebarOpen(!sidebarOpen)} />

Historique

Consultez l'historique de vos publications

{isLoading ? (
{[1, 2, 3].map((i) => (
))}
) : publishedPosts.length === 0 ? (

Aucune publication

Vos publications apparaîtront ici une fois publiées

) : (
{publishedPosts.map((scheduledPost) => { const isPending = !scheduledPost.publishedAt; const hasError = !!scheduledPost.error; return (
{hasError ? ( ) : isPending ? ( ) : ( )}
{scheduledPost.page?.pageName || 'Page inconnue'}

{scheduledPost.post?.content || 'Aucun texte'}

{hasError ? ( <> Échoué ) : isPending ? ( <> Traitement... ) : ( <> Publié )}
{getPostTypeIcon(scheduledPost.postType)} {scheduledPost.postType === 'feed' ? 'Feed' : scheduledPost.postType === 'story' ? 'Story' : scheduledPost.postType === 'reel' ? 'Reel' : 'Feed & Story'}
{scheduledPost.scheduledAt ? format(new Date(scheduledPost.scheduledAt), "d MMM yyyy 'à' HH:mm", { locale: fr }) : 'Date inconnue' }
{scheduledPost.post?.aiGenerated && ( Généré par IA )}
); })}
)}
{ }} isPublishing={false} readOnly={true} generationStatus={previewData.generationStatus} generationProgress={previewData.generationProgress} />
); }