Manos Chorianopoulos

dynamic couponsets in MyRewardsVC

......@@ -263,13 +263,13 @@ public enum Endpoint {
"action": "retrieve_multilingual",
"active": active,
"visible": visible,
"language": language,
"exclude": [
[
"field": "couponset_type",
"value": ["supermarket"]
]
]
"language": language
// "exclude": [
// [
// "field": "couponset_type",
// "value": ["supermarket"]
// ]
// ]
]
if let uuids = uuids {
couponParams["uuids"] = uuids
......
......@@ -68,7 +68,7 @@ public class MyRewardsOfferCollectionViewCell: UICollectionViewCell {
func configureCell(data: CouponSetItemModel) {
// Use coupon set preview image
let imageName = data.img_preview ?? ""
let imageName = data._img_preview
if !imageName.isEmpty {
bannerImage.image = UIImage(named: imageName, in: Bundle.frameworkResourceBundle, compatibleWith: nil)
} else {
......@@ -79,13 +79,13 @@ public class MyRewardsOfferCollectionViewCell: UICollectionViewCell {
favoriteImage.image = UIImage(named: "favorite_empty", in: Bundle.frameworkResourceBundle, compatibleWith: nil)
// Use coupon set discount
discountLabel.text = data.discount ?? ""
discountLabel.text = data._discount
discountLabel.font = UIFont(name: "PingLCG-Bold", size: 17)
discountLabel.textColor = UIColor(rgb: 0xF2F2F2)
// Color based on discount type
let discountColor: UInt = {
switch data.discount_type {
switch data._discount_type {
case "percentage":
return 0xFF6B35
case "value":
......@@ -98,20 +98,20 @@ public class MyRewardsOfferCollectionViewCell: UICollectionViewCell {
}()
discountView.backgroundColor = UIColor(rgb: discountColor)
titleLabel.text = data.name ?? ""
titleLabel.text = data._name
titleLabel.font = UIFont(name: "PingLCG-Bold", size: 17)
titleLabel.textColor = UIColor(rgb: 0x000F1E)
subtitleLabel.text = data.short_description ?? ""
subtitleLabel.text = data._short_description
subtitleLabel.font = UIFont(name: "PingLCG-Regular", size: 14)
subtitleLabel.textColor = UIColor(rgb: 0x00111B)
expirationLabel.text = data.expiration ?? ""
expirationLabel.text = data._expiration_formatted
expirationLabel.font = UIFont(name: "PingLCG-Regular", size: 13)
expirationLabel.textColor = UIColor(rgb: 0x00111B)
// Use first image from img array if available
if let imgArray = data.img, !imgArray.isEmpty {
if let imgArray = data._img, !imgArray.isEmpty {
let logoName = imgArray[0]
if !logoName.isEmpty {
logoImage.image = UIImage(named: logoName, in: Bundle.frameworkResourceBundle, compatibleWith: nil)
......
......@@ -36,31 +36,50 @@ public class ShopAvailabilityItemModel: Codable {
}
public class CouponSetItemModel: Codable {
public let uuid: String?
public let admin_name: String?
public let name: String?
public let img: [String]?
public let img_preview: String?
public let expiration: String?
public let description: String?
public let short_description: String?
public let discount: String?
public let sorting: Int?
public let inner_text: String?
public let buyable: Bool?
public let visible: Bool?
public let terms: String?
public let merchant_uuid: String?
public let discount_type: String? // "value" / "percentage" / "plus_one"
public let final_price: Float?
// Existing fields
private var uuid: String?
private var admin_name: String?
private var name: String?
private var img: [String]?
private var img_preview: String?
private var expiration: String? // Now stores raw date string like "2026-06-30 11:59"
private var description: String?
private var short_description: String?
private var discount: String?
private var sorting: Int?
private var inner_text: String?
private var buyable: Bool?
private var visible: Bool?
private var terms: String?
private var merchant_uuid: String?
private var discount_type: String? // "value" / "percentage" / "plus_one"
private var final_price: Float?
// Universal Coupons
public let couponset_type: String?
private var couponset_type: String?
// PopupMerchantsViewController List
public let shop_availability: Array<ShopAvailabilityItemModel>?
private var shop_availability: Array<ShopAvailabilityItemModel>?
// New fields from API response
private var eligibilities: [String: Any]?
private var created: String?
private var updated: String?
private var app_uuid: String?
private var active: Bool?
private var is_new: Bool?
private var start_date: String?
private var end_date: String?
private var user_generated: Bool?
private var limits: [String: Any]?
private var points: Int?
private var promoted: Bool?
private var points_cause: String?
private var third_party_service: String?
private var category: String?
public init(dictionary: [String: Any]) {
// Existing fields
self.uuid = dictionary["uuid"] as? String? ?? ""
self.admin_name = dictionary["admin_name"] as? String? ?? ""
self.name = dictionary["name"] as? String? ?? ""
......@@ -93,15 +112,27 @@ public class CouponSetItemModel: Codable {
self.final_price = 0.0
}
let expirationObject = dictionary["expiration"] as? [String: Any]? ?? ["":""]
let expirationString = expirationObject?["value"] as? String? ?? ""
// NEW FIELDS from API response
self.eligibilities = dictionary["eligibilities"] as? [String: Any]
self.created = dictionary["created"] as? String? ?? ""
self.updated = dictionary["updated"] as? String? ?? ""
self.app_uuid = dictionary["app_uuid"] as? String? ?? ""
self.active = dictionary["active"] as? Bool? ?? false
self.is_new = dictionary["is_new"] as? Bool? ?? false
self.start_date = dictionary["start_date"] as? String? ?? ""
self.end_date = dictionary["end_date"] as? String? ?? ""
self.user_generated = dictionary["user_generated"] as? Bool? ?? false
self.limits = dictionary["limits"] as? [String: Any]
self.points = dictionary["points"] as? Int? ?? 0
self.promoted = dictionary["promoted"] as? Bool? ?? false
self.points_cause = dictionary["points_cause"] as? String? ?? ""
self.third_party_service = dictionary["third_party_service"] as? String? ?? ""
self.category = dictionary["category"] as? String? ?? ""
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd hh:mm"
if let date = dateFormatter.date(from: expirationString ?? "") {
dateFormatter.dateFormat = "dd/MM/yyyy"
let resultString = dateFormatter.string(from: date)
self.expiration = resultString
// UPDATED EXPIRATION HANDLING - store raw date string
if let expirationObject = dictionary["expiration"] as? [String: Any],
let expirationValue = expirationObject["value"] as? String {
self.expiration = expirationValue // Store "2026-06-30 11:59"
} else {
self.expiration = ""
}
......@@ -164,6 +195,63 @@ public class CouponSetItemModel: Codable {
self.shop_availability = []
}
}
// MARK: - Public Accessors (Following ProfileModel Pattern)
// Existing field accessors
public var _uuid: String { get { return self.uuid ?? "" } }
public var _admin_name: String { get { return self.admin_name ?? "" } }
public var _name: String { get { return self.name ?? "" } }
public var _img: [String]? { get { return self.img } }
public var _img_preview: String { get { return self.img_preview ?? "" } }
public var _expiration: String { get { return self.expiration ?? "" } }
public var _description: String { get { return self.description ?? "" } }
public var _short_description: String { get { return self.short_description ?? "" } }
public var _discount: String { get { return self.discount ?? "" } }
public var _sorting: Int { get { return self.sorting ?? 0 } }
public var _inner_text: String { get { return self.inner_text ?? "" } }
public var _buyable: Bool { get { return self.buyable ?? false } }
public var _visible: Bool { get { return self.visible ?? false } }
public var _terms: String { get { return self.terms ?? "" } }
public var _merchant_uuid: String { get { return self.merchant_uuid ?? "" } }
public var _discount_type: String { get { return self.discount_type ?? "" } }
public var _final_price: Float { get { return self.final_price ?? 0.0 } }
public var _couponset_type: String { get { return self.couponset_type ?? "" } }
public var _shop_availability: Array<ShopAvailabilityItemModel>? { get { return self.shop_availability } }
// New field accessors
public var _eligibilities: [String: Any]? { get { return self.eligibilities } }
public var _created: String { get { return self.created ?? "" } }
public var _updated: String { get { return self.updated ?? "" } }
public var _app_uuid: String { get { return self.app_uuid ?? "" } }
public var _active: Bool { get { return self.active ?? false } }
public var _is_new: Bool { get { return self.is_new ?? false } }
public var _start_date: String { get { return self.start_date ?? "" } }
public var _end_date: String { get { return self.end_date ?? "" } }
public var _user_generated: Bool { get { return self.user_generated ?? false } }
public var _limits: [String: Any]? { get { return self.limits } }
public var _points: Int { get { return self.points ?? 0 } }
public var _promoted: Bool { get { return self.promoted ?? false } }
public var _points_cause: String { get { return self.points_cause ?? "" } }
public var _third_party_service: String { get { return self.third_party_service ?? "" } }
public var _category: String { get { return self.category ?? "" } }
// Formatted expiration date for display
public var _expiration_formatted: String {
guard let expiration = self.expiration, !expiration.isEmpty else {
return ""
}
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
if let date = dateFormatter.date(from: expiration) {
dateFormatter.dateFormat = "dd/MM/yyyy"
return dateFormatter.string(from: date)
}
return ""
}
}
public class RedeemedMerchantDetailsModel: Codable {
......
......@@ -40,6 +40,9 @@ import UIKit
// Campaign data for banners
var bannerCampaigns: [CampaignItemModel] = []
// Coupon sets data
var couponSets: [CouponSetItemModel] = []
// Profile data
var profileModel: ProfileModel?
var profileSection: SectionModel?
......@@ -64,8 +67,9 @@ import UIKit
createDefaultProfileSection()
// Load data
loadProfile() // Try to populate profile with real data
loadCampaigns() // Load campaigns
loadProfile() // Load Profile
loadCampaigns() // Load campaigns
loadCouponSets() // Load couponsets
}
// NEW: Safe XIB registration method
......@@ -136,6 +140,35 @@ import UIKit
}
}
// MARK: - Coupon Sets Loading
private func loadCouponSets() {
// Load coupon sets from WarplySDK
WarplySDK.shared.getCouponSets { [weak self] couponSets in
guard let self = self, let couponSets = couponSets else { return }
self.couponSets = couponSets
// Create coupon sets section with real data
if !self.couponSets.isEmpty {
let couponSetsSection = SectionModel(
sectionType: .myRewardsHorizontalCouponsets,
title: "Προσφορές",
items: self.couponSets,
itemType: .couponSets
)
self.sections.append(couponSetsSection)
}
// Reload table view with new sections
DispatchQueue.main.async {
self.tableView.reloadData()
}
} failureCallback: { [weak self] errorCode in
print("Failed to load coupon sets: \(errorCode)")
// No sections added on failure - table will be empty
}
}
// MARK: - Profile Loading
public func loadProfile() {
// Always attempt to load profile, regardless of authentication status
......