diff --git a/client/src/components/calendar-view.tsx b/client/src/components/calendar-view.tsx index 14979fa..61254c8 100644 --- a/client/src/components/calendar-view.tsx +++ b/client/src/components/calendar-view.tsx @@ -18,7 +18,7 @@ export default function CalendarView() { 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 [previewData, setPreviewData] = useState<{ postText: string; mediaIds: string[]; allMedia: Media[]; generationStatus?: string; generationProgress?: number }>({ postText: '', mediaIds: [], allMedia: [] }); const { toast } = useToast(); const isDesktop = useMediaQuery("(min-width: 768px)"); @@ -28,7 +28,7 @@ export default function CalendarView() { }); const deletePostMutation = useMutation({ - mutationFn: (postId: string) => + mutationFn: (postId: string) => apiRequest('DELETE', `/api/scheduled-posts/${postId}`, {}), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['/api/scheduled-posts'] }); @@ -61,26 +61,28 @@ export default function CalendarView() { 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, + generationStatus: postWithMedia.post.generationStatus, + generationProgress: postWithMedia.post.generationProgress, }); - + setPreviewModalOpen(true); } catch (error) { toast({ @@ -111,11 +113,11 @@ export default function CalendarView() { return (scheduledPosts || []).filter(post => { if (!post.scheduledAt) return false; const postDate = new Date(post.scheduledAt); - + // Compare using local date components to avoid timezone issues return postDate.getFullYear() === date.getFullYear() && - postDate.getMonth() === date.getMonth() && - postDate.getDate() === date.getDate(); + postDate.getMonth() === date.getMonth() && + postDate.getDate() === date.getDate(); }); }; @@ -181,9 +183,9 @@ export default function CalendarView() {
- + {isPending && ( + <> + + + + )}
-
- - {isPending && ( - <> - - - - )} -
- - ); - })} - {postsForDay.length > 2 && ( - - - - - -
-

- Tous les posts du {day.date.getDate()} {monthNames[day.date.getMonth()]} -

- {postsForDay.slice(2).map((post: any, idx) => { - const time = post.scheduledAt ? new Date(post.scheduledAt).toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' }) : ''; - const isPending = !post.publishedAt; - const isPublished = !!post.publishedAt; - const pageName = post.page?.pageName || 'Page inconnue'; - const platform = post.page?.platform || 'facebook'; - const PlatformIcon = platform === 'instagram' ? SiInstagram : SiFacebook; - - return ( -
2 && ( + + + + + +
+

+ Tous les posts du {day.date.getDate()} {monthNames[day.date.getMonth()]} +

+ {postsForDay.slice(2).map((post: any, idx) => { + const time = post.scheduledAt ? new Date(post.scheduledAt).toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' }) : ''; + const isPending = !post.publishedAt; + const isPublished = !!post.publishedAt; + const pageName = post.page?.pageName || 'Page inconnue'; + const platform = post.page?.platform || 'facebook'; + const PlatformIcon = platform === 'instagram' ? SiInstagram : SiFacebook; + + return ( +
-
-
-
- {getPostTypeIcon(post.postType)} - {time} + data-testid={`popover-post-${post.id}`} + > +
+
+
+ {getPostTypeIcon(post.postType)} + {time} +
+
+ + {pageName} +
-
- - {pageName} +
+ + {isPending && ( + <> + + + + )}
-
- - {isPending && ( - <> - - - - )} -
-
- ); - })} -
- - - )} -
- ); - })()} -
- ))} -
+ ); + })} +
+ + + )} +
+ ); + })()} + + ))} +
@@ -438,9 +440,11 @@ export default function CalendarView() { postText={previewData.postText} selectedMedia={previewData.mediaIds} mediaList={previewData.allMedia} - onPublish={() => {}} + onPublish={() => { }} isPublishing={false} readOnly={true} + generationStatus={previewData.generationStatus} + generationProgress={previewData.generationProgress} />
); diff --git a/client/src/components/preview-modal.tsx b/client/src/components/preview-modal.tsx index 1f4b1be..bf92b3c 100644 --- a/client/src/components/preview-modal.tsx +++ b/client/src/components/preview-modal.tsx @@ -2,7 +2,7 @@ import { useState, useEffect, useRef } from 'react'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; -import { ChevronLeft, ChevronRight, Send, Facebook, Instagram, Heart, MessageCircle, Share2, Bookmark } from 'lucide-react'; +import { ChevronLeft, ChevronRight, Send, Facebook, Instagram, Heart, MessageCircle, Share2, Bookmark, Loader2, Video } from 'lucide-react'; import type { Media } from '@shared/schema'; import { removeHashtags } from '@shared/emoji'; import { EmojiText } from '@/components/emoji-text'; @@ -16,6 +16,8 @@ interface PreviewModalProps { onPublish: () => void; isPublishing: boolean; readOnly?: boolean; + generationStatus?: string; + generationProgress?: number; } type PreviewFormat = 'facebook-feed' | 'facebook-story' | 'instagram-feed' | 'instagram-story'; @@ -28,7 +30,9 @@ export function PreviewModal({ mediaList, onPublish, isPublishing, - readOnly = false + readOnly = false, + generationStatus, + generationProgress }: PreviewModalProps) { const [previewFormat, setPreviewFormat] = useState('facebook-feed'); const [currentPhotoIndex, setCurrentPhotoIndex] = useState(0); @@ -68,7 +72,7 @@ export function PreviewModal({ const renderMedia = (media: Media, className: string = "w-full h-auto") => { const url = getMediaUrl(media); - + if (media.type === 'video') { return (