@octopus-community/react-native 1.0.8 → 1.9.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 (108) hide show
  1. package/OctopusReactNativeSdk.podspec +1 -1
  2. package/README.md +40 -35
  3. package/android/build.gradle +2 -0
  4. package/android/gradle.properties +2 -2
  5. package/android/src/main/AndroidManifest.xml +2 -1
  6. package/android/src/main/AndroidManifestNew.xml +2 -1
  7. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusActivity.kt +56 -0
  8. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusContent.kt +396 -0
  9. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusEventEmitter.kt +22 -0
  10. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusEventSerializer.kt +339 -0
  11. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusReactModule.kt +326 -0
  12. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/{OctopusReactNativeSdkPackage.kt → OctopusReactPackage.kt} +3 -3
  13. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusSDKInitializer.kt +22 -9
  14. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusSSOAuthenticator.kt +5 -15
  15. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusUIController.kt +17 -2
  16. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusUIViewManager.kt +63 -0
  17. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/ProfileFieldMapper.kt +2 -2
  18. package/ios/OctopusEventManager.swift +27 -0
  19. package/ios/OctopusEventSerializer.swift +271 -0
  20. package/ios/OctopusReactNativeSdk.mm +26 -1
  21. package/ios/OctopusReactNativeSdk.swift +216 -2
  22. package/ios/OctopusSSOAuthenticator.swift +1 -5
  23. package/ios/OctopusUIManager.swift +83 -0
  24. package/ios/OctopusUIViewManager.m +7 -0
  25. package/ios/OctopusUIViewManager.swift +37 -0
  26. package/lib/module/OctopusUIView.js +39 -0
  27. package/lib/module/OctopusUIView.js.map +1 -0
  28. package/lib/module/addHasAccessToCommunityListener.js +33 -0
  29. package/lib/module/addHasAccessToCommunityListener.js.map +1 -0
  30. package/lib/module/addNavigateToUrlListener.js +41 -0
  31. package/lib/module/addNavigateToUrlListener.js.map +1 -0
  32. package/lib/module/addNotSeenNotificationsCountListener.js +30 -0
  33. package/lib/module/addNotSeenNotificationsCountListener.js.map +1 -0
  34. package/lib/module/addSDKEventListener.js +48 -0
  35. package/lib/module/addSDKEventListener.js.map +1 -0
  36. package/lib/module/connectUser.js +24 -3
  37. package/lib/module/connectUser.js.map +1 -1
  38. package/lib/module/index.js +12 -0
  39. package/lib/module/index.js.map +1 -1
  40. package/lib/module/initialize.js +9 -12
  41. package/lib/module/initialize.js.map +1 -1
  42. package/lib/module/openUI.js +23 -2
  43. package/lib/module/openUI.js.map +1 -1
  44. package/lib/module/overrideCommunityAccess.js +36 -0
  45. package/lib/module/overrideCommunityAccess.js.map +1 -0
  46. package/lib/module/overrideDefaultLocale.js +75 -0
  47. package/lib/module/overrideDefaultLocale.js.map +1 -0
  48. package/lib/module/trackCommunityAccess.js +33 -0
  49. package/lib/module/trackCommunityAccess.js.map +1 -0
  50. package/lib/module/trackCustomEvent.js +36 -0
  51. package/lib/module/trackCustomEvent.js.map +1 -0
  52. package/lib/module/types/sdkEvents.js +2 -0
  53. package/lib/module/types/sdkEvents.js.map +1 -0
  54. package/lib/module/types/urlOpeningStrategy.js +23 -0
  55. package/lib/module/types/urlOpeningStrategy.js.map +1 -0
  56. package/lib/module/updateNotSeenNotificationsCount.js +33 -0
  57. package/lib/module/updateNotSeenNotificationsCount.js.map +1 -0
  58. package/lib/typescript/src/OctopusUIView.d.ts +32 -0
  59. package/lib/typescript/src/OctopusUIView.d.ts.map +1 -0
  60. package/lib/typescript/src/addHasAccessToCommunityListener.d.ts +27 -0
  61. package/lib/typescript/src/addHasAccessToCommunityListener.d.ts.map +1 -0
  62. package/lib/typescript/src/addNavigateToUrlListener.d.ts +31 -0
  63. package/lib/typescript/src/addNavigateToUrlListener.d.ts.map +1 -0
  64. package/lib/typescript/src/addNotSeenNotificationsCountListener.d.ts +24 -0
  65. package/lib/typescript/src/addNotSeenNotificationsCountListener.d.ts.map +1 -0
  66. package/lib/typescript/src/addSDKEventListener.d.ts +43 -0
  67. package/lib/typescript/src/addSDKEventListener.d.ts.map +1 -0
  68. package/lib/typescript/src/connectUser.d.ts +24 -8
  69. package/lib/typescript/src/connectUser.d.ts.map +1 -1
  70. package/lib/typescript/src/index.d.ts +13 -0
  71. package/lib/typescript/src/index.d.ts.map +1 -1
  72. package/lib/typescript/src/initialize.d.ts +9 -12
  73. package/lib/typescript/src/initialize.d.ts.map +1 -1
  74. package/lib/typescript/src/openUI.d.ts +28 -1
  75. package/lib/typescript/src/openUI.d.ts.map +1 -1
  76. package/lib/typescript/src/overrideCommunityAccess.d.ts +30 -0
  77. package/lib/typescript/src/overrideCommunityAccess.d.ts.map +1 -0
  78. package/lib/typescript/src/overrideDefaultLocale.d.ts +37 -0
  79. package/lib/typescript/src/overrideDefaultLocale.d.ts.map +1 -0
  80. package/lib/typescript/src/trackCommunityAccess.d.ts +27 -0
  81. package/lib/typescript/src/trackCommunityAccess.d.ts.map +1 -0
  82. package/lib/typescript/src/trackCustomEvent.d.ts +30 -0
  83. package/lib/typescript/src/trackCustomEvent.d.ts.map +1 -0
  84. package/lib/typescript/src/types/sdkEvents.d.ts +222 -0
  85. package/lib/typescript/src/types/sdkEvents.d.ts.map +1 -0
  86. package/lib/typescript/src/types/urlOpeningStrategy.d.ts +20 -0
  87. package/lib/typescript/src/types/urlOpeningStrategy.d.ts.map +1 -0
  88. package/lib/typescript/src/updateNotSeenNotificationsCount.d.ts +27 -0
  89. package/lib/typescript/src/updateNotSeenNotificationsCount.d.ts.map +1 -0
  90. package/package.json +2 -1
  91. package/src/OctopusUIView.tsx +57 -0
  92. package/src/addHasAccessToCommunityListener.ts +38 -0
  93. package/src/addNavigateToUrlListener.ts +54 -0
  94. package/src/addNotSeenNotificationsCountListener.ts +35 -0
  95. package/src/addSDKEventListener.ts +49 -0
  96. package/src/connectUser.ts +24 -8
  97. package/src/index.ts +13 -0
  98. package/src/initialize.ts +9 -12
  99. package/src/openUI.ts +32 -2
  100. package/src/overrideCommunityAccess.ts +33 -0
  101. package/src/overrideDefaultLocale.ts +88 -0
  102. package/src/trackCommunityAccess.ts +30 -0
  103. package/src/trackCustomEvent.ts +36 -0
  104. package/src/types/sdkEvents.ts +315 -0
  105. package/src/types/urlOpeningStrategy.ts +20 -0
  106. package/src/updateNotSeenNotificationsCount.ts +30 -0
  107. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusReactNativeSdkModule.kt +0 -155
  108. package/android/src/main/java/com/octopuscommunity/octopusreactnativesdk/OctopusUIActivity.kt +0 -434
@@ -9,11 +9,11 @@ import android.graphics.Color
9
9
 
10
10
  class OctopusSDKInitializer {
11
11
 
12
- fun initialize(context: ReactApplicationContext, options: ReadableMap, promise: Promise) {
12
+ fun initialize(context: ReactApplicationContext, options: ReadableMap, promise: Promise): Boolean {
13
13
  val apiKey = options.getString("apiKey")
14
14
  if (apiKey == null) {
15
15
  promise.reject("INITIALIZE_ERROR", "Missing API key")
16
- return
16
+ return false
17
17
  }
18
18
 
19
19
  try {
@@ -27,16 +27,28 @@ class OctopusSDKInitializer {
27
27
  val uiConfiguration = parseUIConfiguration(options)
28
28
  OctopusUIConfigurationManager.setUIConfiguration(uiConfiguration)
29
29
 
30
- OctopusSDK.initialize(
31
- context = context,
32
- apiKey = apiKey,
33
- connectionMode = connectionMode
34
- )
30
+ // For "octopus" mode, don't pass connectionMode (it's the default)
31
+ // For "sso" mode, pass the ConnectionMode.SSO
32
+ if (connectionMode != null) {
33
+ OctopusSDK.initialize(
34
+ context = context,
35
+ apiKey = apiKey,
36
+ connectionMode = connectionMode
37
+ )
38
+ } else {
39
+ OctopusSDK.initialize(
40
+ context = context,
41
+ apiKey = apiKey
42
+ )
43
+ }
35
44
  promise.resolve(null)
45
+ return true
36
46
  } catch (e: InvalidConnectionModeException) {
37
47
  promise.reject("INITIALIZE_ERROR", e.message, e)
48
+ return false
38
49
  } catch (e: Exception) {
39
50
  promise.reject("INITIALIZE_ERROR", "Failed to initialize Octopus SDK", e)
51
+ return false
40
52
  }
41
53
  }
42
54
 
@@ -209,7 +221,7 @@ class OctopusSDKInitializer {
209
221
  }
210
222
  }
211
223
 
212
- private fun parseConnectionMode(options: ReadableMap): ConnectionMode {
224
+ private fun parseConnectionMode(options: ReadableMap): ConnectionMode? {
213
225
  val connectionModeMap = options.getMap("connectionMode")
214
226
  return when (val connectionModeType = connectionModeMap?.getString("type")) {
215
227
  "sso" -> {
@@ -221,7 +233,8 @@ class OctopusSDKInitializer {
221
233
  }
222
234
 
223
235
  "octopus" -> {
224
- ConnectionMode.Octopus
236
+ // For "octopus" mode, return null - OctopusSDK.initialize() will use default mode
237
+ null
225
238
  }
226
239
 
227
240
  else -> {
@@ -4,8 +4,7 @@ import com.facebook.react.bridge.ReadableMap
4
4
  import com.facebook.react.bridge.Promise
5
5
  import com.octopuscommunity.sdk.OctopusSDK
6
6
  import com.octopuscommunity.sdk.domain.model.ClientUser
7
- import com.octopuscommunity.sdk.domain.model.ClientUser.Profile.AgeInformation
8
- import com.octopuscommunity.sdk.domain.model.Image
7
+ import com.octopuscommunity.sdk.domain.model.Resource
9
8
  import kotlinx.coroutines.CoroutineScope
10
9
  import kotlinx.coroutines.Dispatchers
11
10
  import kotlinx.coroutines.launch
@@ -103,24 +102,16 @@ class OctopusSSOAuthenticator(
103
102
  return ClientUser.Profile()
104
103
  }
105
104
 
106
- val ageInformation = if (profileParams.hasKey("legalAgeReached")) {
107
- if (profileParams.getBoolean("legalAgeReached")) {
108
- AgeInformation.LegalAgeReached
109
- } else {
110
- AgeInformation.Underage
111
- }
112
- } else null
113
-
114
105
  val profilePicture = profileParams.getString("profilePicture")?.let { pictureUrl ->
115
106
  if (pictureUrl.startsWith("http://") || pictureUrl.startsWith("https://")) {
116
- Image.Remote(pictureUrl)
107
+ Resource.Remote(url = pictureUrl)
117
108
  } else if (pictureUrl.startsWith("file") || pictureUrl.startsWith("android.resource")) {
118
- Image.Local(pictureUrl)
109
+ Resource.Local(pictureUrl)
119
110
  } else if(pictureUrl.isNotBlank()) {
120
111
  // Asset names like "assets_images_logo" need conversion
121
112
  // Convert to drawable resource URI
122
113
  val resourceId = context.resources.getIdentifier(pictureUrl, "drawable", context.packageName)
123
- Image.Local(
114
+ Resource.Local(
124
115
  if (resourceId != 0) {
125
116
  "android.resource://${context.packageName}/$resourceId"
126
117
  } else {
@@ -136,8 +127,7 @@ class OctopusSSOAuthenticator(
136
127
  return ClientUser.Profile(
137
128
  nickname = profileParams.getString("username"),
138
129
  bio = profileParams.getString("biography"),
139
- ageInformation = ageInformation,
140
- avatar = profilePicture
130
+ picture = profilePicture
141
131
  )
142
132
  }
143
133
  }
@@ -1,15 +1,20 @@
1
1
  package com.octopuscommunity.octopusreactnativesdk
2
2
 
3
3
  import android.content.Intent
4
+ import android.net.Uri
4
5
  import com.facebook.react.bridge.Promise
5
6
  import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.facebook.react.bridge.ReadableMap
6
8
 
7
9
  class OctopusUIController(private val reactContext: ReactApplicationContext) {
8
10
 
9
- fun openUI(promise: Promise) {
11
+ fun openUI(options: ReadableMap?, promise: Promise) {
10
12
  try {
11
- val intent = Intent(reactContext, OctopusUIActivity::class.java)
13
+ val intent = Intent(reactContext, OctopusActivity::class.java)
12
14
  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
15
+ val interceptUrls = options?.hasKey("interceptUrls") == true &&
16
+ options.getBoolean("interceptUrls")
17
+ intent.putExtra(OctopusActivity.EXTRA_INTERCEPT_URLS, interceptUrls)
13
18
  reactContext.startActivity(intent)
14
19
  promise.resolve(null)
15
20
  } catch (e: Exception) {
@@ -28,6 +33,16 @@ class OctopusUIController(private val reactContext: ReactApplicationContext) {
28
33
  }
29
34
  }
30
35
 
36
+ fun openUrlInBrowser(url: String) {
37
+ try {
38
+ val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
39
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
40
+ reactContext.startActivity(intent)
41
+ } catch (e: Exception) {
42
+ // Ignore if no app can handle the URL
43
+ }
44
+ }
45
+
31
46
  companion object {
32
47
  const val CLOSE_UI_ACTION = "com.octopuscommunity.octopusreactnativesdk.CLOSE_UI"
33
48
  }
@@ -0,0 +1,63 @@
1
+ package com.octopuscommunity.octopusreactnativesdk
2
+
3
+ import android.view.ViewGroup
4
+ import androidx.compose.foundation.layout.WindowInsets
5
+ import androidx.compose.foundation.layout.captionBar
6
+ import androidx.compose.foundation.layout.consumeWindowInsets
7
+ import androidx.compose.foundation.layout.displayCutout
8
+ import androidx.compose.foundation.layout.fillMaxSize
9
+ import androidx.compose.foundation.layout.ime
10
+ import androidx.compose.foundation.layout.mandatorySystemGestures
11
+ import androidx.compose.foundation.layout.navigationBars
12
+ import androidx.compose.foundation.layout.safeContent
13
+ import androidx.compose.foundation.layout.safeDrawing
14
+ import androidx.compose.foundation.layout.safeGestures
15
+ import androidx.compose.foundation.layout.statusBars
16
+ import androidx.compose.foundation.layout.systemBars
17
+ import androidx.compose.foundation.layout.systemGestures
18
+ import androidx.compose.foundation.layout.tappableElement
19
+ import androidx.compose.foundation.layout.waterfall
20
+ import androidx.compose.material3.MaterialTheme
21
+ import androidx.compose.ui.Modifier
22
+ import androidx.compose.ui.platform.ComposeView
23
+ import com.facebook.react.bridge.ReactApplicationContext
24
+ import com.facebook.react.uimanager.SimpleViewManager
25
+ import com.facebook.react.uimanager.ThemedReactContext
26
+ import com.facebook.react.uimanager.annotations.ReactProp
27
+
28
+ class OctopusUIViewManager(private val reactContext: ReactApplicationContext) :
29
+ SimpleViewManager<ComposeView>() {
30
+
31
+ private var interceptUrls: Boolean = false
32
+
33
+ override fun getName(): String = REACT_CLASS_NAME
34
+
35
+ override fun createViewInstance(reactContext: ThemedReactContext) =
36
+ ComposeView(reactContext).apply {
37
+ layoutParams = ViewGroup.LayoutParams(
38
+ ViewGroup.LayoutParams.MATCH_PARENT,
39
+ ViewGroup.LayoutParams.MATCH_PARENT
40
+ )
41
+
42
+ setContent {
43
+ MaterialTheme {
44
+ OctopusContent(
45
+ modifier = Modifier.fillMaxSize()
46
+ .consumeWindowInsets(WindowInsets.statusBars)
47
+ .consumeWindowInsets(WindowInsets.navigationBars)
48
+ .consumeWindowInsets(WindowInsets.systemBars),
49
+ interceptUrls = interceptUrls
50
+ )
51
+ }
52
+ }
53
+ }
54
+
55
+ @ReactProp(name = "interceptUrls")
56
+ fun setInterceptUrls(view: ComposeView, interceptUrls: Boolean) {
57
+ this.interceptUrls = interceptUrls
58
+ }
59
+
60
+ companion object Companion {
61
+ const val REACT_CLASS_NAME = "OctopusUIView"
62
+ }
63
+ }
@@ -23,7 +23,7 @@ object ProfileFieldMapper {
23
23
  return when (fieldName) {
24
24
  "username" -> ProfileField.NICKNAME
25
25
  "biography" -> ProfileField.BIO
26
- "profilePicture" -> ProfileField.AVATAR
26
+ "profilePicture" -> ProfileField.PICTURE
27
27
  else -> null
28
28
  }
29
29
  }
@@ -32,7 +32,7 @@ object ProfileFieldMapper {
32
32
  return when (profileField) {
33
33
  ProfileField.NICKNAME -> "username"
34
34
  ProfileField.BIO -> "biography"
35
- ProfileField.AVATAR -> "profilePicture"
35
+ ProfileField.PICTURE -> "profilePicture"
36
36
  else -> null
37
37
  }
38
38
  }
@@ -30,6 +30,33 @@ class OctopusEventManager {
30
30
  }
31
31
  }
32
32
 
33
+ func emitNotSeenNotificationsCountChanged(count: Int) {
34
+ if hasListeners {
35
+ let eventBody = ["count": count]
36
+ bridge?.eventDispatcher().sendAppEvent(withName: "notSeenNotificationsCountChanged", body: eventBody)
37
+ }
38
+ }
39
+
40
+ func emitHasAccessToCommunityChanged(hasAccess: Bool) {
41
+ if hasListeners {
42
+ let eventBody = ["hasAccess": hasAccess]
43
+ bridge?.eventDispatcher().sendAppEvent(withName: "hasAccessToCommunityChanged", body: eventBody)
44
+ }
45
+ }
46
+
47
+ func emitSDKEvent(eventData: [String: Any]) {
48
+ if hasListeners {
49
+ bridge?.eventDispatcher().sendAppEvent(withName: "sdkEvent", body: eventData)
50
+ }
51
+ }
52
+
53
+ func emitNavigateToUrl(url: String) {
54
+ if hasListeners {
55
+ let eventBody = ["url": url]
56
+ bridge?.eventDispatcher().sendAppEvent(withName: "navigateToUrl", body: eventBody)
57
+ }
58
+ }
59
+
33
60
  func startObserving() {
34
61
  hasListeners = true
35
62
  }
@@ -0,0 +1,271 @@
1
+ import Foundation
2
+ import Octopus
3
+
4
+ /**
5
+ * Serializes OctopusEvent objects to dictionaries for React Native bridge.
6
+ */
7
+ class OctopusEventSerializer {
8
+
9
+ static func serializeEvent(_ event: OctopusEvent) -> [String: Any]? {
10
+ switch event {
11
+ case .postCreated(let context):
12
+ var contentList: [String] = []
13
+ if context.content.contains(.text) { contentList.append("text") }
14
+ if context.content.contains(.image) { contentList.append("image") }
15
+ if context.content.contains(.poll) { contentList.append("poll") }
16
+ return [
17
+ "type": "postCreated",
18
+ "postId": context.postId,
19
+ "content": contentList,
20
+ "topicId": context.topicId,
21
+ "textLength": context.textLength
22
+ ]
23
+
24
+ case .commentCreated(let context):
25
+ return [
26
+ "type": "commentCreated",
27
+ "commentId": context.commentId,
28
+ "postId": context.postId,
29
+ "textLength": context.textLength
30
+ ]
31
+
32
+ case .replyCreated(let context):
33
+ return [
34
+ "type": "replyCreated",
35
+ "replyId": context.replyId,
36
+ "commentId": context.commentId,
37
+ "textLength": context.textLength
38
+ ]
39
+
40
+ case .contentDeleted(let context):
41
+ return [
42
+ "type": "contentDeleted",
43
+ "contentId": context.contentId,
44
+ "contentKind": serializeContentKind(context.kind)
45
+ ]
46
+
47
+ case .reactionModified(let context):
48
+ var data: [String: Any] = [
49
+ "type": "reactionModified",
50
+ "contentId": context.contentId,
51
+ "contentKind": serializeContentKind(context.contentKind)
52
+ ]
53
+ if let prev = context.previousReaction {
54
+ data["previousReaction"] = serializeReactionKind(prev)
55
+ }
56
+ if let next = context.newReaction {
57
+ data["newReaction"] = serializeReactionKind(next)
58
+ }
59
+ return data
60
+
61
+ case .pollVoted(let context):
62
+ return [
63
+ "type": "pollVoted",
64
+ "contentId": context.contentId,
65
+ "optionId": context.optionId
66
+ ]
67
+
68
+ case .contentReported(let context):
69
+ return [
70
+ "type": "contentReported",
71
+ "contentId": context.contentId,
72
+ "reasons": context.reasons.map { serializeReportReason($0) }
73
+ ]
74
+
75
+ case .gamificationPointsGained(let context):
76
+ return [
77
+ "type": "gamificationPointsGained",
78
+ "points": context.pointsGained,
79
+ "action": serializeGamificationPointsGainedAction(context.action)
80
+ ]
81
+
82
+ case .gamificationPointsRemoved(let context):
83
+ return [
84
+ "type": "gamificationPointsRemoved",
85
+ "points": context.pointsRemoved,
86
+ "action": serializeGamificationPointsRemovedAction(context.action)
87
+ ]
88
+
89
+ case .screenDisplayed(let context):
90
+ return [
91
+ "type": "screenDisplayed",
92
+ "screen": serializeScreen(context.screen)
93
+ ]
94
+
95
+ case .notificationClicked(let context):
96
+ var data: [String: Any] = [
97
+ "type": "notificationClicked",
98
+ "notificationId": context.notificationId
99
+ ]
100
+ if let contentId = context.contentId {
101
+ data["contentId"] = contentId
102
+ }
103
+ return data
104
+
105
+ case .postClicked(let context):
106
+ return [
107
+ "type": "postClicked",
108
+ "postId": context.postId,
109
+ "source": serializePostClickedSource(context.source)
110
+ ]
111
+
112
+ case .translationButtonClicked(let context):
113
+ return [
114
+ "type": "translationButtonClicked",
115
+ "contentId": context.contentId,
116
+ "viewTranslated": context.viewTranslated,
117
+ "contentKind": serializeContentKind(context.contentKind)
118
+ ]
119
+
120
+ case .commentButtonClicked(let context):
121
+ return [
122
+ "type": "commentButtonClicked",
123
+ "postId": context.postId
124
+ ]
125
+
126
+ case .replyButtonClicked(let context):
127
+ return [
128
+ "type": "replyButtonClicked",
129
+ "commentId": context.commentId
130
+ ]
131
+
132
+ case .seeRepliesButtonClicked(let context):
133
+ return [
134
+ "type": "seeRepliesButtonClicked",
135
+ "commentId": context.commentId
136
+ ]
137
+
138
+ case .profileModified(let context):
139
+ var data: [String: Any] = [
140
+ "type": "profileModified",
141
+ "nicknameUpdated": context.nickname.isUpdated,
142
+ "bioUpdated": context.bio.isUpdated,
143
+ "pictureUpdated": context.picture.isUpdated
144
+ ]
145
+ if case .updated(let bioContext) = context.bio {
146
+ data["bioLength"] = bioContext.bioLength
147
+ }
148
+ if case .updated(let pictureContext) = context.picture {
149
+ data["hasPicture"] = pictureContext.hasPicture
150
+ }
151
+ return data
152
+
153
+ case .sessionStarted(let context):
154
+ return [
155
+ "type": "sessionStarted",
156
+ "sessionId": context.sessionId
157
+ ]
158
+
159
+ case .sessionStopped(let context):
160
+ return [
161
+ "type": "sessionStopped",
162
+ "sessionId": context.sessionId
163
+ ]
164
+
165
+ @unknown default:
166
+ return nil
167
+ }
168
+ }
169
+
170
+ private static func serializeContentKind(_ kind: OctopusEvent.ContentKind) -> String {
171
+ switch kind {
172
+ case .post: return "post"
173
+ case .comment: return "comment"
174
+ case .reply: return "reply"
175
+ }
176
+ }
177
+
178
+ private static func serializeReactionKind(_ kind: OctopusEvent.ReactionKind) -> String {
179
+ switch kind {
180
+ case .heart: return "heart"
181
+ case .joy: return "joy"
182
+ case .mouthOpen: return "mouthOpen"
183
+ case .clap: return "clap"
184
+ case .cry: return "cry"
185
+ case .rage: return "rage"
186
+ case .unknown: return "unknown"
187
+ }
188
+ }
189
+
190
+ private static func serializeReportReason(_ reason: OctopusEvent.ReportReason) -> String {
191
+ switch reason {
192
+ case .hateSpeechOrDiscriminationOrHarassment: return "hateSpeech"
193
+ case .explicitOrInappropriateContent: return "explicit"
194
+ case .violenceAndTerrorism: return "violence"
195
+ case .spamAndScams: return "spam"
196
+ case .suicideAndSelfHarm: return "suicide"
197
+ case .fakeProfilesAndImpersonation: return "fakeProfile"
198
+ case .childExploitationOrAbuse: return "childExploitation"
199
+ case .intellectualPropertyViolation: return "intellectualProperty"
200
+ case .other: return "other"
201
+ }
202
+ }
203
+
204
+ private static func serializeGamificationPointsGainedAction(_ action: OctopusEvent.GamificationPointsGainedAction) -> String {
205
+ switch action {
206
+ case .post: return "post"
207
+ case .comment: return "comment"
208
+ case .reply: return "reply"
209
+ case .reaction: return "reaction"
210
+ case .vote: return "vote"
211
+ case .postCommented: return "postCommented"
212
+ case .profileCompleted: return "profileCompleted"
213
+ case .dailySession: return "dailySession"
214
+ }
215
+ }
216
+
217
+ private static func serializeGamificationPointsRemovedAction(_ action: OctopusEvent.GamificationPointsRemovedAction) -> String {
218
+ switch action {
219
+ case .postDeleted: return "postDeleted"
220
+ case .commentDeleted: return "commentDeleted"
221
+ case .replyDeleted: return "replyDeleted"
222
+ case .reactionDeleted: return "reactionDeleted"
223
+ }
224
+ }
225
+
226
+ private static func serializePostClickedSource(_ source: OctopusEvent.PostClickedSource) -> String {
227
+ switch source {
228
+ case .feed: return "feed"
229
+ case .profile: return "profile"
230
+ }
231
+ }
232
+
233
+ private static func serializeScreen(_ screen: OctopusEvent.Screen) -> [String: Any] {
234
+ switch screen {
235
+ case .postsFeed(let context):
236
+ var data: [String: Any] = ["type": "postsFeed", "feedId": context.feedId]
237
+ if let relatedTopicId = context.relatedTopicId {
238
+ data["relatedTopicId"] = relatedTopicId
239
+ }
240
+ return data
241
+ case .postDetail(let context):
242
+ return ["type": "postDetail", "postId": context.postId]
243
+ case .commentDetail(let context):
244
+ return ["type": "commentDetail", "commentId": context.commentId]
245
+ case .createPost:
246
+ return ["type": "createPost"]
247
+ case .profile:
248
+ return ["type": "profile"]
249
+ case .otherUserProfile(let context):
250
+ return ["type": "otherUserProfile", "profileId": context.profileId]
251
+ case .editProfile:
252
+ return ["type": "editProfile"]
253
+ case .reportContent:
254
+ return ["type": "reportContent"]
255
+ case .reportProfile:
256
+ return ["type": "reportProfile"]
257
+ case .validateNickname:
258
+ return ["type": "validateNickname"]
259
+ case .settingsList:
260
+ return ["type": "settingsList"]
261
+ case .settingsAccount:
262
+ return ["type": "settingsAccount"]
263
+ case .settingsAbout:
264
+ return ["type": "settingsAbout"]
265
+ case .reportExplanation:
266
+ return ["type": "reportExplanation"]
267
+ case .deleteAccount:
268
+ return ["type": "deleteAccount"]
269
+ }
270
+ }
271
+ }
@@ -6,9 +6,13 @@ RCT_EXTERN_METHOD(initialize:(NSDictionary *)options
6
6
  withResolver:(RCTPromiseResolveBlock)resolve
7
7
  withRejecter:(RCTPromiseRejectBlock)reject)
8
8
 
9
- RCT_EXTERN_METHOD(openUI:(RCTPromiseResolveBlock)resolve
9
+ RCT_EXTERN_METHOD(openUI:(NSDictionary *)options
10
+ withResolver:(RCTPromiseResolveBlock)resolve
10
11
  withRejecter:(RCTPromiseRejectBlock)reject)
11
12
 
13
+ RCT_EXTERN_METHOD(handleUrlStrategy:(NSString *)url
14
+ withStrategy:(NSString *)strategy)
15
+
12
16
  RCT_EXTERN_METHOD(closeUI:(RCTPromiseResolveBlock)resolve
13
17
  withRejecter:(RCTPromiseRejectBlock)reject)
14
18
 
@@ -36,6 +40,27 @@ RCT_EXTERN_METHOD(updateTheme:(NSDictionary *)themeOptions
36
40
  withResolver:(RCTPromiseResolveBlock)resolve
37
41
  withRejecter:(RCTPromiseRejectBlock)reject)
38
42
 
43
+ RCT_EXTERN_METHOD(updateNotSeenNotificationsCount:(RCTPromiseResolveBlock)resolve
44
+ withRejecter:(RCTPromiseRejectBlock)reject)
45
+
46
+ RCT_EXTERN_METHOD(trackCustomEvent:(NSString *)name
47
+ withProperties:(NSDictionary *)properties
48
+ withResolver:(RCTPromiseResolveBlock)resolve
49
+ withRejecter:(RCTPromiseRejectBlock)reject)
50
+
51
+ RCT_EXTERN_METHOD(overrideDefaultLocale:(NSString *)languageCode
52
+ withCountryCode:(NSString *)countryCode
53
+ withResolver:(RCTPromiseResolveBlock)resolve
54
+ withRejecter:(RCTPromiseRejectBlock)reject)
55
+
56
+ RCT_EXTERN_METHOD(overrideCommunityAccess:(BOOL)hasAccess
57
+ withResolver:(RCTPromiseResolveBlock)resolve
58
+ withRejecter:(RCTPromiseRejectBlock)reject)
59
+
60
+ RCT_EXTERN_METHOD(trackCommunityAccess:(BOOL)hasAccess
61
+ withResolver:(RCTPromiseResolveBlock)resolve
62
+ withRejecter:(RCTPromiseRejectBlock)reject)
63
+
39
64
  RCT_EXTERN_METHOD(addListener:(NSString *)eventName)
40
65
 
41
66
  RCT_EXTERN_METHOD(removeListeners:(NSInteger)count)