Manos Chorianopoulos

new getCouponFilters request and MyRewardsViewController sections handling

......@@ -438,6 +438,7 @@ private final class SDKState {
var carouselList: [CampaignItemModel] = []
var marketPassDetails: MarketPassDetailsModel?
var supermarketCampaign: CampaignItemModel?
var couponFilters: CouponFiltersDataModel?
private init() {}
}
......@@ -2545,6 +2546,77 @@ public final class WarplySDK {
}
}
/// Get coupon filters via new endpoint
/// - Parameters:
/// - language: Optional language code (defaults to applicationLocale)
/// - completion: Returns the raw response dictionary on success
/// - failureCallback: Returns error code on failure
public func getCouponFilters(
language: String? = nil,
completion: @escaping (CouponFiltersDataModel?) -> Void,
failureCallback: @escaping (Int) -> Void
) {
let finalLanguage = language ?? self.applicationLocale
Task {
do {
let endpoint = Endpoint.getCouponFilters(language: finalLanguage)
let response = try await networkService.requestRaw(endpoint)
await MainActor.run {
print("📥 getCouponFilters response: \(response)")
let dynatraceEvent = LoyaltySDKDynatraceEventModel()
dynatraceEvent._eventName = "custom_success_couponfilters_loyalty"
dynatraceEvent._parameters = nil
self.postFrameworkEvent("dynatrace", sender: dynatraceEvent)
if let resultData = response["result"] as? [String: Any] {
let filterModel = CouponFiltersDataModel(dictionary: resultData)
self.setCouponFilters(filterModel)
completion(filterModel)
} else {
completion(nil)
}
}
} catch {
await MainActor.run {
let dynatraceEvent = LoyaltySDKDynatraceEventModel()
dynatraceEvent._eventName = "custom_error_couponfilters_loyalty"
dynatraceEvent._parameters = nil
self.postFrameworkEvent("dynatrace", sender: dynatraceEvent)
if let networkError = error as? NetworkError {
failureCallback(networkError.code)
} else {
failureCallback(-1)
}
}
}
}
}
/// Get coupon filters (async/await variant)
/// - Parameters:
/// - language: Language code for localized content (optional, defaults to applicationLocale)
/// - Returns: Parsed filters model
/// - Throws: WarplyError if the request fails
public func getCouponFilters(
language: String? = nil
) async throws -> CouponFiltersDataModel {
return try await withCheckedThrowingContinuation { continuation in
getCouponFilters(language: language, completion: { response in
if let response = response {
continuation.resume(returning: response)
} 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
......@@ -4344,6 +4416,16 @@ public final class WarplySDK {
return state.couponSets
}
/// Set coupon filters data
public func setCouponFilters(_ filters: CouponFiltersDataModel) {
state.couponFilters = filters
}
/// Get coupon filters data
public func getCouponFilters() -> CouponFiltersDataModel? {
return state.couponFilters
}
/// Set seasonal list
public func setSeasonalList(_ seasonalCoupons: [LoyaltyGiftsForYouPackage]) {
state.seasonalList = seasonalCoupons
......
......@@ -68,6 +68,7 @@ public enum Endpoint {
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 getCouponFilters(language: String)
case getAvailableCoupons
// Market & Merchants
......@@ -143,7 +144,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, .getCouponSetsNew:
case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getCarouselContent, .getCouponSetsNew, .getCouponFilters:
return "/oauth/{appUUID}/context"
// Session endpoints - /api/session/{sessionUuid}
......@@ -171,7 +172,7 @@ public enum Endpoint {
public var method: HTTPMethod {
switch self {
case .register, .changePassword, .resetPassword, .requestOtp, .verifyTicket, .refreshToken, .logout, .getCampaigns, .getCampaignsPersonalized,
.getCoupons, .getCouponSets, .getCouponSetsNew, .getAvailableCoupons,
.getCoupons, .getCouponSets, .getCouponSetsNew, .getCouponFilters, .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:
......@@ -314,6 +315,14 @@ public enum Endpoint {
"coupon": couponParams
]
case .getCouponFilters(let language):
return [
"coupon": [
"action": "get_filters",
"language": language
]
]
case .getAvailableCoupons:
return [
"coupon": [
......@@ -523,7 +532,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, .getCouponSetsNew:
case .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getCarouselContent, .getCouponSetsNew, .getCouponFilters:
return .authenticatedContext
// Authentication - /oauth/{appUUID}/login, /oauth/{appUUID}/token
......@@ -565,7 +574,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, .getCouponSetsNew:
case .changePassword, .getCampaignsPersonalized, .getCoupons, .getMarketPassDetails, .getProfile, .addCard, .getCards, .deleteCard, .getTransactionHistory, .getPointsHistory, .validateCoupon, .redeemCoupon, .retrieveCoupon, .getCarouselContent, .getCouponSetsNew, .getCouponFilters:
return .bearerToken
// Basic Authentication (loyalty headers + Authorization: Basic)
......
......@@ -659,6 +659,72 @@ public class RedeemedSMHistoryModel {
}
}
// MARK: - Coupon Filters Models
public class CouponFiltersDataModel {
private var offer_categories: [CouponOfferCategoryModel]?
private var regions: [String]?
public init(dictionary: [String: Any]) {
if let regionsArray = dictionary["regions"] as? [Any] {
self.regions = regionsArray.compactMap { $0 as? String }
} else {
self.regions = []
}
if let categoriesArray = dictionary["offer_categories"] as? [[String: Any]] {
var tempCategories: [CouponOfferCategoryModel] = []
for catDict in categoriesArray {
tempCategories.append(CouponOfferCategoryModel(dictionary: catDict))
}
self.offer_categories = tempCategories
} else {
self.offer_categories = []
}
}
public var _offer_categories: [CouponOfferCategoryModel]? { get { return self.offer_categories } }
public var _regions: [String]? { get { return self.regions } }
}
public class CouponOfferCategoryModel {
private var uuid: String?
private var admin_name: String?
private var name: String?
private var image: String?
private var parent: String?
private var children: [CouponOfferCategoryModel]?
public init(dictionary: [String: Any]) {
self.uuid = dictionary["uuid"] as? String
self.admin_name = dictionary["admin_name"] as? String
self.name = dictionary["name"] as? String
if let imgString = dictionary["image"] as? String {
self.image = imgString.trimmingCharacters(in: .whitespacesAndNewlines)
}
self.parent = dictionary["parent"] as? String
if let childrenArray = dictionary["children"] as? [[String: Any]] {
var tempChildren: [CouponOfferCategoryModel] = []
for childDict in childrenArray {
tempChildren.append(CouponOfferCategoryModel(dictionary: childDict))
}
self.children = tempChildren
} else {
self.children = []
}
}
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 _image: String { get { return self.image ?? "" } }
public var _parent: String { get { return self.parent ?? "" } }
public var _children: [CouponOfferCategoryModel]? { get { return self.children } }
}
// MARK: - String Extension for HTML
// extension String {
......