11import { Request , Response } from 'express' ;
22import { asyncHandler } from '../utils/asyncHandler.js' ;
3- import { BannerTemplateType } from '../types/index.js' ;
3+ import { BackgroundType , BannerTemplateType } from '../types/index.js' ;
44import { validateBanner } from '../schemas/bannerSchema.js' ;
55import Banner from '../models/bannerModel.js' ;
66import { deleteFile } from '../middleware/uploadMiddleware.js' ;
@@ -139,7 +139,10 @@ export const createBanner = asyncHandler(async (req: Request, res: Response) =>
139139 }
140140
141141 // Handle resource project specific logic
142- const finalBannerData = _handleResourceProjectBannerLogic ( { ...validation . data } ) ;
142+ let finalBannerData = _handleResourceProjectBannerLogic ( { ...validation . data } ) ;
143+
144+ // Handle background image specific logic
145+ finalBannerData = handleBackgroundImageLogic ( finalBannerData ) ;
143146
144147 // Add creator information and system fields
145148 const bannerData = {
@@ -181,8 +184,17 @@ export const updateBanner = asyncHandler(async (req: Request, res: Response) =>
181184 // Store old banner data for file cleanup
182185 const oldBannerData = banner . toObject ( ) ;
183186
187+ // Handle template type change from RESOURCE_PROJECT to another type
188+ if ( oldBannerData . TemplateType === BannerTemplateType . RESOURCE_PROJECT &&
189+ validation ?. data ?. TemplateType !== BannerTemplateType . RESOURCE_PROJECT ) {
190+ await handleResourceProjectTemplateChange ( oldBannerData , validation . data ) ;
191+ }
192+
184193 // Handle resource project specific logic
185- const finalBannerData = _handleResourceProjectBannerLogic ( { ...validation . data } ) ;
194+ let finalBannerData = _handleResourceProjectBannerLogic ( { ...validation . data } ) ;
195+
196+ // Handle background image specific logic
197+ finalBannerData = handleBackgroundImageLogic ( finalBannerData ) ;
186198
187199 // Preserve existing activation date fields and IsActive (not editable in edit form)
188200 finalBannerData . StartDate = banner . StartDate ;
@@ -331,20 +343,63 @@ function _handleResourceProjectBannerLogic(bannerData: any): any {
331343 if ( resourceFile . Url && ! resourceFile . FileUrl ) {
332344 bannerData . ResourceProject . ResourceFile . FileUrl = resourceFile . Url ;
333345 }
334- // Add foreach to populate Url depending on AutomaticallyPopulatedUrl
346+
335347 // Update the 'Download' CTA button URL to use the file URL
336348 const fileUrl = bannerData . ResourceProject . ResourceFile . FileUrl ;
337349 if ( bannerData . CtaButtons && bannerData . CtaButtons . length > 0 && fileUrl ) {
338350 const downloadButtonIndex = 0 ;
339351 const button = bannerData . CtaButtons [ downloadButtonIndex ] ;
340- if ( button && button . AutomaticallyPopulatedUrl ) {
352+ if ( button ) {
341353 button . Url = fileUrl ;
342354 }
343355 }
344356 }
345357 return bannerData ;
346358}
347359
360+ // Private helper to handle template type change from RESOURCE_PROJECT
361+ // Cleans up resource file and CTA button with blob URL when template type changes
362+ async function handleResourceProjectTemplateChange ( oldBannerData : any , newBannerData : any ) : Promise < void > {
363+ // Check if old banner had a resource file with a blob URL
364+ if ( oldBannerData . ResourceProject ?. ResourceFile ?. FileUrl ) {
365+ const fileUrl = oldBannerData . ResourceProject . ResourceFile . FileUrl ;
366+
367+ // Delete the resource file from blob storage if it's a blob URL
368+ if ( fileUrl . includes ( 'blob.core.windows.net' ) ) {
369+ try {
370+ await deleteFile ( fileUrl ) ;
371+ console . log ( `Cleaned up resource file during template type change: ${ fileUrl } ` ) ;
372+ } catch ( error ) {
373+ console . error ( `Failed to delete resource file ${ fileUrl } during template type change:` , error ) ;
374+ // Don't throw error - file cleanup failure shouldn't break the update
375+ }
376+ }
377+ }
378+ }
379+
380+ // Private helper to handle background image logic
381+ // Automatically populates Background.Value with BackgroundImage URL when Background.Type is 'image'
382+ function handleBackgroundImageLogic ( bannerData : any ) : any {
383+ // Ensure Background object exists
384+ if ( ! bannerData . Background ) {
385+ return bannerData ;
386+ }
387+
388+ // If Background.Type is 'image', handle the BackgroundImage URL
389+ if ( bannerData . Background . Type === BackgroundType . IMAGE ) {
390+ // Case 1: BackgroundImage exists - populate Background.Value with its URL
391+ if ( bannerData . BackgroundImage && bannerData . BackgroundImage . Url ) {
392+ bannerData . Background . Value = bannerData . BackgroundImage . Url ;
393+ }
394+ // Case 2: BackgroundImage was removed - clear Background.Value
395+ else {
396+ bannerData . Background . Value = '' ;
397+ }
398+ }
399+
400+ return bannerData ;
401+ }
402+
348403// Helper function to extract all file URLs from a banner
349404function extractFileUrls ( banner : any ) : string [ ] {
350405 const urls : string [ ] = [ ] ;
@@ -353,8 +408,6 @@ function extractFileUrls(banner: any): string[] {
353408 if ( banner . Logo ?. Url ) urls . push ( banner . Logo . Url ) ;
354409 if ( banner . BackgroundImage ?. Url ) urls . push ( banner . BackgroundImage . Url ) ;
355410 if ( banner . MainImage ?. Url ) urls . push ( banner . MainImage . Url ) ;
356- // TODO: Uncomment if AccentGraphic is needed. In the other case, remove.
357- // if (banner.AccentGraphic?.Url) urls.push(banner.AccentGraphic.Url);
358411
359412 // Partner logos for partnership charter banners (nested structure)
360413 if ( banner . PartnershipCharter ?. PartnerLogos && Array . isArray ( banner . PartnershipCharter . PartnerLogos ) ) {
@@ -377,8 +430,6 @@ function processMediaFields(req: Request): any {
377430 // Note: I still not sure if it makes sense to use this merging instead of req.body
378431 const processedData = { ...req . body , ...req . preValidatedData } ;
379432
380- // TODO: Uncomment if AccentGraphic is needed. In the other case, remove.
381- // Process single media assets: Logo, BackgroundImage, MainImage, AccentGraphic
382433 [ 'Logo' , 'BackgroundImage' , 'MainImage' /*, 'AccentGraphic'*/ ] . forEach ( field => {
383434 const newFileData = processedData [ `newfile_${ field } ` ] ;
384435 const newMetadata = processedData [ `newmetadata_${ field } ` ]
0 commit comments