Merge pull request #1 from R0m1k3/dev

Dev
This commit is contained in:
LogiFlow authored and GitHub committed 2025-10-01 15:55:58 +02:00
commit 2dbc5c4b85
4 files changed
+77 -32

No files matched your search

+12 -2
View File
@@ -173,11 +173,21 @@ export default function AiChat() {
</Button>
</div>
<div className="mt-3 flex items-center gap-2">
<Button variant="outline" size="sm" data-testid="button-suggestions">
<Button
variant="outline"
size="sm"
onClick={() => toast({ title: "Bientôt disponible", description: "Les suggestions de produits seront disponibles prochainement" })}
data-testid="button-suggestions"
>
<Lightbulb className="w-4 h-4 mr-1" />
Suggestions
</Button>
<Button variant="outline" size="sm" data-testid="button-history">
<Button
variant="outline"
size="sm"
onClick={() => toast({ title: "Bientôt disponible", description: "L'historique des générations sera disponible prochainement" })}
data-testid="button-history"
>
<History className="w-4 h-4 mr-1" />
Historique
</Button>
+46 -28
View File
@@ -2,14 +2,23 @@ import { useState } from "react";
import { Button } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
import type { ScheduledPost } from "@shared/schema";
export default function CalendarView() {
const [currentDate, setCurrentDate] = useState(new Date());
const { data: scheduledPosts } = useQuery({
const { data: scheduledPosts = [] } = useQuery<ScheduledPost[]>({
queryKey: ["/api/scheduled-posts"],
});
const getPostsForDate = (date: Date) => {
return (scheduledPosts || []).filter(post => {
if (!post.scheduledAt) return false;
const postDate = new Date(post.scheduledAt);
return postDate.toDateString() === date.toDateString();
});
};
const goToPreviousMonth = () => {
setCurrentDate(new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1));
};
@@ -131,45 +140,54 @@ export default function CalendarView() {
)}
</div>
{/* Sample events - in real app, filter scheduledPosts by date */}
{day.isCurrentMonth && day.date.getDate() % 7 === 5 && (
<div className="space-y-1">
<div className="px-2 py-1 rounded text-xs bg-chart-1/20 text-chart-1 cursor-pointer hover:bg-chart-1/30 transition-all">
<i className="fab fa-facebook text-[10px] mr-1"></i>
<span>14h - Promo</span>
{/* Real scheduled posts for this date */}
{(() => {
if (!day.isCurrentMonth) return null;
const postsForDay = getPostsForDate(day.date);
if (postsForDay.length === 0) return null;
return (
<div className="space-y-1">
{postsForDay.slice(0, 2).map((post, 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;
return (
<div
key={idx}
className={`
px-2 py-1 rounded text-xs cursor-pointer transition-all
${isPending ? 'bg-chart-3/20 text-chart-3 hover:bg-chart-3/30' : ''}
${isPublished ? 'bg-chart-2/20 text-chart-2 hover:bg-chart-2/30' : ''}
`}
data-testid={`calendar-post-${post.id}`}
>
<span>{time} - {post.postType || 'Post'}</span>
</div>
);
})}
{postsForDay.length > 2 && (
<div className="text-[10px] text-muted-foreground pl-2">
+{postsForDay.length - 2} autre(s)
</div>
)}
</div>
</div>
)}
{day.isCurrentMonth && day.date.getDate() % 7 === 0 && (
<div className="space-y-1">
<div className="px-2 py-1 rounded text-xs bg-chart-5/20 text-chart-5 cursor-pointer hover:bg-chart-5/30 transition-all">
<i className="fab fa-instagram text-[10px] mr-1"></i>
<span>10h - Story</span>
</div>
</div>
)}
);
})()}
</div>
))}
</div>
{/* Legend */}
<div className="mt-6 flex items-center justify-center gap-6 flex-wrap">
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded bg-chart-1"></div>
<span className="text-sm text-muted-foreground">Facebook</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded bg-chart-5"></div>
<span className="text-sm text-muted-foreground">Instagram</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded bg-chart-3"></div>
<span className="text-sm text-muted-foreground">Story</span>
<span className="text-sm text-muted-foreground">Programmé</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded bg-chart-2"></div>
<span className="text-sm text-muted-foreground">Vidéo</span>
<span className="text-sm text-muted-foreground">Publié</span>
</div>
</div>
</div>
+5 -2
View File
@@ -48,7 +48,7 @@ export default function MediaUpload() {
}
}, []);
const { getRootProps, getInputProps, isDragActive } = useDropzone({
const { getRootProps, getInputProps, isDragActive, open } = useDropzone({
onDrop,
accept: {
"image/*": [".png", ".jpg", ".jpeg", ".gif"],
@@ -76,7 +76,10 @@ export default function MediaUpload() {
Ajoutez des photos ou vidéos, elles seront automatiquement recadrées pour Facebook et Instagram
</p>
</div>
<Button data-testid="button-browse">
<Button
onClick={open}
data-testid="button-browse"
>
<CloudUpload className="w-4 h-4 mr-2" />
Parcourir
</Button>
+14
View File
@@ -12,6 +12,8 @@ services:
POSTGRES_PASSWORD: ${PGPASSWORD:-changeme}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- internal
# Port non exposé sur l'hôte pour plus de sécurité en production
# Décommentez la ligne suivante si vous avez besoin d'accéder à la DB localement
# ports:
@@ -40,6 +42,9 @@ services:
APP_URL: ${APP_URL:-http://localhost:5000}
volumes:
- ./uploads:/app/uploads
networks:
- internal
- nginx_default
depends_on:
postgres:
condition: service_healthy
@@ -48,3 +53,12 @@ services:
volumes:
postgres_data:
driver: local
networks:
# Réseau interne pour la communication DB <-> App
internal:
driver: bridge
# Réseau externe pour nginx reverse proxy
nginx_default:
external: true