Update post creation to support multiple media items and carousels

Refactor post creation logic in `server/routes.ts` to handle an array of media items (`mediaIds`) for posts, supporting both single media and carousel formats. Implement validation for a maximum of 10 media items and ensure stories have at least one media. Modify `server/storage.ts` to order media by `displayOrder` when retrieving post media.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/WzkpF6q
This commit is contained in:
michaelschal committed 2025-10-08 20:07:12 +00:00
1 parent b2df4ee031
commit 3d4ceaa5d8
3 files changed
+44 -10

No files matched your search

+4
View File
@@ -22,6 +22,10 @@ externalPort = 3003
localPort = 35357
externalPort = 3002
[[ports]]
localPort = 35903
externalPort = 6800
[[ports]]
localPort = 37431
externalPort = 5000
+38 -8
View File
@@ -557,11 +557,39 @@ export async function registerRoutes(app: Express): Promise<Server> {
try {
const user = req.user as User;
const userId = user.id;
const { pageIds, postType, mediaId, ...postFields } = req.body;
const { pageIds, postType, mediaId, mediaIds, ...postFields } = req.body;
// Convert mediaIds to standardized format: array of { mediaId, displayOrder }
let finalMediaItems: Array<{ mediaId: string; displayOrder: number }> = [];
if (mediaIds && Array.isArray(mediaIds)) {
// New format: array of objects or strings
finalMediaItems = mediaIds.map((item: any, index: number) => {
if (typeof item === 'string') {
// Legacy array of strings: use index as displayOrder
return { mediaId: item, displayOrder: index };
} else if (item.mediaId) {
// New format: object with mediaId and displayOrder
return {
mediaId: item.mediaId,
displayOrder: item.displayOrder ?? index,
};
}
throw new Error("Invalid media format");
});
} else if (mediaId) {
// Legacy single mediaId
finalMediaItems = [{ mediaId, displayOrder: 0 }];
}
// Validate max 10 photos
if (finalMediaItems.length > 10) {
return res.status(400).json({ error: "Maximum 10 photos autorisées par publication" });
}
// Validate that stories require media
if ((postType === 'story' || postType === 'both') && !mediaId) {
return res.status(400).json({ error: "Les stories nécessitent un média (image ou vidéo)" });
if ((postType === 'story' || postType === 'both') && finalMediaItems.length === 0) {
return res.status(400).json({ error: "Les stories nécessitent au moins un média (image ou vidéo)" });
}
// Convert scheduledFor string to Date if provided
@@ -573,12 +601,14 @@ export async function registerRoutes(app: Express): Promise<Server> {
const postData = insertPostSchema.parse({ ...postFields, userId });
const post = await storage.createPost(postData);
// Link media to post if provided
if (mediaId) {
await db.insert(postMedia).values({
// Link media to post if provided (with display order)
if (finalMediaItems.length > 0) {
const postMediaValues = finalMediaItems.map(item => ({
postId: post.id,
mediaId: mediaId,
});
mediaId: item.mediaId,
displayOrder: item.displayOrder,
}));
await db.insert(postMedia).values(postMediaValues);
}
// Create scheduled posts for each selected page
+2 -2
View File
@@ -30,7 +30,7 @@ import {
type InsertUserPagePermission,
} from "@shared/schema";
import { db } from "./db";
import { eq, and, gte, lte, desc, isNull } from "drizzle-orm";
import { eq, and, gte, lte, desc, asc, isNull } from "drizzle-orm";
export interface IStorage {
// Users
@@ -168,7 +168,7 @@ export class DatabaseStorage implements IStorage {
}
async getPostMedia(postId: string): Promise<PostMedia[]> {
return await db.select().from(postMedia).where(eq(postMedia.postId, postId));
return await db.select().from(postMedia).where(eq(postMedia.postId, postId)).orderBy(asc(postMedia.displayOrder));
}
// Posts