Merge pull request #190 from R0m1k3/1.1

1.1
This commit is contained in:
LogiFlow authored and GitHub committed 2025-08-17 10:52:50 +02:00
commit 6524d75d6b
3 files changed
+129 -28

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

+6 -8
View File
@@ -267,10 +267,7 @@ export default function AnnouncementCard() {
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<div className="flex items-center gap-2">
<Megaphone className="h-4 w-4 text-muted-foreground" />
<CardTitle className="text-sm font-medium">Informations</CardTitle>
</div>
<CardTitle className="text-sm font-medium">Informations</CardTitle>
<div className="flex items-center gap-2">
{user?.role === 'admin' && (
<Dialog open={isCreateDialogOpen} onOpenChange={(open) => {
@@ -371,6 +368,7 @@ export default function AnnouncementCard() {
</DialogContent>
</Dialog>
)}
<Megaphone className="h-4 w-4 text-muted-foreground" />
</div>
</CardHeader>
<CardContent>
@@ -388,15 +386,15 @@ export default function AnnouncementCard() {
const TypeIcon = getTypeIcon(announcement.type);
return (
<div key={announcement.id} className="flex items-start justify-between p-3 bg-muted/30 transition-colors">
<div key={announcement.id} className="flex items-start justify-between p-3 rounded-lg border bg-card hover:bg-accent/50 transition-colors">
<div className="flex items-start gap-3 flex-1 min-w-0">
<TypeIcon className="h-4 w-4 text-muted-foreground mt-0.5 flex-shrink-0" />
<TypeIcon className="h-4 w-4 text-blue-600 mt-0.5 flex-shrink-0" />
<div className="flex-1 min-w-0">
<div className="flex items-center justify-between gap-2 mb-1">
<div className="flex items-center gap-2 mb-1">
<h4 className="font-medium text-sm truncate">
{announcement.title}
</h4>
<Badge variant={priorityConfig.color} className="flex items-center gap-1 text-xs flex-shrink-0">
<Badge variant={priorityConfig.color} className="flex items-center gap-1 text-xs">
{priorityConfig.label}
</Badge>
</div>
+123 -20
View File
@@ -39,15 +39,22 @@ import {
insertSavTicketSchema,
insertSavTicketHistorySchema,
insertWeatherDataSchema,
insertWeatherSettingsSchema
insertWeatherSettingsSchema,
users, groups, userGroups, suppliers, orders, deliveries, publicities, publicityParticipations,
customerOrders, nocodbConfigs, dlcProducts, tasks, invoiceVerifications, dashboardMessages
} from "@shared/schema";
import { hasPermission } from "@shared/permissions";
import { z } from "zod";
import { eq, desc } from "drizzle-orm";
import { invoiceVerificationService } from "./invoiceVerification";
import { backupService } from "./backupService";
import { weatherService } from "./weatherService.js";
export async function registerRoutes(app: Express): Promise<Server> {
// Detect environment
const environment = process.env.NODE_ENV || 'development';
console.log('🌍 Environment detected:', environment);
// Health check endpoint for Docker
app.get('/api/health', (req, res) => {
res.status(200).json({
@@ -2997,33 +3004,102 @@ RÉSUMÉ DU SCAN
});
// Route de géolocalisation météo
// Announcement routes
// Announcement routes - PostgreSQL en production, mémoire en développement
app.get('/api/announcements', isAuthenticated, async (req: any, res) => {
try {
const userId = req.user.claims ? req.user.claims.sub : req.user.id;
console.log('📢 [SERVER] Fetching announcements for user:', userId, 'environment:', environment);
const user = await storage.getUserWithGroups(userId);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
// Get user's group IDs for filtering
let groupIds: number[] = [];
if (user.role === 'admin') {
// Admin can see all announcements, but can filter by selected store
const storeId = req.query.storeId;
if (storeId) {
groupIds = [parseInt(storeId)];
console.log('📢 [SERVER] User found:', { username: user.username, role: user.role });
if (environment === 'production') {
// PRODUCTION: Utiliser PostgreSQL avec DASHBOARD_MESSAGES
console.log('🎯 [PRODUCTION] Using PostgreSQL DASHBOARD_MESSAGES table');
try {
let query = db.select({
id: dashboardMessages.id,
title: dashboardMessages.title,
content: dashboardMessages.content,
type: dashboardMessages.type,
storeId: dashboardMessages.storeId,
createdBy: dashboardMessages.createdBy,
createdAt: dashboardMessages.createdAt,
}).from(dashboardMessages);
// Filtrage par magasin pour admin
if (user.role === 'admin' && req.query.storeId) {
query = query.where(eq(dashboardMessages.storeId, parseInt(req.query.storeId as string)));
}
const messages = await query.orderBy(desc(dashboardMessages.createdAt)).limit(5);
// Ajouter les relations manuellement
const announcements = await Promise.all(
messages.map(async (message) => {
// Récupérer l'auteur
let author = { id: parseInt(message.createdBy) || 0, firstName: 'Utilisateur', lastName: 'Inconnu' };
try {
const [userResult] = await db.select().from(users).where(eq(users.id, message.createdBy));
if (userResult) {
author = {
id: parseInt(message.createdBy),
firstName: userResult.firstName || 'Utilisateur',
lastName: userResult.lastName || 'Inconnu'
};
}
} catch (e) {
console.warn('Could not fetch author for message:', message.id);
}
// Récupérer le groupe si storeId est défini
let group = null;
if (message.storeId) {
try {
const [groupResult] = await db.select().from(groups).where(eq(groups.id, message.storeId));
if (groupResult) {
group = { id: groupResult.id, name: groupResult.name };
}
} catch (e) {
console.warn('Could not fetch group for message:', message.id);
}
}
return {
...message,
author,
group
};
})
);
console.log('🎯 [PRODUCTION] Found announcements:', announcements.length);
res.json(announcements);
} catch (dbError) {
console.error('🎯 [PRODUCTION] Database error:', dbError);
// Fallback au stockage mémoire en cas d'erreur DB
console.log('🧠 [FALLBACK] Using memory storage due to DB error');
const announcements = await storage.getAnnouncements();
res.json(announcements);
}
} else {
// Other roles see only their assigned groups + global announcements
const userGroups = (user as any).userGroups;
groupIds = userGroups ? userGroups.map((ug: any) => ug.groupId) : [];
// DÉVELOPPEMENT: Utiliser stockage mémoire
console.log('🧠 [DEV] Using memory storage for announcements');
const groupIds = user.role === 'admin' && req.query.storeId
? [parseInt(req.query.storeId as string)]
: undefined;
const announcements = await storage.getAnnouncements(groupIds);
res.json(announcements);
}
const announcements = await storage.getAnnouncements(groupIds.length > 0 ? groupIds : undefined);
res.json(announcements);
} catch (error) {
console.error("Error fetching announcements:", error);
console.error("📢 [SERVER] Error fetching announcements:", error);
res.status(500).json({ message: "Failed to fetch announcements" });
}
});
@@ -3067,10 +3143,37 @@ RÉSUMÉ DU SCAN
console.log('🎯 [SERVER] Announcement data validated:', announcementData);
const announcement = await storage.createAnnouncement(announcementData);
console.log('🎯 [SERVER] Announcement created successfully:', announcement);
res.status(201).json(announcement);
if (environment === 'production') {
// PRODUCTION: Créer dans PostgreSQL DASHBOARD_MESSAGES
console.log('🎯 [PRODUCTION] Creating in PostgreSQL DASHBOARD_MESSAGES table');
try {
const [newMessage] = await db.insert(dashboardMessages).values({
title: announcementData.title,
content: announcementData.content,
type: announcementData.type,
storeId: announcementData.storeId,
createdBy: user.id.toString(),
}).returning();
const announcement = {
...newMessage,
author: { id: user.id, firstName: user.firstName, lastName: user.lastName },
group: null
};
console.log('🎯 [PRODUCTION] Announcement created successfully in DB:', announcement);
res.status(201).json(announcement);
} catch (dbError) {
console.error('🎯 [PRODUCTION] DB error, fallback to memory:', dbError);
const announcement = await storage.createAnnouncement(announcementData);
res.status(201).json(announcement);
}
} else {
// DÉVELOPPEMENT: Créer en mémoire
const announcement = await storage.createAnnouncement(announcementData);
console.log('🧠 [DEV] Announcement created in memory:', announcement);
res.status(201).json(announcement);
}
} catch (error) {
console.error('🎯 [SERVER] Error creating announcement:', error);
if (error instanceof z.ZodError) {