diff --git a/client/src/pages/new-post.tsx b/client/src/pages/new-post.tsx
index 73dd561..32c1c73 100644
--- a/client/src/pages/new-post.tsx
+++ b/client/src/pages/new-post.tsx
@@ -1,4 +1,4 @@
-import { useState, useCallback, useRef, useEffect } from "react";
+import { useState, useCallback, useRef, useMemo } from "react";
import { useQuery, useMutation } from "@tanstack/react-query";
import { useLocation } from "wouter";
import { Send, Sparkles, Image as ImageIcon, Calendar, Upload, Camera, GripVertical, Loader2 } from "lucide-react";
@@ -60,6 +60,8 @@ function SortableMediaItem({
transition,
};
+ const isVideo = media.type === 'video';
+
return (
-
+ {isVideo ? (
+
+ ) : (
+
+ )}
{isSelected && (
<>
@@ -114,20 +126,28 @@ export default function NewPost() {
const [postText, setPostText] = useState('');
const [postType, setPostType] = useState<'feed' | 'story' | 'both'>('feed');
const [previewModalOpen, setPreviewModalOpen] = useState(false);
- const [visibleMediaCount, setVisibleMediaCount] = useState(() => {
- // Chargement initial adapté à la taille d'écran : 6 sur mobile, 12 sur desktop
- return window.innerWidth < 768 ? 6 : 12;
- });
- const loadMoreMediaRef = useRef
(null);
const { data: pages = [] } = useQuery({
queryKey: ['/api/pages'],
});
- const { data: mediaList = [] } = useQuery({
+ const { data: allMedia = [] } = useQuery({
queryKey: ['/api/media'],
});
+ // Afficher seulement les 12 derniers médias triés par date décroissante
+ // Utilisation de useMemo pour éviter de re-trier à chaque render
+ // Création d'une copie pour ne pas muter le cache React Query
+ const mediaList = useMemo(() => {
+ return [...allMedia]
+ .sort((a, b) => {
+ const dateA = a.createdAt ? new Date(a.createdAt).getTime() : 0;
+ const dateB = b.createdAt ? new Date(b.createdAt).getTime() : 0;
+ return dateB - dateA; // Tri décroissant (plus récent en premier)
+ })
+ .slice(0, 12);
+ }, [allMedia]);
+
const { data: scheduledPosts = [] } = useQuery({
queryKey: ['/api/scheduled-posts'],
});
@@ -352,28 +372,6 @@ export default function NewPost() {
}
};
- // Scroll infini - IntersectionObserver pour la grille de médias
- useEffect(() => {
- const observer = new IntersectionObserver(
- (entries) => {
- if (entries[0].isIntersecting && mediaList && visibleMediaCount < mediaList.length) {
- setVisibleMediaCount(prev => Math.min(prev + 12, mediaList.length));
- }
- },
- { threshold: 0.1 }
- );
-
- if (loadMoreMediaRef.current) {
- observer.observe(loadMoreMediaRef.current);
- }
-
- return () => {
- if (loadMoreMediaRef.current) {
- observer.unobserve(loadMoreMediaRef.current);
- }
- };
- }, [mediaList, visibleMediaCount]);
-
return (
{sidebarOpen && (
@@ -513,12 +511,13 @@ export default function NewPost() {
)}
- Toutes les photos
+ Toutes les photos ({mediaList.length})
- {mediaList.slice(0, visibleMediaCount).map((media) => {
+ {mediaList.map((media) => {
const isSelected = selectedMedia.includes(media.id);
+ const isVideo = media.type === 'video';
return (
-
+ {isVideo ? (
+
+ ) : (
+
+ )}
{isSelected && (
Sélectionnée
@@ -560,13 +569,6 @@ export default function NewPost() {
);
})}
-
- {/* Élément sentinelle pour le scroll infini */}
- {mediaList && visibleMediaCount < mediaList.length && (
-
-
-
- )}
>
)}
diff --git a/replit.md b/replit.md
index 8e67deb..261645d 100644
--- a/replit.md
+++ b/replit.md
@@ -11,6 +11,7 @@ Preferred communication style: Simple, everyday language.
## Recent Changes
### November 5, 2025
+- **New Post Media Grid Optimization**: Optimized the "Nouvelle publication" media grid for better performance and usability. Changes: (1) Limited display to 12 most recent media items sorted by createdAt descending, (2) Removed infinite scroll functionality, (3) Implemented useMemo with spread copy to prevent React Query cache mutation during sorting, (4) Added conditional rendering for videos using `
` elements with `preload="metadata"` instead of broken ` ` tags to display proper video thumbnails. This ensures faster page load, prevents cache corruption, and provides visual previews for both images and videos.
- **Mobile Calendar Visual Separator**: Added visual separator between future and past dates in mobile calendar list view. A horizontal divider with centered text "PUBLICATIONS PASSÉES" now appears before the first past date when both future/today and past dates exist. The separator uses gray horizontal lines on both sides of uppercase text, providing clear visual distinction between upcoming posts and past posts. The separator only appears when transitioning from future to past dates - it does not show when only past or only future dates exist.
- **Mobile Calendar List Sorting Fix**: Fixed illogical date ordering in mobile calendar list view. Problem: After displaying today's date first, remaining dates were sorted using simple localeCompare, mixing past and future dates together. Solution: Implemented intelligent chronological sorting in `calendar-list-view.tsx` with three-tier logic: (1) Today's date always appears first, (2) Future dates display in ascending chronological order (soonest first), (3) Past dates appear last in descending order (most recent first). The sorting uses ISO date string comparison (yyyy-MM-dd) which preserves chronological order. This provides intuitive navigation where users see today, then upcoming posts in order, then recent past posts.