diff --git a/attached_assets/{C9C96055-5E48-4703-83C2-B25A1F76E1D1}_1763393627167.png b/attached_assets/{C9C96055-5E48-4703-83C2-B25A1F76E1D1}_1763393627167.png new file mode 100644 index 0000000..f202dde Binary files /dev/null and b/attached_assets/{C9C96055-5E48-4703-83C2-B25A1F76E1D1}_1763393627167.png differ diff --git a/replit.md b/replit.md index af6d0c6..7ec8f42 100644 --- a/replit.md +++ b/replit.md @@ -11,7 +11,7 @@ Preferred communication style: Simple, everyday language. ## Recent Changes ### November 17, 2025 -- **Access Token Expiration Tracking**: Added automatic tracking and visual display of Facebook/Instagram access token expiration dates in the "Pages gérées" section. Implementation: (1) Added `tokenExpiresAt` timestamp column to `social_pages` table in database schema, (2) POST endpoint automatically calculates expiration date as current date + 60 days when adding a new page, (3) Updated existing pages via SQL migration to populate expiration dates based on `createdAt + 60 days`, (4) UI displays expiration status with color-coded visual indicators in page cards: green (>15 days), orange (7-15 days), red (<7 days or expired), with warning icon for urgent/expired tokens, (5) Shows remaining days and formatted expiration date using date-fns with French locale. This helps users proactively identify and renew expiring tokens before they cause publishing failures. Files modified: `shared/schema.ts`, `server/routes.ts`, `client/src/pages/pages.tsx`. +- **Access Token Expiration Tracking**: Added automatic tracking and visual display of Facebook/Instagram access token expiration dates in the "Pages gérées" section. Implementation: (1) Added `tokenExpiresAt` timestamp column to `social_pages` table in database schema, (2) POST endpoint automatically calculates expiration date as current date + 90 days when adding a new page, (3) PUT endpoint recalculates expiration date (current date + 90 days) when updating the access token, (4) UI displays expiration status with color-coded visual indicators in page cards: green (>15 days), orange (7-15 days), red (<7 days or expired), with warning icon for urgent/expired tokens, (5) Shows remaining days and formatted expiration date using date-fns with French locale. This helps users proactively identify and renew expiring tokens before they cause publishing failures. Files modified: `shared/schema.ts`, `server/routes.ts`, `client/src/pages/pages.tsx`. - **Story Text Overlay Minimum Font Size Reduction**: Reduced minimum font size in adaptive text overlay system from 24px to 12px for both Instagram and Facebook stories. This allows significantly more text to fit within the story text box (bottom 25% of image) by enabling smaller font sizes when needed. The adaptive sizing algorithm now scales between 12-72px, reducing in 2px increments until text fits or reaches the new 12px minimum. Modified both server-side image generation (`server/services/imageProcessor.ts`) and client-side preview (`client/src/components/preview-modal.tsx`) to maintain consistency between preview and published stories. - **Facebook Story Preview with Text Overlay**: Added preview support for Facebook Story format in PreviewModal, matching the existing Instagram Story preview functionality. The unified `renderStory()` function now handles both platforms with platform-specific icons (blue Facebook icon vs. gradient Instagram icon) while maintaining identical text overlay rendering with adaptive font sizing (12-72px), semi-transparent background, and centered text display. Both Facebook Story and Instagram Story previews now accurately show how published stories will appear with text burned into the image. - **Story Text Overlay with Adaptive Sizing**: Implemented automatic text overlay on Instagram and Facebook stories with intelligent font size adaptation. When publishing a story with text content, the system now generates a composite image with the text burned into the bottom 25% of the image. Features: (1) Adaptive font sizing (originally 24-72px, now 12-72px) that automatically adjusts based on text length to fit within the text box, (2) Aspect ratio preservation for source images (centered with black letterboxing if needed to maintain 9:16 story format), (3) Automatic text wrapping with line breaks on word boundaries, (4) Ellipsis truncation for extremely long text that exceeds available space, (5) Semi-transparent black background (60% opacity) behind text for readability. Implementation uses Canvas (node-canvas) for image composition in `imageProcessor.addTextToStoryImage()`, with the generated image uploaded to Cloudinary in a dedicated `social-flow/stories` folder before publication. This ensures text appears correctly on published stories since Facebook/Instagram APIs don't support text overlays natively. The text box reserves 25% of the image height with 40px padding, and font size reduces in 2px increments until text fits or reaches the minimum. diff --git a/server/routes.ts b/server/routes.ts index c5124f7..3e44843 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -1156,9 +1156,9 @@ export async function registerRoutes(app: Express): Promise { const user = req.user as User; const userId = user.id; - // Calculate token expiration date (60 days from now) + // Calculate token expiration date (90 days from now) const tokenExpiresAt = new Date(); - tokenExpiresAt.setDate(tokenExpiresAt.getDate() + 60); + tokenExpiresAt.setDate(tokenExpiresAt.getDate() + 90); const pageData = insertSocialPageSchema.parse({ ...req.body, @@ -1184,7 +1184,15 @@ export async function registerRoutes(app: Express): Promise { return res.status(404).json({ error: "Page non trouvée" }); } - const pageData = insertSocialPageSchema.partial().parse(req.body); + let pageData = insertSocialPageSchema.partial().parse(req.body); + + // If accessToken is being updated, recalculate expiration date (90 days from now) + if (pageData.accessToken) { + const tokenExpiresAt = new Date(); + tokenExpiresAt.setDate(tokenExpiresAt.getDate() + 90); + pageData = { ...pageData, tokenExpiresAt }; + } + const updatedPage = await storage.updateSocialPage(pageId, pageData); res.json(updatedPage); } catch (error) {