Updated on 2026-08-14

This commit is contained in:
Tangem 2026-07-01 14:50:27 +05:00
parent 4caff5dc00
commit dd0a223583
5 changed files with 33 additions and 2 deletions

View file

@ -495,6 +495,8 @@ internal class ChildFactory @Inject constructor(
context = context, context = context,
params = UsedeskComponent.Params( params = UsedeskComponent.Params(
userWalletId = route.walletMetaInfo.userWalletId?.stringValue, userWalletId = route.walletMetaInfo.userWalletId?.stringValue,
source = route.source,
prefilledMessage = route.prefilledMessage,
), ),
componentFactory = usedeskComponentFactory, componentFactory = usedeskComponentFactory,
) )

View file

@ -100,9 +100,19 @@ sealed class AppRoute(val path: String) : Route {
val userWalletId: UserWalletId, val userWalletId: UserWalletId,
) : AppRoute(path = "/details/security") ) : AppRoute(path = "/details/security")
/**
* Support chat (Usedesk) screen.
*
* @property walletMetaInfo wallet meta info; its user wallet id is sent to Usedesk as the client email
* @property source source of the chat opening (Settings by default, Swap for FR-02). Drives both
* analytics and the Usedesk additional fields mapped by the component.
* @property prefilledMessage optional message sent to the chat on behalf of the user right after init
*/
@Serializable @Serializable
data class Usedesk( data class Usedesk(
val walletMetaInfo: WalletMetaInfo, val walletMetaInfo: WalletMetaInfo,
val source: AnalyticsParam.ScreensSources = AnalyticsParam.ScreensSources.Settings,
val prefilledMessage: String? = null,
) : AppRoute(path = "/usedesk/${walletMetaInfo.userWalletId}") ) : AppRoute(path = "/usedesk/${walletMetaInfo.userWalletId}")
@Serializable @Serializable

View file

@ -13,5 +13,6 @@ dependencies {
/** Core */ /** Core */
implementation(projects.core.decompose) implementation(projects.core.decompose)
implementation(projects.core.ui) implementation(projects.core.ui)
implementation(projects.core.analytics.models)
} }

View file

@ -1,5 +1,6 @@
package com.tangem.feature.usedesk.api package com.tangem.feature.usedesk.api
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.core.ui.decompose.ComposableContentComponent
@ -8,6 +9,13 @@ interface UsedeskComponent : ComposableContentComponent {
data class Params( data class Params(
/** User wallet id (hex string) sent to Usedesk as the client email to identify the user. */ /** User wallet id (hex string) sent to Usedesk as the client email to identify the user. */
val userWalletId: String? = null, val userWalletId: String? = null,
/**
* Source of the chat opening. Drives the analytics source and the Usedesk additional fields,
* which the component maps internally (e.g. [AnalyticsParam.ScreensSources.Swap] -> `swap`).
*/
val source: AnalyticsParam.ScreensSources = AnalyticsParam.ScreensSources.Settings,
/** Optional message sent to the chat on behalf of the user right after initialization. */
val prefilledMessage: String? = null,
) )
interface Factory : ComponentFactory<Params, UsedeskComponent> interface Factory : ComponentFactory<Params, UsedeskComponent>

View file

@ -2,7 +2,7 @@ package com.tangem.feature.usedesk.model
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AnalyticsParam.ScreensSources
import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.model.ParamsContainer
@ -52,6 +52,8 @@ internal class UsedeskModel @Inject constructor(
channelId = CHANNEL_ID, channelId = CHANNEL_ID,
clientId = clientId, clientId = clientId,
clientEmail = params.userWalletId, clientEmail = params.userWalletId,
clientInitMessage = params.prefilledMessage,
additionalFields = additionalFieldsFor(params.source),
), ),
) )
} }
@ -61,7 +63,7 @@ internal class UsedeskModel @Inject constructor(
if (isScreenLoadEventSent) return if (isScreenLoadEventSent) return
isScreenLoadEventSent = true isScreenLoadEventSent = true
analyticsEventHandler.send( analyticsEventHandler.send(
UsedeskAnalyticsEvents.ChatScreenOpened(source = AnalyticsParam.ScreensSources.Settings), UsedeskAnalyticsEvents.ChatScreenOpened(source = params.source),
) )
} }
@ -87,6 +89,11 @@ internal class UsedeskModel @Inject constructor(
super.onDestroy() super.onDestroy()
} }
private fun additionalFieldsFor(source: ScreensSources): Map<Long, String> = when (source) {
ScreensSources.Swap -> mapOf(SWAP_ADDITIONAL_FIELD_ID to SWAP_ADDITIONAL_FIELD_VALUE)
else -> emptyMap()
}
private suspend fun getOrCreateClientId(): String { private suspend fun getOrCreateClientId(): String {
var clientId = "" var clientId = ""
appPreferencesStore.editData { preferences -> appPreferencesStore.editData { preferences ->
@ -105,5 +112,8 @@ internal class UsedeskModel @Inject constructor(
const val URL_CHAT_API = "https://ud.tangem.org" const val URL_CHAT_API = "https://ud.tangem.org"
const val COMPANY_ID = "2" const val COMPANY_ID = "2"
const val CHANNEL_ID = "54" const val CHANNEL_ID = "54"
const val SWAP_ADDITIONAL_FIELD_ID = 245L
const val SWAP_ADDITIONAL_FIELD_VALUE = "swap"
} }
} }