react-native-mytatva-rn-sdk 1.2.96 → 1.2.98
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.
- package/android/src/main/java/com/mytatvarnsdk/CgmTrackyLibModule.kt +84 -0
- package/android/src/main/java/com/mytatvarnsdk/activity/ConnectSensorActivity.kt +158 -18
- package/android/src/main/java/com/mytatvarnsdk/activity/HelpActivity.kt +3 -9
- package/android/src/main/java/com/mytatvarnsdk/activity/PermissionActivity.kt +51 -16
- package/android/src/main/java/com/mytatvarnsdk/activity/PlaceSensorActivity.kt +29 -13
- package/android/src/main/java/com/mytatvarnsdk/activity/PlaceTransmitterActivity.kt +29 -13
- package/android/src/main/java/com/mytatvarnsdk/activity/QRActivity.kt +146 -5
- package/android/src/main/java/com/mytatvarnsdk/activity/SearchTransmitterActivity.kt +108 -13
- package/android/src/main/java/com/mytatvarnsdk/activity/SensorConnectSuccessActivity.kt +43 -16
- package/android/src/main/java/com/mytatvarnsdk/activity/StartCGMActivity.kt +26 -15
- package/android/src/main/java/com/mytatvarnsdk/activity/VideoActivity.kt +96 -50
- package/android/src/main/java/com/mytatvarnsdk/network/AuthenticateSDKService.kt +113 -0
- package/android/src/main/java/com/mytatvarnsdk/utils/CgmModuleSentryLog.kt +205 -0
- package/android/src/main/java/com/mytatvarnsdk/utils/CgmSentryLog.kt +28 -0
- package/android/src/main/java/com/mytatvarnsdk/utils/CustomerSupportConfig.kt +137 -0
- package/android/src/main/java/com/mytatvarnsdk/utils/ToolbarSupportHelper.kt +83 -0
- package/ios/Custom/CustomTopUIView.swift +25 -0
- package/ios/MyReactNativeBridge.m +4 -0
- package/ios/Support/API.swift +117 -18
- package/ios/Support/CustomTopViewSupportHelper.swift +55 -0
- package/ios/Support/CustomerSupportConfig.swift +169 -0
- package/ios/Support/Global.swift +2 -2
- package/ios/Support/GlobalYouTubePlayerView.swift +102 -11
- package/ios/ViewControllers/AttachTransmitterViewController.swift +16 -21
- package/ios/ViewControllers/ChatWithExpertViewController.swift +1 -7
- package/ios/ViewControllers/ConnectToSensorViewController.swift +16 -21
- package/ios/ViewControllers/ConnectToTransmitterViewController.swift +16 -21
- package/ios/ViewControllers/ProvidePermissionViewController.swift +16 -21
- package/ios/ViewControllers/PutOnTheSensorViewController.swift +16 -21
- package/ios/ViewControllers/StartConnectionViewController.swift +18 -25
- package/ios/ViewModel/FinalViewModel.swift +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
package com.mytatvarnsdk.utils
|
|
2
|
+
|
|
3
|
+
import android.os.Handler
|
|
4
|
+
import android.os.Looper
|
|
5
|
+
import android.util.Log
|
|
6
|
+
import org.json.JSONObject
|
|
7
|
+
import java.util.concurrent.CopyOnWriteArraySet
|
|
8
|
+
|
|
9
|
+
object CustomerSupportConfig {
|
|
10
|
+
private const val TAG = "CustomerSupportConfig"
|
|
11
|
+
|
|
12
|
+
const val DEFAULT_WHATSAPP_NUMBER = "918511975757"
|
|
13
|
+
const val DEFAULT_DEMO_VIDEO_ID = "65vl2aE1K_I"
|
|
14
|
+
const val DEFAULT_DEMO_VIDEO_URL =
|
|
15
|
+
"https://www.youtube.com/embed/65vl2aE1K_I"
|
|
16
|
+
|
|
17
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
18
|
+
private val updateListeners = CopyOnWriteArraySet<() -> Unit>()
|
|
19
|
+
|
|
20
|
+
@Volatile
|
|
21
|
+
var isLoaded: Boolean = false
|
|
22
|
+
|
|
23
|
+
@Volatile
|
|
24
|
+
var isShowWhatsapp: Boolean = false
|
|
25
|
+
|
|
26
|
+
@Volatile
|
|
27
|
+
var whatsAppNumber: String = DEFAULT_WHATSAPP_NUMBER
|
|
28
|
+
|
|
29
|
+
@Volatile
|
|
30
|
+
var watchCGMDemoUrl: String = DEFAULT_DEMO_VIDEO_URL
|
|
31
|
+
|
|
32
|
+
fun addUpdateListener(listener: () -> Unit) {
|
|
33
|
+
updateListeners.add(listener)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
fun removeUpdateListener(listener: () -> Unit) {
|
|
37
|
+
updateListeners.remove(listener)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
fun applyFailureDefaults() {
|
|
41
|
+
isShowWhatsapp = true
|
|
42
|
+
whatsAppNumber = DEFAULT_WHATSAPP_NUMBER
|
|
43
|
+
watchCGMDemoUrl = DEFAULT_DEMO_VIDEO_URL
|
|
44
|
+
isLoaded = true
|
|
45
|
+
Log.d(
|
|
46
|
+
TAG,
|
|
47
|
+
"Failure defaults applied | showWhatsapp=$isShowWhatsapp | demoUrl=$watchCGMDemoUrl"
|
|
48
|
+
)
|
|
49
|
+
notifyConfigUpdated()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fun updateFromResponse(response: String) {
|
|
53
|
+
try {
|
|
54
|
+
val json = JSONObject(response)
|
|
55
|
+
if (json.optInt("code", 0) != 1) {
|
|
56
|
+
Log.w(TAG, "Customer support API returned non-success code, using failure defaults")
|
|
57
|
+
applyFailureDefaults()
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
val data = json.optJSONObject("data")
|
|
62
|
+
if (data == null) {
|
|
63
|
+
Log.w(TAG, "Customer support API missing data, using failure defaults")
|
|
64
|
+
applyFailureDefaults()
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
isShowWhatsapp = parseBoolean(data, "isShowWhatsapp")
|
|
69
|
+
whatsAppNumber = data.optString("whatsAppNumber", "").trim()
|
|
70
|
+
.ifEmpty { DEFAULT_WHATSAPP_NUMBER }
|
|
71
|
+
watchCGMDemoUrl = data.optString("watchCGMDemoUrl", "").trim()
|
|
72
|
+
.ifEmpty { DEFAULT_DEMO_VIDEO_URL }
|
|
73
|
+
isLoaded = true
|
|
74
|
+
|
|
75
|
+
Log.d(
|
|
76
|
+
TAG,
|
|
77
|
+
"Customer support loaded | showWhatsapp=$isShowWhatsapp | demoUrl=$watchCGMDemoUrl"
|
|
78
|
+
)
|
|
79
|
+
notifyConfigUpdated()
|
|
80
|
+
} catch (e: Exception) {
|
|
81
|
+
Log.w(TAG, "Failed to parse customer support response: ${e.message}, using failure defaults")
|
|
82
|
+
applyFailureDefaults()
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private fun notifyConfigUpdated() {
|
|
87
|
+
mainHandler.post {
|
|
88
|
+
updateListeners.forEach { listener ->
|
|
89
|
+
try {
|
|
90
|
+
listener.invoke()
|
|
91
|
+
} catch (e: Exception) {
|
|
92
|
+
Log.w(TAG, "Customer support listener failed: ${e.message}")
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
fun effectiveWhatsAppNumber(): String =
|
|
99
|
+
whatsAppNumber.ifEmpty { DEFAULT_WHATSAPP_NUMBER }
|
|
100
|
+
|
|
101
|
+
fun shouldShowWhatsapp(): Boolean =
|
|
102
|
+
isLoaded && isShowWhatsapp && effectiveWhatsAppNumber().isNotEmpty()
|
|
103
|
+
|
|
104
|
+
fun getDemoVideoId(isForReconnect: Boolean): String {
|
|
105
|
+
val url = watchCGMDemoUrl.ifEmpty { DEFAULT_DEMO_VIDEO_URL }
|
|
106
|
+
extractYouTubeVideoId(url)?.let { return it }
|
|
107
|
+
return DEFAULT_DEMO_VIDEO_ID
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
fun getDemoVideoUrl(isForReconnect: Boolean): String =
|
|
111
|
+
watchCGMDemoUrl.ifEmpty { DEFAULT_DEMO_VIDEO_URL }
|
|
112
|
+
|
|
113
|
+
fun extractYouTubeVideoId(url: String): String? {
|
|
114
|
+
val trimmed = url.trim()
|
|
115
|
+
if (trimmed.isEmpty()) return null
|
|
116
|
+
|
|
117
|
+
val patterns = listOf(
|
|
118
|
+
Regex("(?:embed/|/v/|watch\\?v=|youtu\\.be/)([\\w-]{11})"),
|
|
119
|
+
Regex("^([\\w-]{11})$")
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
for (pattern in patterns) {
|
|
123
|
+
pattern.find(trimmed)?.groupValues?.getOrNull(1)?.let { return it }
|
|
124
|
+
}
|
|
125
|
+
return null
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private fun parseBoolean(json: JSONObject, key: String): Boolean {
|
|
129
|
+
if (!json.has(key)) return false
|
|
130
|
+
return when (val value = json.get(key)) {
|
|
131
|
+
is Boolean -> value
|
|
132
|
+
is Int -> value == 1
|
|
133
|
+
is String -> value.equals("true", ignoreCase = true) || value == "1"
|
|
134
|
+
else -> false
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
package com.mytatvarnsdk.utils
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.Intent
|
|
5
|
+
import android.net.Uri
|
|
6
|
+
import android.view.View
|
|
7
|
+
import android.widget.Toast
|
|
8
|
+
import androidx.appcompat.app.AppCompatActivity
|
|
9
|
+
import androidx.lifecycle.DefaultLifecycleObserver
|
|
10
|
+
import androidx.lifecycle.LifecycleOwner
|
|
11
|
+
import com.mytatvarnsdk.activity.VideoActivity
|
|
12
|
+
|
|
13
|
+
object ToolbarSupportHelper {
|
|
14
|
+
|
|
15
|
+
fun configureWhatsappButton(
|
|
16
|
+
context: Context,
|
|
17
|
+
btnWhatsapp: View,
|
|
18
|
+
onClickAnalytics: (() -> Unit)? = null
|
|
19
|
+
) {
|
|
20
|
+
if (CustomerSupportConfig.shouldShowWhatsapp()) {
|
|
21
|
+
btnWhatsapp.visibility = View.VISIBLE
|
|
22
|
+
btnWhatsapp.setOnClickListener {
|
|
23
|
+
onClickAnalytics?.invoke()
|
|
24
|
+
openWhatsApp(context, CustomerSupportConfig.effectiveWhatsAppNumber())
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
btnWhatsapp.visibility = View.GONE
|
|
28
|
+
btnWhatsapp.setOnClickListener(null)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
fun bindWhatsappButton(
|
|
33
|
+
activity: AppCompatActivity,
|
|
34
|
+
btnWhatsapp: View,
|
|
35
|
+
onClickAnalytics: (() -> Unit)? = null
|
|
36
|
+
) {
|
|
37
|
+
btnWhatsapp.setOnClickListener(null)
|
|
38
|
+
val refresh: () -> Unit = {
|
|
39
|
+
configureWhatsappButton(activity, btnWhatsapp, onClickAnalytics)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
refresh()
|
|
43
|
+
CustomerSupportConfig.addUpdateListener(refresh)
|
|
44
|
+
|
|
45
|
+
activity.lifecycle.addObserver(object : DefaultLifecycleObserver {
|
|
46
|
+
override fun onDestroy(owner: LifecycleOwner) {
|
|
47
|
+
CustomerSupportConfig.removeUpdateListener(refresh)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fun configureWatchDemoButton(
|
|
53
|
+
context: Context,
|
|
54
|
+
btnWatchDemo: View,
|
|
55
|
+
isForReconnect: Boolean,
|
|
56
|
+
onClickAnalytics: (() -> Unit)? = null
|
|
57
|
+
) {
|
|
58
|
+
btnWatchDemo.setOnClickListener {
|
|
59
|
+
onClickAnalytics?.invoke()
|
|
60
|
+
val intent = Intent(context, VideoActivity::class.java)
|
|
61
|
+
val videoId = CustomerSupportConfig.getDemoVideoId(isForReconnect)
|
|
62
|
+
intent.putExtra("VideoId", videoId)
|
|
63
|
+
context.startActivity(intent)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
fun openWhatsApp(context: Context, number: String) {
|
|
68
|
+
val cleanedNumber = number.replace(Regex("[^0-9]"), "")
|
|
69
|
+
if (cleanedNumber.isEmpty()) {
|
|
70
|
+
Toast.makeText(context, "WhatsApp number unavailable", Toast.LENGTH_SHORT).show()
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
val waUri = Uri.parse("https://wa.me/$cleanedNumber")
|
|
75
|
+
val intent = Intent(Intent.ACTION_VIEW, waUri)
|
|
76
|
+
try {
|
|
77
|
+
context.startActivity(intent)
|
|
78
|
+
} catch (e: Exception) {
|
|
79
|
+
e.printStackTrace()
|
|
80
|
+
Toast.makeText(context, "Error opening WhatsApp", Toast.LENGTH_SHORT).show()
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -48,6 +48,8 @@ class CustomTopUIView: UIView {
|
|
|
48
48
|
var onWhatsAppTapped: (() -> Void)?
|
|
49
49
|
var onCloseTapped: (() -> Void)?
|
|
50
50
|
|
|
51
|
+
private var customerSupportConfigObserver: NSObjectProtocol?
|
|
52
|
+
|
|
51
53
|
|
|
52
54
|
// For Interface Builder
|
|
53
55
|
override init(frame: CGRect) {
|
|
@@ -124,6 +126,21 @@ class CustomTopUIView: UIView {
|
|
|
124
126
|
whatsappButton.addTarget(self, action: #selector(whatsappButtonTapped), for: .touchUpInside)
|
|
125
127
|
closeButton.addTarget(self, action: #selector(closeButtonTapped), for: .touchUpInside)
|
|
126
128
|
|
|
129
|
+
customerSupportConfigObserver = NotificationCenter.default.addObserver(
|
|
130
|
+
forName: .customerSupportConfigDidUpdate,
|
|
131
|
+
object: nil,
|
|
132
|
+
queue: .main
|
|
133
|
+
) { [weak self] _ in
|
|
134
|
+
self?.refreshWhatsappVisibility()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
refreshWhatsappVisibility()
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
deinit {
|
|
142
|
+
if let customerSupportConfigObserver {
|
|
143
|
+
NotificationCenter.default.removeObserver(customerSupportConfigObserver)
|
|
127
144
|
}
|
|
128
145
|
}
|
|
129
146
|
|
|
@@ -131,6 +148,14 @@ class CustomTopUIView: UIView {
|
|
|
131
148
|
demoButton.isHidden = true
|
|
132
149
|
whatsappButton.isHidden = true
|
|
133
150
|
}
|
|
151
|
+
|
|
152
|
+
func setWhatsappVisible(_ isVisible: Bool) {
|
|
153
|
+
whatsappButton.isHidden = !isVisible
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
func refreshWhatsappVisibility() {
|
|
157
|
+
setWhatsappVisible(CustomerSupportConfig.shared.shouldShowWhatsapp())
|
|
158
|
+
}
|
|
134
159
|
|
|
135
160
|
@objc private func demoButtonTapped() {
|
|
136
161
|
onDemoTapped?()
|
|
@@ -471,6 +471,8 @@ RCT_EXPORT_METHOD(startCgmTracky:(NSString *)token envType:(NSString *)envType
|
|
|
471
471
|
|
|
472
472
|
[defaults synchronize];
|
|
473
473
|
|
|
474
|
+
[[CustomerSupportConfig shared] fetchCustomerSupportWithToken:token];
|
|
475
|
+
|
|
474
476
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
475
477
|
UIWindow *keyWindow = [UIApplication sharedApplication].delegate.window;
|
|
476
478
|
UIViewController *rootVC = keyWindow.rootViewController;
|
|
@@ -513,6 +515,8 @@ RCT_EXPORT_METHOD(reconnectCgmTracky:(NSString *)token envType:(NSString *)envT
|
|
|
513
515
|
|
|
514
516
|
[defaults synchronize];
|
|
515
517
|
|
|
518
|
+
[[CustomerSupportConfig shared] fetchCustomerSupportWithToken:token];
|
|
519
|
+
|
|
516
520
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
517
521
|
UIWindow *keyWindow = [UIApplication sharedApplication].delegate.window;
|
|
518
522
|
UIViewController *rootVC = keyWindow.rootViewController;
|
package/ios/Support/API.swift
CHANGED
|
@@ -23,8 +23,22 @@ let STAGE_ENC_IV = "9Ddyaf6rfywpiTvT"
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
let defaultToken = "ILtFcw+xtbuy8IgsBCSyD6nSpgZd5AOz7T+g3N8Tef/INZi+dxwPJhnBc2kfdq2e8Kw2yayjaKjuji64coUJsK7e4QcF7sqXCp3Cy5S2OVE+hONwCipkrn9d1yjsBWIDqfLK9ModJCWdigDj5ZeSwkWYSSeTEVoN3Dc2Y8cuqKUQvN9ZcNGmdRrXz2oo3rm4EHQrXPo1Ijufm0HfcqzSH/Gh0TC5gFKjde/GEXIm5Z2Ju1/TTXVSJg/zxNuOF4iUKNEh4UIFUYxYpnqlALRCdF75J+9WAZ7/LBGyB1Wrx+D7bsrzRiQ5sCTwxE3TCM3s66lYJizX22VIzYKOIrJ6GTOYGTINHeIJKEPEvFceR+cG54ez15V1r77ErQElevItD3xIGe0uDezfnixJYPxPhSEOPOyIpxUFInXBRdGjllHPIevzBqqHeP76nz+1U7mFNs1kofugN+5huT3/tCifTQqFyWuxD+VIhl0UJxhxPMbBgoryANgKCToWrK2FqdJwBtZKwCj3S+yp0rff0fwrbMXXsYytJyVLLY2oNviHtzDa/kih0AnMA3vEbqYkf1PQ6LZv+AmtpNYHKh7kMDrhVE3wVxH4+ga0+sfuxYgfiZXCoQW7yY0wOZTiFbgvL2TQflDZR6ttK5abtyKYV4gl5KqbFLZW+d4pKLQoZb02NbJc+5h5gAH2VclTJc6fbkd0qIWuXyqGIBEc2uYrNl2v3vmVvbcGevSqb900ozo6SbFccQLjLcEon+okmgBIDPvBEZFj8fZgQV4z8/yzayDcfqZQPc9Wrw8JNrFLCd8emvo7QHFfGttnIsAtmR8Yp3x49sjEn3hFW6nEKl9FRtRT1r3LzHmIdokL5tz3nO/T3FzLn5sqfp5QBJKKK2dgJdmAz0KC6vKtJ0PtVR4shL7pqjoZuJimFObYKyQbQudW7gLH8WjqORNG2dsplOLzDQ0y7nQdQ0tWrLJtnAch0p5PyTXtunlkNWeuzrldkqVMTUPaAtGcEnmS4RFncD3C6sq9V6lpBKLdrh99vnH3EX81DTH2Hrqm0bN5Tl3UqzUJ7n/JQCR3phDmOo+Uk81y3z3ikiGZZpZikN7c3DtSP34Vc+cNUosWrChqj1gLL4Eg/jMDxE4+bdAGr03ALxEAj2uLGEsDaZRuio6e8/iMcA0z3oqhtAxQ0nU1ivAK7cHeddjRFtvrNb0l+TgrcQI9UVffMOoGDEfAQNUpT2+R5dIysw=="
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
|
|
27
|
+
func currentAuthToken() -> String {
|
|
28
|
+
UserDefaults.standard.string(forKey: "authToken") ?? defaultToken
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
func currentEnvType() -> String {
|
|
32
|
+
UserDefaults.standard.string(forKey: "envType") ?? "uat"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
func normalizedCipherText(_ response: String) -> String {
|
|
36
|
+
var text = response.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
37
|
+
if text.hasPrefix("\""), text.hasSuffix("\""), text.count >= 2 {
|
|
38
|
+
text = String(text.dropFirst().dropLast())
|
|
39
|
+
}
|
|
40
|
+
return text
|
|
41
|
+
}
|
|
28
42
|
|
|
29
43
|
/*TatvaEncryptionConfig {
|
|
30
44
|
const val STAGE_BASE_URL = "https://api-feature2.mytatva.in/api/v8"
|
|
@@ -99,7 +113,7 @@ class API {
|
|
|
99
113
|
func postCGMData(
|
|
100
114
|
data: Payload,
|
|
101
115
|
environment: TatvaEnvironment,
|
|
102
|
-
token: String =
|
|
116
|
+
token: String = currentAuthToken(),
|
|
103
117
|
encryptionKey: String = PROD_ENC_KEY,
|
|
104
118
|
encryptionIv: String = PROD_ENC_IV,
|
|
105
119
|
onSuccess: @escaping () -> Void,
|
|
@@ -137,7 +151,8 @@ class API {
|
|
|
137
151
|
print("===>Decrypted (for verification): \(decrypted)")
|
|
138
152
|
}
|
|
139
153
|
|
|
140
|
-
let
|
|
154
|
+
let env = currentEnvType()
|
|
155
|
+
let urlString = (env.lowercased() == "uat" ? STAGE_BASE_URL : PROD_BASE_URL) + "/cgm/logs"
|
|
141
156
|
// let urlString = (environment == .stage ? STAGE_BASE_URL : PROD_BASE_URL) + "/cgm/logs"
|
|
142
157
|
guard let url = URL(string: urlString) else {
|
|
143
158
|
throw URLError(.badURL)
|
|
@@ -146,7 +161,7 @@ class API {
|
|
|
146
161
|
var request = URLRequest(url: url)
|
|
147
162
|
request.httpMethod = "POST"
|
|
148
163
|
request.timeoutInterval = 30
|
|
149
|
-
request.setValue(
|
|
164
|
+
request.setValue(env.lowercased() == "uat" ? STAGE_API_KEY : PROD_API_KEY, forHTTPHeaderField: "api-key")
|
|
150
165
|
// request.setValue(environment == .stage ? STAGE_API_KEY : PROD_API_KEY, forHTTPHeaderField: "api-key")
|
|
151
166
|
request.setValue(token, forHTTPHeaderField: "token")
|
|
152
167
|
request.setValue("text/plain", forHTTPHeaderField: "Content-Type")
|
|
@@ -172,7 +187,8 @@ class API {
|
|
|
172
187
|
|
|
173
188
|
if let data = data, let responseStr = String(data: data, encoding: .utf8) {
|
|
174
189
|
print("===>Server Response: \(responseStr)")
|
|
175
|
-
|
|
190
|
+
let cipherText = normalizedCipherText(responseStr)
|
|
191
|
+
if let decrypted = Crypto.shared.getDecryptedData(cipherText: cipherText, encryptionKey: encryptionKey, encryptionIv: encryptionIv) {
|
|
176
192
|
print("===>Decrypted post cgm data response (for verification): \(decrypted)")
|
|
177
193
|
}
|
|
178
194
|
}
|
|
@@ -203,9 +219,9 @@ class API {
|
|
|
203
219
|
encryptionKey: String = PROD_ENC_KEY,
|
|
204
220
|
encryptionIv: String = PROD_ENC_IV) {
|
|
205
221
|
if sensorId.isEmpty { return }
|
|
206
|
-
|
|
207
|
-
print("envType: \(
|
|
208
|
-
let urlString = (
|
|
222
|
+
let env = currentEnvType()
|
|
223
|
+
print("envType: \(env.lowercased())")
|
|
224
|
+
let urlString = (env.lowercased() == "uat" ? STAGE_BASE_URL : PROD_BASE_URL) + "/cgm/connection"
|
|
209
225
|
//let urlString = (environment == .stage ? STAGE_BASE_URL : PROD_BASE_URL) + "/cgm/connection"
|
|
210
226
|
let url = URL(string: urlString)!
|
|
211
227
|
var request = URLRequest(url: url)
|
|
@@ -214,13 +230,14 @@ class API {
|
|
|
214
230
|
|
|
215
231
|
// Set headers
|
|
216
232
|
request.addValue("text/plain", forHTTPHeaderField: "Content-Type")
|
|
217
|
-
request.setValue(
|
|
233
|
+
request.setValue(env.lowercased() == "uat" ? STAGE_API_KEY : PROD_API_KEY, forHTTPHeaderField: "api-key")
|
|
218
234
|
//request.setValue(environment == .stage ? STAGE_API_KEY : PROD_API_KEY, forHTTPHeaderField: "api-key")
|
|
219
|
-
|
|
235
|
+
let token = currentAuthToken()
|
|
236
|
+
request.addValue(token, forHTTPHeaderField: "token")
|
|
220
237
|
print("===>url:", urlString)
|
|
221
238
|
print("===>api-key:", PROD_API_KEY)
|
|
222
239
|
print("===>httpmMethod:","POST")
|
|
223
|
-
print("===>ios token:",
|
|
240
|
+
print("===>ios token:", token)
|
|
224
241
|
// Set request body
|
|
225
242
|
let json: [String: Any] = [
|
|
226
243
|
"sensorId": sensorId,
|
|
@@ -259,7 +276,8 @@ class API {
|
|
|
259
276
|
}
|
|
260
277
|
if let responseString = String(data: data, encoding: .utf8) {
|
|
261
278
|
print("===>Server Response: \(responseString)")
|
|
262
|
-
|
|
279
|
+
let cipherText = normalizedCipherText(responseString)
|
|
280
|
+
if let decrypted = Crypto.shared.getDecryptedData(cipherText: cipherText, encryptionKey: encryptionKey, encryptionIv: encryptionIv) {
|
|
263
281
|
print("===>Decrypted connection api response (for verification): \(decrypted)")
|
|
264
282
|
}
|
|
265
283
|
}
|
|
@@ -330,6 +348,84 @@ class API {
|
|
|
330
348
|
|
|
331
349
|
}*/
|
|
332
350
|
|
|
351
|
+
func fetchCustomerSupportDetails(
|
|
352
|
+
token: String = currentAuthToken(),
|
|
353
|
+
encryptionKey: String = PROD_ENC_KEY,
|
|
354
|
+
encryptionIv: String = PROD_ENC_IV,
|
|
355
|
+
onSuccess: @escaping (String) -> Void,
|
|
356
|
+
onFailure: @escaping () -> Void
|
|
357
|
+
) {
|
|
358
|
+
guard !token.isEmpty else {
|
|
359
|
+
print("===>fetchCustomerSupportDetails: empty token")
|
|
360
|
+
onFailure()
|
|
361
|
+
return
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
let env = currentEnvType()
|
|
365
|
+
let urlString = (env.lowercased() == "uat" ? STAGE_BASE_URL : PROD_BASE_URL) + "/helper/customer_support_details"
|
|
366
|
+
|
|
367
|
+
guard let url = URL(string: urlString) else {
|
|
368
|
+
print("===>fetchCustomerSupportDetails: Invalid URL")
|
|
369
|
+
onFailure()
|
|
370
|
+
return
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
var request = URLRequest(url: url)
|
|
374
|
+
request.httpMethod = "GET"
|
|
375
|
+
request.setValue(env.lowercased() == "uat" ? STAGE_API_KEY : PROD_API_KEY, forHTTPHeaderField: "api-key")
|
|
376
|
+
request.setValue(token, forHTTPHeaderField: "token")
|
|
377
|
+
|
|
378
|
+
print("===>fetchCustomerSupportDetails URL:", urlString)
|
|
379
|
+
print("===>fetchCustomerSupportDetails env:", env)
|
|
380
|
+
print("===>fetchCustomerSupportDetails usingDefaultToken:", token == defaultToken)
|
|
381
|
+
|
|
382
|
+
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
|
383
|
+
if let error = error {
|
|
384
|
+
print("===>fetchCustomerSupportDetails Error: \(error.localizedDescription)")
|
|
385
|
+
DispatchQueue.main.async { onFailure() }
|
|
386
|
+
return
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
let statusCode = (response as? HTTPURLResponse)?.statusCode ?? 0
|
|
390
|
+
if statusCode > 0 {
|
|
391
|
+
print("===>fetchCustomerSupportDetails HTTP Status: \(statusCode)")
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
guard let data = data, let responseString = String(data: data, encoding: .utf8) else {
|
|
395
|
+
print("===>fetchCustomerSupportDetails: No data received")
|
|
396
|
+
DispatchQueue.main.async { onFailure() }
|
|
397
|
+
return
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
print("===>fetchCustomerSupportDetails Server Response: \(responseString)")
|
|
401
|
+
|
|
402
|
+
let cipherText = normalizedCipherText(responseString)
|
|
403
|
+
if let decrypted = Crypto.shared.getDecryptedData(
|
|
404
|
+
cipherText: cipherText,
|
|
405
|
+
encryptionKey: encryptionKey,
|
|
406
|
+
encryptionIv: encryptionIv
|
|
407
|
+
) {
|
|
408
|
+
print("===>fetchCustomerSupportDetails Decrypted: \(decrypted)")
|
|
409
|
+
if statusCode >= 400 {
|
|
410
|
+
print("===>fetchCustomerSupportDetails: API error \(statusCode)")
|
|
411
|
+
DispatchQueue.main.async { onFailure() }
|
|
412
|
+
return
|
|
413
|
+
}
|
|
414
|
+
DispatchQueue.main.async { onSuccess(decrypted) }
|
|
415
|
+
return
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if responseString.contains("\"code\"") {
|
|
419
|
+
DispatchQueue.main.async { onSuccess(responseString) }
|
|
420
|
+
return
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
print("===>fetchCustomerSupportDetails: Decryption failed")
|
|
424
|
+
DispatchQueue.main.async { onFailure() }
|
|
425
|
+
}
|
|
426
|
+
task.resume()
|
|
427
|
+
}
|
|
428
|
+
|
|
333
429
|
func verifyDevice(
|
|
334
430
|
sensorId: String,
|
|
335
431
|
encryptionKey: String = PROD_ENC_KEY,
|
|
@@ -337,7 +433,9 @@ class API {
|
|
|
337
433
|
onSuccess: @escaping (Int, Bool, String) -> Void,
|
|
338
434
|
onFailure: @escaping () -> Void
|
|
339
435
|
) {
|
|
340
|
-
let
|
|
436
|
+
let env = currentEnvType()
|
|
437
|
+
let token = currentAuthToken()
|
|
438
|
+
let urlString = (env.lowercased() == "uat" ? STAGE_BASE_URL : PROD_BASE_URL) + "/helper/device_verification?deviceId=\(sensorId)&deviceType=CGM&vendor=diasens"
|
|
341
439
|
|
|
342
440
|
guard let url = URL(string: urlString) else {
|
|
343
441
|
print("===>verifyDevice: Invalid URL")
|
|
@@ -347,11 +445,11 @@ class API {
|
|
|
347
445
|
|
|
348
446
|
var request = URLRequest(url: url)
|
|
349
447
|
request.httpMethod = "GET"
|
|
350
|
-
request.setValue(
|
|
351
|
-
request.setValue(
|
|
448
|
+
request.setValue(env.lowercased() == "uat" ? STAGE_API_KEY : PROD_API_KEY, forHTTPHeaderField: "api-key")
|
|
449
|
+
request.setValue(token, forHTTPHeaderField: "token")
|
|
352
450
|
|
|
353
451
|
print("===>verifyDevice URL:", urlString)
|
|
354
|
-
print("===>verifyDevice token:",
|
|
452
|
+
print("===>verifyDevice token:", token)
|
|
355
453
|
|
|
356
454
|
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
|
357
455
|
if let error = error {
|
|
@@ -368,7 +466,8 @@ class API {
|
|
|
368
466
|
|
|
369
467
|
print("===>verifyDevice Server Response: \(responseString)")
|
|
370
468
|
|
|
371
|
-
|
|
469
|
+
let cipherText = normalizedCipherText(responseString)
|
|
470
|
+
guard let decrypted = Crypto.shared.getDecryptedData(cipherText: cipherText, encryptionKey: encryptionKey, encryptionIv: encryptionIv) else {
|
|
372
471
|
print("===>verifyDevice: Decryption failed")
|
|
373
472
|
DispatchQueue.main.async { onFailure() }
|
|
374
473
|
return
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CustomTopViewSupportHelper.swift
|
|
3
|
+
// MyTatvaCare
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import UIKit
|
|
7
|
+
|
|
8
|
+
enum CustomTopViewSupportHelper {
|
|
9
|
+
static func configureWhatsapp(customTopView: CustomTopUIView) {
|
|
10
|
+
customTopView.refreshWhatsappVisibility()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static func bindDemoAction(
|
|
14
|
+
customTopView: CustomTopUIView,
|
|
15
|
+
isForReconnect: Bool,
|
|
16
|
+
presenter: UIViewController,
|
|
17
|
+
analyticsHandler: (() -> Void)? = nil
|
|
18
|
+
) {
|
|
19
|
+
customTopView.onDemoTapped = {
|
|
20
|
+
analyticsHandler?()
|
|
21
|
+
|
|
22
|
+
let payload = ["status": "cgm_watch_demo_clicked"]
|
|
23
|
+
NotificationCenter.default.post(
|
|
24
|
+
name: Notification.Name("cgmwatchdemoclicked"),
|
|
25
|
+
object: nil,
|
|
26
|
+
userInfo: payload
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
let webVC = WebViewController()
|
|
30
|
+
webVC.modalPresentationStyle = .formSheet
|
|
31
|
+
webVC.videoURL = URL(string: CustomerSupportConfig.shared.demoVideoURL(isForReconnect: isForReconnect))
|
|
32
|
+
presenter.present(webVC, animated: true, completion: nil)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static func bindWhatsappAction(
|
|
37
|
+
customTopView: CustomTopUIView,
|
|
38
|
+
navigationController: UINavigationController?
|
|
39
|
+
) {
|
|
40
|
+
customTopView.onWhatsAppTapped = {
|
|
41
|
+
let payload = [
|
|
42
|
+
"screen_name": "connection journey page",
|
|
43
|
+
"status": "cgm_WA_support_clicked"
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
NotificationCenter.default.post(
|
|
47
|
+
name: Notification.Name("cgmWAsupportclicked"),
|
|
48
|
+
object: nil,
|
|
49
|
+
userInfo: payload
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
CustomerSupportConfig.shared.openWhatsApp()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|