How to apply Clean Architecture principle in Swift to implement reusable banners?

I’m working on an iOS application where multiple pages (ex: Homepage, help page) display multiple banners. A banner is like a card with a message and a possible action/link.

For example, there’s an ActivatedMotorBanner to show a banner if the user has a motor policy with an ACTIVATED status. Another example is a SuspendedPolicyBanner that is to show when there is a policy SUSPENDED.

I want to implement that logic with clean code, which must be reusable; the same banner can appear on multiple pages.

The problem that I'm facing is that every banner has a different formatting; for example one banner has some parts of the message bold while another has a link to a specific app section.

Inside the domain/entity I have already that struct that represents the user contract.

struct Contract {
    let name: String
    let type: ContractType
}

enum ContractType {
    case Suspended, Activated, Cancelled
}

I add inside the domain a struct for each type of banner I want to implement because every banner has different information. Each banner implements the Banner protocol)

For example, the ActivatedMotorBanner has that logic

protocol Banner {
    var hasToShow: Bool
}

struct ActivatedMotorBanner: Banner {
    let type: ContractType
    let vehicleName: String
    
    init(type: ContractType, vehicleName: String) {
        self.type = type
        self.vehicleName = vehicleName
    }

    var hasToShow: Bool {
        type == .Activated
    }
}

while the SuspendedPolicyBanner has the logic that must be shown if the policy expire date is after today.

struct SuspendedPolicyBanner: Banner {
    let expireDate: Date     
    
    init(expireDate: Date) {
        self.expireDate = expireDate
    }

    var hasToShow: Bool {
        expireDate > Date()
    }
}

The first question is: Is it correct to have such information inside the domain/entity folder or that information must be inside the use case? I put inside the domain because every banner has different data

Next inside the USE CASE, I create the use cases for each type of banner. For example, I create the MotoryBannerUseCase that handles all the motor banners (ActivatedMotorBanner and others) and the PolicyUseCase that handles all the banners for generic status of the contracts (for example all suspended contract or all the cancelled contract etc).

class MotoryBannerUseCase: BannerUseCase { 
    private let contracts: Contract

    init(contracts: Contract) {
        self.contracts = contracts
    }

    func execute() throws -> [Banner] {
      contracts.flatmap { getBanners(for $0) }
    }

   // Here the use case know all the banner that handle and pass the data to the banner
   // then we filter the banner 
   func getBanners(for contract: Contract) -> [Banner] {
     let supportedBanners = [
       ActivatedMotorBanner(type: contract.type),
       // ... other motor banner ...
    ]

    return supportedBanners.filter { $0.hasToShow() }
   }
}

Next, inside the presentation layer (view model), I get all the banners from the use cases

func load() -> [BannerPresentationModel] {
  let banners = MotoryBannerUseCase().execute()
  banners.map { banner in
     if let bannerMapper = banner as? BannerMapper {
         return bannerMapper.map()
     }
     
     // Generic BannerMapper without formatting logic or textlink
     return BannerMapper(.....)
  }

  /// ... other use cases ....


  return banners
}

The problem here is that every banner has a different formatting logic (for example, some banners have the contract number in bold while others have some part of the text in bold). Moreover, I have some banners with links that can be clicked to navigate. In general I don't want to depend on the formatting logic because can change quickly.

I didn't understand how to format the presentation with clean code architecture. I understand that clean architecture wants to separate the display from implementation logic

In particular, I would like to separate the visualization logic from the model, so I create a BannerMapper that maps the domain model to the presentation model.

The only solution I found is to have a protocol extension and that extension can live in the presentation module only. Like this but i don't think is scalable.

extension ActivatedMotorBanner: BannerMapper { 

 func map() -> BannerPresentationModel { 
    // make formatting logic with bold, fonts etc. 
    let formattedString = String.formatBold("The policy for the vehicle \(vehicleName) is active", text: "active")    

    return BannerPresentationModel(
                message: formattedString, 
                link: "See details", 
                action: { ... }
         )
 }
}

protocol BannerMapper { 
func map(_ banner: Banner) -> BannerPresentationModel 
}

Do you have some better ideas to implement that?