Manos Chorianopoulos

add getCouponSetsNew request

......@@ -2457,6 +2457,94 @@ public final class WarplySDK {
}
}
/// Get coupon sets via new endpoint with optional region/offer_category filters
/// - Parameters:
/// - region: Optional region filter (omitted from payload if nil)
/// - offerCategory: Optional offer category filter (omitted from payload if nil)
/// - completion: Returns the raw response dictionary on success
/// - failureCallback: Returns error code on failure
public func getCouponSetsNew(
language: String? = nil,
region: String? = nil,
offerCategory: String? = nil,
completion: @escaping ([CouponSetItemModel]?) -> Void,
failureCallback: @escaping (Int) -> Void
) {
let finalLanguage = language ?? self.applicationLocale
Task {
do {
let endpoint = Endpoint.getCouponSetsNew(
language: finalLanguage,
active: true,
visible: true,
region: region,
offerCategory: offerCategory
)
let response = try await networkService.requestRaw(endpoint)
var couponSetsArray: [CouponSetItemModel] = []
await MainActor.run {
print("📥 getCouponSetsNew response: \(response)")
let dynatraceEvent = LoyaltySDKDynatraceEventModel()
dynatraceEvent._eventName = "custom_success_couponsetsnew_loyalty"
dynatraceEvent._parameters = nil
self.postFrameworkEvent("dynatrace", sender: dynatraceEvent)
if let resultData = response["result"] as? [[String: Any]] {
for couponsetDict in resultData {
let tempCouponset = CouponSetItemModel(dictionary: couponsetDict)
couponSetsArray.append(tempCouponset)
}
}
self.setCouponSetList(couponSetsArray)
completion(couponSetsArray)
}
} catch {
await MainActor.run {
let dynatraceEvent = LoyaltySDKDynatraceEventModel()
dynatraceEvent._eventName = "custom_error_couponsetsnew_loyalty"
dynatraceEvent._parameters = nil
self.postFrameworkEvent("dynatrace", sender: dynatraceEvent)
if let networkError = error as? NetworkError {
failureCallback(networkError.code)
} else {
failureCallback(-1)
}
}
}
}
}
/// Get coupon sets new (async/await variant)
/// - Parameters:
/// - language: Language code for localized content (optional, defaults to applicationLocale)
/// - region: Optional region filter (omitted from payload if nil)
/// - offerCategory: Optional offer category filter (omitted from payload if nil)
/// - Returns: Array of coupon set models
/// - Throws: WarplyError if the request fails
public func getCouponSetsNew(
language: String? = nil,
region: String? = nil,
offerCategory: String? = nil
) async throws -> [CouponSetItemModel] {
return try await withCheckedThrowingContinuation { continuation in
getCouponSetsNew(language: language, region: region, offerCategory: offerCategory, completion: { couponSets in
if let couponSets = couponSets {
continuation.resume(returning: couponSets)
} else {
continuation.resume(throwing: WarplyError.networkError)
}
}, failureCallback: { errorCode in
continuation.resume(throwing: WarplyError.unknownError(errorCode))
})
}
}
/// Get available coupons (async/await variant)
/// - Returns: Dictionary of coupon availability data
/// - Throws: WarplyError if the request fails
......
......@@ -67,6 +67,7 @@ public enum Endpoint {
// Coupons
case getCoupons(language: String, couponsetType: String)
case getCouponSets(language: String, active: Bool, visible: Bool, uuids: [String]?)
case getCouponSetsNew(language: String, active: Bool, visible: Bool, region: String?, offerCategory: String?)
case getAvailableCoupons
// Market & Merchants
......@@ -142,7 +143,7 @@ public enum Endpoint {
return "/api/mobile/v2/{appUUID}/context/"
// Authenticated Context endpoints - /oauth/{appUUID}/context
case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getCarouselContent:
case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getCarouselContent, .getCouponSetsNew:
return "/oauth/{appUUID}/context"
// Session endpoints - /api/session/{sessionUuid}
......@@ -170,7 +171,7 @@ public enum Endpoint {
public var method: HTTPMethod {
switch self {
case .register, .changePassword, .resetPassword, .requestOtp, .verifyTicket, .refreshToken, .logout, .getCampaigns, .getCampaignsPersonalized,
.getCoupons, .getCouponSets, .getAvailableCoupons,
.getCoupons, .getCouponSets, .getCouponSetsNew, .getAvailableCoupons,
.getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getMerchants, .getMerchantCategories, .getStores, .getArticles, .sendEvent, .sendDeviceInfo, .getCosmoteUser, .deiLogin, .getCarouselContent:
return .POST
case .getSingleCampaign, .getNetworkStatus:
......@@ -296,6 +297,23 @@ public enum Endpoint {
"coupon": couponParams
]
case .getCouponSetsNew(let language, let active, let visible, let region, let offerCategory):
var couponParams: [String: Any] = [
"action": "get_offers",
"active": active,
"visible": visible,
"language": language
]
if let region = region {
couponParams["region"] = region
}
if let offerCategory = offerCategory {
couponParams["offer_category"] = offerCategory
}
return [
"coupon": couponParams
]
case .getAvailableCoupons:
return [
"coupon": [
......@@ -505,7 +523,7 @@ public enum Endpoint {
return .standardContext
// Authenticated Context - /oauth/{appUUID}/context
case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getCarouselContent:
case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getCarouselContent, .getCouponSetsNew:
return .authenticatedContext
// Authentication - /oauth/{appUUID}/login, /oauth/{appUUID}/token
......@@ -547,7 +565,7 @@ public enum Endpoint {
return .standard
// Bearer Token Authentication (loyalty headers + Authorization: Bearer)
case .changePassword, .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getCarouselContent:
case .changePassword, .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getCarouselContent, .getCouponSetsNew:
return .bearerToken
// Basic Authentication (loyalty headers + Authorization: Basic)
......
......@@ -77,7 +77,20 @@ public class CouponSetItemModel {
private var points_cause: String?
private var third_party_service: String?
private var category: String?
private var offer_category: String?
// getCouponSetsNew fields
private var score: String?
private var locked: Bool?
private var app_img_preview: String?
private var app_imgs: [String]?
private var merchant_admin_name: String?
private var merchant_img_preview: String?
private var merchant_website: String?
private var regions: [String]?
private var show_as_banner: [String: Any]?
private var tagging: [String: Any]?
// Bound merchant data for performance
private var merchant: MerchantModel?
......@@ -159,7 +172,38 @@ public class CouponSetItemModel {
self.points_cause = dictionary["points_cause"] as? String? ?? ""
self.third_party_service = dictionary["third_party_service"] as? String? ?? ""
self.category = dictionary["category"] as? String? ?? ""
self.offer_category = dictionary["offer_category"] as? String? ?? ""
// getCouponSetsNew fields
self.score = dictionary["score"] as? String
if let lockedInt = dictionary["locked"] as? Int {
self.locked = lockedInt == 1
} else {
self.locked = dictionary["locked"] as? Bool
}
self.app_img_preview = dictionary["app_img_preview"] as? String
self.merchant_admin_name = dictionary["merchant_admin_name"] as? String
self.merchant_img_preview = dictionary["merchant_img_preview"] as? String
self.merchant_website = dictionary["merchant_website"] as? String
self.show_as_banner = dictionary["show_as_banner"] as? [String: Any]
self.tagging = dictionary["tagging"] as? [String: Any]
// app_imgs — JSON-encoded string array, same pattern as img
if let appImgsString = dictionary["app_imgs"] as? String,
let appImgsData = appImgsString.data(using: .utf8),
let appImgsArray = try? JSONSerialization.jsonObject(with: appImgsData, options: []) as? [String] {
self.app_imgs = appImgsArray
} else {
self.app_imgs = []
}
// regions — array with potential NSNull entries, filter them out
if let regionsArray = dictionary["regions"] as? [Any] {
self.regions = regionsArray.compactMap { $0 as? String }
} else {
self.regions = []
}
// UPDATED EXPIRATION HANDLING - store raw date string
if let expirationObject = dictionary["expiration"] as? [String: Any],
let expirationValue = expirationObject["value"] as? String {
......@@ -266,7 +310,20 @@ public class CouponSetItemModel {
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 ?? "" } }
public var _offer_category: String { get { return self.offer_category ?? "" } }
// getCouponSetsNew field accessors
public var _score: String? { get { return self.score } set { self.score = newValue } }
public var _locked: Bool { get { return self.locked ?? false } }
public var _app_img_preview: String { get { return self.app_img_preview ?? "" } }
public var _app_imgs: [String]? { get { return self.app_imgs } }
public var _merchant_admin_name: String { get { return self.merchant_admin_name ?? "" } }
public var _merchant_img_preview: String { get { return self.merchant_img_preview ?? "" } }
public var _merchant_website: String { get { return self.merchant_website ?? "" } }
public var _regions: [String]? { get { return self.regions } }
public var _show_as_banner: [String: Any]? { get { return self.show_as_banner } }
public var _tagging: [String: Any]? { get { return self.tagging } }
// Bound merchant data accessor
public var _merchant: MerchantModel? {
get { return self.merchant }
......
......@@ -270,20 +270,49 @@ 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
// // Load merchants after getting coupon sets
// self.loadMerchants()
// } failureCallback: { [weak self] errorCode in
// print("Failed to load coupon sets: \(errorCode)")
// // No sections added on failure - table will be empty
// }
// }
private func loadCouponSets() {
// Load coupon sets from WarplySDK
WarplySDK.shared.getCouponSets { [weak self] couponSets in
guard let self = self, let couponSets = couponSets else { return }
// WarplySDK.shared.getCouponSets { [weak self] couponSets in
// guard let self = self, let couponSets = couponSets else { return }
self.couponSets = couponSets
// self.couponSets = couponSets
// Load merchants after getting coupon sets
self.loadMerchants()
// // Load merchants after getting coupon sets
// self.loadMerchants()
} failureCallback: { [weak self] errorCode in
print("Failed to load coupon sets: \(errorCode)")
// No sections added on failure - table will be empty
}
// } failureCallback: { [weak self] errorCode in
// print("Failed to load coupon sets: \(errorCode)")
// // No sections added on failure - table will be empty
// }
WarplySDK.shared.getCouponSetsNew(
completion: { [weak self] couponSets in
guard let self = self, let couponSets = couponSets else { return }
self.couponSets = couponSets
self?.createCouponSetsSection()
},
failureCallback: { errorCode in
print("=== getCouponSetsNew Error: \(errorCode)")
}
)
}
// MARK: - Coupons Loading
......@@ -385,6 +414,8 @@ import UIKit
}
private func createCouponSetsSection() {
// TODO: no merchant match any more
print("🔍 [MyRewardsViewController] Starting coupon filtering:")
print(" - Coupon Sets: \(couponSets.count)")
print(" - Merchants: \(merchants.count)")
......