mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-12 01:37:40 +02:00
Merge pull request #191 from R0m1k3/1.1
Update announcement system to use production database and improve car…
This commit is contained in:
3 files changed
+138
-44
No files matched your search
@@ -387,33 +387,31 @@ export default function AnnouncementCard() {
|
||||
|
||||
return (
|
||||
<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-blue-600 mt-0.5 flex-shrink-0" />
|
||||
<div className="flex-1 min-w-0">
|
||||
<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">
|
||||
{priorityConfig.label}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
{announcement.content && (
|
||||
<p className="text-xs text-muted-foreground mb-1 line-clamp-1">
|
||||
{announcement.content}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-3 text-xs text-muted-foreground">
|
||||
<span>
|
||||
{safeFormat(safeDate(announcement.createdAt), 'dd/MM à HH:mm')}
|
||||
</span>
|
||||
<span>
|
||||
{announcement.author.firstName} {announcement.author.lastName}
|
||||
{announcement.group && ` • ${announcement.group.name}`}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<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">
|
||||
<TypeIcon className="w-2.5 h-2.5" />
|
||||
{priorityConfig.label}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
{announcement.content && (
|
||||
<p className="text-xs text-muted-foreground mb-1 line-clamp-1">
|
||||
{announcement.content}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-3 text-xs text-muted-foreground">
|
||||
<span>
|
||||
{safeFormat(safeDate(announcement.createdAt), 'dd/MM à HH:mm')}
|
||||
</span>
|
||||
<span>
|
||||
{announcement.author.firstName} {announcement.author.lastName}
|
||||
{announcement.group && ` • ${announcement.group.name}`}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{user?.role === 'admin' && (
|
||||
|
||||
+109
-12
@@ -1,7 +1,90 @@
|
||||
import { Announcement, InsertAnnouncement, AnnouncementWithRelations, User, Group } from "@shared/schema";
|
||||
import { DashboardMessage, InsertDashboardMessage, DashboardMessageWithRelations, User, Group } from "@shared/schema";
|
||||
import { db } from "./db";
|
||||
import { dashboardMessages, users, groups } from "@shared/schema";
|
||||
import { eq, desc } from "drizzle-orm";
|
||||
|
||||
// Stockage en mémoire partagé pour les annonces (maximum 5)
|
||||
class AnnouncementMemoryStorage {
|
||||
// Type aliases pour compatibilité
|
||||
type Announcement = DashboardMessage;
|
||||
type InsertAnnouncement = InsertDashboardMessage;
|
||||
type AnnouncementWithRelations = DashboardMessageWithRelations;
|
||||
|
||||
// Interface commune pour le stockage
|
||||
interface IAnnouncementStorage {
|
||||
getAnnouncements(groupIds?: number[]): Promise<AnnouncementWithRelations[]>;
|
||||
createAnnouncement(announcement: InsertAnnouncement): Promise<DashboardMessage>;
|
||||
updateAnnouncement(id: number, announcement: Partial<InsertAnnouncement>): Promise<DashboardMessage>;
|
||||
deleteAnnouncement(id: number): Promise<void>;
|
||||
}
|
||||
|
||||
// Stockage PostgreSQL pour la production
|
||||
class AnnouncementDatabaseStorage implements IAnnouncementStorage {
|
||||
async getAnnouncements(groupIds?: number[]): Promise<AnnouncementWithRelations[]> {
|
||||
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,
|
||||
author: {
|
||||
id: users.id,
|
||||
firstName: users.firstName,
|
||||
lastName: users.lastName,
|
||||
username: users.username,
|
||||
},
|
||||
group: {
|
||||
id: groups.id,
|
||||
name: groups.name,
|
||||
},
|
||||
})
|
||||
.from(dashboardMessages)
|
||||
.leftJoin(users, eq(dashboardMessages.createdBy, users.id))
|
||||
.leftJoin(groups, eq(dashboardMessages.storeId, groups.id))
|
||||
.orderBy(desc(dashboardMessages.createdAt));
|
||||
|
||||
const results = await query;
|
||||
|
||||
return results.map(result => ({
|
||||
id: result.id,
|
||||
title: result.title,
|
||||
content: result.content,
|
||||
type: result.type,
|
||||
storeId: result.storeId,
|
||||
createdBy: result.createdBy,
|
||||
createdAt: result.createdAt,
|
||||
author: result.author as User,
|
||||
group: result.group as Group | undefined,
|
||||
}));
|
||||
}
|
||||
|
||||
async createAnnouncement(announcement: InsertAnnouncement): Promise<DashboardMessage> {
|
||||
const [created] = await db
|
||||
.insert(dashboardMessages)
|
||||
.values(announcement)
|
||||
.returning();
|
||||
return created;
|
||||
}
|
||||
|
||||
async updateAnnouncement(id: number, announcement: Partial<InsertAnnouncement>): Promise<DashboardMessage> {
|
||||
const [updated] = await db
|
||||
.update(dashboardMessages)
|
||||
.set(announcement)
|
||||
.where(eq(dashboardMessages.id, id))
|
||||
.returning();
|
||||
return updated;
|
||||
}
|
||||
|
||||
async deleteAnnouncement(id: number): Promise<void> {
|
||||
await db
|
||||
.delete(dashboardMessages)
|
||||
.where(eq(dashboardMessages.id, id));
|
||||
}
|
||||
}
|
||||
|
||||
// Stockage en mémoire pour le développement
|
||||
class AnnouncementMemoryStorage implements IAnnouncementStorage {
|
||||
private announcements = new Map<number, Announcement>();
|
||||
private idCounter = 1;
|
||||
private readonly MAX_ANNOUNCEMENTS = 5;
|
||||
@@ -178,16 +261,30 @@ class AnnouncementMemoryStorage {
|
||||
}
|
||||
}
|
||||
|
||||
// Instance globale partagée
|
||||
let globalAnnouncementStorage: AnnouncementMemoryStorage | null = null;
|
||||
// Instances globales pour les différents environnements
|
||||
let memoryInstance: AnnouncementMemoryStorage | null = null;
|
||||
let databaseInstance: AnnouncementDatabaseStorage | null = null;
|
||||
|
||||
export function getAnnouncementStorage(
|
||||
usersGetter: () => Promise<User[]>,
|
||||
groupsGetter: () => Promise<Group[]>
|
||||
): AnnouncementMemoryStorage {
|
||||
if (!globalAnnouncementStorage) {
|
||||
globalAnnouncementStorage = new AnnouncementMemoryStorage(usersGetter, groupsGetter);
|
||||
console.log('📢 Stockage mémoire des annonces initialisé');
|
||||
usersGetter?: () => Promise<User[]>,
|
||||
groupsGetter?: () => Promise<Group[]>
|
||||
): IAnnouncementStorage {
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
if (isProduction) {
|
||||
if (!databaseInstance) {
|
||||
databaseInstance = new AnnouncementDatabaseStorage();
|
||||
console.log('📢 Stockage PostgreSQL des annonces initialisé pour la production');
|
||||
}
|
||||
return databaseInstance;
|
||||
} else {
|
||||
if (!memoryInstance) {
|
||||
if (!usersGetter || !groupsGetter) {
|
||||
throw new Error("usersGetter and groupsGetter are required for memory storage initialization");
|
||||
}
|
||||
memoryInstance = new AnnouncementMemoryStorage(usersGetter, groupsGetter);
|
||||
console.log('📢 Stockage mémoire des annonces initialisé pour le développement');
|
||||
}
|
||||
return memoryInstance;
|
||||
}
|
||||
return globalAnnouncementStorage;
|
||||
}
|
||||
+4
-5
@@ -70,6 +70,8 @@ export const userGroups = pgTable("user_groups", {
|
||||
createdAt: timestamp("created_at").defaultNow(),
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Suppliers - Schema exact correspondant à la production
|
||||
export const suppliers = pgTable("suppliers", {
|
||||
id: serial("id").primaryKey(),
|
||||
@@ -530,15 +532,12 @@ export const insertTaskSchema = createInsertSchema(tasks).omit({
|
||||
dueDate: z.coerce.date().optional().nullable(), // Convertit automatiquement les chaînes en Date
|
||||
});
|
||||
|
||||
export const insertAnnouncementSchema = createInsertSchema(dashboardMessages).omit({
|
||||
export const insertDashboardMessageSchema = createInsertSchema(dashboardMessages).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
}).extend({
|
||||
type: z.enum(["info", "warning", "error", "success"]).default("info"),
|
||||
});
|
||||
|
||||
// Mapping pour la compatibilité avec l'interface actuelle
|
||||
export const insertDashboardMessageSchema = insertAnnouncementSchema;
|
||||
export const insertAnnouncementSchema = insertDashboardMessageSchema;
|
||||
|
||||
export const insertNocodbConfigSchema = createInsertSchema(nocodbConfig).omit({
|
||||
id: true,
|
||||
|
||||
Reference in new issue
Block a user