Skip to content

Commit b940a2c

Browse files
committed
DEV-3525: send tracking method popup/showed
1 parent 09b9ac3 commit b940a2c

File tree

8 files changed

+132
-13
lines changed

8 files changed

+132
-13
lines changed

DemoApp/REES46Demo/MainViewController.swift

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class MainViewController: UIViewController, UIScrollViewDelegate {
2525
@IBOutlet private weak var resetDidButton: UIButton!
2626
@IBOutlet private weak var showStoriesButton: UIButton!
2727
@IBOutlet private weak var showSnackBarButton: UIButton!
28+
private var showTestPopupButton: UIButton!
2829

2930
public var waitIndicator: SdkActivityIndicator!
3031

@@ -188,6 +189,48 @@ class MainViewController: UIViewController, UIScrollViewDelegate {
188189
storiesCollectionView.showStories()
189190
}
190191

192+
@objc
193+
private func showTestPopup() {
194+
guard let sdk = globalSDK else {
195+
return
196+
}
197+
198+
let componentsDict: [String: Any] = [
199+
"header": "Test Popup",
200+
"text": "This is a test popup for iOS SDK"
201+
]
202+
203+
let componentsJSON: String
204+
if let componentsData = try? JSONSerialization.data(withJSONObject: componentsDict),
205+
let componentsString = String(data: componentsData, encoding: .utf8) {
206+
componentsJSON = componentsString
207+
} else {
208+
componentsJSON = "{}"
209+
}
210+
211+
let testPopupData: [String: Any] = [
212+
"id": 999,
213+
"channels": ["email"],
214+
"position": "centered",
215+
"delay": 0,
216+
"html": """
217+
<div class="popup-title">Test Popup</div>
218+
<p class="popup-999__intro">This is a test popup for iOS SDK</p>
219+
""",
220+
"components": componentsJSON,
221+
"web_push_system": false,
222+
"popup_actions": "{}"
223+
]
224+
225+
let testPopup = Popup(json: testPopupData)
226+
227+
sdk.popupPresenter.dismissCurrentPopup()
228+
229+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
230+
sdk.popupPresenter.presentPopup(testPopup)
231+
}
232+
}
233+
191234
func setupSdkDemoAppViews() {
192235
navigationController?.navigationBar.isHidden = true
193236
scrollView.contentSize = CGSize(width: UIScreen.main.bounds.size.width, height: 2000)
@@ -199,6 +242,8 @@ class MainViewController: UIViewController, UIScrollViewDelegate {
199242
resetDidButton.addTarget(self, action: #selector(didTapReset), for: .touchUpInside)
200243
showStoriesButton.addTarget(self, action: #selector(showStories), for: .touchUpInside)
201244

245+
setupTestPopupButton()
246+
202247
fontInterPreload()
203248
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
204249
self.setupSdkLabels()
@@ -231,6 +276,24 @@ class MainViewController: UIViewController, UIScrollViewDelegate {
231276
self.waitIndicator.hideIndicatorWhenStopped = true
232277
}
233278

279+
func setupTestPopupButton() {
280+
showTestPopupButton = DemoShopButton(type: .system)
281+
showTestPopupButton.setTitle("Show Test Popup", for: .normal)
282+
showTestPopupButton.setTitleColor(.white, for: .normal)
283+
showTestPopupButton.translatesAutoresizingMaskIntoConstraints = false
284+
scrollView.addSubview(showTestPopupButton)
285+
286+
// Размещаем кнопку рядом с другими тестовыми кнопками
287+
NSLayoutConstraint.activate([
288+
showTestPopupButton.topAnchor.constraint(equalTo: showStoriesButton.bottomAnchor, constant: 10),
289+
showTestPopupButton.leadingAnchor.constraint(equalTo: showStoriesButton.leadingAnchor),
290+
showTestPopupButton.widthAnchor.constraint(equalTo: showStoriesButton.widthAnchor),
291+
showTestPopupButton.heightAnchor.constraint(equalTo: showStoriesButton.heightAnchor)
292+
])
293+
294+
showTestPopupButton.addTarget(self, action: #selector(showTestPopup), for: .touchUpInside)
295+
}
296+
234297
func fontInterPreload() {
235298
fcmTokenLabel.font = SdkDynamicFont.dynamicFont(textStyle: .headline, weight: .bold)
236299
pushTokenLabel .font = SdkDynamicFont.dynamicFont(textStyle: .headline, weight: .bold)

REES46/Classes/Presentation/PopupPresenter.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public class PopupPresenter {
1515
private var currentPopup: NotificationWidget?
1616
private var popupQueue: [Popup] = []
1717
private let serialQueue = DispatchQueue(label: "com.rees46.popup.presenter")
18+
private var popupShownFlags: [Int: Date] = [:]
1819

1920
public init(sdk: AnyObject) {
2021
self.sdk = sdk
@@ -55,6 +56,14 @@ public class PopupPresenter {
5556
// MARK: - Private Methods
5657

5758
private func showPopupNow(_ popup: Popup) {
59+
// Проверяем, был ли попап показан в последние 60 секунд
60+
if let shownDate = popupShownFlags[popup.id] {
61+
let timeSinceShown = Date().timeIntervalSince(shownDate)
62+
if timeSinceShown < 60 {
63+
return // Попап уже был показан, не показываем снова
64+
}
65+
}
66+
5867
guard let presentingVC = getPresentingViewController(for: popup) else {
5968
return // No VC available or delegate prevented presentation
6069
}
@@ -68,6 +77,21 @@ public class PopupPresenter {
6877
self?.dismissCurrentPopup()
6978
}
7079
)
80+
81+
// Сохраняем флаг показа в памяти на 60 секунд
82+
self.popupShownFlags[popup.id] = Date()
83+
84+
// Удаляем флаг через 60 секунд
85+
DispatchQueue.main.asyncAfter(deadline: .now() + 60) { [weak self] in
86+
self?.popupShownFlags.removeValue(forKey: popup.id)
87+
}
88+
89+
// Отправляем событие показа попапа на сервер
90+
if let sdk = self.sdk as? PersonalizationSDK {
91+
sdk.trackPopupShown(popupId: popup.id) { _ in
92+
// Обработка результата (логирование при необходимости)
93+
}
94+
}
7195
}
7296
}
7397

REES46/Classes/Sdk/Extensions/Popup.extension.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Foundation
22
extension Popup {
3-
init(json: [String: Any]) {
3+
public init(json: [String: Any]) {
44
self.id = json["id"] as? Int ?? 0
55
self.channels = json["channels"] as? [String] ?? []
66
self.position = json["position"] as? String ?? ""
@@ -17,7 +17,7 @@ extension Popup {
1717
}
1818
}
1919

20-
func extractTitleAndSubtitle() -> (title: String?, subTitle: String?) {
20+
public func extractTitleAndSubtitle() -> (title: String?, subTitle: String?) {
2121
let title = RegexHelper.extract(
2222
using: RegexPattern.title,
2323
from: html

REES46/Classes/Sdk/Model/Popup.struct.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import Foundation
22

33
public struct Popup: Codable {
4-
enum Position: String {
4+
public enum Position: String {
55
case centered = "centered"
66
case bottom = "fixed_bottom"
77
case top = "top"
88
}
99

10-
let id: Int
11-
let channels: [String]
12-
let position: String
13-
let delay: Int
14-
let html: String
15-
let components: PopupComponents?
16-
let web_push_system: Bool
17-
let popup_actions: String
10+
public let id: Int
11+
public let channels: [String]
12+
public let position: String
13+
public let delay: Int
14+
public let html: String
15+
public let components: PopupComponents?
16+
public let web_push_system: Bool
17+
public let popup_actions: String
1818

19-
func getParsedPopupActions() -> PopupActions? {
19+
public func getParsedPopupActions() -> PopupActions? {
2020
guard let data = popup_actions.data(using: .utf8) else { return nil }
2121
let decoder = JSONDecoder()
2222
do {

REES46/Classes/Sdk/impl/SimplePersonalizationSDK.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,10 @@ class SimplePersonalizationSDK: PersonalizationSDK {
408408
trackEventService.trackEvent(event: event, category: category, label: label, value: value, completion: completion)
409409
}
410410

411+
func trackPopupShown(popupId: Int, completion: @escaping (Result<Void, SdkError>) -> Void) {
412+
trackEventService.trackPopupShown(popupId: popupId, completion: completion)
413+
}
414+
411415
func trackSource(source: RecommendedByCase, code: String) {
412416
trackSourceService.trackSource(source: source, code: code)
413417
}
@@ -1196,7 +1200,7 @@ class SimplePersonalizationSDK: PersonalizationSDK {
11961200
}
11971201
do {
11981202
if data.isEmpty {
1199-
if path.contains("clicked") || path.contains("closed") || path.contains("received") {
1203+
if path.contains("clicked") || path.contains("closed") || path.contains("received") || path.contains("showed") {
12001204
completion(.success([:]))
12011205
return
12021206
}

REES46/Classes/Sdk/protocol/PersonalizationSDK.protocol.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public protocol PersonalizationSDK {
3535
func track(event: Event, recommendedBy: RecomendedBy?, completion: @escaping (Result<Void, SdkError>) -> Void)
3636
func trackSource(source: RecommendedByCase, code: String)
3737
func trackEvent(event: String, category: String?, label: String?, value: Int?, completion: @escaping (Result<Void, SdkError>) -> Void)
38+
func trackPopupShown(popupId: Int, completion: @escaping (Result<Void, SdkError>) -> Void)
3839
func recommend(blockId: String, currentProductId: String?, currentCategoryId: String?, locations: String?, imageSize: String?,timeOut: Double?, withLocations: Bool, extended: Bool, completion: @escaping (Result<RecommenderResponse, SdkError>) -> Void)
3940
func suggest(query: String, locations: String?, excludedMerchants: [String]?, excludedBrands: [String]?, timeOut: Double?, extended: String?, completion: @escaping (Result<SearchResponse, SdkError>) -> Void)
4041
func getProductsList(brands: String?, merchants: String?, categories: String?, locations: String?, limit: Int?, page: Int?, filters: [String: Any]?, completion: @escaping(Result<ProductsListResponse, SdkError>) -> Void)

REES46/Classes/Tracking/Service/impl/TrackServiceImpl.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class TrackEventServiceImpl: TrackEventServiceProtocol {
1515
private struct Constants {
1616
static let trackStoriesPath = "track/stories"
1717
static let trackCustomEventPath = "push/custom"
18+
static let popupShownPath = "popup/showed"
1819

1920
static let id = "id"
2021
static let amount = "amount"
@@ -283,6 +284,31 @@ class TrackEventServiceImpl: TrackEventServiceProtocol {
283284
}
284285
}
285286

287+
func trackPopupShown(popupId: Int, completion: @escaping (Result<Void, SdkError>) -> Void) {
288+
guard let sdk = sdk else {
289+
completion(.failure(.custom(error: "trackPopupShown: SDK is not initialized")))
290+
return
291+
}
292+
293+
sessionQueue.addOperation {
294+
let params: [String: Any] = [
295+
Constants.shopId: sdk.shopId,
296+
Constants.did: sdk.deviceId,
297+
Constants.sid: sdk.userSeance,
298+
"popup": popupId
299+
]
300+
301+
sdk.postRequest(path: Constants.popupShownPath, params: params) { result in
302+
switch result {
303+
case .success:
304+
completion(.success(Void()))
305+
case .failure(let error):
306+
completion(.failure(error))
307+
}
308+
}
309+
}
310+
}
311+
286312
private func showPopup(jsonResult: [String: Any]) {
287313
guard let popupData = jsonResult["popup"] as? [String: Any], !popupData.isEmpty else {
288314
return

REES46/Classes/Tracking/Service/protocol/TrackEventServiceProtocol.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ import Foundation
44
protocol TrackEventServiceProtocol {
55
func track(event: Event, recommendedBy: RecomendedBy?, completion: @escaping (Result<Void, SdkError>) -> Void)
66
func trackEvent(event: String, category: String?, label: String?, value: Int?, completion: @escaping (Result<Void, SdkError>) -> Void)
7+
func trackPopupShown(popupId: Int, completion: @escaping (Result<Void, SdkError>) -> Void)
78
}

0 commit comments

Comments
 (0)