mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-23 15:08:13 +02:00
feat: implement multi-step reel creation flow with video upload, music selection, text generation, and scheduling.
This commit is contained in:
1 parent
0e9622b5eb
commit
9e9eb7d1bb
6 files changed
+10
-10
No files matched your search
Binary file not shown.
@@ -269,7 +269,7 @@ export default function MobileNewReel() {
|
|||||||
) : (
|
) : (
|
||||||
<div className="grid grid-cols-2 gap-3 mt-4">
|
<div className="grid grid-cols-2 gap-3 mt-4">
|
||||||
{videoList.map((media) => (
|
{videoList.map((media) => (
|
||||||
<div key={media.id} onClick={() => setSelectedVideoId(media.id) || setSelectedVideo(media)} className={`relative aspect-[9/16] bg-black rounded-lg overflow-hidden border-2 transition-all ${selectedVideoId === media.id ? 'border-primary' : 'border-transparent'}`}>
|
<div key={media.id} onClick={() => { setSelectedVideoId(media.id); setSelectedVideo(media); }} className={`relative aspect-[9/16] bg-black rounded-lg overflow-hidden border-2 transition-all ${selectedVideoId === media.id ? 'border-primary' : 'border-transparent'}`}>
|
||||||
<video src={media.originalUrl} className="w-full h-full object-cover" muted />
|
<video src={media.originalUrl} className="w-full h-full object-cover" muted />
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
+3
-2
@@ -1514,11 +1514,12 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
return res.status(404).json({ error: "Page non trouvée" });
|
return res.status(404).json({ error: "Page non trouvée" });
|
||||||
}
|
}
|
||||||
|
|
||||||
let pageData = insertSocialPageSchema.partial().parse(req.body);
|
let parsedData = insertSocialPageSchema.partial().parse(req.body);
|
||||||
|
let pageData: Partial<SocialPage> = { ...parsedData };
|
||||||
|
|
||||||
// If accessToken is being updated, recalculate expiration date (60 days from now)
|
// If accessToken is being updated, recalculate expiration date (60 days from now)
|
||||||
// AND reset the status to valid so the UI updates immediately
|
// AND reset the status to valid so the UI updates immediately
|
||||||
if (pageData.accessToken) {
|
if (parsedData.accessToken) {
|
||||||
const tokenExpiresAt = new Date();
|
const tokenExpiresAt = new Date();
|
||||||
tokenExpiresAt.setDate(tokenExpiresAt.getDate() + 60);
|
tokenExpiresAt.setDate(tokenExpiresAt.getDate() + 60);
|
||||||
pageData = {
|
pageData = {
|
||||||
|
|||||||
@@ -333,7 +333,8 @@ reelsRouter.post('/reels/preview', async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
let watermarkUrl: string | undefined = undefined;
|
let watermarkUrl: string | undefined = undefined;
|
||||||
if (req.user) {
|
if (req.user) {
|
||||||
const [userCloudinary] = await db.select().from(cloudinaryConfig).where(eq(cloudinaryConfig.userId, req.user.id));
|
const user = req.user as User;
|
||||||
|
const [userCloudinary] = await db.select().from(cloudinaryConfig).where(eq(cloudinaryConfig.userId, user.id));
|
||||||
if (userCloudinary && userCloudinary.logoPublicId) {
|
if (userCloudinary && userCloudinary.logoPublicId) {
|
||||||
watermarkUrl = `https://res.cloudinary.com/${userCloudinary.cloudName}/image/upload/${userCloudinary.logoPublicId}`;
|
watermarkUrl = `https://res.cloudinary.com/${userCloudinary.cloudName}/image/upload/${userCloudinary.logoPublicId}`;
|
||||||
}
|
}
|
||||||
@@ -656,7 +657,7 @@ async function processReelBackground(
|
|||||||
|
|
||||||
// Si au moins une réussite, on considère "published" (ou partial), sinon "failed"
|
// Si au moins une réussite, on considère "published" (ou partial), sinon "failed"
|
||||||
// Si planifié, reste "scheduled".
|
// Si planifié, reste "scheduled".
|
||||||
let finalStatus = 'failed';
|
let finalStatus: 'failed' | 'scheduled' | 'published' = 'failed';
|
||||||
if (scheduledFor) {
|
if (scheduledFor) {
|
||||||
finalStatus = 'scheduled';
|
finalStatus = 'scheduled';
|
||||||
} else if (allSuccess) {
|
} else if (allSuccess) {
|
||||||
|
|||||||
+2
-2
@@ -55,7 +55,7 @@ export interface IStorage {
|
|||||||
getSocialPages(userId: string): Promise<SocialPage[]>;
|
getSocialPages(userId: string): Promise<SocialPage[]>;
|
||||||
getSocialPage(id: string): Promise<SocialPage | undefined>;
|
getSocialPage(id: string): Promise<SocialPage | undefined>;
|
||||||
createSocialPage(page: InsertSocialPage): Promise<SocialPage>;
|
createSocialPage(page: InsertSocialPage): Promise<SocialPage>;
|
||||||
updateSocialPage(id: string, page: Partial<InsertSocialPage>): Promise<SocialPage>;
|
updateSocialPage(id: string, page: Partial<SocialPage>): Promise<SocialPage>;
|
||||||
deleteSocialPage(id: string): Promise<void>;
|
deleteSocialPage(id: string): Promise<void>;
|
||||||
|
|
||||||
// Media
|
// Media
|
||||||
@@ -190,7 +190,7 @@ export class DatabaseStorage implements IStorage {
|
|||||||
return newPage;
|
return newPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateSocialPage(id: string, page: Partial<InsertSocialPage>): Promise<SocialPage> {
|
async updateSocialPage(id: string, page: Partial<SocialPage>): Promise<SocialPage> {
|
||||||
// Chiffrer le token si présent dans la mise à jour
|
// Chiffrer le token si présent dans la mise à jour
|
||||||
const updateData = page.accessToken
|
const updateData = page.accessToken
|
||||||
? { ...page, accessToken: encrypt(page.accessToken) }
|
? { ...page, accessToken: encrypt(page.accessToken) }
|
||||||
|
|||||||
+1
-3
@@ -456,9 +456,7 @@ export type OpenrouterConfig = typeof openrouterConfig.$inferSelect;
|
|||||||
export type InsertOpenrouterConfig = z.infer<typeof insertOpenrouterConfigSchema>;
|
export type InsertOpenrouterConfig = z.infer<typeof insertOpenrouterConfigSchema>;
|
||||||
export type UpdateOpenrouterConfig = z.infer<typeof updateOpenrouterConfigSchema>;
|
export type UpdateOpenrouterConfig = z.infer<typeof updateOpenrouterConfigSchema>;
|
||||||
|
|
||||||
export const insertPostMediaSchema = createInsertSchema(postMedia).omit({
|
|
||||||
id: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
export type PostMedia = typeof postMedia.$inferSelect;
|
export type PostMedia = typeof postMedia.$inferSelect;
|
||||||
export type InsertPostMedia = z.infer<typeof insertPostMediaSchema>;
|
export type InsertPostMedia = z.infer<typeof insertPostMediaSchema>;
|
||||||
|
|||||||
Reference in new issue
Block a user