mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-19 13:08:23 +02:00
Merge pull request #186 from R0m1k3/1.1
Update announcement system to use new dashboard messages table
This commit is contained in:
4 files changed
+73
-49
No files matched your search
@@ -17,16 +17,15 @@ class AnnouncementMemoryStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private initializeTestData() {
|
private initializeTestData() {
|
||||||
// Créer quelques annonces de test
|
// Créer quelques annonces de test avec la nouvelle structure DASHBOARD_MESSAGES
|
||||||
const testAnnouncement: Announcement = {
|
const testAnnouncement: Announcement = {
|
||||||
id: this.idCounter++,
|
id: this.idCounter++,
|
||||||
title: "Bienvenue dans le système d'informations",
|
title: "Bienvenue dans le système d'informations",
|
||||||
content: "Ce nouveau système remplace l'ancienne carte des commandes clients. Vous pouvez maintenant créer et gérer des annonces importantes.",
|
content: "Ce nouveau système remplace l'ancienne carte des commandes clients. Vous pouvez maintenant créer et gérer des annonces importantes.",
|
||||||
priority: 'important',
|
type: 'warning',
|
||||||
authorId: 'admin',
|
createdBy: 'admin',
|
||||||
groupId: 1,
|
storeId: 1,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
updatedAt: new Date(),
|
|
||||||
};
|
};
|
||||||
this.announcements.set(testAnnouncement.id, testAnnouncement);
|
this.announcements.set(testAnnouncement.id, testAnnouncement);
|
||||||
|
|
||||||
@@ -34,11 +33,10 @@ class AnnouncementMemoryStorage {
|
|||||||
id: this.idCounter++,
|
id: this.idCounter++,
|
||||||
title: "Maintenance programmée",
|
title: "Maintenance programmée",
|
||||||
content: "Une maintenance système aura lieu dimanche prochain de 2h à 4h du matin.",
|
content: "Une maintenance système aura lieu dimanche prochain de 2h à 4h du matin.",
|
||||||
priority: 'normal',
|
type: 'info',
|
||||||
authorId: 'admin',
|
createdBy: 'admin',
|
||||||
groupId: null, // Annonce globale
|
storeId: null, // Annonce globale
|
||||||
createdAt: new Date(Date.now() - 24 * 60 * 60 * 1000), // Hier
|
createdAt: new Date(Date.now() - 24 * 60 * 60 * 1000), // Hier
|
||||||
updatedAt: new Date(Date.now() - 24 * 60 * 60 * 1000),
|
|
||||||
};
|
};
|
||||||
this.announcements.set(testAnnouncement2.id, testAnnouncement2);
|
this.announcements.set(testAnnouncement2.id, testAnnouncement2);
|
||||||
}
|
}
|
||||||
@@ -51,7 +49,7 @@ class AnnouncementMemoryStorage {
|
|||||||
// Filtrer par groupIds si fourni (pour le filtrage admin par magasin)
|
// Filtrer par groupIds si fourni (pour le filtrage admin par magasin)
|
||||||
if (groupIds && groupIds.length > 0) {
|
if (groupIds && groupIds.length > 0) {
|
||||||
filteredAnnouncements = announcements.filter(announcement =>
|
filteredAnnouncements = announcements.filter(announcement =>
|
||||||
!announcement.groupId || groupIds.includes(announcement.groupId)
|
!announcement.storeId || groupIds.includes(announcement.storeId)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,8 +64,8 @@ class AnnouncementMemoryStorage {
|
|||||||
|
|
||||||
// Ajouter les relations
|
// Ajouter les relations
|
||||||
const announcementsWithRelations = filteredAnnouncements.map(announcement => {
|
const announcementsWithRelations = filteredAnnouncements.map(announcement => {
|
||||||
const author = usersMap.get(announcement.authorId);
|
const author = usersMap.get(announcement.createdBy);
|
||||||
const group = announcement.groupId ? groupsMap.get(announcement.groupId) : undefined;
|
const group = announcement.storeId ? groupsMap.get(announcement.storeId) : undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...announcement,
|
...announcement,
|
||||||
@@ -76,12 +74,12 @@ class AnnouncementMemoryStorage {
|
|||||||
};
|
};
|
||||||
}).filter(a => a.author); // Filtrer celles sans auteur valide
|
}).filter(a => a.author); // Filtrer celles sans auteur valide
|
||||||
|
|
||||||
// Trier par priorité (urgent > important > normal) puis par date (plus récent d'abord)
|
// Trier par type (error > warning > success > info) puis par date (plus récent d'abord)
|
||||||
return announcementsWithRelations.sort((a, b) => {
|
return announcementsWithRelations.sort((a, b) => {
|
||||||
const priorityOrder = { urgent: 3, important: 2, normal: 1 };
|
const typeOrder = { error: 4, warning: 3, success: 2, info: 1 };
|
||||||
const priorityDiff = (priorityOrder[b.priority as keyof typeof priorityOrder] || 1) -
|
const typeDiff = (typeOrder[b.type as keyof typeof typeOrder] || 1) -
|
||||||
(priorityOrder[a.priority as keyof typeof priorityOrder] || 1);
|
(typeOrder[a.type as keyof typeof typeOrder] || 1);
|
||||||
if (priorityDiff !== 0) return priorityDiff;
|
if (typeDiff !== 0) return typeDiff;
|
||||||
return new Date(b.createdAt!).getTime() - new Date(a.createdAt!).getTime();
|
return new Date(b.createdAt!).getTime() - new Date(a.createdAt!).getTime();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -103,10 +101,9 @@ class AnnouncementMemoryStorage {
|
|||||||
const announcement: Announcement = {
|
const announcement: Announcement = {
|
||||||
id,
|
id,
|
||||||
...announcementData,
|
...announcementData,
|
||||||
priority: announcementData.priority || 'normal',
|
type: announcementData.type || 'info',
|
||||||
groupId: announcementData.groupId || null,
|
storeId: announcementData.storeId || null,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
updatedAt: new Date(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.announcements.set(id, announcement);
|
this.announcements.set(id, announcement);
|
||||||
@@ -130,8 +127,8 @@ class AnnouncementMemoryStorage {
|
|||||||
const usersMap = new Map(users.map(u => [u.id, u]));
|
const usersMap = new Map(users.map(u => [u.id, u]));
|
||||||
const groupsMap = new Map(groups.map(g => [g.id, g]));
|
const groupsMap = new Map(groups.map(g => [g.id, g]));
|
||||||
|
|
||||||
const author = usersMap.get(announcement.authorId);
|
const author = usersMap.get(announcement.createdBy);
|
||||||
const group = announcement.groupId ? groupsMap.get(announcement.groupId) : undefined;
|
const group = announcement.storeId ? groupsMap.get(announcement.storeId) : undefined;
|
||||||
|
|
||||||
if (!author) {
|
if (!author) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -154,7 +151,7 @@ class AnnouncementMemoryStorage {
|
|||||||
...existingAnnouncement,
|
...existingAnnouncement,
|
||||||
...announcementData,
|
...announcementData,
|
||||||
id, // Ensure ID doesn't change
|
id, // Ensure ID doesn't change
|
||||||
updatedAt: new Date(),
|
// Note: DASHBOARD_MESSAGES table n'a pas de champ updatedAt
|
||||||
};
|
};
|
||||||
|
|
||||||
this.announcements.set(id, updatedAnnouncement);
|
this.announcements.set(id, updatedAnnouncement);
|
||||||
|
|||||||
+2
-8
@@ -49,14 +49,8 @@ if (isProduction && dbUrl && (dbUrl.includes('logiflow-db') || dbUrl.includes('l
|
|||||||
neonConfig.webSocketConstructor = ws.default;
|
neonConfig.webSocketConstructor = ws.default;
|
||||||
|
|
||||||
if (dbUrl) {
|
if (dbUrl) {
|
||||||
try {
|
pool = new Pool({ connectionString: dbUrl });
|
||||||
pool = new Pool({ connectionString: dbUrl });
|
db = drizzle({ client: pool, schema });
|
||||||
db = drizzle({ client: pool, schema });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('❌ Neon connection failed, will use MemStorage:', error);
|
|
||||||
pool = null;
|
|
||||||
db = null;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Create dummy instances for development
|
// Create dummy instances for development
|
||||||
pool = null;
|
pool = null;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
customerOrders,
|
customerOrders,
|
||||||
dlcProducts,
|
dlcProducts,
|
||||||
tasks,
|
tasks,
|
||||||
|
dashboardMessages,
|
||||||
announcements,
|
announcements,
|
||||||
nocodbConfig,
|
nocodbConfig,
|
||||||
invoiceVerificationCache,
|
invoiceVerificationCache,
|
||||||
@@ -3346,6 +3347,22 @@ export class MemStorage implements IStorage {
|
|||||||
return await announcementStorage.getAnnouncements(groupIds);
|
return await announcementStorage.getAnnouncements(groupIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAnnouncement(id: number): Promise<AnnouncementWithRelations | undefined> {
|
||||||
|
const announcementStorage = getAnnouncementStorage(
|
||||||
|
async () => Array.from(this.users.values()),
|
||||||
|
async () => Array.from(this.groups.values())
|
||||||
|
);
|
||||||
|
return await announcementStorage.getAnnouncement(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateAnnouncement(id: number, announcementData: Partial<InsertAnnouncement>): Promise<AnnouncementWithRelations> {
|
||||||
|
const announcementStorage = getAnnouncementStorage(
|
||||||
|
async () => Array.from(this.users.values()),
|
||||||
|
async () => Array.from(this.groups.values())
|
||||||
|
);
|
||||||
|
return await announcementStorage.updateAnnouncement(id, announcementData);
|
||||||
|
}
|
||||||
|
|
||||||
async deleteAnnouncement(id: number): Promise<boolean> {
|
async deleteAnnouncement(id: number): Promise<boolean> {
|
||||||
const announcementStorage = getAnnouncementStorage(
|
const announcementStorage = getAnnouncementStorage(
|
||||||
async () => Array.from(this.users.values()),
|
async () => Array.from(this.users.values()),
|
||||||
|
|||||||
+34
-18
@@ -255,18 +255,20 @@ export const tasks = pgTable("tasks", {
|
|||||||
updatedAt: timestamp("updated_at").defaultNow(),
|
updatedAt: timestamp("updated_at").defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Announcements - Système d'information du dashboard
|
// Dashboard Messages - Utilise la table existante DASHBOARD_MESSAGES
|
||||||
export const announcements = pgTable("announcements", {
|
export const dashboardMessages = pgTable("dashboard_messages", {
|
||||||
id: serial("id").primaryKey(),
|
id: serial("id").primaryKey(),
|
||||||
title: varchar("title").notNull(), // Titre du message
|
title: varchar("title", { length: 255 }).notNull(), // Titre du message
|
||||||
content: text("content").notNull(), // Contenu du message
|
content: text("content").notNull(), // Contenu du message
|
||||||
priority: varchar("priority").notNull().default("normal"), // normal, important, urgent
|
type: varchar("type", { length: 50 }).notNull().default("info"), // info, warning, error, success
|
||||||
authorId: varchar("author_id").notNull(), // Référence vers l'utilisateur créateur
|
storeId: integer("store_id"), // Filtrage par magasin (null = global)
|
||||||
groupId: integer("group_id"), // Filtrage par magasin (null = global)
|
createdBy: varchar("created_by", { length: 255 }).notNull(), // Référence vers l'utilisateur créateur
|
||||||
createdAt: timestamp("created_at").defaultNow(),
|
createdAt: timestamp("created_at").defaultNow(),
|
||||||
updatedAt: timestamp("updated_at").defaultNow(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Alias pour la compatibilité avec le code existant
|
||||||
|
export const announcements = dashboardMessages;
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
export const usersRelations = relations(users, ({ many }) => ({
|
export const usersRelations = relations(users, ({ many }) => ({
|
||||||
userGroups: many(userGroups),
|
userGroups: many(userGroups),
|
||||||
@@ -277,7 +279,7 @@ export const usersRelations = relations(users, ({ many }) => ({
|
|||||||
createdDlcProducts: many(dlcProducts),
|
createdDlcProducts: many(dlcProducts),
|
||||||
createdTasks: many(tasks),
|
createdTasks: many(tasks),
|
||||||
assignedTasks: many(tasks),
|
assignedTasks: many(tasks),
|
||||||
createdAnnouncements: many(announcements),
|
createdAnnouncements: many(dashboardMessages),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const groupsRelations = relations(groups, ({ one, many }) => ({
|
export const groupsRelations = relations(groups, ({ one, many }) => ({
|
||||||
@@ -288,7 +290,7 @@ export const groupsRelations = relations(groups, ({ one, many }) => ({
|
|||||||
customerOrders: many(customerOrders),
|
customerOrders: many(customerOrders),
|
||||||
dlcProducts: many(dlcProducts),
|
dlcProducts: many(dlcProducts),
|
||||||
tasks: many(tasks),
|
tasks: many(tasks),
|
||||||
announcements: many(announcements),
|
announcements: many(dashboardMessages),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const userGroupsRelations = relations(userGroups, ({ one }) => ({
|
export const userGroupsRelations = relations(userGroups, ({ one }) => ({
|
||||||
@@ -409,17 +411,20 @@ export const tasksRelations = relations(tasks, ({ one }) => ({
|
|||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const announcementsRelations = relations(announcements, ({ one }) => ({
|
export const dashboardMessagesRelations = relations(dashboardMessages, ({ one }) => ({
|
||||||
author: one(users, {
|
author: one(users, {
|
||||||
fields: [announcements.authorId],
|
fields: [dashboardMessages.createdBy],
|
||||||
references: [users.id],
|
references: [users.id],
|
||||||
}),
|
}),
|
||||||
group: one(groups, {
|
group: one(groups, {
|
||||||
fields: [announcements.groupId],
|
fields: [dashboardMessages.storeId],
|
||||||
references: [groups.id],
|
references: [groups.id],
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Alias pour compatibilité
|
||||||
|
export const announcementsRelations = dashboardMessagesRelations;
|
||||||
|
|
||||||
// Zod schemas
|
// Zod schemas
|
||||||
export const insertUserSchema = createInsertSchema(users).pick({
|
export const insertUserSchema = createInsertSchema(users).pick({
|
||||||
id: true,
|
id: true,
|
||||||
@@ -525,12 +530,16 @@ 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(announcements).omit({
|
export const insertAnnouncementSchema = createInsertSchema(dashboardMessages).omit({
|
||||||
id: true,
|
id: true,
|
||||||
createdAt: true,
|
createdAt: true,
|
||||||
updatedAt: 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 insertNocodbConfigSchema = createInsertSchema(nocodbConfig).omit({
|
export const insertNocodbConfigSchema = createInsertSchema(nocodbConfig).omit({
|
||||||
id: true,
|
id: true,
|
||||||
createdAt: true,
|
createdAt: true,
|
||||||
@@ -587,8 +596,12 @@ export type DlcProductFrontend = Omit<DlcProduct, 'expiryDate'> & { dlcDate: Dat
|
|||||||
export type InsertDlcProductFrontend = z.infer<typeof insertDlcProductFrontendSchema>;
|
export type InsertDlcProductFrontend = z.infer<typeof insertDlcProductFrontendSchema>;
|
||||||
export type Task = typeof tasks.$inferSelect;
|
export type Task = typeof tasks.$inferSelect;
|
||||||
export type InsertTask = z.infer<typeof insertTaskSchema>;
|
export type InsertTask = z.infer<typeof insertTaskSchema>;
|
||||||
export type Announcement = typeof announcements.$inferSelect;
|
export type DashboardMessage = typeof dashboardMessages.$inferSelect;
|
||||||
export type InsertAnnouncement = z.infer<typeof insertAnnouncementSchema>;
|
export type InsertDashboardMessage = z.infer<typeof insertDashboardMessageSchema>;
|
||||||
|
|
||||||
|
// Alias pour compatibilité
|
||||||
|
export type Announcement = DashboardMessage;
|
||||||
|
export type InsertAnnouncement = InsertDashboardMessage;
|
||||||
|
|
||||||
// Complex types with relations
|
// Complex types with relations
|
||||||
|
|
||||||
@@ -637,12 +650,15 @@ export type TaskWithRelations = Task & {
|
|||||||
group: Group;
|
group: Group;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Announcement with relations type
|
// Dashboard Message with relations type
|
||||||
export type AnnouncementWithRelations = Announcement & {
|
export type DashboardMessageWithRelations = DashboardMessage & {
|
||||||
author: User;
|
author: User;
|
||||||
group?: Group;
|
group?: Group;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Alias pour compatibilité
|
||||||
|
export type AnnouncementWithRelations = DashboardMessageWithRelations;
|
||||||
|
|
||||||
// SAV (Service Après-Vente) Tables
|
// SAV (Service Après-Vente) Tables
|
||||||
export const savTickets = pgTable("sav_tickets", {
|
export const savTickets = pgTable("sav_tickets", {
|
||||||
id: serial("id").primaryKey(),
|
id: serial("id").primaryKey(),
|
||||||
|
|||||||
Reference in new issue
Block a user