From 983ba33a9dc692ea5bb51b4f56cc3dcdf2817e36 Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Mon, 17 Nov 2025 15:34:20 +0000 Subject: [PATCH 1/2] Add image file containing a diagram or screenshot Attached an image file to the repository. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 174a54fa-5ca2-4c96-8802-7f8c269b3035 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/5aomXd9 --- ...48-4703-83C2-B25A1F76E1D1}_1763393627167.png | Bin 0 -> 24578 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 attached_assets/{C9C96055-5E48-4703-83C2-B25A1F76E1D1}_1763393627167.png 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 0000000000000000000000000000000000000000..f202ddecd70b37892a8f973492ed678271686f3e GIT binary patch literal 24578 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�!lZr?u^ib#tBkq!Y19SOZk38>Ua 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%0D3mQ>}R8hRc_f+voRD9 zG$-`#3yWzsZXnv~)XFz$y4%@sLQdqd0ubECn%V(FHlWe)wd8NSFkpq27C7YEjnzT{ z`8&Q;Sx6qnDsDaupX!RCK*pua`u*&F0;XvaQ5{NS^#P6nc7%$56s*mD5Opa}%9SY# f{ Date: Mon, 17 Nov 2025 15:38:55 +0000 Subject: [PATCH 2/2] Update token expiration to 90 days and recalculate upon update Adjusted access token expiration to 90 days in POST and PUT routes, updating shared/schema.ts and client/src/pages/pages.tsx. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 9b68577b-34d3-49be-8a1f-69c8bcb3cdb3 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/5aomXd9 --- replit.md | 2 +- server/routes.ts | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) 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) {