diff --git a/client/src/components/calendar-list-view.tsx b/client/src/components/calendar-list-view.tsx index edac5de..82105eb 100644 --- a/client/src/components/calendar-list-view.tsx +++ b/client/src/components/calendar-list-view.tsx @@ -1,6 +1,6 @@ import { format, isSameDay, parseISO } from "date-fns"; import { fr } from "date-fns/locale"; -import { Edit, Trash2, ChevronDown, ChevronUp } from "lucide-react"; +import { Edit, Trash2, ChevronDown, ChevronUp, Eye } from "lucide-react"; import { SiFacebook, SiInstagram } from "react-icons/si"; import { Button } from "@/components/ui/button"; import { useState } from "react"; @@ -9,9 +9,10 @@ interface CalendarListViewProps { scheduledPosts: any[]; onEditPost: (post: any) => void; onDeletePost: (postId: string) => void; + onPreviewPost: (post: any) => void; } -export default function CalendarListView({ scheduledPosts, onEditPost, onDeletePost }: CalendarListViewProps) { +export default function CalendarListView({ scheduledPosts, onEditPost, onDeletePost, onPreviewPost }: CalendarListViewProps) { const [expandedDates, setExpandedDates] = useState>(new Set()); // Group posts by date @@ -129,30 +130,42 @@ export default function CalendarListView({ scheduledPosts, onEditPost, onDeleteP - {isPending && ( -
- - -
- )} +
+ + {isPending && ( + <> + + + + )} +
); diff --git a/client/src/components/calendar-view.tsx b/client/src/components/calendar-view.tsx index 5a1c5fb..1466388 100644 --- a/client/src/components/calendar-view.tsx +++ b/client/src/components/calendar-view.tsx @@ -1,7 +1,7 @@ import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; -import { ChevronLeft, ChevronRight, Calendar as CalendarIcon, Trash2, Edit, MoreHorizontal } from "lucide-react"; +import { ChevronLeft, ChevronRight, Calendar as CalendarIcon, Trash2, Edit, MoreHorizontal, Eye } from "lucide-react"; import { useQuery, useMutation } from "@tanstack/react-query"; import { useToast } from "@/hooks/use-toast"; import { apiRequest, queryClient } from "@/lib/queryClient"; @@ -10,11 +10,15 @@ import { SiFacebook, SiInstagram } from "react-icons/si"; import EditScheduledPostDialog from "./edit-scheduled-post-dialog"; import CalendarListView from "./calendar-list-view"; import { useMediaQuery } from "@/hooks/use-media-query"; +import { PreviewModal } from "@/components/preview-modal"; +import type { Media } from "@shared/schema"; export default function CalendarView() { const [currentDate, setCurrentDate] = useState(new Date()); const [editDialogOpen, setEditDialogOpen] = useState(false); const [selectedPost, setSelectedPost] = useState(null); + const [previewModalOpen, setPreviewModalOpen] = useState(false); + const [previewData, setPreviewData] = useState<{ postText: string; mediaIds: string[]; allMedia: Media[] }>({ postText: '', mediaIds: [], allMedia: [] }); const { toast } = useToast(); const isDesktop = useMediaQuery("(min-width: 768px)"); @@ -54,6 +58,38 @@ export default function CalendarView() { setEditDialogOpen(true); }; + const handlePreviewPost = async (scheduledPost: any, e?: React.MouseEvent) => { + if (e) e.stopPropagation(); + + 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, + }); + + setPreviewModalOpen(true); + } catch (error) { + toast({ + title: "Erreur", + description: "Impossible de charger la prévisualisation", + variant: "destructive", + }); + } + }; + const getPostsForDate = (date: Date) => { return (scheduledPosts || []).filter(post => { if (!post.scheduledAt) return false; @@ -226,26 +262,36 @@ export default function CalendarView() { {pageName} - {isPending && ( -
- - -
- )} +
+ + {isPending && ( + <> + + + + )} +
); @@ -292,26 +338,36 @@ export default function CalendarView() { {pageName} - {isPending && ( -
- - -
- )} +
+ + {isPending && ( + <> + + + + )} +
); @@ -343,6 +399,7 @@ export default function CalendarView() { scheduledPosts={scheduledPosts} onEditPost={handleEditPost} onDeletePost={handleDeletePost} + onPreviewPost={handlePreviewPost} /> )} @@ -351,6 +408,16 @@ export default function CalendarView() { onOpenChange={setEditDialogOpen} scheduledPost={selectedPost || {}} /> + + {}} + isPublishing={false} + /> ); } diff --git a/client/src/components/recent-publications.tsx b/client/src/components/recent-publications.tsx index ffb83c4..86808b4 100644 --- a/client/src/components/recent-publications.tsx +++ b/client/src/components/recent-publications.tsx @@ -1,9 +1,13 @@ import { useQuery } from "@tanstack/react-query"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Facebook, Instagram, Clock, CheckCircle2, XCircle } from "lucide-react"; +import { Facebook, Instagram, Clock, CheckCircle2, XCircle, Eye } from "lucide-react"; import { format } from "date-fns"; import { fr } from "date-fns/locale"; -import type { ScheduledPost, SocialPage, Post } from "@shared/schema"; +import type { ScheduledPost, SocialPage, Post, Media } from "@shared/schema"; +import { PreviewModal } from "@/components/preview-modal"; +import { useState } from "react"; +import { useToast } from "@/hooks/use-toast"; +import { Button } from "@/components/ui/button"; type ScheduledPostWithRelations = ScheduledPost & { post?: Post; @@ -11,6 +15,10 @@ type ScheduledPostWithRelations = ScheduledPost & { }; export default function RecentPublications() { + const [previewModalOpen, setPreviewModalOpen] = useState(false); + const [previewData, setPreviewData] = useState<{ postText: string; mediaIds: string[]; allMedia: Media[] }>({ postText: '', mediaIds: [], allMedia: [] }); + const { toast } = useToast(); + const { data: scheduledPosts = [], isLoading } = useQuery({ queryKey: ['/api/scheduled-posts'], }); @@ -21,6 +29,36 @@ export default function RecentPublications() { .sort((a, b) => new Date(b.publishedAt!).getTime() - new Date(a.publishedAt!).getTime()) .slice(0, 10); + 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, + }); + + setPreviewModalOpen(true); + } catch (error) { + toast({ + title: "Erreur", + description: "Impossible de charger la prévisualisation", + variant: "destructive", + }); + } + }; + return ( @@ -77,7 +115,17 @@ export default function RecentPublications() { )}

-
+
+ {scheduledPost.error ? ( ) : ( @@ -108,6 +156,16 @@ export default function RecentPublications() {
)} + + {}} + isPublishing={false} + /> ); }