diff --git a/client/src/components/preview-modal.tsx b/client/src/components/preview-modal.tsx new file mode 100644 index 0000000..5e1f55a --- /dev/null +++ b/client/src/components/preview-modal.tsx @@ -0,0 +1,335 @@ +import { useState, useEffect } 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 type { Media } from '@shared/schema'; + +interface PreviewModalProps { + open: boolean; + onOpenChange: (open: boolean) => void; + postText: string; + selectedMedia: string[]; + mediaList: Media[]; + onPublish: () => void; + isPublishing: boolean; +} + +type PreviewFormat = 'facebook-feed' | 'instagram-feed' | 'instagram-story'; + +export function PreviewModal({ + open, + onOpenChange, + postText, + selectedMedia, + mediaList, + onPublish, + isPublishing +}: PreviewModalProps) { + const [previewFormat, setPreviewFormat] = useState('facebook-feed'); + const [currentPhotoIndex, setCurrentPhotoIndex] = useState(0); + + const orderedMedia = selectedMedia + .map(id => mediaList.find(m => m.id === id)) + .filter((m): m is Media => m !== undefined); + + // Reset photo index when modal opens or media changes + useEffect(() => { + if (open) { + setCurrentPhotoIndex(0); + } + }, [open, selectedMedia.length]); + + const nextPhoto = () => { + setCurrentPhotoIndex((prev) => (prev + 1) % orderedMedia.length); + }; + + const prevPhoto = () => { + setCurrentPhotoIndex((prev) => (prev - 1 + orderedMedia.length) % orderedMedia.length); + }; + + const goToPhoto = (index: number) => { + setCurrentPhotoIndex(index); + }; + + const getMediaUrl = (media: Media) => { + if (previewFormat === 'facebook-feed') { + return media.facebookFeedUrl || media.originalUrl; + } else if (previewFormat === 'instagram-feed') { + return media.instagramFeedUrl || media.originalUrl; + } else { + return media.instagramStoryUrl || media.originalUrl; + } + }; + + const renderFacebookFeed = () => ( +
+ {/* Header */} +
+
+ +
+
+
Votre Page
+
À l'instant
+
+
+ + {/* Text */} + {postText && ( +
+ {postText} +
+ )} + + {/* Media Carousel */} + {orderedMedia.length > 0 && ( +
+ {`Photo + {orderedMedia.length > 1 && ( + <> + + +
+ {orderedMedia.map((_, idx) => ( +
+ + )} +
+ )} + + {/* Actions */} +
+ + + +
+
+ ); + + const renderInstagramFeed = () => ( +
+ {/* Header */} +
+
+ +
+
+
votre_page
+
+
+ + {/* Media Carousel */} + {orderedMedia.length > 0 && ( +
+ {`Photo + {orderedMedia.length > 1 && ( + <> + + +
+ {orderedMedia.map((_, idx) => ( +
+ + )} +
+ )} + + {/* Actions */} +
+ + + + +
+ + {/* Text */} + {postText && ( +
+ votre_page + {postText} +
+ )} +
+ ); + + const renderInstagramStory = () => ( +
+ {/* Header */} +
+
+ +
+
+
votre_page
+
+
+ + {/* Media */} + {orderedMedia.length > 0 && ( +
+ {`Story + {orderedMedia.length > 1 && ( + <> +
+ {orderedMedia.map((_, idx) => ( +
+ + + + )} + {/* Text overlay */} + {postText && ( +
+
+

{postText}

+
+
+ )} +
+ )} +
+ ); + + return ( + + + + Prévisualisation de la publication + + Visualisez votre publication avant de la publier + + + +
+ {/* Format selector */} +
+ + +
+ + {/* Preview */} +
+ {previewFormat === 'facebook-feed' && renderFacebookFeed()} + {previewFormat === 'instagram-feed' && renderInstagramFeed()} + {previewFormat === 'instagram-story' && renderInstagramStory()} +
+ + {/* Actions */} +
+ + +
+
+
+
+ ); +} diff --git a/client/src/pages/new-post.tsx b/client/src/pages/new-post.tsx index b165cdf..35f2d7e 100644 --- a/client/src/pages/new-post.tsx +++ b/client/src/pages/new-post.tsx @@ -32,6 +32,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@ import { useToast } from "@/hooks/use-toast"; import { apiRequest, queryClient } from "@/lib/queryClient"; import type { SocialPage, Media } from "@shared/schema"; +import { PreviewModal } from "@/components/preview-modal"; function SortableMediaItem({ media, @@ -109,6 +110,7 @@ export default function NewPost() { const [generatedVariants, setGeneratedVariants] = useState([]); const [postText, setPostText] = useState(''); const [postType, setPostType] = useState<'feed' | 'story' | 'both'>('feed'); + const [previewModalOpen, setPreviewModalOpen] = useState(false); const { data: pages = [] } = useQuery({ queryKey: ['/api/pages'], @@ -675,19 +677,29 @@ export default function NewPost() { + + ); }