Merge pull request #88 from R0m1k3/dev

Dev
This commit is contained in:
LogiFlow authored and GitHub committed 2025-11-05 17:33:51 +01:00
commit e4d17c7d25
2 files changed
+53 -50

No files matched your search

+52 -50
View File
@@ -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 (
<div
ref={setNodeRef}
@@ -75,12 +77,22 @@ function SortableMediaItem({
className="w-full h-full"
data-testid={`button-select-media-${media.id}`}
>
<img
src={media.facebookFeedUrl || media.originalUrl}
alt={media.fileName}
className="w-full h-full object-cover"
loading="lazy"
/>
{isVideo ? (
<video
src={media.originalUrl}
className="w-full h-full object-cover"
muted
playsInline
preload="metadata"
/>
) : (
<img
src={media.facebookFeedUrl || media.originalUrl}
alt={media.fileName}
className="w-full h-full object-cover"
loading="lazy"
/>
)}
</button>
{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<HTMLDivElement>(null);
const { data: pages = [] } = useQuery<SocialPage[]>({
queryKey: ['/api/pages'],
});
const { data: mediaList = [] } = useQuery<Media[]>({
const { data: allMedia = [] } = useQuery<Media[]>({
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<ScheduledPost[]>({
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 (
<div className="flex h-screen overflow-hidden bg-background">
{sidebarOpen && (
@@ -513,12 +511,13 @@ export default function NewPost() {
</div>
)}
<div className="text-sm font-medium text-muted-foreground mb-2">
Toutes les photos
Toutes les photos ({mediaList.length})
</div>
<div className="max-h-[500px] overflow-y-auto">
<div className="grid grid-cols-2 sm:grid-cols-3 gap-2">
{mediaList.slice(0, visibleMediaCount).map((media) => {
{mediaList.map((media) => {
const isSelected = selectedMedia.includes(media.id);
const isVideo = media.type === 'video';
return (
<button
@@ -545,12 +544,22 @@ export default function NewPost() {
}`}
data-testid={`button-select-media-${media.id}`}
>
<img
src={media.facebookFeedUrl || media.originalUrl}
alt={media.fileName}
className="w-full h-full object-cover"
loading="lazy"
/>
{isVideo ? (
<video
src={media.originalUrl}
className="w-full h-full object-cover"
muted
playsInline
preload="metadata"
/>
) : (
<img
src={media.facebookFeedUrl || media.originalUrl}
alt={media.fileName}
className="w-full h-full object-cover"
loading="lazy"
/>
)}
{isSelected && (
<div className="absolute inset-0 bg-primary/10 flex items-center justify-center">
<div className="text-xs font-semibold text-primary">Sélectionnée</div>
@@ -560,13 +569,6 @@ export default function NewPost() {
);
})}
</div>
{/* Élément sentinelle pour le scroll infini */}
{mediaList && visibleMediaCount < mediaList.length && (
<div ref={loadMoreMediaRef} className="flex justify-center py-4 col-span-3">
<Loader2 className="w-5 h-5 text-primary animate-spin" />
</div>
)}
</div>
</>
)}
+1
View File
@@ -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 `<video>` elements with `preload="metadata"` instead of broken `<img>` 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.