mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-19 13:08:23 +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 (
|
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 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">
|
<div className="flex-1 min-w-0">
|
||||||
<TypeIcon className="h-4 w-4 text-blue-600 mt-0.5 flex-shrink-0" />
|
<div className="flex items-center gap-2 mb-1">
|
||||||
<div className="flex-1 min-w-0">
|
<h4 className="font-medium text-sm truncate">
|
||||||
<div className="flex items-center gap-2 mb-1">
|
{announcement.title}
|
||||||
<h4 className="font-medium text-sm truncate">
|
</h4>
|
||||||
{announcement.title}
|
<Badge variant={priorityConfig.color} className="flex items-center gap-1 text-xs">
|
||||||
</h4>
|
<TypeIcon className="w-2.5 h-2.5" />
|
||||||
<Badge variant={priorityConfig.color} className="flex items-center gap-1 text-xs">
|
{priorityConfig.label}
|
||||||
{priorityConfig.label}
|
</Badge>
|
||||||
</Badge>
|
</div>
|
||||||
</div>
|
|
||||||
|
{announcement.content && (
|
||||||
{announcement.content && (
|
<p className="text-xs text-muted-foreground mb-1 line-clamp-1">
|
||||||
<p className="text-xs text-muted-foreground mb-1 line-clamp-1">
|
{announcement.content}
|
||||||
{announcement.content}
|
</p>
|
||||||
</p>
|
)}
|
||||||
)}
|
|
||||||
|
<div className="flex items-center gap-3 text-xs text-muted-foreground">
|
||||||
<div className="flex items-center gap-3 text-xs text-muted-foreground">
|
<span>
|
||||||
<span>
|
{safeFormat(safeDate(announcement.createdAt), 'dd/MM à HH:mm')}
|
||||||
{safeFormat(safeDate(announcement.createdAt), 'dd/MM à HH:mm')}
|
</span>
|
||||||
</span>
|
<span>
|
||||||
<span>
|
{announcement.author.firstName} {announcement.author.lastName}
|
||||||
{announcement.author.firstName} {announcement.author.lastName}
|
{announcement.group && ` • ${announcement.group.name}`}
|
||||||
{announcement.group && ` • ${announcement.group.name}`}
|
</span>
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{user?.role === 'admin' && (
|
{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)
|
// Type aliases pour compatibilité
|
||||||
class AnnouncementMemoryStorage {
|
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 announcements = new Map<number, Announcement>();
|
||||||
private idCounter = 1;
|
private idCounter = 1;
|
||||||
private readonly MAX_ANNOUNCEMENTS = 5;
|
private readonly MAX_ANNOUNCEMENTS = 5;
|
||||||
@@ -178,16 +261,30 @@ class AnnouncementMemoryStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instance globale partagée
|
// Instances globales pour les différents environnements
|
||||||
let globalAnnouncementStorage: AnnouncementMemoryStorage | null = null;
|
let memoryInstance: AnnouncementMemoryStorage | null = null;
|
||||||
|
let databaseInstance: AnnouncementDatabaseStorage | null = null;
|
||||||
|
|
||||||
export function getAnnouncementStorage(
|
export function getAnnouncementStorage(
|
||||||
usersGetter: () => Promise<User[]>,
|
usersGetter?: () => Promise<User[]>,
|
||||||
groupsGetter: () => Promise<Group[]>
|
groupsGetter?: () => Promise<Group[]>
|
||||||
): AnnouncementMemoryStorage {
|
): IAnnouncementStorage {
|
||||||
if (!globalAnnouncementStorage) {
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
globalAnnouncementStorage = new AnnouncementMemoryStorage(usersGetter, groupsGetter);
|
|
||||||
console.log('📢 Stockage mémoire des annonces initialisé');
|
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(),
|
createdAt: timestamp("created_at").defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Suppliers - Schema exact correspondant à la production
|
// Suppliers - Schema exact correspondant à la production
|
||||||
export const suppliers = pgTable("suppliers", {
|
export const suppliers = pgTable("suppliers", {
|
||||||
id: serial("id").primaryKey(),
|
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
|
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,
|
id: true,
|
||||||
createdAt: true,
|
createdAt: true,
|
||||||
}).extend({
|
|
||||||
type: z.enum(["info", "warning", "error", "success"]).default("info"),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Mapping pour la compatibilité avec l'interface actuelle
|
export const insertAnnouncementSchema = insertDashboardMessageSchema;
|
||||||
export const insertDashboardMessageSchema = insertAnnouncementSchema;
|
|
||||||
|
|
||||||
export const insertNocodbConfigSchema = createInsertSchema(nocodbConfig).omit({
|
export const insertNocodbConfigSchema = createInsertSchema(nocodbConfig).omit({
|
||||||
id: true,
|
id: true,
|
||||||
|
|||||||
Reference in new issue
Block a user