Showing
4 changed files
with
351 additions
and
18 deletions
... | @@ -19,6 +19,43 @@ public class MyRewardsOfferCollectionViewCell: UICollectionViewCell { | ... | @@ -19,6 +19,43 @@ public class MyRewardsOfferCollectionViewCell: UICollectionViewCell { |
19 | @IBOutlet weak var expirationLabel: UILabel! | 19 | @IBOutlet weak var expirationLabel: UILabel! |
20 | @IBOutlet weak var logoImage: UIImageView! | 20 | @IBOutlet weak var logoImage: UIImageView! |
21 | 21 | ||
22 | + var postImageURL: String? { | ||
23 | + didSet { | ||
24 | + if let url = postImageURL { | ||
25 | + self.bannerImage.image = UIImage() // UIImage(named: "loading") | ||
26 | + | ||
27 | + UIImage.loadImageUsingCacheWithUrlString(url) { image in | ||
28 | + // set the image only when we are still displaying the content for the image we finished downloading | ||
29 | + if url == self.postImageURL { | ||
30 | + self.bannerImage.image = image | ||
31 | + } | ||
32 | + } | ||
33 | + } | ||
34 | + else { | ||
35 | + self.bannerImage.image = nil | ||
36 | + } | ||
37 | + } | ||
38 | + } | ||
39 | + | ||
40 | + var logoImageURL: String? { | ||
41 | + didSet { | ||
42 | + if let url = logoImageURL { | ||
43 | + self.logoImage.image = UIImage() // UIImage(named: "loading") | ||
44 | + | ||
45 | + UIImage.loadImageUsingCacheWithUrlString(url) { image in | ||
46 | + // set the image only when we are still displaying the content for the image we finished downloading | ||
47 | + if url == self.logoImageURL { | ||
48 | + self.logoImage.image = image | ||
49 | + } | ||
50 | + } | ||
51 | + } | ||
52 | + else { | ||
53 | + self.logoImage.image = nil | ||
54 | + } | ||
55 | + } | ||
56 | + } | ||
57 | + | ||
58 | + | ||
22 | public override func awakeFromNib() { | 59 | public override func awakeFromNib() { |
23 | super.awakeFromNib() | 60 | super.awakeFromNib() |
24 | // Initialization code | 61 | // Initialization code |
... | @@ -68,12 +105,7 @@ public class MyRewardsOfferCollectionViewCell: UICollectionViewCell { | ... | @@ -68,12 +105,7 @@ public class MyRewardsOfferCollectionViewCell: UICollectionViewCell { |
68 | 105 | ||
69 | func configureCell(data: CouponSetItemModel) { | 106 | func configureCell(data: CouponSetItemModel) { |
70 | // Use coupon set preview image | 107 | // Use coupon set preview image |
71 | - let imageName = data._img_preview | 108 | + self.postImageURL = data._img_preview |
72 | - if !imageName.isEmpty { | ||
73 | - bannerImage.image = UIImage(named: imageName, in: Bundle.frameworkResourceBundle, compatibleWith: nil) | ||
74 | - } else { | ||
75 | - bannerImage.image = nil | ||
76 | - } | ||
77 | 109 | ||
78 | // Default to not favorite for coupon sets | 110 | // Default to not favorite for coupon sets |
79 | favoriteImage.image = UIImage(named: "favorite_empty", in: Bundle.frameworkResourceBundle, compatibleWith: nil) | 111 | favoriteImage.image = UIImage(named: "favorite_empty", in: Bundle.frameworkResourceBundle, compatibleWith: nil) |
... | @@ -93,7 +125,7 @@ public class MyRewardsOfferCollectionViewCell: UICollectionViewCell { | ... | @@ -93,7 +125,7 @@ public class MyRewardsOfferCollectionViewCell: UICollectionViewCell { |
93 | case "plus_one": | 125 | case "plus_one": |
94 | return 0x007AFF | 126 | return 0x007AFF |
95 | default: | 127 | default: |
96 | - return 0x6C757D | 128 | + return 0xEE417D |
97 | } | 129 | } |
98 | }() | 130 | }() |
99 | discountView.backgroundColor = UIColor(rgb: discountColor) | 131 | discountView.backgroundColor = UIColor(rgb: discountColor) |
... | @@ -106,20 +138,16 @@ public class MyRewardsOfferCollectionViewCell: UICollectionViewCell { | ... | @@ -106,20 +138,16 @@ public class MyRewardsOfferCollectionViewCell: UICollectionViewCell { |
106 | subtitleLabel.font = UIFont(name: "PingLCG-Regular", size: 14) | 138 | subtitleLabel.font = UIFont(name: "PingLCG-Regular", size: 14) |
107 | subtitleLabel.textColor = UIColor(rgb: 0x00111B) | 139 | subtitleLabel.textColor = UIColor(rgb: 0x00111B) |
108 | 140 | ||
109 | - expirationLabel.text = "έως " + data.formattedExpiration(format: "dd-MM") | 141 | + expirationLabel.text = "έως " + data.formattedEndDate(format: "dd-MM") |
110 | expirationLabel.font = UIFont(name: "PingLCG-Regular", size: 13) | 142 | expirationLabel.font = UIFont(name: "PingLCG-Regular", size: 13) |
111 | expirationLabel.textColor = UIColor(rgb: 0x00111B) | 143 | expirationLabel.textColor = UIColor(rgb: 0x00111B) |
112 | 144 | ||
113 | - // Use first image from img array if available | 145 | + // Use merchant logo from bound merchant data |
114 | - if let imgArray = data._img, !imgArray.isEmpty { | 146 | + if let merchant = data._merchant, !merchant._img_preview.isEmpty { |
115 | - let logoName = imgArray[0] | 147 | + // Use merchant's img_preview for logo |
116 | - if !logoName.isEmpty { | 148 | + self.logoImageURL = merchant._img_preview |
117 | - logoImage.image = UIImage(named: logoName, in: Bundle.frameworkResourceBundle, compatibleWith: nil) | ||
118 | - } else { | ||
119 | - logoImage.image = nil | ||
120 | - } | ||
121 | } else { | 149 | } else { |
122 | - logoImage.image = nil | 150 | + self.logoImageURL = nil |
123 | } | 151 | } |
124 | } | 152 | } |
125 | 153 | ... | ... |
... | @@ -78,6 +78,9 @@ public class CouponSetItemModel { | ... | @@ -78,6 +78,9 @@ public class CouponSetItemModel { |
78 | private var third_party_service: String? | 78 | private var third_party_service: String? |
79 | private var category: String? | 79 | private var category: String? |
80 | 80 | ||
81 | + // Bound merchant data for performance | ||
82 | + private var merchant: MerchantModel? | ||
83 | + | ||
81 | public init(dictionary: [String: Any]) { | 84 | public init(dictionary: [String: Any]) { |
82 | // Existing fields | 85 | // Existing fields |
83 | self.uuid = dictionary["uuid"] as? String? ?? "" | 86 | self.uuid = dictionary["uuid"] as? String? ?? "" |
... | @@ -236,6 +239,12 @@ public class CouponSetItemModel { | ... | @@ -236,6 +239,12 @@ public class CouponSetItemModel { |
236 | public var _third_party_service: String { get { return self.third_party_service ?? "" } } | 239 | public var _third_party_service: String { get { return self.third_party_service ?? "" } } |
237 | public var _category: String { get { return self.category ?? "" } } | 240 | public var _category: String { get { return self.category ?? "" } } |
238 | 241 | ||
242 | + // Bound merchant data accessor | ||
243 | + public var _merchant: MerchantModel? { | ||
244 | + get { return self.merchant } | ||
245 | + set(newValue) { self.merchant = newValue } | ||
246 | + } | ||
247 | + | ||
239 | // Formatted expiration date for display | 248 | // Formatted expiration date for display |
240 | public var _expiration_formatted: String { | 249 | public var _expiration_formatted: String { |
241 | guard let expiration = self.expiration, !expiration.isEmpty else { | 250 | guard let expiration = self.expiration, !expiration.isEmpty else { |
... | @@ -272,6 +281,46 @@ public class CouponSetItemModel { | ... | @@ -272,6 +281,46 @@ public class CouponSetItemModel { |
272 | 281 | ||
273 | return "" | 282 | return "" |
274 | } | 283 | } |
284 | + | ||
285 | + /// Format start date with custom format | ||
286 | + /// - Parameter format: DateFormatter format string (e.g., "dd/MM/yyyy", "MMM yyyy", "dd-MM") | ||
287 | + /// - Returns: Formatted date string or empty string if invalid | ||
288 | + public func formattedStartDate(format: String) -> String { | ||
289 | + guard let startDate = self.start_date, !startDate.isEmpty else { | ||
290 | + return "" | ||
291 | + } | ||
292 | + | ||
293 | + let inputFormatter = DateFormatter() | ||
294 | + inputFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" | ||
295 | + | ||
296 | + if let date = inputFormatter.date(from: startDate) { | ||
297 | + let outputFormatter = DateFormatter() | ||
298 | + outputFormatter.dateFormat = format | ||
299 | + return outputFormatter.string(from: date) | ||
300 | + } | ||
301 | + | ||
302 | + return "" | ||
303 | + } | ||
304 | + | ||
305 | + /// Format end date with custom format | ||
306 | + /// - Parameter format: DateFormatter format string (e.g., "dd/MM/yyyy", "MMM yyyy", "dd-MM") | ||
307 | + /// - Returns: Formatted date string or empty string if invalid | ||
308 | + public func formattedEndDate(format: String) -> String { | ||
309 | + guard let endDate = self.end_date, !endDate.isEmpty else { | ||
310 | + return "" | ||
311 | + } | ||
312 | + | ||
313 | + let inputFormatter = DateFormatter() | ||
314 | + inputFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" | ||
315 | + | ||
316 | + if let date = inputFormatter.date(from: endDate) { | ||
317 | + let outputFormatter = DateFormatter() | ||
318 | + outputFormatter.dateFormat = format | ||
319 | + return outputFormatter.string(from: date) | ||
320 | + } | ||
321 | + | ||
322 | + return "" | ||
323 | + } | ||
275 | } | 324 | } |
276 | 325 | ||
277 | public class RedeemedMerchantDetailsModel: Codable { | 326 | public class RedeemedMerchantDetailsModel: Codable { | ... | ... |
... | @@ -10,7 +10,8 @@ import Foundation | ... | @@ -10,7 +10,8 @@ import Foundation |
10 | 10 | ||
11 | // MARK: - Merchant Models | 11 | // MARK: - Merchant Models |
12 | 12 | ||
13 | -public class MerchantModel: Codable { | 13 | +public class MerchantModel { |
14 | + // Existing fields | ||
14 | private var address: String? | 15 | private var address: String? |
15 | private var id: String? | 16 | private var id: String? |
16 | private var store_id: String? | 17 | private var store_id: String? |
... | @@ -48,7 +49,35 @@ public class MerchantModel: Codable { | ... | @@ -48,7 +49,35 @@ public class MerchantModel: Codable { |
48 | private var show_map: Bool? | 49 | private var show_map: Bool? |
49 | private var eshop: Bool? | 50 | private var eshop: Bool? |
50 | 51 | ||
52 | + // NEW FIELDS - Missing from API response | ||
53 | + // Image array - multiple merchant images | ||
54 | + private var img: [String]? | ||
55 | + | ||
56 | + // Business metadata - stored as JSON string for safety | ||
57 | + private var merchant_metadata_raw: String? | ||
58 | + | ||
59 | + // Contact details | ||
60 | + private var telephones_raw: String? | ||
61 | + | ||
62 | + // Business operations | ||
63 | + private var working_hours: String? | ||
64 | + private var year_established: Int? | ||
65 | + private var currency: String? | ||
66 | + private var bank: String? | ||
67 | + | ||
68 | + // E-commerce fields | ||
69 | + private var min_order_price: Double? | ||
70 | + private var min_order_price_takeaway: Double? | ||
71 | + private var min_price: Double? | ||
72 | + private var max_price: Double? | ||
73 | + | ||
74 | + // SEO and categorization | ||
75 | + private var url_name: String? | ||
76 | + private var tags_raw: String? // Store as comma-separated string | ||
77 | + private var product_raw: String? // Store as JSON string | ||
78 | + | ||
51 | public init() { | 79 | public init() { |
80 | + // Existing fields | ||
52 | self.address = "" | 81 | self.address = "" |
53 | self.id = "" | 82 | self.id = "" |
54 | self.store_id = "" | 83 | self.store_id = "" |
... | @@ -85,9 +114,26 @@ public class MerchantModel: Codable { | ... | @@ -85,9 +114,26 @@ public class MerchantModel: Codable { |
85 | self.hidden = false | 114 | self.hidden = false |
86 | self.show_map = false | 115 | self.show_map = false |
87 | self.eshop = false | 116 | self.eshop = false |
117 | + | ||
118 | + // New fields - initialize with appropriate defaults | ||
119 | + self.img = [] | ||
120 | + self.merchant_metadata_raw = "" | ||
121 | + self.telephones_raw = "" | ||
122 | + self.working_hours = "" | ||
123 | + self.year_established = nil | ||
124 | + self.currency = "" | ||
125 | + self.bank = "" | ||
126 | + self.min_order_price = nil | ||
127 | + self.min_order_price_takeaway = nil | ||
128 | + self.min_price = nil | ||
129 | + self.max_price = nil | ||
130 | + self.url_name = "" | ||
131 | + self.tags_raw = "" | ||
132 | + self.product_raw = "" | ||
88 | } | 133 | } |
89 | 134 | ||
90 | public init(dictionary: [String: Any]) { | 135 | public init(dictionary: [String: Any]) { |
136 | + // Parse existing fields | ||
91 | self.address = dictionary["address"] as? String? ?? "" | 137 | self.address = dictionary["address"] as? String? ?? "" |
92 | self.id = dictionary["id"] as? String? ?? "" | 138 | self.id = dictionary["id"] as? String? ?? "" |
93 | self.store_id = dictionary["store_id"] as? String? ?? "" | 139 | self.store_id = dictionary["store_id"] as? String? ?? "" |
... | @@ -123,6 +169,7 @@ public class MerchantModel: Codable { | ... | @@ -123,6 +169,7 @@ public class MerchantModel: Codable { |
123 | self.default_shown = dictionary["default_shown"] as? Bool? ?? false | 169 | self.default_shown = dictionary["default_shown"] as? Bool? ?? false |
124 | self.hidden = dictionary["hidden"] as? Bool? ?? false | 170 | self.hidden = dictionary["hidden"] as? Bool? ?? false |
125 | 171 | ||
172 | + // Parse extra_fields | ||
126 | if let extra_fields = dictionary["extra_fields"] as? [String: Any] { | 173 | if let extra_fields = dictionary["extra_fields"] as? [String: Any] { |
127 | self.show_map = extra_fields["show_map"] as? Bool? ?? false | 174 | self.show_map = extra_fields["show_map"] as? Bool? ?? false |
128 | self.eshop = extra_fields["eshop"] as? Bool? ?? false | 175 | self.eshop = extra_fields["eshop"] as? Bool? ?? false |
... | @@ -130,6 +177,72 @@ public class MerchantModel: Codable { | ... | @@ -130,6 +177,72 @@ public class MerchantModel: Codable { |
130 | self.show_map = false | 177 | self.show_map = false |
131 | self.eshop = false | 178 | self.eshop = false |
132 | } | 179 | } |
180 | + | ||
181 | + // Parse NEW FIELDS - with safe type handling | ||
182 | + | ||
183 | + // Parse img array safely | ||
184 | + if let imgArray = dictionary["img"] as? [String] { | ||
185 | + self.img = imgArray | ||
186 | + } else { | ||
187 | + self.img = [] | ||
188 | + } | ||
189 | + | ||
190 | + // Parse merchant_metadata as JSON string for safety | ||
191 | + if let metadata = dictionary["merchant_metadata"] as? [String: Any] { | ||
192 | + do { | ||
193 | + let jsonData = try JSONSerialization.data(withJSONObject: metadata, options: []) | ||
194 | + if let jsonString = String(data: jsonData, encoding: .utf8) { | ||
195 | + self.merchant_metadata_raw = jsonString | ||
196 | + } else { | ||
197 | + self.merchant_metadata_raw = "" | ||
198 | + } | ||
199 | + } catch { | ||
200 | + self.merchant_metadata_raw = "" | ||
201 | + } | ||
202 | + } else { | ||
203 | + self.merchant_metadata_raw = "" | ||
204 | + } | ||
205 | + | ||
206 | + // Parse contact details | ||
207 | + self.telephones_raw = dictionary["telephones_raw"] as? String? ?? "" | ||
208 | + | ||
209 | + // Parse business operations | ||
210 | + self.working_hours = dictionary["working_hours"] as? String? ?? "" | ||
211 | + self.year_established = dictionary["year_established"] as? Int? | ||
212 | + self.currency = dictionary["currency"] as? String? ?? "" | ||
213 | + self.bank = dictionary["bank"] as? String? ?? "" | ||
214 | + | ||
215 | + // Parse e-commerce fields | ||
216 | + self.min_order_price = dictionary["min_order_price"] as? Double? | ||
217 | + self.min_order_price_takeaway = dictionary["min_order_price_takeaway"] as? Double? | ||
218 | + self.min_price = dictionary["min_price"] as? Double? | ||
219 | + self.max_price = dictionary["max_price"] as? Double? | ||
220 | + | ||
221 | + // Parse SEO and categorization | ||
222 | + self.url_name = dictionary["url_name"] as? String? ?? "" | ||
223 | + | ||
224 | + // Parse tags array to comma-separated string | ||
225 | + if let tagsArray = dictionary["tags"] as? [String] { | ||
226 | + self.tags_raw = tagsArray.joined(separator: ",") | ||
227 | + } else { | ||
228 | + self.tags_raw = "" | ||
229 | + } | ||
230 | + | ||
231 | + // Parse product object as JSON string | ||
232 | + if let product = dictionary["product"] as? [String: Any] { | ||
233 | + do { | ||
234 | + let jsonData = try JSONSerialization.data(withJSONObject: product, options: []) | ||
235 | + if let jsonString = String(data: jsonData, encoding: .utf8) { | ||
236 | + self.product_raw = jsonString | ||
237 | + } else { | ||
238 | + self.product_raw = "" | ||
239 | + } | ||
240 | + } catch { | ||
241 | + self.product_raw = "" | ||
242 | + } | ||
243 | + } else { | ||
244 | + self.product_raw = "" | ||
245 | + } | ||
133 | } | 246 | } |
134 | 247 | ||
135 | public var _address: String { | 248 | public var _address: String { |
... | @@ -311,4 +424,133 @@ public class MerchantModel: Codable { | ... | @@ -311,4 +424,133 @@ public class MerchantModel: Codable { |
311 | get { return self.eshop ?? false } | 424 | get { return self.eshop ?? false } |
312 | set(newValue) { self.eshop = newValue } | 425 | set(newValue) { self.eshop = newValue } |
313 | } | 426 | } |
427 | + | ||
428 | + // MARK: - NEW FIELD ACCESSORS | ||
429 | + | ||
430 | + // Image array accessor | ||
431 | + public var _img: [String] { | ||
432 | + get { return self.img ?? [] } | ||
433 | + set(newValue) { self.img = newValue } | ||
434 | + } | ||
435 | + | ||
436 | + // Business metadata accessor (raw JSON string) | ||
437 | + public var _merchant_metadata_raw: String { | ||
438 | + get { return self.merchant_metadata_raw ?? "" } | ||
439 | + set(newValue) { self.merchant_metadata_raw = newValue } | ||
440 | + } | ||
441 | + | ||
442 | + // Contact details | ||
443 | + public var _telephones_raw: String { | ||
444 | + get { return self.telephones_raw ?? "" } | ||
445 | + set(newValue) { self.telephones_raw = newValue } | ||
446 | + } | ||
447 | + | ||
448 | + // Business operations | ||
449 | + public var _working_hours: String { | ||
450 | + get { return self.working_hours ?? "" } | ||
451 | + set(newValue) { self.working_hours = newValue } | ||
452 | + } | ||
453 | + | ||
454 | + public var _year_established: Int? { | ||
455 | + get { return self.year_established } | ||
456 | + set(newValue) { self.year_established = newValue } | ||
457 | + } | ||
458 | + | ||
459 | + public var _currency: String { | ||
460 | + get { return self.currency ?? "" } | ||
461 | + set(newValue) { self.currency = newValue } | ||
462 | + } | ||
463 | + | ||
464 | + public var _bank: String { | ||
465 | + get { return self.bank ?? "" } | ||
466 | + set(newValue) { self.bank = newValue } | ||
467 | + } | ||
468 | + | ||
469 | + // E-commerce fields | ||
470 | + public var _min_order_price: Double? { | ||
471 | + get { return self.min_order_price } | ||
472 | + set(newValue) { self.min_order_price = newValue } | ||
473 | + } | ||
474 | + | ||
475 | + public var _min_order_price_takeaway: Double? { | ||
476 | + get { return self.min_order_price_takeaway } | ||
477 | + set(newValue) { self.min_order_price_takeaway = newValue } | ||
478 | + } | ||
479 | + | ||
480 | + public var _min_price: Double? { | ||
481 | + get { return self.min_price } | ||
482 | + set(newValue) { self.min_price = newValue } | ||
483 | + } | ||
484 | + | ||
485 | + public var _max_price: Double? { | ||
486 | + get { return self.max_price } | ||
487 | + set(newValue) { self.max_price = newValue } | ||
488 | + } | ||
489 | + | ||
490 | + // SEO and categorization | ||
491 | + public var _url_name: String { | ||
492 | + get { return self.url_name ?? "" } | ||
493 | + set(newValue) { self.url_name = newValue } | ||
494 | + } | ||
495 | + | ||
496 | + public var _tags_raw: String { | ||
497 | + get { return self.tags_raw ?? "" } | ||
498 | + set(newValue) { self.tags_raw = newValue } | ||
499 | + } | ||
500 | + | ||
501 | + public var _product_raw: String { | ||
502 | + get { return self.product_raw ?? "" } | ||
503 | + set(newValue) { self.product_raw = newValue } | ||
504 | + } | ||
505 | + | ||
506 | + // MARK: - COMPUTED PROPERTIES FOR COMPLEX DATA | ||
507 | + | ||
508 | + // Computed property to get metadata as dictionary | ||
509 | + public var merchantMetadata: [String: Any]? { | ||
510 | + guard let rawString = merchant_metadata_raw, | ||
511 | + !rawString.isEmpty, | ||
512 | + let data = rawString.data(using: .utf8), | ||
513 | + let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { | ||
514 | + return nil | ||
515 | + } | ||
516 | + return dict | ||
517 | + } | ||
518 | + | ||
519 | + // Computed property to get tags as array | ||
520 | + public var tagsArray: [String] { | ||
521 | + guard let rawTags = tags_raw, !rawTags.isEmpty else { return [] } | ||
522 | + return rawTags.components(separatedBy: ",").filter { !$0.isEmpty } | ||
523 | + } | ||
524 | + | ||
525 | + // Computed property to get product info as dictionary | ||
526 | + public var productInfo: [String: Any]? { | ||
527 | + guard let rawString = product_raw, | ||
528 | + !rawString.isEmpty, | ||
529 | + let data = rawString.data(using: .utf8), | ||
530 | + let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { | ||
531 | + return nil | ||
532 | + } | ||
533 | + return dict | ||
534 | + } | ||
535 | + | ||
536 | + // Computed property to check if merchant has progress completed | ||
537 | + public var hasProgressCompleted: Bool { | ||
538 | + return merchantMetadata?["progressCompleted"] as? Bool ?? false | ||
539 | + } | ||
540 | + | ||
541 | + // Computed property to get main image URL (first in img array or fallback to img_preview) | ||
542 | + public var mainImageURL: String { | ||
543 | + if let imgArray = img, !imgArray.isEmpty { | ||
544 | + return imgArray.first ?? _img_preview | ||
545 | + } | ||
546 | + return _img_preview | ||
547 | + } | ||
548 | + | ||
549 | + // Computed property to get pin image URL (second in img array if available) | ||
550 | + public var pinImageURL: String? { | ||
551 | + if let imgArray = img, imgArray.count > 1 { | ||
552 | + return imgArray[1] | ||
553 | + } | ||
554 | + return nil | ||
555 | + } | ||
314 | } | 556 | } | ... | ... |
... | @@ -256,6 +256,12 @@ import UIKit | ... | @@ -256,6 +256,12 @@ import UIKit |
256 | 256 | ||
257 | if belongsToCategory { | 257 | if belongsToCategory { |
258 | processedCouponSets.insert(couponSet._uuid) | 258 | processedCouponSets.insert(couponSet._uuid) |
259 | + | ||
260 | + // BIND MERCHANT DATA: Find and bind the merchant to this coupon set | ||
261 | + if let merchant = categoryMerchants.first(where: { $0._uuid == couponSet._merchant_uuid }) { | ||
262 | + couponSet._merchant = merchant | ||
263 | + print(" 🔗 Bound merchant '\(merchant._name)' to coupon set '\(couponSet._name)'") | ||
264 | + } | ||
259 | } | 265 | } |
260 | 266 | ||
261 | return belongsToCategory | 267 | return belongsToCategory |
... | @@ -285,6 +291,14 @@ import UIKit | ... | @@ -285,6 +291,14 @@ import UIKit |
285 | if !unmatchedCouponSets.isEmpty { | 291 | if !unmatchedCouponSets.isEmpty { |
286 | print(" ⚠️ Found \(unmatchedCouponSets.count) unmatched coupon sets - adding to 'Άλλες Προσφορές' section") | 292 | print(" ⚠️ Found \(unmatchedCouponSets.count) unmatched coupon sets - adding to 'Άλλες Προσφορές' section") |
287 | 293 | ||
294 | + // BIND MERCHANT DATA for unmatched coupon sets too | ||
295 | + for couponSet in unmatchedCouponSets { | ||
296 | + if let merchant = merchants.first(where: { $0._uuid == couponSet._merchant_uuid }) { | ||
297 | + couponSet._merchant = merchant | ||
298 | + print(" 🔗 Bound merchant '\(merchant._name)' to unmatched coupon set '\(couponSet._name)'") | ||
299 | + } | ||
300 | + } | ||
301 | + | ||
288 | let unmatchedSection = SectionModel( | 302 | let unmatchedSection = SectionModel( |
289 | sectionType: .myRewardsHorizontalCouponsets, | 303 | sectionType: .myRewardsHorizontalCouponsets, |
290 | title: "Άλλες Προσφορές", // "Other Offers" | 304 | title: "Άλλες Προσφορές", // "Other Offers" | ... | ... |
-
Please register or login to post a comment