Manos Chorianopoulos

add new CarouselContent at MyRewardsViewController

...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
7 <key>Pods-SwiftWarplyFramework.xcscheme_^#shared#^_</key> 7 <key>Pods-SwiftWarplyFramework.xcscheme_^#shared#^_</key>
8 <dict> 8 <dict>
9 <key>orderHint</key> 9 <key>orderHint</key>
10 - <integer>1</integer> 10 + <integer>0</integer>
11 </dict> 11 </dict>
12 </dict> 12 </dict>
13 </dict> 13 </dict>
......
...@@ -76,6 +76,7 @@ ...@@ -76,6 +76,7 @@
76 626AF6DB2F698FF1008BCA08 /* MerchantAnnotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 626AF6DA2F698FF1008BCA08 /* MerchantAnnotation.swift */; }; 76 626AF6DB2F698FF1008BCA08 /* MerchantAnnotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 626AF6DA2F698FF1008BCA08 /* MerchantAnnotation.swift */; };
77 626AF6DE2F699081008BCA08 /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 626AF6DC2F699081008BCA08 /* MapViewController.swift */; }; 77 626AF6DE2F699081008BCA08 /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 626AF6DC2F699081008BCA08 /* MapViewController.swift */; };
78 626AF6DF2F699081008BCA08 /* MapViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 626AF6DD2F699081008BCA08 /* MapViewController.xib */; }; 78 626AF6DF2F699081008BCA08 /* MapViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 626AF6DD2F699081008BCA08 /* MapViewController.xib */; };
79 + 626DC8012F6ACA3B00CFC8C2 /* CarouselItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 626DC8002F6ACA3B00CFC8C2 /* CarouselItemModel.swift */; };
79 62A0A6D32F67FEDC00508534 /* MyCouponsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A0A6D12F67FEDC00508534 /* MyCouponsViewController.swift */; }; 80 62A0A6D32F67FEDC00508534 /* MyCouponsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A0A6D12F67FEDC00508534 /* MyCouponsViewController.swift */; };
80 62A0A6D42F67FEDC00508534 /* MyCouponsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 62A0A6D22F67FEDC00508534 /* MyCouponsViewController.xib */; }; 81 62A0A6D42F67FEDC00508534 /* MyCouponsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 62A0A6D22F67FEDC00508534 /* MyCouponsViewController.xib */; };
81 62A0A6D82F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A0A6D62F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift */; }; 82 62A0A6D82F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A0A6D62F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift */; };
...@@ -160,6 +161,7 @@ ...@@ -160,6 +161,7 @@
160 626AF6DA2F698FF1008BCA08 /* MerchantAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MerchantAnnotation.swift; sourceTree = "<group>"; }; 161 626AF6DA2F698FF1008BCA08 /* MerchantAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MerchantAnnotation.swift; sourceTree = "<group>"; };
161 626AF6DC2F699081008BCA08 /* MapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = "<group>"; }; 162 626AF6DC2F699081008BCA08 /* MapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = "<group>"; };
162 626AF6DD2F699081008BCA08 /* MapViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MapViewController.xib; sourceTree = "<group>"; }; 163 626AF6DD2F699081008BCA08 /* MapViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MapViewController.xib; sourceTree = "<group>"; };
164 + 626DC8002F6ACA3B00CFC8C2 /* CarouselItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselItemModel.swift; sourceTree = "<group>"; };
163 62A0A6D12F67FEDC00508534 /* MyCouponsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCouponsViewController.swift; sourceTree = "<group>"; }; 165 62A0A6D12F67FEDC00508534 /* MyCouponsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCouponsViewController.swift; sourceTree = "<group>"; };
164 62A0A6D22F67FEDC00508534 /* MyCouponsViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MyCouponsViewController.xib; sourceTree = "<group>"; }; 166 62A0A6D22F67FEDC00508534 /* MyCouponsViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MyCouponsViewController.xib; sourceTree = "<group>"; };
165 62A0A6D62F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCouponsHeaderTableViewCell.swift; sourceTree = "<group>"; }; 167 62A0A6D62F680C6A00508534 /* MyCouponsHeaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCouponsHeaderTableViewCell.swift; sourceTree = "<group>"; };
...@@ -212,6 +214,7 @@ ...@@ -212,6 +214,7 @@
212 1E089DF42DF87C39007459F1 /* Response.swift */, 214 1E089DF42DF87C39007459F1 /* Response.swift */,
213 1E089DF52DF87C39007459F1 /* SectionModel.swift */, 215 1E089DF52DF87C39007459F1 /* SectionModel.swift */,
214 1E116F6A2DE86CAD009AE791 /* Models.swift */, 216 1E116F6A2DE86CAD009AE791 /* Models.swift */,
217 + 626DC8002F6ACA3B00CFC8C2 /* CarouselItemModel.swift */,
215 ); 218 );
216 path = models; 219 path = models;
217 sourceTree = "<group>"; 220 sourceTree = "<group>";
...@@ -733,6 +736,7 @@ ...@@ -733,6 +736,7 @@
733 1E089E0A2DF87D16007459F1 /* EventDispatcher.swift in Sources */, 736 1E089E0A2DF87D16007459F1 /* EventDispatcher.swift in Sources */,
734 1E116F692DE845B1009AE791 /* ProfileFilterCollectionViewCell.swift in Sources */, 737 1E116F692DE845B1009AE791 /* ProfileFilterCollectionViewCell.swift in Sources */,
735 1E0E72472E0C3B1200BC926F /* DatabaseManager.swift in Sources */, 738 1E0E72472E0C3B1200BC926F /* DatabaseManager.swift in Sources */,
739 + 626DC8012F6ACA3B00CFC8C2 /* CarouselItemModel.swift in Sources */,
736 1EDBAF0D2DE8441000911E79 /* ProfileQuestionnaireTableViewCell.swift in Sources */, 740 1EDBAF0D2DE8441000911E79 /* ProfileQuestionnaireTableViewCell.swift in Sources */,
737 1E64E1842DE48E0600543217 /* MyRewardsOfferCollectionViewCell.swift in Sources */, 741 1E64E1842DE48E0600543217 /* MyRewardsOfferCollectionViewCell.swift in Sources */,
738 E6A77955282933E70045BBA8 /* ViewControllerExtensions.swift in Sources */, 742 E6A77955282933E70045BBA8 /* ViewControllerExtensions.swift in Sources */,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
7 <key>SwiftWarplyFramework.xcscheme_^#shared#^_</key> 7 <key>SwiftWarplyFramework.xcscheme_^#shared#^_</key>
8 <dict> 8 <dict>
9 <key>orderHint</key> 9 <key>orderHint</key>
10 - <integer>0</integer> 10 + <integer>1</integer>
11 </dict> 11 </dict>
12 </dict> 12 </dict>
13 </dict> 13 </dict>
......
...@@ -4335,3 +4335,66 @@ public final class WarplySDK { ...@@ -4335,3 +4335,66 @@ public final class WarplySDK {
4335 setCarouselList(carouselArray) 4335 setCarouselList(carouselArray)
4336 } 4336 }
4337 } 4337 }
4338 +
4339 +// MARK: - Carousel Content
4340 +
4341 +extension WarplySDK {
4342 +
4343 + /// Get carousel content
4344 + /// - Parameters:
4345 + /// - completion: Completion handler with array of CarouselItemModel
4346 + /// - failureCallback: Failure callback with error code
4347 + public func getCarouselContent(completion: @escaping ([CarouselItemModel]?) -> Void, failureCallback: @escaping (Int) -> Void) {
4348 + Task {
4349 + do {
4350 + let endpoint = Endpoint.getCarouselContent
4351 + let response = try await networkService.requestRaw(endpoint)
4352 +
4353 + await MainActor.run {
4354 + if response["status"] as? Int == 1 {
4355 + let dynatraceEvent = LoyaltySDKDynatraceEventModel()
4356 + dynatraceEvent._eventName = "custom_success_get_carousel_content_loyalty"
4357 + dynatraceEvent._parameters = nil
4358 + self.postFrameworkEvent("dynatrace", sender: dynatraceEvent)
4359 +
4360 + var items: [CarouselItemModel] = []
4361 + if let resultArray = response["result"] as? [[String: Any]] {
4362 + for itemDict in resultArray {
4363 + items.append(CarouselItemModel(dictionary: itemDict))
4364 + }
4365 + }
4366 + print("✅ [getCarouselContent] Parsed \(items.count) carousel items")
4367 + completion(items)
4368 + } else {
4369 + let dynatraceEvent = LoyaltySDKDynatraceEventModel()
4370 + dynatraceEvent._eventName = "custom_error_get_carousel_content_loyalty"
4371 + dynatraceEvent._parameters = nil
4372 + self.postFrameworkEvent("dynatrace", sender: dynatraceEvent)
4373 + failureCallback(-1)
4374 + }
4375 + }
4376 + } catch {
4377 + await MainActor.run {
4378 + self.handleError(error, context: "getCarouselContent", endpoint: "getCarouselContent", failureCallback: failureCallback)
4379 + }
4380 + }
4381 + }
4382 + }
4383 +
4384 + /// Get carousel content (async/await variant)
4385 + /// - Returns: Array of CarouselItemModel
4386 + /// - Throws: WarplyError if the request fails
4387 + public func getCarouselContent() async throws -> [CarouselItemModel] {
4388 + return try await withCheckedThrowingContinuation { continuation in
4389 + getCarouselContent(completion: { result in
4390 + if let result = result {
4391 + continuation.resume(returning: result)
4392 + } else {
4393 + continuation.resume(throwing: WarplyError.networkError)
4394 + }
4395 + }, failureCallback: { errorCode in
4396 + continuation.resume(throwing: WarplyError.unknownError(errorCode))
4397 + })
4398 + }
4399 + }
4400 +}
......
...@@ -78,6 +78,9 @@ public enum Endpoint { ...@@ -78,6 +78,9 @@ public enum Endpoint {
78 // Articles 78 // Articles
79 case getArticles(language: String, categories: [String]?) 79 case getArticles(language: String, categories: [String]?)
80 80
81 + // Carousel Content
82 + case getCarouselContent
83 +
81 // Card Management 84 // Card Management
82 case addCard(cardNumber: String, cardIssuer: String, cardHolder: String, expirationMonth: String, expirationYear: String) 85 case addCard(cardNumber: String, cardIssuer: String, cardHolder: String, expirationMonth: String, expirationYear: String)
83 case getCards 86 case getCards
...@@ -139,7 +142,7 @@ public enum Endpoint { ...@@ -139,7 +142,7 @@ public enum Endpoint {
139 return "/api/mobile/v2/{appUUID}/context/" 142 return "/api/mobile/v2/{appUUID}/context/"
140 143
141 // Authenticated Context endpoints - /oauth/{appUUID}/context 144 // Authenticated Context endpoints - /oauth/{appUUID}/context
142 - case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon: 145 + case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getCarouselContent:
143 return "/oauth/{appUUID}/context" 146 return "/oauth/{appUUID}/context"
144 147
145 // Session endpoints - /api/session/{sessionUuid} 148 // Session endpoints - /api/session/{sessionUuid}
...@@ -168,7 +171,7 @@ public enum Endpoint { ...@@ -168,7 +171,7 @@ public enum Endpoint {
168 switch self { 171 switch self {
169 case .register, .changePassword, .resetPassword, .requestOtp, .verifyTicket, .refreshToken, .logout, .getCampaigns, .getCampaignsPersonalized, 172 case .register, .changePassword, .resetPassword, .requestOtp, .verifyTicket, .refreshToken, .logout, .getCampaigns, .getCampaignsPersonalized,
170 .getCoupons, .getCouponSets, .getAvailableCoupons, 173 .getCoupons, .getCouponSets, .getAvailableCoupons,
171 - .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getMerchants, .getMerchantCategories, .getStores, .getArticles, .sendEvent, .sendDeviceInfo, .getCosmoteUser, .deiLogin: 174 + .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getMerchants, .getMerchantCategories, .getStores, .getArticles, .sendEvent, .sendDeviceInfo, .getCosmoteUser, .deiLogin, .getCarouselContent:
172 return .POST 175 return .POST
173 case .getSingleCampaign, .getNetworkStatus: 176 case .getSingleCampaign, .getNetworkStatus:
174 return .GET 177 return .GET
...@@ -438,6 +441,14 @@ public enum Endpoint { ...@@ -438,6 +441,14 @@ public enum Endpoint {
438 "content": contentParams 441 "content": contentParams
439 ] 442 ]
440 443
444 + // Carousel Content - using content structure with get_carousel action
445 + case .getCarouselContent:
446 + return [
447 + "content": [
448 + "action": "get_carousel"
449 + ]
450 + ]
451 +
441 // Analytics endpoints - events structure 452 // Analytics endpoints - events structure
442 case .sendEvent(let eventName, let priority): 453 case .sendEvent(let eventName, let priority):
443 return [ 454 return [
...@@ -494,7 +505,7 @@ public enum Endpoint { ...@@ -494,7 +505,7 @@ public enum Endpoint {
494 return .standardContext 505 return .standardContext
495 506
496 // Authenticated Context - /oauth/{appUUID}/context 507 // Authenticated Context - /oauth/{appUUID}/context
497 - case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon: 508 + case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getCarouselContent:
498 return .authenticatedContext 509 return .authenticatedContext
499 510
500 // Authentication - /oauth/{appUUID}/login, /oauth/{appUUID}/token 511 // Authentication - /oauth/{appUUID}/login, /oauth/{appUUID}/token
...@@ -536,7 +547,7 @@ public enum Endpoint { ...@@ -536,7 +547,7 @@ public enum Endpoint {
536 return .standard 547 return .standard
537 548
538 // Bearer Token Authentication (loyalty headers + Authorization: Bearer) 549 // Bearer Token Authentication (loyalty headers + Authorization: Bearer)
539 - case .changePassword, .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon: 550 + case .changePassword, .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getCarouselContent:
540 return .bearerToken 551 return .bearerToken
541 552
542 // Basic Authentication (loyalty headers + Authorization: Basic) 553 // Basic Authentication (loyalty headers + Authorization: Basic)
......
...@@ -38,13 +38,17 @@ public class MyRewardsBannerOfferCollectionViewCell: UICollectionViewCell { ...@@ -38,13 +38,17 @@ public class MyRewardsBannerOfferCollectionViewCell: UICollectionViewCell {
38 contentView.layer.masksToBounds = true 38 contentView.layer.masksToBounds = true
39 } 39 }
40 40
41 - func configureCell(data: CampaignItemModel) { 41 + // func configureCell(data: CampaignItemModel) {
42 - // Use campaign's banner image - no hardcoded defaults 42 + // // Use campaign's banner image - no hardcoded defaults
43 - self.postImageURL = data._banner_img_mobile ?? "" 43 + // self.postImageURL = data._banner_img_mobile ?? ""
44 - } 44 + // }
45 45
46 - func configureCell(data: ArticleModel) { 46 + // func configureCell(data: ArticleModel) {
47 - // Use article's preview image - same visual treatment as campaigns 47 + // // Use article's preview image - same visual treatment as campaigns
48 - self.postImageURL = data._img_preview.isEmpty ? nil : data._img_preview 48 + // self.postImageURL = data._img_preview.isEmpty ? nil : data._img_preview
49 + // }
50 +
51 + func configureCell(data: CarouselItemModel) {
52 + self.postImageURL = data._app_img
49 } 53 }
50 } 54 }
......
...@@ -10,6 +10,7 @@ import UIKit ...@@ -10,6 +10,7 @@ import UIKit
10 protocol MyRewardsBannerOffersScrollTableViewCellDelegate: AnyObject { 10 protocol MyRewardsBannerOffersScrollTableViewCellDelegate: AnyObject {
11 func didSelectBannerOffer(_ index: Int) 11 func didSelectBannerOffer(_ index: Int)
12 func didSelectBannerArticle(_ index: Int) 12 func didSelectBannerArticle(_ index: Int)
13 + func didSelectBannerCarouselItem(_ index: Int)
13 } 14 }
14 15
15 @objc(MyRewardsBannerOffersScrollTableViewCell) 16 @objc(MyRewardsBannerOffersScrollTableViewCell)
...@@ -96,7 +97,7 @@ extension MyRewardsBannerOffersScrollTableViewCell: UICollectionViewDataSource, ...@@ -96,7 +97,7 @@ extension MyRewardsBannerOffersScrollTableViewCell: UICollectionViewDataSource,
96 public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 97 public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
97 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyRewardsBannerOfferCollectionViewCell", for: indexPath) as! MyRewardsBannerOfferCollectionViewCell 98 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyRewardsBannerOfferCollectionViewCell", for: indexPath) as! MyRewardsBannerOfferCollectionViewCell
98 99
99 - // Handle both CampaignItemModel and ArticleModel 100 + // Handle CarouselItemModel
100 guard let data = self.data, 101 guard let data = self.data,
101 let items = data.items, 102 let items = data.items,
102 indexPath.row < items.count else { 103 indexPath.row < items.count else {
...@@ -105,10 +106,13 @@ extension MyRewardsBannerOffersScrollTableViewCell: UICollectionViewDataSource, ...@@ -105,10 +106,13 @@ extension MyRewardsBannerOffersScrollTableViewCell: UICollectionViewDataSource,
105 106
106 let item = items[indexPath.row] 107 let item = items[indexPath.row]
107 108
108 - if let campaign = item as? CampaignItemModel { 109 + // if let campaign = item as? CampaignItemModel {
109 - cell.configureCell(data: campaign) 110 + // cell.configureCell(data: campaign)
110 - } else if let article = item as? ArticleModel { 111 + // } else if let article = item as? ArticleModel {
111 - cell.configureCell(data: article) 112 + // cell.configureCell(data: article)
113 + // }
114 + if let carouselItem = item as? CarouselItemModel {
115 + cell.configureCell(data: carouselItem)
112 } 116 }
113 117
114 return cell 118 return cell
...@@ -124,10 +128,13 @@ extension MyRewardsBannerOffersScrollTableViewCell: UICollectionViewDataSource, ...@@ -124,10 +128,13 @@ extension MyRewardsBannerOffersScrollTableViewCell: UICollectionViewDataSource,
124 128
125 let item = items[indexPath.row] 129 let item = items[indexPath.row]
126 130
127 - if item is CampaignItemModel { 131 + // if item is CampaignItemModel {
128 - delegate?.didSelectBannerOffer(indexPath.row) 132 + // delegate?.didSelectBannerOffer(indexPath.row)
129 - } else if item is ArticleModel { 133 + // } else if item is ArticleModel {
130 - delegate?.didSelectBannerArticle(indexPath.row) 134 + // delegate?.didSelectBannerArticle(indexPath.row)
135 + // }
136 + if item is CarouselItemModel {
137 + delegate?.didSelectBannerCarouselItem(indexPath.row)
131 } 138 }
132 } 139 }
133 140
......
1 +//
2 +// CarouselItemModel.swift
3 +// SwiftWarplyFramework
4 +//
5 +// Created by Manos Chorianopoulos on 18/3/26.
6 +//
7 +
8 +import Foundation
9 +
10 +public class CarouselItemModel: NSObject {
11 +
12 + private var uuid: String?
13 + private var name: String?
14 + private var entity: String?
15 + private var app_img: String?
16 + private var app_url: String?
17 + private var url: String?
18 + private var web_img: String?
19 + private var web_img_responsive: String?
20 +
21 + public override init() {
22 + super.init()
23 + }
24 +
25 + public init(dictionary: [String: Any]) {
26 + self.uuid = dictionary["uuid"] as? String ?? ""
27 + self.name = dictionary["name"] as? String ?? ""
28 + self.entity = dictionary["entity"] as? String ?? ""
29 + self.app_img = dictionary["app_img"] as? String
30 + self.app_url = dictionary["app_url"] as? String
31 + self.url = dictionary["url"] as? String
32 + self.web_img = dictionary["web_img"] as? String
33 + self.web_img_responsive = dictionary["web_img_responsive"] as? String
34 + }
35 +
36 + public var _uuid: String { get { return self.uuid ?? "" } }
37 + public var _name: String { get { return self.name ?? "" } }
38 + public var _entity: String { get { return self.entity ?? "" } }
39 + public var _app_img: String? { get { return self.app_img } }
40 + public var _app_url: String? { get { return self.app_url } }
41 + public var _url: String? { get { return self.url } }
42 + public var _web_img: String? { get { return self.web_img } }
43 + public var _web_img_responsive: String? { get { return self.web_img_responsive } }
44 +}
...@@ -42,6 +42,9 @@ import UIKit ...@@ -42,6 +42,9 @@ import UIKit
42 // Dynamic sections array - populated by API calls 42 // Dynamic sections array - populated by API calls
43 var sections: [SectionModel] = [] 43 var sections: [SectionModel] = []
44 44
45 + // carouselItems data for banners
46 + var carouselItems: [CarouselItemModel] = []
47 +
45 // Campaign data for banners 48 // Campaign data for banners
46 var bannerCampaigns: [CampaignItemModel] = [] 49 var bannerCampaigns: [CampaignItemModel] = []
47 50
...@@ -87,7 +90,8 @@ import UIKit ...@@ -87,7 +90,8 @@ import UIKit
87 90
88 // Load data 91 // Load data
89 loadProfile() // Load Profile 92 loadProfile() // Load Profile
90 - loadCampaigns() // Load campaigns 93 + loadCarouselContent()
94 + // loadCampaigns() // Load campaigns
91 loadCouponSets() // Load couponsets 95 loadCouponSets() // Load couponsets
92 loadCoupons() 96 loadCoupons()
93 97
...@@ -160,6 +164,23 @@ import UIKit ...@@ -160,6 +164,23 @@ import UIKit
160 self.navigationController?.setNavigationBarHidden(false, animated: animated) 164 self.navigationController?.setNavigationBarHidden(false, animated: animated)
161 } 165 }
162 166
167 + // MARK: - CarouselContent Loading
168 + private func loadCarouselContent() {
169 + // Load CarouselContent from WarplySDK
170 + WarplySDK.shared.getCarouselContent { [weak self] carouselContent in
171 + guard let self = self, let carouselContent = carouselContent else {
172 + return
173 + }
174 +
175 + self.carouselItems = carouselContent
176 + self.createBannerSection()
177 +
178 + print("=== getCarouselContent ✅ [MyRewardsViewController] Loaded \(carouselContent.count) carouselContent")
179 +
180 + } failureCallback: { [weak self] errorCode in
181 + print("=== getCarouselContent Failed to load carouselContent: \(errorCode)")
182 + }
183 + }
163 184
164 // MARK: - Campaign Loading 185 // MARK: - Campaign Loading
165 private func loadCampaigns() { 186 private func loadCampaigns() {
...@@ -220,11 +241,14 @@ import UIKit ...@@ -220,11 +241,14 @@ import UIKit
220 // Combine campaigns and articles for banner section 241 // Combine campaigns and articles for banner section
221 var bannerItems: [Any] = [] 242 var bannerItems: [Any] = []
222 243
223 - // Add campaigns first 244 + // // Add campaigns first
224 - bannerItems.append(contentsOf: self.bannerCampaigns) 245 + // bannerItems.append(contentsOf: self.bannerCampaigns)
225 246
226 - // Add articles after campaigns 247 + // // Add articles after campaigns
227 - bannerItems.append(contentsOf: self.articles) 248 + // bannerItems.append(contentsOf: self.articles)
249 +
250 + // // Add articles after campaigns
251 + bannerItems.append(contentsOf: self.carouselItems)
228 252
229 // Create banner section if we have any items 253 // Create banner section if we have any items
230 if !bannerItems.isEmpty { 254 if !bannerItems.isEmpty {
...@@ -779,6 +803,10 @@ extension MyRewardsViewController: MyRewardsBannerOffersScrollTableViewCellDeleg ...@@ -779,6 +803,10 @@ extension MyRewardsViewController: MyRewardsBannerOffersScrollTableViewCellDeleg
779 openArticleViewController(with: index) 803 openArticleViewController(with: index)
780 } 804 }
781 805
806 + func didSelectBannerCarouselItem(_ index: Int) {
807 + // TODO: handle carousel item tap
808 + }
809 +
782 // func didTapProfileButton() { 810 // func didTapProfileButton() {
783 // // Navigate to ProfileViewController 811 // // Navigate to ProfileViewController
784 // openProfileViewController() 812 // openProfileViewController()
......