react-native-sdk-pianoio 0.2.5 → 0.3.1

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 (50) hide show
  1. package/README.md +36 -2
  2. package/SdkPianoio.podspec +4 -16
  3. package/android/build.gradle +12 -19
  4. package/android/gradle.properties +17 -2
  5. package/android/src/main/java/com/sdkpianoio/SdkPianoioModule.kt +543 -7
  6. package/android/src/main/java/com/sdkpianoio/SdkPianoioPackage.kt +3 -3
  7. package/ios/ComposerPianoImpl.swift +247 -0
  8. package/ios/MyComposerDelegate.swift +79 -200
  9. package/ios/SdkPianoio.swift +150 -0
  10. package/ios/SdkPianoioBridge.m +81 -0
  11. package/ios/services/TokenService.swift +10 -7
  12. package/lib/commonjs/NativeSdkPianoio.ts +13 -4
  13. package/lib/commonjs/PianoComposer.js +16 -9
  14. package/lib/commonjs/PianoComposer.js.map +1 -1
  15. package/lib/commonjs/debug.js +23 -0
  16. package/lib/commonjs/debug.js.map +1 -0
  17. package/lib/commonjs/index.js +7 -0
  18. package/lib/commonjs/index.js.map +1 -1
  19. package/lib/module/NativeSdkPianoio.ts +13 -4
  20. package/lib/module/PianoComposer.js +16 -9
  21. package/lib/module/PianoComposer.js.map +1 -1
  22. package/lib/module/debug.js +18 -0
  23. package/lib/module/debug.js.map +1 -0
  24. package/lib/module/index.js +1 -0
  25. package/lib/module/index.js.map +1 -1
  26. package/lib/typescript/commonjs/src/NativeSdkPianoio.d.ts +2 -2
  27. package/lib/typescript/commonjs/src/NativeSdkPianoio.d.ts.map +1 -1
  28. package/lib/typescript/commonjs/src/PianoComposer.d.ts +2 -2
  29. package/lib/typescript/commonjs/src/PianoComposer.d.ts.map +1 -1
  30. package/lib/typescript/commonjs/src/debug.d.ts +2 -0
  31. package/lib/typescript/commonjs/src/debug.d.ts.map +1 -0
  32. package/lib/typescript/commonjs/src/index.d.ts +1 -0
  33. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  34. package/lib/typescript/module/src/NativeSdkPianoio.d.ts +2 -2
  35. package/lib/typescript/module/src/NativeSdkPianoio.d.ts.map +1 -1
  36. package/lib/typescript/module/src/PianoComposer.d.ts +2 -2
  37. package/lib/typescript/module/src/PianoComposer.d.ts.map +1 -1
  38. package/lib/typescript/module/src/debug.d.ts +2 -0
  39. package/lib/typescript/module/src/debug.d.ts.map +1 -0
  40. package/lib/typescript/module/src/index.d.ts +1 -0
  41. package/lib/typescript/module/src/index.d.ts.map +1 -1
  42. package/package.json +31 -16
  43. package/src/NativeSdkPianoio.ts +13 -4
  44. package/src/PianoComposer.tsx +17 -10
  45. package/src/debug.ts +19 -0
  46. package/src/index.tsx +1 -0
  47. package/ios/ComposerPiano.swift +0 -297
  48. package/ios/SdkPianoio.h +0 -4
  49. package/ios/SdkPianoio.mm +0 -267
  50. package/ios/services/ComposerService.swift +0 -49
@@ -0,0 +1,247 @@
1
+ //
2
+ // ComposerPianoImpl.swift
3
+ // SdkPianoio
4
+ //
5
+ //
6
+ import Foundation
7
+ import PianoComposer
8
+ import PianoOAuth
9
+ import React
10
+
11
+ @objcMembers public class ComposerPianoImpl: NSObject {
12
+ private var composer: PianoComposer?
13
+ private var delegateHelper: MyComposerDelegate?
14
+
15
+ // ✅ These will hold the promise functions from React Native
16
+ var promiseResolver: RCTPromiseResolveBlock?
17
+ var promiseRejecter: RCTPromiseRejectBlock?
18
+
19
+ // This is a static property to hold the AID
20
+ public static var aid = ""
21
+
22
+ @objc public func initializeComposer(_ aid: String) {
23
+ ComposerPianoImpl.aid = aid
24
+
25
+ // 1. Correctly initialize the TokenService first.
26
+ let tokenService = TokenService()
27
+
28
+ // 2. Initialize the delegate.
29
+ self.delegateHelper = MyComposerDelegate()
30
+
31
+ // 3. Link the delegate back to this class so it can resolve promises.
32
+ self.delegateHelper?.moduleImpl = self
33
+
34
+ // 4. Initialize the composer.
35
+ self.composer = PianoComposer(
36
+ aid: ComposerPianoImpl.aid, endpoint: PianoEndpoint.productionEurope)
37
+
38
+ // 5. Set the composer's delegate property directly. This is the standard Swift way.
39
+ self.composer?.delegate = self.delegateHelper
40
+ }
41
+
42
+ @objc public func executeComposer() {
43
+ print("Esecuzione composer")
44
+ DispatchQueue.main.async {
45
+ if let composer = self.composer {
46
+ print("Calling composer.execute()")
47
+ composer.execute()
48
+ } else {
49
+ print("⚠️ Composer è nil")
50
+ self.promiseRejecter?(
51
+ "composer_nil", "Piano Composer is not initialized.", nil)
52
+ }
53
+ }
54
+ }
55
+
56
+ @objc public func executeExperience(
57
+ resolver: @escaping RCTPromiseResolveBlock,
58
+ rejecter: @escaping RCTPromiseRejectBlock
59
+ ) {
60
+ self.promiseResolver = resolver
61
+ self.promiseRejecter = rejecter
62
+
63
+ self.executeComposer()
64
+ }
65
+
66
+ public func findViewBySelector(selector: String) -> UIView? {
67
+ return nil
68
+ }
69
+
70
+ // --- Configuration methods ---
71
+
72
+ @objc public func addTag(_ tag: String) {
73
+ _ = composer?.tag(tag)
74
+ }
75
+
76
+ @objc public func addTags(_ tags: [String]) {
77
+ _ = composer?.tags(tags)
78
+ }
79
+
80
+ @objc public func setZoneId(_ zoneId: String) {
81
+ _ = composer?.zoneId(zoneId)
82
+ }
83
+
84
+ @objc public func setReferrer(_ referrer: String) {
85
+ _ = composer?.referrer(referrer)
86
+ }
87
+
88
+ @objc public func setUrl(_ url: String) {
89
+ _ = composer?.url(url)
90
+ }
91
+
92
+ @objc public func setCustomVariable(_ name: String, value: String) {
93
+ _ = composer?.customVariable(name: name, value: value)
94
+ }
95
+
96
+ @objc public func setUserToken(_ token: String) {
97
+ _ = composer?.userToken(token)
98
+ }
99
+
100
+ // method to get values and helpers
101
+ @objc public func getAid() -> String {
102
+ if composer != nil {
103
+ return composer?.aid ?? ""
104
+ } else {
105
+ return ""
106
+ }
107
+ }
108
+
109
+ @objc public func getTags() -> [String] {
110
+ if let tags = composer?.tags, !tags.isEmpty {
111
+ return Array(tags)
112
+ } else {
113
+ return []
114
+ }
115
+ }
116
+
117
+ @objc public func getComposer() -> PianoComposer? {
118
+ return composer
119
+ }
120
+
121
+ @objc public func getZoneId() -> String {
122
+ return composer?.zoneId ?? ""
123
+ }
124
+
125
+ @objc public func getReferrer() -> String {
126
+ return composer?.referrer ?? ""
127
+ }
128
+
129
+ @objc public func getUrl() -> String {
130
+ return composer?.url ?? ""
131
+ }
132
+
133
+ @objc public func getUserToken() -> String {
134
+ return composer?.userToken ?? ""
135
+ }
136
+
137
+ // MARK: - Additional Methods for React Native Bridge
138
+
139
+ @objc public func executeComposerWithResolver(
140
+ resolver: @escaping RCTPromiseResolveBlock,
141
+ rejecter: @escaping RCTPromiseRejectBlock
142
+ ) {
143
+ self.promiseResolver = resolver
144
+ self.promiseRejecter = rejecter
145
+ self.executeComposer()
146
+ }
147
+
148
+ @objc public func showLoginWithResolver(
149
+ resolver: @escaping RCTPromiseResolveBlock,
150
+ rejecter: @escaping RCTPromiseRejectBlock
151
+ ) {
152
+ self.promiseResolver = resolver
153
+ self.promiseRejecter = rejecter
154
+
155
+ DispatchQueue.main.async {
156
+ if let composer = self.composer {
157
+ // This would need to be implemented based on Piano SDK's login functionality
158
+ print("Show login triggered")
159
+ resolver(true)
160
+ } else {
161
+ rejecter("composer_nil", "Piano Composer is not initialized.", nil)
162
+ }
163
+ }
164
+ }
165
+
166
+ @objc public func showTemplateWithResolver(
167
+ resolver: @escaping RCTPromiseResolveBlock,
168
+ rejecter: @escaping RCTPromiseRejectBlock
169
+ ) {
170
+ self.promiseResolver = resolver
171
+ self.promiseRejecter = rejecter
172
+ self.executeComposer()
173
+ }
174
+
175
+ @objc public func showFormWithResolver(
176
+ resolver: @escaping RCTPromiseResolveBlock,
177
+ rejecter: @escaping RCTPromiseRejectBlock
178
+ ) {
179
+ self.promiseResolver = resolver
180
+ self.promiseRejecter = rejecter
181
+ self.executeComposer()
182
+ }
183
+
184
+ @objc public func showRecommendationsWithResolver(
185
+ resolver: @escaping RCTPromiseResolveBlock,
186
+ rejecter: @escaping RCTPromiseRejectBlock
187
+ ) {
188
+ self.promiseResolver = resolver
189
+ self.promiseRejecter = rejecter
190
+ self.executeComposer()
191
+ }
192
+
193
+ @objc public func nonSiteWithResolver(
194
+ resolver: @escaping RCTPromiseResolveBlock,
195
+ rejecter: @escaping RCTPromiseRejectBlock
196
+ ) {
197
+ self.promiseResolver = resolver
198
+ self.promiseRejecter = rejecter
199
+ self.executeComposer()
200
+ }
201
+
202
+ @objc public func userSegmentTrueWithResolver(
203
+ resolver: @escaping RCTPromiseResolveBlock,
204
+ rejecter: @escaping RCTPromiseRejectBlock
205
+ ) {
206
+ self.promiseResolver = resolver
207
+ self.promiseRejecter = rejecter
208
+ self.executeComposer()
209
+ }
210
+
211
+ @objc public func userSegmentFalseWithResolver(
212
+ resolver: @escaping RCTPromiseResolveBlock,
213
+ rejecter: @escaping RCTPromiseRejectBlock
214
+ ) {
215
+ self.promiseResolver = resolver
216
+ self.promiseRejecter = rejecter
217
+ self.executeComposer()
218
+ }
219
+
220
+ @objc public func meterActiveWithResolver(
221
+ resolver: @escaping RCTPromiseResolveBlock,
222
+ rejecter: @escaping RCTPromiseRejectBlock
223
+ ) {
224
+ self.promiseResolver = resolver
225
+ self.promiseRejecter = rejecter
226
+ self.executeComposer()
227
+ }
228
+
229
+ @objc public func meterExpiredWithResolver(
230
+ resolver: @escaping RCTPromiseResolveBlock,
231
+ rejecter: @escaping RCTPromiseRejectBlock
232
+ ) {
233
+ self.promiseResolver = resolver
234
+ self.promiseRejecter = rejecter
235
+ self.executeComposer()
236
+ }
237
+
238
+ @objc public func composerExecutionCompletedWithResolver(
239
+ resolver: @escaping RCTPromiseResolveBlock,
240
+ rejecter: @escaping RCTPromiseRejectBlock
241
+ ) {
242
+ self.promiseResolver = resolver
243
+ self.promiseRejecter = rejecter
244
+ self.executeComposer()
245
+ }
246
+
247
+ }
@@ -7,230 +7,109 @@
7
7
  import Foundation
8
8
  import PianoComposer
9
9
  import PianoOAuth
10
- import PianoCommon
11
- import PianoTemplate
12
-
13
- import SwiftUI
14
- import WebKit
15
-
16
- public class MyComposerDelegate: ComposerService, PianoShowTemplateDelegate {
17
-
18
- var view: WKWebView?
19
-
20
- func experienceExecute(composer: PianoComposer, event: XpEvent, params: ExperienceExecuteEventParams?) {
21
- print("Evento ricevuto: \(event)")
22
- print(event.eventType)
23
- }
24
-
25
- func showTemplate(params: ShowTemplateEventParams) {
26
- if params.displayMode == .inline {
27
- let request = URLRequest(url: URL(string: params.templateUrl)!)
28
- view?.load(request)
29
- }
30
- }
31
-
32
- public func setComposerAndDelegate(_ myComposer: PianoComposer) -> PianoComposer? {
33
- myComposer.delegate = self;
34
- return myComposer;
35
- }
36
-
37
- public func myShowLogin(composer: PianoComposer, event: XpEvent, params: [AnyHashable: Any]?) {
38
- DispatchQueue.main.async {
39
- PianoID.shared.aid = composer.aid;
40
- PianoID.shared.endpoint = composer.endpoint;
41
- PianoID.shared.signUpEnabled = true;
42
-
43
- PianoID.shared.signIn();
44
- };
45
- }
46
-
47
- public func myShowForm(composer: PianoComposer, event: XpEvent, params: [AnyHashable: Any]?) {
48
- DispatchQueue.main.async {
49
- PianoID.shared.formInfo(accessToken: PianoIDToken.description()) { formInfo, error in
50
- if let error = error {
51
- print("Errore nel recuperare il form: \(error.localizedDescription)")
52
- return
53
- }
54
-
55
- guard let formInfo = formInfo else {
56
- print("FormInfo non disponibile.")
57
- return
58
- }
59
-
60
- composer.delegate?.showForm?(composer: composer, event: event, params: nil)
61
- }
62
- }
63
- }
64
10
 
11
+ // import PianoTemplate
65
12
 
66
-
67
- public func myShowTemplate(composer: PianoComposer, event: XpEvent, params: ShowTemplateEventParams?) {
68
- if let p = params {
69
- let webView = WKWebView()
70
- let request = URLRequest(url: URL(string: p.templateUrl)!)
71
- webView.load(request)
72
-
73
- // Aggiungi webView alla vista principale
74
- let controller = PianoShowTemplateController(p)
75
- controller.delegate = self
76
- controller.show()
77
-
78
- self.execute();
79
- }
80
- }
81
-
82
- public func executeExperience(composer: PianoComposer, event: XpEvent, params: ExperienceExecuteEventParams?) {
83
- composer.delegate?.experienceExecute?(composer: composer, event: event, params: params)
84
- }
13
+ @objcMembers public class MyComposerDelegate: NSObject, PianoComposerDelegate {
85
14
 
15
+ // ✅ STEP 1: Add a weak reference back to the main implementation class.
16
+ // This lets us access the stored promiseResolver and promiseRejecter.
17
+ weak var moduleImpl: ComposerPianoImpl?
86
18
 
87
-
88
- public func findViewBySelector(selector: String) -> UIView? {
89
- return nil;
90
- }
91
-
92
- public func showRecommendations(composer: PianoComposer, event: XpEvent, params: ShowRecommendationsEventParams?) {
93
- DispatchQueue.main.async {
94
- composer.delegate?.showRecommendations?(composer: composer, event: event, params: params)
95
- }
96
- }
97
-
98
- public func nonSite(composer: PianoComposer, event: XpEvent) {
99
- DispatchQueue.main.async {
100
- composer.delegate?.nonSite?(composer: composer, event: event)
101
- }
102
- }
103
-
104
- public func userSegmentTrue(composer: PianoComposer, event: XpEvent) {
105
- DispatchQueue.main.async {
106
- composer.delegate?.userSegmentTrue?(composer: composer, event: event)
107
- }
108
- }
109
-
110
- public func userSegmentFalse(composer: PianoComposer, event: XpEvent) {
111
- DispatchQueue.main.async {
112
- composer.delegate?.userSegmentFalse?(composer: composer, event: event)
113
- }
114
- }
115
-
116
- public func meterActive(composer: PianoComposer, event: XpEvent, params: PageViewMeterEventParams?) {
117
- DispatchQueue.main.async {
118
- composer.delegate?.meterActive?(composer: composer, event: event, params: params)
119
- }
120
- }
121
-
122
- public func meterExpired(composer: PianoComposer, event: XpEvent, params: PageViewMeterEventParams?) {
123
- DispatchQueue.main.async {
124
- composer.delegate?.meterExpired?(composer: composer, event: event, params: params)
125
- }
126
- }
127
-
128
- public func composerDidCompleteExecution(_ composer: PianoComposer, result: PianoComposerEdgeResult?) {
129
- print("✅ Composer execution finished.")
130
-
131
- // Qui puoi notificare JS, inviare un evento, ecc.
132
- // Ad esempio: invia una notifica o chiama una callback
133
- }
19
+ // ✅ STEP 2: This is a generic helper function to resolve the promise.
20
+ // We'll call this from all the different delegate methods.
21
+ private func resolvePromise(with eventData: [String: Any]) {
22
+ guard self.moduleImpl?.promiseResolver != nil else { return }
134
23
 
135
- public func composerExecutionFailed(_ composer: PianoComposer, error: Error) {
136
- print("❌ Composer execution failed with error: \(error.localizedDescription)")
24
+ self.moduleImpl?.promiseResolver?(eventData)
25
+ self.clearPromiseHandlers()
137
26
  }
138
- }
139
-
140
-
141
-
142
27
 
28
+ private func rejectPromise(with error: Error) {
29
+ guard self.moduleImpl?.promiseRejecter != nil else { return }
143
30
 
31
+ let errorCode = "execution_failed"
32
+ let errorMessage = error.localizedDescription
33
+ self.moduleImpl?.promiseRejecter?(errorCode, errorMessage, error)
34
+ self.clearPromiseHandlers()
35
+ }
144
36
 
145
- struct WebView : UIViewRepresentable {
37
+ private func clearPromiseHandlers() {
38
+ self.moduleImpl?.promiseResolver = nil
39
+ self.moduleImpl?.promiseRejecter = nil
40
+ }
146
41
 
147
- let webView: WKWebView
42
+ // ✅ STEP 3: Implement the real delegate methods.
43
+ // The Piano SDK will call these automatically.
148
44
 
149
- @Binding var height: CGFloat
45
+ public func executeExperience(
46
+ composer: PianoComposer, event: XpEvent
47
+ ) {
48
+ print("✅ Delegate received: executeExperience")
150
49
 
151
- class Coordinator: NSObject, WKNavigationDelegate {
50
+ // Correct: Access the experienceId from the public 'eventExecutionContext' object
51
+ let experienceId = event.eventExecutionContext?.experienceId ?? ""
152
52
 
153
- var parent: WebView
53
+ let eventData: [String: Any] = [
54
+ "eventType": event.eventType,
55
+ "experienceId": experienceId,
56
+ ]
154
57
 
155
- init(_ parent: WebView) {
156
- self.parent = parent
157
- }
58
+ resolvePromise(with: eventData)
59
+ }
158
60
 
159
- func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
160
- webView.evaluateJavaScript("document.documentElement.scrollHeight", completionHandler: { (height, error) in
161
- DispatchQueue.main.async {
162
- self.parent.height = height as! CGFloat
163
- }
164
- })
165
- }
166
- }
61
+ public func showTemplate(
62
+ composer: PianoComposer, event: XpEvent, params: ShowTemplateEventParams?
63
+ ) {
64
+ print("✅ Delegate received: showTemplate")
167
65
 
168
- func makeCoordinator() -> Coordinator {
169
- Coordinator(self)
170
- }
66
+ // Correct: Access the experienceId from the public 'eventExecutionContext' object
67
+ let experienceId = event.eventExecutionContext?.experienceId ?? ""
171
68
 
172
- func makeUIView(context: Context) -> WKWebView {
173
- webView.scrollView.bounces = false
174
- webView.navigationDelegate = context.coordinator
69
+ let eventData: [String: Any] = [
70
+ "eventType": event.eventType,
71
+ "experienceId": experienceId,
72
+ "templateUrl": params?.templateUrl ?? "",
73
+ "displayMode": params?.displayMode.rawValue ?? "",
74
+ ]
175
75
 
176
- return webView
177
- }
76
+ resolvePromise(with: eventData)
77
+ }
178
78
 
179
- func updateUIView(_ uiView: WKWebView, context: Context) {}
180
- }
79
+ public func meterExpired(
80
+ composer: PianoComposer, event: XpEvent, params: PageViewMeterEventParams?
81
+ ) {
82
+ print("✅ Delegate received: meterExpired")
181
83
 
182
- fileprivate class ShowTemplateService: ComposerService, PianoShowTemplateDelegate {
84
+ // Correct: Access the experienceId from the public 'eventExecutionContext' object
85
+ let experienceId = event.eventExecutionContext?.experienceId ?? ""
183
86
 
184
- @Published var webView: WKWebView? = nil
87
+ let eventData: [String: Any] = [
88
+ "eventType": event.eventType,
89
+ "experienceId": experienceId,
90
+ "meterName": params?.meterName ?? "",
91
+ ]
185
92
 
186
- override func prepare(composer: PianoComposer) {
187
- webView = nil
188
- _ = composer.tag("templates")
189
- }
93
+ resolvePromise(with: eventData)
94
+ }
190
95
 
191
- func showTemplate(composer: PianoComposer, event: XpEvent, params: ShowTemplateEventParams?) {
192
- if let p = params {
193
- if p.displayMode == .inline {
194
- webView = WKWebView()
195
- }
96
+ public func composerExecutionFailed(_ composer: PianoComposer, error: Error) {
97
+ print("❌ Delegate received: composerExecutionFailed")
98
+ rejectPromise(with: error)
99
+ }
196
100
 
197
- let controller = PianoShowTemplateController(p)
198
- controller.delegate = self
199
- controller.show()
200
- }
201
- }
101
+ public func composerExecutionCompleted(composer: PianoComposer) {
102
+ print("✅ Delegate received: composerExecutionCompleted")
103
+ resolvePromise(with: ["eventType": "composerExecutionCompleted"])
104
+ }
202
105
 
203
- func findViewBySelector(selector: String) -> UIView? {
204
- selector == "template" ? webView : nil
205
- }
206
- }
106
+ public func experienceExecutionFailed(composer: PianoComposer, event: XpEvent, params: FailureEventParams?) {
107
+ print(" Delegate received: experienceExecutionFailed")
108
+ let error = NSError(domain: "PianoSDK", code: -1, userInfo: [NSLocalizedDescriptionKey: "Experience execution failed"])
109
+ rejectPromise(with: error)
110
+ }
207
111
 
208
- struct ShowTemplateView: View {
209
-
210
- @ObservedObject private var service: ShowTemplateService
211
-
212
- @State private var height: CGFloat = .zero
213
-
214
- init(tokenService: TokenService) {
215
- service = ShowTemplateService(tokenService: tokenService)
216
- }
217
-
218
- var body: some View {
219
- if #available(iOS 14.0, *) {
220
- VStack(spacing: 20) {
221
- if !service.loading {
222
- Button("Execute") {
223
- service.execute()
224
- }
225
-
226
- if let wv = service.webView {
227
- WebView(webView: wv, height: $height)
228
- .frame(height: height > 320 ? 320 : height)
229
- }
230
- } else {
231
-
232
- }
233
- }.navigationTitle("Show template")
234
- }
235
- }
112
+ public func findViewBySelector(selector: String) -> UIView? {
113
+ return nil
114
+ }
236
115
  }