mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-16 19:59:42 +02:00
Improve calendar view and add scheduling conflict warnings
Enhance the calendar list view to prioritize today's date and introduce visual indicators for optimal posting times and existing scheduled posts on the new post page. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/VJoXNjs
This commit is contained in:
1 parent
44ec6abe00
commit
eec5e397fe
3 files changed
+90
-4
No files matched your search
@@ -42,8 +42,15 @@ export default function CalendarListView({ scheduledPosts, onEditPost, onDeleteP
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
// Sort dates
|
||||
const sortedDates = Object.keys(groupedPosts).sort();
|
||||
// Sort dates - put today first, then chronological order
|
||||
const today = format(new Date(), "yyyy-MM-dd");
|
||||
const sortedDates = Object.keys(groupedPosts).sort((a, b) => {
|
||||
// Today always comes first
|
||||
if (a === today && b !== today) return -1;
|
||||
if (b === today && a !== today) return 1;
|
||||
// Otherwise chronological order
|
||||
return a.localeCompare(b);
|
||||
});
|
||||
|
||||
const toggleDate = (date: string) => {
|
||||
const newExpanded = new Set(expandedDates);
|
||||
|
||||
@@ -32,7 +32,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { apiRequest, queryClient } from "@/lib/queryClient";
|
||||
import type { SocialPage, Media } from "@shared/schema";
|
||||
import type { SocialPage, Media, ScheduledPost } from "@shared/schema";
|
||||
import { PreviewModal } from "@/components/preview-modal";
|
||||
|
||||
function SortableMediaItem({
|
||||
@@ -127,6 +127,10 @@ export default function NewPost() {
|
||||
queryKey: ['/api/media'],
|
||||
});
|
||||
|
||||
const { data: scheduledPosts = [] } = useQuery<ScheduledPost[]>({
|
||||
queryKey: ['/api/scheduled-posts'],
|
||||
});
|
||||
|
||||
const uploadMutation = useMutation({
|
||||
mutationFn: async (file: File) => {
|
||||
const formData = new FormData();
|
||||
@@ -707,7 +711,7 @@ export default function NewPost() {
|
||||
<CardDescription>Programmez la publication (optionnel)</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-2">
|
||||
<div className="space-y-3">
|
||||
<Label htmlFor="scheduledDate">Date et heure</Label>
|
||||
<Input
|
||||
id="scheduledDate"
|
||||
@@ -719,6 +723,80 @@ export default function NewPost() {
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Laissez vide pour publier immédiatement
|
||||
</p>
|
||||
|
||||
{(() => {
|
||||
// Get dates with scheduled posts
|
||||
const datesWithPosts = scheduledPosts
|
||||
.filter(post => post.scheduledAt)
|
||||
.map(post => {
|
||||
const date = new Date(post.scheduledAt!);
|
||||
return date.toISOString().split('T')[0];
|
||||
})
|
||||
.filter((date, index, self) => self.indexOf(date) === index)
|
||||
.sort();
|
||||
|
||||
if (datesWithPosts.length > 0) {
|
||||
return (
|
||||
<div className="p-3 bg-red-500/10 rounded-lg border border-red-500/20">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div className="w-2 h-2 rounded-full bg-red-500"></div>
|
||||
<span className="text-xs font-semibold text-red-600 dark:text-red-400">
|
||||
Dates avec publications programmées
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{datesWithPosts.slice(0, 5).map((date) => {
|
||||
const dateObj = new Date(date + 'T00:00:00');
|
||||
const formatted = dateObj.toLocaleDateString('fr-FR', {
|
||||
day: '2-digit',
|
||||
month: 'short'
|
||||
});
|
||||
return (
|
||||
<span
|
||||
key={date}
|
||||
className="text-xs px-2 py-1 bg-red-500/20 text-red-700 dark:text-red-300 rounded-md font-medium"
|
||||
>
|
||||
{formatted}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
{datesWithPosts.length > 5 && (
|
||||
<span className="text-xs px-2 py-1 text-red-600 dark:text-red-400 font-medium">
|
||||
+{datesWithPosts.length - 5} autre{datesWithPosts.length - 5 > 1 ? 's' : ''}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-[10px] text-red-600/80 dark:text-red-400/80 mt-2">
|
||||
Ces dates ont déjà des publications planifiées
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})()}
|
||||
|
||||
<div className="p-3 bg-green-500/10 rounded-lg border border-green-500/20">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div className="w-2 h-2 rounded-full bg-green-500"></div>
|
||||
<span className="text-xs font-semibold text-green-600 dark:text-green-400">
|
||||
Heures optimales pour l'audience
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<span className="text-xs px-2 py-1 bg-green-500/20 text-green-700 dark:text-green-300 rounded-md font-medium">
|
||||
8h - 9h
|
||||
</span>
|
||||
<span className="text-xs px-2 py-1 bg-green-500/20 text-green-700 dark:text-green-300 rounded-md font-medium">
|
||||
12h - 14h
|
||||
</span>
|
||||
<span className="text-xs px-2 py-1 bg-green-500/20 text-green-700 dark:text-green-300 rounded-md font-medium">
|
||||
18h - 21h
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-[10px] text-green-600/80 dark:text-green-400/80 mt-2">
|
||||
Ces créneaux maximisent la portée de vos publications
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in new issue
Block a user