@tyrads.com/tyrads-sdk 3.1.0-beta.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/src/main/java/com/tyradssdk/TyradsSdkModule.kt +130 -46
  3. package/ios/Tyrads/AcmoAssets.swift +14 -0
  4. package/ios/Tyrads/ApiHeaders.swift +1 -0
  5. package/ios/Tyrads/Tyrads.swift +184 -57
  6. package/ios/Tyrads/WebViewController.swift +27 -3
  7. package/ios/Tyrads/core/utils/AcmoKeyNames.swift +29 -0
  8. package/ios/Tyrads/core/utils/ColorExtension.swift +55 -0
  9. package/ios/Tyrads/core/utils/Services/LocalizationService.swift +175 -0
  10. package/ios/Tyrads/helpers/device_details.swift +148 -46
  11. package/ios/Tyrads/legal/AcmoPrivacyPage.swift +353 -0
  12. package/ios/Tyrads/legal/PrivacyPageController.swift +31 -0
  13. package/ios/Tyrads/user/AcmoUserUpdatePage.swift +302 -0
  14. package/ios/Tyrads/user/AcmoUsersUpdateController.swift +26 -0
  15. package/ios/Tyrads/user/Repository.swift +89 -0
  16. package/ios/TyradsSdk.mm +15 -3
  17. package/ios/TyradsSdk.swift +101 -46
  18. package/lib/commonjs/acmo/core/helpers/native_methods.js +37 -0
  19. package/lib/commonjs/acmo/core/helpers/native_methods.js.map +1 -0
  20. package/lib/commonjs/acmo/core/helpers/numeral.js +19 -0
  21. package/lib/commonjs/acmo/core/helpers/numeral.js.map +1 -0
  22. package/lib/commonjs/acmo/core/services/localization_service.js +164 -0
  23. package/lib/commonjs/acmo/core/services/localization_service.js.map +1 -0
  24. package/lib/commonjs/acmo/core/storage/storage.js +15 -1
  25. package/lib/commonjs/acmo/core/storage/storage.js.map +1 -1
  26. package/lib/commonjs/acmo/modules/dashboard/components/active_offers_button.js +5 -2
  27. package/lib/commonjs/acmo/modules/dashboard/components/active_offers_button.js.map +1 -1
  28. package/lib/commonjs/acmo/modules/dashboard/components/custom_scroller.js +1 -2
  29. package/lib/commonjs/acmo/modules/dashboard/components/custom_scroller.js.map +1 -1
  30. package/lib/commonjs/acmo/modules/dashboard/components/custom_shimmer.js +1 -2
  31. package/lib/commonjs/acmo/modules/dashboard/components/custom_shimmer.js.map +1 -1
  32. package/lib/commonjs/acmo/modules/dashboard/components/offer_card.js +4 -6
  33. package/lib/commonjs/acmo/modules/dashboard/components/offer_card.js.map +1 -1
  34. package/lib/commonjs/acmo/modules/dashboard/components/offer_list_item.js +14 -9
  35. package/lib/commonjs/acmo/modules/dashboard/components/offer_list_item.js.map +1 -1
  36. package/lib/commonjs/acmo/modules/dashboard/components/premium_empty_widget.js +6 -2
  37. package/lib/commonjs/acmo/modules/dashboard/components/premium_empty_widget.js.map +1 -1
  38. package/lib/commonjs/acmo/modules/dashboard/components/premium_header.js +4 -4
  39. package/lib/commonjs/acmo/modules/dashboard/components/premium_header.js.map +1 -1
  40. package/lib/commonjs/acmo/modules/dashboard/components/premium_loading.js +4 -11
  41. package/lib/commonjs/acmo/modules/dashboard/components/premium_loading.js.map +1 -1
  42. package/lib/commonjs/acmo/modules/dashboard/repository.js +1 -1
  43. package/lib/commonjs/acmo/modules/dashboard/top_offers.js +16 -2
  44. package/lib/commonjs/acmo/modules/dashboard/top_offers.js.map +1 -1
  45. package/lib/commonjs/acmo/modules/localization/localization_context.js +55 -0
  46. package/lib/commonjs/acmo/modules/localization/localization_context.js.map +1 -0
  47. package/lib/commonjs/index.js +38 -5
  48. package/lib/commonjs/index.js.map +1 -1
  49. package/lib/module/acmo/core/helpers/native_methods.js +33 -0
  50. package/lib/module/acmo/core/helpers/native_methods.js.map +1 -0
  51. package/lib/module/acmo/core/helpers/numeral.js +14 -0
  52. package/lib/module/acmo/core/helpers/numeral.js.map +1 -0
  53. package/lib/module/acmo/core/services/localization_service.js +159 -0
  54. package/lib/module/acmo/core/services/localization_service.js.map +1 -0
  55. package/lib/module/acmo/core/storage/storage.js +13 -0
  56. package/lib/module/acmo/core/storage/storage.js.map +1 -1
  57. package/lib/module/acmo/modules/dashboard/components/active_offers_button.js +5 -2
  58. package/lib/module/acmo/modules/dashboard/components/active_offers_button.js.map +1 -1
  59. package/lib/module/acmo/modules/dashboard/components/offer_card.js +3 -3
  60. package/lib/module/acmo/modules/dashboard/components/offer_card.js.map +1 -1
  61. package/lib/module/acmo/modules/dashboard/components/offer_list_item.js +14 -9
  62. package/lib/module/acmo/modules/dashboard/components/offer_list_item.js.map +1 -1
  63. package/lib/module/acmo/modules/dashboard/components/premium_empty_widget.js +6 -2
  64. package/lib/module/acmo/modules/dashboard/components/premium_empty_widget.js.map +1 -1
  65. package/lib/module/acmo/modules/dashboard/components/premium_header.js +4 -4
  66. package/lib/module/acmo/modules/dashboard/components/premium_header.js.map +1 -1
  67. package/lib/module/acmo/modules/dashboard/components/premium_loading.js +5 -12
  68. package/lib/module/acmo/modules/dashboard/components/premium_loading.js.map +1 -1
  69. package/lib/module/acmo/modules/dashboard/repository.js +1 -1
  70. package/lib/module/acmo/modules/dashboard/top_offers.js +15 -0
  71. package/lib/module/acmo/modules/dashboard/top_offers.js.map +1 -1
  72. package/lib/module/acmo/modules/localization/localization_context.js +45 -0
  73. package/lib/module/acmo/modules/localization/localization_context.js.map +1 -0
  74. package/lib/module/index.js +38 -6
  75. package/lib/module/index.js.map +1 -1
  76. package/lib/typescript/commonjs/src/acmo/core/helpers/native_methods.d.ts +6 -0
  77. package/lib/typescript/commonjs/src/acmo/core/helpers/native_methods.d.ts.map +1 -0
  78. package/lib/typescript/commonjs/src/acmo/core/helpers/numeral.d.ts +2 -0
  79. package/lib/typescript/commonjs/src/acmo/core/helpers/numeral.d.ts.map +1 -0
  80. package/lib/typescript/commonjs/src/acmo/core/services/localization_service.d.ts +18 -0
  81. package/lib/typescript/commonjs/src/acmo/core/services/localization_service.d.ts.map +1 -0
  82. package/lib/typescript/commonjs/src/acmo/core/storage/storage.d.ts +1 -0
  83. package/lib/typescript/commonjs/src/acmo/core/storage/storage.d.ts.map +1 -1
  84. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/active_offers_button.d.ts.map +1 -1
  85. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/offer_card.d.ts.map +1 -1
  86. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/offer_list_item.d.ts.map +1 -1
  87. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_empty_widget.d.ts.map +1 -1
  88. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_header.d.ts.map +1 -1
  89. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_loading.d.ts +0 -1
  90. package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_loading.d.ts.map +1 -1
  91. package/lib/typescript/commonjs/src/acmo/modules/dashboard/repository.d.ts.map +1 -1
  92. package/lib/typescript/commonjs/src/acmo/modules/dashboard/top_offers.d.ts.map +1 -1
  93. package/lib/typescript/commonjs/src/acmo/modules/localization/localization_context.d.ts +14 -0
  94. package/lib/typescript/commonjs/src/acmo/modules/localization/localization_context.d.ts.map +1 -0
  95. package/lib/typescript/commonjs/src/index.d.ts +4 -0
  96. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  97. package/lib/typescript/module/src/acmo/core/helpers/native_methods.d.ts +6 -0
  98. package/lib/typescript/module/src/acmo/core/helpers/native_methods.d.ts.map +1 -0
  99. package/lib/typescript/module/src/acmo/core/helpers/numeral.d.ts +2 -0
  100. package/lib/typescript/module/src/acmo/core/helpers/numeral.d.ts.map +1 -0
  101. package/lib/typescript/module/src/acmo/core/services/localization_service.d.ts +18 -0
  102. package/lib/typescript/module/src/acmo/core/services/localization_service.d.ts.map +1 -0
  103. package/lib/typescript/module/src/acmo/core/storage/storage.d.ts +1 -0
  104. package/lib/typescript/module/src/acmo/core/storage/storage.d.ts.map +1 -1
  105. package/lib/typescript/module/src/acmo/modules/dashboard/components/active_offers_button.d.ts.map +1 -1
  106. package/lib/typescript/module/src/acmo/modules/dashboard/components/offer_card.d.ts.map +1 -1
  107. package/lib/typescript/module/src/acmo/modules/dashboard/components/offer_list_item.d.ts.map +1 -1
  108. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_empty_widget.d.ts.map +1 -1
  109. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_header.d.ts.map +1 -1
  110. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_loading.d.ts +0 -1
  111. package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_loading.d.ts.map +1 -1
  112. package/lib/typescript/module/src/acmo/modules/dashboard/repository.d.ts.map +1 -1
  113. package/lib/typescript/module/src/acmo/modules/dashboard/top_offers.d.ts.map +1 -1
  114. package/lib/typescript/module/src/acmo/modules/localization/localization_context.d.ts +14 -0
  115. package/lib/typescript/module/src/acmo/modules/localization/localization_context.d.ts.map +1 -0
  116. package/lib/typescript/module/src/index.d.ts +4 -0
  117. package/lib/typescript/module/src/index.d.ts.map +1 -1
  118. package/package.json +7 -10
  119. package/src/acmo/core/helpers/native_methods.ts +43 -0
  120. package/src/acmo/core/helpers/numeral.ts +14 -0
  121. package/src/acmo/core/services/localization_service.ts +200 -0
  122. package/src/acmo/core/storage/storage.ts +14 -0
  123. package/src/acmo/modules/dashboard/components/active_offers_button.tsx +3 -2
  124. package/src/acmo/modules/dashboard/components/offer_card.tsx +3 -3
  125. package/src/acmo/modules/dashboard/components/offer_list_item.tsx +9 -7
  126. package/src/acmo/modules/dashboard/components/premium_empty_widget.tsx +5 -2
  127. package/src/acmo/modules/dashboard/components/premium_header.tsx +6 -5
  128. package/src/acmo/modules/dashboard/components/premium_loading.tsx +2 -8
  129. package/src/acmo/modules/dashboard/repository.ts +1 -1
  130. package/src/acmo/modules/dashboard/top_offers.tsx +18 -3
  131. package/src/acmo/modules/localization/localization_context.tsx +52 -0
  132. package/src/index.tsx +63 -18
  133. package/lib/commonjs/i18n.js +0 -112
  134. package/lib/commonjs/i18n.js.map +0 -1
  135. package/lib/module/i18n.js +0 -107
  136. package/lib/module/i18n.js.map +0 -1
  137. package/lib/typescript/commonjs/src/i18n.d.ts +0 -3
  138. package/lib/typescript/commonjs/src/i18n.d.ts.map +0 -1
  139. package/lib/typescript/module/src/i18n.d.ts +0 -3
  140. package/lib/typescript/module/src/i18n.d.ts.map +0 -1
  141. package/src/i18n.ts +0 -115
@@ -0,0 +1,302 @@
1
+ //
2
+ // AcmoUserUpdatePage.swift
3
+ // Pods
4
+ //
5
+ // Created by Basharat Mehdi on 30/09/25.
6
+ //
7
+
8
+ import SwiftUI
9
+
10
+ struct AcmoUsersUpdatePage: View {
11
+ @Environment(\.presentationMode) var presentationMode
12
+
13
+ var localization: LocalizationService = LocalizationService.shared
14
+
15
+ var onSubmit: (() -> Void)?
16
+
17
+ public init(onSubmit: (() -> Void)? = nil) {
18
+ self.onSubmit = onSubmit
19
+ }
20
+
21
+ @State private var selectedGender: String? = nil
22
+ @State private var selectedAge: String = "18"
23
+ @State private var isSubmitting = false
24
+ @State private var showError = false
25
+ @State private var errorMessage = ""
26
+
27
+ var body: some View {
28
+ ZStack{
29
+ VStack {
30
+ HStack {
31
+ Spacer()
32
+ Button(action: {
33
+ Tyrads.instance.setSkipUserUpdate(true)
34
+ Tyrads.instance.setNewUser(false)
35
+ presentationMode.wrappedValue.dismiss()
36
+ onSubmit?()
37
+ }) {
38
+ Text(localization.translate("data.shared.button.skip"))
39
+ .font(.system(size: 14))
40
+ .fontWeight(.semibold)
41
+ .frame(minWidth: 80, minHeight: 35)
42
+ .foregroundColor(Color(hex: Tyrads.instance.mainColor ?? "#000000"))
43
+ .overlay(
44
+ RoundedRectangle(cornerRadius: 50)
45
+ .stroke(Color(hex: Tyrads.instance.mainColor ?? "#000000"), lineWidth: 2)
46
+ ).padding(.horizontal, 16)
47
+ }
48
+ }
49
+
50
+ ScrollView {
51
+ VStack(spacing: 40) {
52
+ Text(localization.translate("data.initialization.userInfo.title"))
53
+ .font(.system(size: 16, weight: .semibold))
54
+ .multilineTextAlignment(.center)
55
+ .foregroundColor(Color(hex: Tyrads.instance.mainColor ?? "#000000"))
56
+ Spacer()
57
+ .frame(height: 20)
58
+
59
+ VStack(spacing: 25) {
60
+ Text(localization.translate(
61
+ "data.initialization.userInfo.chooseGender.label"))
62
+ .font(.system(size: 16, weight: .semibold))
63
+ .foregroundColor(Color(hex: Tyrads.instance.mainColor ?? "#000000"))
64
+
65
+ GenderSelectView(selectedGender: $selectedGender, localization: localization)
66
+ Spacer().frame(height: 50)
67
+
68
+ Text(localization.translate(
69
+ "data.initialization.userInfo.chooseAge.label"))
70
+ .font(.system(size: 16, weight: .semibold))
71
+ .foregroundColor(Color(hex: Tyrads.instance.mainColor ?? "#000000"))
72
+
73
+ AgeSelectView(selectedAge: $selectedAge)
74
+ }
75
+
76
+ Spacer().frame(height: 10)
77
+
78
+ Button(action: {
79
+ submit()
80
+ }) {
81
+ Text(isSubmitting ? "Submitting..." : localization.translate(
82
+ "data.initialization.userInfo.cta.continue"))
83
+ .font(.system(size: 15, weight: .semibold))
84
+ .foregroundColor(.white)
85
+ .frame(maxWidth: .infinity)
86
+ .frame(height: 44)
87
+ .background(Color(hex: Tyrads.instance.mainColor ?? "#000000"))
88
+ .cornerRadius(4)
89
+ }
90
+ .disabled(isSubmitting)
91
+ }
92
+ .padding(.horizontal, 20)
93
+ }
94
+ }
95
+ .alert(isPresented: $showError) {
96
+ Alert(title: Text("Error"), message: Text(errorMessage), dismissButton: .default(Text("OK")))
97
+ }
98
+ }
99
+
100
+ }
101
+ func submit() {
102
+ guard let gender = selectedGender, !gender.isEmpty else {
103
+ errorMessage = "Please select gender to proceed."
104
+ showError = true
105
+ return
106
+ }
107
+
108
+ isSubmitting = true
109
+ errorMessage = ""
110
+ showError = false
111
+
112
+ Task {
113
+ do {
114
+ try await UserRepository.shared.updateUser(
115
+ userID: Tyrads.instance.publisherUserID,
116
+ gender: gender,
117
+ age: selectedAge
118
+ )
119
+
120
+ await MainActor.run {
121
+ self.isSubmitting = false
122
+ Tyrads.instance.setNewUser(false)
123
+ self.presentationMode.wrappedValue.dismiss()
124
+ self.onSubmit?()
125
+ }
126
+
127
+ } catch {
128
+ await MainActor.run {
129
+ self.isSubmitting = false
130
+ self.errorMessage = "Failed to update user data: \(error.localizedDescription)"
131
+ self.showError = true
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+
138
+ struct GenderSelectView: View {
139
+ @Binding var selectedGender: String?
140
+ let localization: LocalizationService
141
+
142
+ var body: some View {
143
+ HStack(spacing: 20) {
144
+ GenderButton(title: localization.translate("data.initialization.userInfo.gender.male"), selectedGender: $selectedGender,
145
+ localization: localization
146
+ )
147
+ GenderButton(title: localization.translate("data.initialization.userInfo.gender.female"), selectedGender: $selectedGender, localization: localization)
148
+ }
149
+ }
150
+ }
151
+
152
+ struct GenderButton: View {
153
+
154
+ func decodeBase64Image(_ base64: String) -> UIImage? {
155
+ guard let data = Data(base64Encoded: base64) else { return nil }
156
+ return UIImage(data: data)
157
+ }
158
+ let title: String
159
+ @Binding var selectedGender: String?
160
+ let localization: LocalizationService
161
+
162
+ var body: some View {
163
+ Button(action: {
164
+ selectedGender = title
165
+ }) {
166
+ VStack{
167
+ if let image = decodeBase64Image(title == localization.translate("data.initialization.userInfo.gender.male") ? AcmoAssets.maleBase64 : AcmoAssets.femaleBase64) {
168
+ Image(uiImage: image)
169
+ .renderingMode(.template)
170
+ .resizable()
171
+ .scaledToFit()
172
+ .foregroundColor(selectedGender == title ? .white : Color(hex: "#667085"))
173
+ .frame(width: 24, height: 24)
174
+ }
175
+ Text(title)
176
+ .foregroundColor(selectedGender == title ? .white : Color(hex: "#667085"))
177
+ }
178
+ }
179
+ .frame(width: 100, height: 102)
180
+ .background(selectedGender == title ? Color(hex: Tyrads.instance.mainColor ?? "#000000") : Color.white)
181
+ .cornerRadius(4)
182
+ .shadow(color: Color.black.opacity(0.25), radius: 4, x: 0, y: 1)
183
+ }
184
+ }
185
+
186
+ struct AgeSelectView: View {
187
+ @Binding var selectedAge: String
188
+ private let ages = Array(13..<109).map { String($0) }
189
+
190
+ var body: some View {
191
+ HorizontalAgePicker(selectedAge: $selectedAge)
192
+ }
193
+ }
194
+
195
+ struct HorizontalAgePicker: View {
196
+ @Binding var selectedAge: String
197
+ private let ages = Array(13...108).map { String($0) }
198
+
199
+ var body: some View {
200
+ GeometryReader { geometry in
201
+ let screenCenter = geometry.size.width / 2
202
+
203
+ if #available(iOS 14.0, *) {
204
+ ScrollViewReader{ proxy in
205
+ ScrollView(.horizontal, showsIndicators: false) {
206
+ HStack(spacing: 4) {
207
+ Spacer()
208
+ .frame(width: screenCenter - 30)
209
+
210
+ ForEach(ages, id: \.self) { age in
211
+ GeometryReader { geo in
212
+ let itemCenter = geo.frame(in: .global).midX
213
+ let distance = abs(itemCenter - screenCenter)
214
+ let scale = max(0.8, 1.2 - distance / 200)
215
+
216
+ var fontSize: CGFloat {
217
+ selectedAge == age ? 30 : 17
218
+ }
219
+
220
+ var fontWeight: Font.Weight {
221
+ selectedAge == age ? .semibold : .regular
222
+ }
223
+
224
+ Text(age)
225
+ .font(.system(size: fontSize, weight: fontWeight))
226
+ .frame(width: 90, height: 58)
227
+ .background(selectedAge == age ? Color(hex: "#F6F6F6") : .clear)
228
+ .foregroundColor(selectedAge == age ? Color(hex: Tyrads.instance.mainColor ?? "#FFFFFF") : .gray)
229
+ .cornerRadius(10)
230
+ .animation(.easeOut(duration: 0.2), value: scale)
231
+ .onAppear {
232
+ DispatchQueue.main.async {
233
+ proxy.scrollTo("18", anchor: .center)
234
+ }
235
+ }
236
+ .onChange(of: distance) { _ in
237
+ if distance < 20 {
238
+ if selectedAge != age {
239
+ DispatchQueue.main.async {
240
+ selectedAge = age
241
+ }
242
+ }
243
+ }
244
+ }
245
+
246
+ }
247
+ .frame(width: 60, height: 74)
248
+ }
249
+
250
+ Spacer()
251
+ .frame(width: screenCenter - 30)
252
+ }
253
+ }
254
+ }
255
+ } else {
256
+ ScrollView(.horizontal, showsIndicators: false) {
257
+ HStack(spacing: 4) {
258
+ Spacer()
259
+ .frame(width: screenCenter - 30)
260
+
261
+ ForEach(ages, id: \.self) { age in
262
+ GeometryReader { geo in
263
+ let itemCenter = geo.frame(in: .global).midX
264
+ let distance = abs(itemCenter - screenCenter)
265
+ let scale = max(0.8, 1.2 - distance / 200)
266
+
267
+ var fontSize: CGFloat {
268
+ selectedAge == age ? 30 : 17
269
+ }
270
+
271
+ var fontWeight: Font.Weight {
272
+ selectedAge == age ? .semibold : .regular
273
+ }
274
+ Text(age)
275
+ .font(.system(size: selectedAge == age ? 30 : 20, weight: .semibold))
276
+ .frame(width: 90, height: 58)
277
+ .background(selectedAge == age ? Color("#F6F6F6") : .clear)
278
+ .foregroundColor(selectedAge == age ? Color(hex: Tyrads.instance.mainColor ?? "#FFFFFF") : .black)
279
+ .cornerRadius(10)
280
+ .animation(.easeOut(duration: 0.2), value: scale)
281
+ .onAppear {
282
+ if age == ages.first {
283
+ selectedAge = age
284
+ }
285
+ }
286
+
287
+ }
288
+ .frame(width: 60, height: 74)
289
+ }
290
+
291
+ Spacer()
292
+ .frame(width: screenCenter - 30)
293
+ }
294
+
295
+ }
296
+ }
297
+ }
298
+ .frame(height: 100)
299
+ }
300
+ }
301
+
302
+
@@ -0,0 +1,26 @@
1
+ //
2
+ // AcmoUserUpdatePageController.swift
3
+ // Pods
4
+ //
5
+ // Created by Basharat Mehdi on 30/09/25.
6
+ //
7
+
8
+ import UIKit
9
+ import SwiftUI
10
+
11
+ public typealias UserUpdateCompletion = () -> Void
12
+ class AcmoUsersUpdateController: UIHostingController<AcmoUsersUpdatePage> {
13
+ public init(onSubmit: UserUpdateCompletion? = nil) {
14
+ let rootView = AcmoUsersUpdatePage(onSubmit: onSubmit)
15
+ super.init(rootView: rootView)
16
+ self.modalPresentationStyle = .fullScreen
17
+ }
18
+
19
+ @MainActor required dynamic init?(coder aDecoder: NSCoder) {
20
+ fatalError("init(coder:) has not been implemented")
21
+ }
22
+
23
+ override func viewWillDisappear(_ animated: Bool) {
24
+ super.viewWillDisappear(animated)
25
+ }
26
+ }
@@ -0,0 +1,89 @@
1
+ //
2
+ //  Repository.swift
3
+ //  Pods
4
+ //
5
+ //  Created by Basharat Mehdi on 01/10/25.
6
+ //
7
+
8
+ import Foundation
9
+ import UIKit
10
+
11
+ public class UserRepository {
12
+
13
+ public static let shared = UserRepository()
14
+
15
+ private init() {}
16
+
17
+ public func updateUser(userID: String, gender: String, age: String) async throws {
18
+ let sdk = Tyrads.instance
19
+
20
+ guard let ageInt = Int(age) else {
21
+ print("ERROR: Failed to convert age string '\(age)' to integer.")
22
+ throw NSError(domain: "TyradsSdk", code: 4, userInfo: [NSLocalizedDescriptionKey: "Invalid age format."])
23
+ }
24
+
25
+ let fd: [String: Any] = [
26
+ "gender": gender == "Male" ? 1 : 2,
27
+ "age": ageInt,
28
+ ]
29
+
30
+ let fullURLString = AcmoConfig.BASE_URL + "update-user"
31
+
32
+ print("--- USER UPDATE REQUEST ---")
33
+ print("UserID: \(userID)")
34
+ print("URL: \(fullURLString)")
35
+ print("Data Sent: \(fd)")
36
+
37
+ let requestBody = sdk.isSecure && !(sdk.encKey ?? "").isEmpty ? try AcmoEncrypt(sdk.encKey!).encryptDataAESGCM(data: fd) : fd
38
+
39
+ guard let url = URL(string: fullURLString) else {
40
+ throw NSError(domain: "TyradsSdk", code: 1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL for user update"])
41
+ }
42
+
43
+ var request = URLRequest(url: url)
44
+ request.httpMethod = "PUT"
45
+ request.setValue("application/json", forHTTPHeaderField: "Content-Type")
46
+ request.setValue(sdk.apiKey, forHTTPHeaderField: "X-API-Key")
47
+ request.setValue(sdk.apiSecret, forHTTPHeaderField: "X-API-Secret")
48
+ request.setValue(userID, forHTTPHeaderField: "X-User-ID")
49
+ request.setValue(AcmoConfig.SDK_PLATFORM, forHTTPHeaderField: "X-SDK-Platform")
50
+ request.setValue(AcmoConfig.SDK_VERSION, forHTTPHeaderField: "X-SDK-Version")
51
+ request.setValue(sdk.isSecure ? "BASIC" : "PLAIN", forHTTPHeaderField: "X-Secure-Mode")
52
+
53
+ print("X-API-Key: \(sdk.apiKey)")
54
+ print("X-API-Secret: \(sdk.apiSecret)")
55
+ print("X-Publisher-User-Id: \(userID)")
56
+ print("Request Body: \(requestBody)")
57
+
58
+ do {
59
+ request.httpBody = try JSONSerialization.data(withJSONObject: requestBody)
60
+ } catch {
61
+ print("ERROR: Failed to serialize request body: \(error)")
62
+ throw error
63
+ }
64
+
65
+ let (data, response) = try await URLSession.shared.data(for: request)
66
+
67
+ let responseString = String(data: data, encoding: .utf8) ?? "No readable response data"
68
+
69
+ guard let httpResponse = response as? HTTPURLResponse else {
70
+ print("ERROR: Response was not HTTPURLResponse.")
71
+ throw NSError(domain: "TyradsSdk", code: 0, userInfo: [NSLocalizedDescriptionKey: "Non-HTTP response received."])
72
+ }
73
+
74
+ print("Response Status Code: \(httpResponse.statusCode)")
75
+ print("Response Body: \(responseString)")
76
+
77
+ guard (200...299).contains(httpResponse.statusCode) else {
78
+ let statusCode = httpResponse.statusCode
79
+ sdk.log("User update failed with status: \(statusCode)")
80
+
81
+ let fullErrorDescription = "Failed to update user demographics."
82
+ throw NSError(domain: "TyradsSdk", code: statusCode,
83
+ userInfo: [NSLocalizedDescriptionKey: "Failed to update user demographics."])
84
+ }
85
+
86
+ print("User has been updated please check")
87
+ sdk.log("User update successful.")
88
+ }
89
+ }
package/ios/TyradsSdk.mm CHANGED
@@ -2,9 +2,13 @@
2
2
 
3
3
  @interface RCT_EXTERN_MODULE(TyradsSdk, NSObject)
4
4
 
5
- RCT_EXTERN_METHOD(init:(NSString *)apiKey
6
- secretKey:(NSString *)secretKey
7
- encKey:(NSString * _Nullable)encKey)
5
+ RCT_EXTERN_METHOD(startObserving)
6
+ RCT_EXTERN_METHOD(stopObserving)
7
+ RCT_EXTERN_METHOD(init:(NSString *)apiKey
8
+ secretKey:(NSString *)secretKey
9
+ encKey:(NSString * _Nullable)encKey
10
+ resolver:(RCTPromiseResolveBlock)resolve
11
+ rejecter:(RCTPromiseRejectBlock)reject)
8
12
  // RCT_EXTERN_METHOD(loginUser:(NSString *)userId)
9
13
  RCT_EXTERN_METHOD(loginUser:(NSString *)userId
10
14
  resolver:(RCTPromiseResolveBlock)resolve
@@ -18,5 +22,13 @@ RCT_EXTERN_METHOD(showOfferDetails:(NSInteger)launchMode
18
22
  campaignID:(NSInteger)campaignID
19
23
  resolver:(RCTPromiseResolveBlock)resolve
20
24
  rejecter:(RCTPromiseRejectBlock)reject)
25
+ RCT_EXTERN_METHOD(changeLanguage:(NSString *)lang
26
+ resolver:(RCTPromiseResolveBlock)resolve
27
+ rejecter:(RCTPromiseRejectBlock)reject)
28
+ RCT_EXTERN_METHOD(isPrivacyAccepted:(RCTPromiseResolveBlock)resolve
29
+ rejecter:(RCTPromiseRejectBlock)reject)
30
+ RCT_EXTERN_METHOD(checkOnboardingProcess:(RCTPromiseResolveBlock)resolve
31
+ rejecter:(RCTPromiseRejectBlock)reject)
32
+
21
33
 
22
34
  @end
@@ -1,62 +1,117 @@
1
1
  import Foundation
2
2
  import UIKit
3
+ import Combine
4
+ import React
3
5
 
4
6
 
5
7
  @objc(TyradsSdk)
6
- class TyradsSdk: NSObject {
7
-
8
+ class TyradsSdk: RCTEventEmitter {
9
+
10
+ private var cancellable: AnyCancellable?
11
+
12
+ override func startObserving() {
13
+ cancellable = Tyrads.instance.languagePublisher
14
+ .sink { [weak self] lang in
15
+ self?.sendEvent(withName: "LanguageChanged", body: lang)
16
+ }
17
+ }
18
+
19
+ override func stopObserving() {
20
+ cancellable?.cancel()
21
+ cancellable = nil
22
+ }
23
+
24
+ override func supportedEvents() -> [String]! {
25
+ return ["LanguageChanged"]
26
+ }
27
+
8
28
  @objc
9
- func `init`(_ apiKey: String, secretKey: String, encKey: String? = nil) {
29
+ func `init`(_ apiKey: String, secretKey: String, encKey: String? = nil, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
10
30
  NSLog("TyradsModule: init called with apiKey: \(apiKey) and secretKey: \(secretKey)")
11
- Tyrads.instance.configure(apiKey: apiKey, secretKey: secretKey, encKey: encKey)
31
+ Task {
32
+ do{
33
+ let locale = await Tyrads.instance.configure(apiKey: apiKey, secretKey: secretKey, encKey: encKey)
34
+ let result: [String: Any] = [
35
+ "success": true,
36
+ "languageCode": locale
37
+ ]
38
+ resolve (result)
39
+ } catch {
40
+ reject("INIT_FAILED", "Failed to initialize", error)
41
+ }
42
+ }
43
+
12
44
  }
13
-
45
+
14
46
  @objc
15
47
  func loginUser(_ userId: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
16
- NSLog("TyradsModule: loginUser called with userId: \(userId)")
17
-
18
- Task {
19
- do {
20
- guard let apiHeaders = try await Tyrads.instance.loginUser(userId) else {
21
- reject("LOGIN_ERROR", "Login failed or returned nil headers", nil)
22
- return
23
- }
24
-
25
- let result: [String: Any] = [
26
- "xApiKey": apiHeaders.xApiKey,
27
- "xApiSecret": apiHeaders.xApiSecret,
28
- "xUserId": apiHeaders.xUserId,
29
- "xSdkPlatform": apiHeaders.xSdkPlatform ?? "",
30
- "xSdkVersion": apiHeaders.xSdkVersion ?? "",
31
- "userAgent": apiHeaders.userAgent,
32
- "languageCode": apiHeaders.languageCode,
33
- "premiumColor": apiHeaders.premiumColor,
34
- "headerColor": apiHeaders.headerColor,
35
- "mainColor": apiHeaders.mainColor
36
- ]
37
-
38
- resolve(result)
39
- } catch {
40
- reject("LOGIN_ERROR", error.localizedDescription, error)
41
- }
48
+ NSLog("TyradsModule: loginUser called with userId: \(userId)")
49
+
50
+ Task {
51
+ do {
52
+ guard let apiHeaders = try await Tyrads.instance.loginUser(userId) else {
53
+ reject("LOGIN_ERROR", "Login failed or returned nil headers", nil)
54
+ return
55
+ }
56
+
57
+ let result: [String: Any] = [
58
+ "xApiKey": apiHeaders.xApiKey,
59
+ "xApiSecret": apiHeaders.xApiSecret,
60
+ "xUserId": apiHeaders.xUserId,
61
+ "xSdkPlatform": apiHeaders.xSdkPlatform ?? "",
62
+ "xSdkVersion": apiHeaders.xSdkVersion ?? "",
63
+ "userAgent": apiHeaders.userAgent,
64
+ "languageCode": apiHeaders.languageCode,
65
+ "premiumColor": apiHeaders.premiumColor,
66
+ "headerColor": apiHeaders.headerColor,
67
+ "mainColor": apiHeaders.mainColor,
68
+ "privacyAccepted": apiHeaders.privacyAccepted
69
+ ]
70
+
71
+ resolve(result)
72
+ } catch {
73
+ reject("LOGIN_ERROR", error.localizedDescription, error)
42
74
  }
75
+ }
43
76
  }
44
-
77
+
45
78
 
46
79
  @objc(showOffers:route:resolver:rejecter:)
47
- func showOffers(_ launchMode: Int, route: String?, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
48
- Task {
49
- await Tyrads.instance.showOffers(launchMode, route: route, campaignID: nil)
50
- resolve(nil)
51
- }
52
- }
53
-
54
- @objc(showOfferDetails:route:campaignID:resolver:rejecter:)
55
- func showOfferDetails(_ launchMode: Int, route: String?, campaignID: Int, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
56
- Task {
57
- await Tyrads.instance.showOffers(launchMode, route: route, campaignID: campaignID)
58
- resolve(nil)
59
- }
60
- }
80
+ func showOffers(_ launchMode: Int, route: String?, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
81
+ Task {
82
+ await Tyrads.instance.showOffers(launchMode, route: route, campaignID: nil)
83
+ resolve(nil)
84
+ }
85
+ }
86
+
87
+ @objc(showOfferDetails:route:campaignID:resolver:rejecter:)
88
+ func showOfferDetails(_ launchMode: Int, route: String?, campaignID: Int, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
89
+ Task {
90
+ await Tyrads.instance.showOffers(launchMode, route: route, campaignID: campaignID)
91
+ resolve(nil)
92
+ }
93
+ }
94
+
95
+ @objc(changeLanguage:resolver:rejecter:)
96
+ func changeLanguage(_ lang: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
97
+ Task {
98
+ await Tyrads.instance.changeLanguage(lang)
99
+ resolve(nil)
100
+ }
101
+ }
102
+
103
+ @objc
104
+ func isPrivacyAccepted(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
105
+ let accepted = Tyrads.instance.isPrivacyAccepted()
106
+ resolve(accepted)
107
+ }
108
+
109
+ @objc
110
+ func checkOnboardingProcess(_ resolver: @escaping RCTPromiseResolveBlock,rejecter: @escaping RCTPromiseRejectBlock) {
111
+ Task {
112
+ let result = await Tyrads.instance.checkOnboardingProcess()
113
+ resolver(result)
114
+ }
115
+ }
61
116
 
62
117
  }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _reactNative = require("react-native");
8
+ const LINKING_ERROR = `The package 'tyrads-sdk' doesn't seem to be linked. Make sure: \n\n` + _reactNative.Platform.select({
9
+ ios: "- You have run 'pod install'\n",
10
+ default: ''
11
+ }) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
12
+ const TyradsSdk = _reactNative.NativeModules.TyradsSdk ? _reactNative.NativeModules.TyradsSdk : new Proxy({}, {
13
+ get() {
14
+ throw new Error(LINKING_ERROR);
15
+ }
16
+ });
17
+ const TyradsNativeMethods = {
18
+ isPrivacyAccepted: async () => {
19
+ try {
20
+ return await TyradsSdk.isPrivacyAccepted();
21
+ } catch (err) {
22
+ console.error("Error checking privacy acceptance:", err);
23
+ return false;
24
+ }
25
+ },
26
+ checkOnboardingProcess: async () => {
27
+ try {
28
+ const result = await TyradsSdk.checkOnboardingProcess();
29
+ return result === true;
30
+ } catch (err) {
31
+ console.error("Error showing privacy flow:", err);
32
+ return false;
33
+ }
34
+ }
35
+ };
36
+ var _default = exports.default = TyradsNativeMethods;
37
+ //# sourceMappingURL=native_methods.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","TyradsSdk","NativeModules","Proxy","get","Error","TyradsNativeMethods","isPrivacyAccepted","err","console","error","checkOnboardingProcess","result","_default","exports"],"sourceRoot":"../../../../../src","sources":["acmo/core/helpers/native_methods.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA,MAAMC,aAAa,GACjB,qEAAqE,GACrEC,qBAAQ,CAACC,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,SAAS,GAAGC,0BAAa,CAACD,SAAS,GACrCC,0BAAa,CAACD,SAAS,GACvB,IAAIE,KAAK,CACT,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACT,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAGH,MAAMU,mBAAmB,GAAG;EAE1BC,iBAAiB,EAAE,MAAAA,CAAA,KAAY;IAC7B,IAAI;MACF,OAAO,MAAMN,SAAS,CAACM,iBAAiB,CAAC,CAAC;IAC5C,CAAC,CAAC,OAAOC,GAAG,EAAE;MACZC,OAAO,CAACC,KAAK,CAAC,oCAAoC,EAAEF,GAAG,CAAC;MACxD,OAAO,KAAK;IACd;EACF,CAAC;EAEDG,sBAAsB,EAAE,MAAAA,CAAA,KAAY;IAClC,IAAI;MACF,MAAMC,MAAM,GAAG,MAAMX,SAAS,CAACU,sBAAsB,CAAC,CAAC;MACvD,OAAOC,MAAM,KAAK,IAAI;IACxB,CAAC,CAAC,OAAOJ,GAAG,EAAE;MACZC,OAAO,CAACC,KAAK,CAAC,6BAA6B,EAAEF,GAAG,CAAC;MACjD,OAAO,KAAK;IACd;EACF;AACF,CAAC;AAAC,IAAAK,QAAA,GAAAC,OAAA,CAAAd,OAAA,GAEaM,mBAAmB","ignoreList":[]}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.numeral = void 0;
7
+ const numeral = (value, decimals = 2) => {
8
+ const suffixes = ['', 'K', 'M', 'B', 'T'];
9
+ let suffixIndex = 0;
10
+ let dividedValue = value;
11
+ while (dividedValue >= 1000 && suffixIndex < suffixes.length - 1) {
12
+ dividedValue /= 1000;
13
+ suffixIndex++;
14
+ }
15
+ const roundedValue = Math.floor(dividedValue * Math.pow(10, decimals)) / Math.pow(10, decimals);
16
+ return `${roundedValue}${suffixes[suffixIndex]}`;
17
+ };
18
+ exports.numeral = numeral;
19
+ //# sourceMappingURL=numeral.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["numeral","value","decimals","suffixes","suffixIndex","dividedValue","length","roundedValue","Math","floor","pow","exports"],"sourceRoot":"../../../../../src","sources":["acmo/core/helpers/numeral.ts"],"mappings":";;;;;;AAAO,MAAMA,OAAO,GAAGA,CAACC,KAAa,EAAEC,QAAgB,GAAG,CAAC,KAAa;EACtE,MAAMC,QAAQ,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;EACzC,IAAIC,WAAW,GAAG,CAAC;EACnB,IAAIC,YAAY,GAAGJ,KAAK;EAExB,OAAOI,YAAY,IAAI,IAAI,IAAID,WAAW,GAAGD,QAAQ,CAACG,MAAM,GAAG,CAAC,EAAE;IAChED,YAAY,IAAI,IAAI;IACpBD,WAAW,EAAE;EACf;EAEA,MAAMG,YAAY,GAAGC,IAAI,CAACC,KAAK,CAACJ,YAAY,GAAGG,IAAI,CAACE,GAAG,CAAC,EAAE,EAAER,QAAQ,CAAC,CAAC,GAAGM,IAAI,CAACE,GAAG,CAAC,EAAE,EAAER,QAAQ,CAAC;EAE/F,OAAO,GAAGK,YAAY,GAAGJ,QAAQ,CAACC,WAAW,CAAC,EAAE;AAClD,CAAC;AAACO,OAAA,CAAAX,OAAA,GAAAA,OAAA","ignoreList":[]}