diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/PromoBannerV2Response.kt b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/PromoBannerV2Response.kt new file mode 100644 index 0000000000..23b62757cb --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/promotion/models/PromoBannerV2Response.kt @@ -0,0 +1,10 @@ +package com.tangem.datasource.api.promotion.models + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class PromoBannerV2Response( + @Json(name = "promotions") + val promotions: List, +) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt index a3b38cb1f0..f9bdbc2aa6 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechApi.kt @@ -2,6 +2,7 @@ package com.tangem.datasource.api.tangemTech import com.tangem.datasource.api.common.response.ApiResponse import com.tangem.datasource.api.promotion.models.PromoBannerResponse +import com.tangem.datasource.api.promotion.models.PromoBannerV2Response import com.tangem.datasource.api.promotion.models.StoryContentResponse import com.tangem.datasource.api.tangemTech.models.* import com.tangem.datasource.api.tangemTech.models.account.GetWalletAccountsResponse @@ -188,6 +189,12 @@ interface TangemTechApi { @Query("programName") name: String, @Header("Cache-Control") cacheControl: String = "max-age=600", ): ApiResponse + + @GET("/v2/promotion") + suspend fun getPromoBannersV2( + @Query("walletId") walletId: String, + @Header("Cache-Control") cacheControl: String = "max-age=600", + ): ApiResponse // endregion /** diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index 2a9bd1b3eb..4175f06e1c 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -899,6 +899,9 @@ Krypto mit SEPA kaufen Trage dich in die Warteliste ein und erhalte eine Zahlungskarte, die es so noch nie gab. Tangem Visa Card + Bedingungen + Zahlen Sie mindestens $100 ein, halten Sie den Betrag 30 Tage und erhalten Sie $10. + Yield-Mode-Kampagne Du musst einen einzigen Zugangscode einrichten, um alle deine Geräte zu schützen Schützen Du kannst später auf jeder Karte oder Ring einen individuellen Zugangscode einrichten diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index 124b0453e1..c3b8bb8a6a 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -907,6 +907,9 @@ Comprar criptomonedas con SEPA Únete a la lista de espera y consigue una tarjeta de pago como ninguna otra. Tangem Visa Card + Términos y condiciones + Deposite $100 o más, manténgalo durante 30 días y reciba $10. + ¡Únase a la campaña Yield Mode! Configure un código de acceso único para proteger todos sus dispositivos. Proteger Puede configurar un código de acceso individual en cada tarjeta más adelante diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 9e7bbf5db8..d88cdd4e57 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -907,6 +907,9 @@ Acheter des cryptomonnaies avec SEPA Rejoignez la liste d’attente et obtenez une carte de paiement pas comme les autres. Tangem Visa Card + Conditions générales + Déposez 100 $ ou plus, conservez le dépôt pendant 30 jours et recevez 10 $. + Rejoignez la campagne Yield Mode ! Vous devez définir un seul code d\'accès pour protéger tous vos appareils. Protéger Vous pourrez définir un code d\'accès individuel sur chaque carte plus tard @@ -1468,7 +1471,7 @@ Geler Votre carte est gelée. Obtenir de l\'aide - Raison : %s + Raison: %s %s · %s MCC %s Autre diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index bbdf1ef746..770eb98276 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -894,6 +894,9 @@ SEPAで暗号資産を購入 事前申し込み受付中。他にない特別なカードを、いち早く体験しよう。 Tangem Visaカード + 利用規約 + 100ドル以上を入金し、30日間保持すると、10ドルを受け取れます。 + Yield Mode キャンペーンに参加しよう! すべてのデバイスを保護するには、単一のアクセスコードを設定してください。 保護する 後で各カードおよびリングに個別のアクセスコードを設定できます。 diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 2e53a41bee..b0e42bdf47 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -925,6 +925,9 @@ Покупайте крипту через SEPA Присоединяйтесь к списку ожидания и получите уникальную платёжную карту, не похожую ни на одну другую. Tangem Visa Card + Условия программы + Внесите депозит от $100, удерживайте его 30 дней и получите бонус $10 + Подключите Режим доходности! Установите единый код доступа для защиты всех ваших карт или колец Защита Установите индивидуальный код доступа для каждой карты или кольца позже. diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml index 8ff96286b1..67360c1ce3 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -909,6 +909,9 @@ Купуйте криптовалюту через SEPA Приєднуйтесь до списку очікування та отримайте унікальну платіжну картку, якої ще не було. Tangem Visa Card + Умови та положення + Внесіть депозит від $100, утримуйте його 30 днів та отримайте $10. + Кампанія Yield Mode! Налаштуйте єдиний код доступу для захисту всіх ваших карток або кілець Захист Встановіть індивідуальний код доступу для кожної картки або кільця пізніше. diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 39efffd2f0..ed8c132108 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -86,6 +86,8 @@ Send only %1$s (%2$s) from %3$s network to this address. Using other tokens and networks may result in loss of funds. Default Legacy + Try to reset biometrics on your device or contact support + Authentication error How to scan Request support Try again @@ -908,6 +910,9 @@ Buy Crypto with SEPA Join the waitlist and get a payment card unlike any other Tangem Visa Card + Terms and conditions + Deposit $100+, hold for 30 days, get $10 + Join the Yield Mode Campaign! Set up a single access code to protect all your devices. Protect Set an individual access code for each card or ring later. diff --git a/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt b/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt index 31133bb96f..625fdc2535 100644 --- a/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt +++ b/data/promo/src/main/java/com/tangem/data/promo/DefaultPromoRepository.kt @@ -66,6 +66,11 @@ internal class DefaultPromoRepository( PromoId.OnePlusOne -> { val isActive = getOnePlusOnePromoBanner()?.isActive == true + isActive && shouldShow + } + PromoId.YieldPromo -> { + val isActive = getYieldPromoBanner(userWalletId)?.isActive == true + isActive && shouldShow } } @@ -79,6 +84,7 @@ internal class DefaultPromoRepository( PromoId.VisaPresale -> flowOf(false) PromoId.BlackFriday -> flowOf(false) PromoId.OnePlusOne -> flowOf(false) + PromoId.YieldPromo -> flowOf(false) } } @@ -190,12 +196,22 @@ internal class DefaultPromoRepository( }.getOrNull() } + private suspend fun getYieldPromoBanner(userWalletId: UserWalletId): PromoBanner? { + return runCatching(dispatchers.io) { + val response = tangemApi.getPromoBannersV2(userWalletId.stringValue).getOrThrow() + val yieldPromotion = response.promotions.find { it.name == YIELD_PROMO_NAME } + ?: return@runCatching null + promoBannerConverter.convert(yieldPromotion) + }.getOrNull() + } + private companion object { const val SEPA_NAME = "sepa" const val VISA_NAME = "visa-waitlist" const val BLACK_FRIDAY_NAME = "black-friday" const val MOONPAY_NAME = "moonpay" const val ONE_PLUS_ONE_NAME = "one-plus-one" + const val YIELD_PROMO_NAME = "promo-yield" const val STORIES_LOAD_DELAY = 1000L } } \ No newline at end of file diff --git a/domain/promo/models/src/main/java/com/tangem/domain/promo/models/PromoBanner.kt b/domain/promo/models/src/main/java/com/tangem/domain/promo/models/PromoBanner.kt index 9f8055dc60..ee31586b29 100644 --- a/domain/promo/models/src/main/java/com/tangem/domain/promo/models/PromoBanner.kt +++ b/domain/promo/models/src/main/java/com/tangem/domain/promo/models/PromoBanner.kt @@ -31,4 +31,5 @@ enum class PromoId { VisaPresale, BlackFriday, OnePlusOne, + YieldPromo, } \ No newline at end of file diff --git a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt index 5cab5b1cde..7f6f41114d 100644 --- a/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt +++ b/domain/promo/src/main/java/com/tangem/domain/promo/ShouldShowPromoWalletUseCase.kt @@ -33,6 +33,7 @@ class ShouldShowPromoWalletUseCase( PromoId.VisaPresale, PromoId.BlackFriday, PromoId.OnePlusOne, + PromoId.YieldPromo, -> true PromoId.Sepa -> { val walletFirstUsageDate = settingsRepository.getWalletFirstUsageDate() diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/PromoAnalyticsEvent.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/PromoAnalyticsEvent.kt index 3d3f0fbdb1..df7fde5ad2 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/PromoAnalyticsEvent.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/analytics/PromoAnalyticsEvent.kt @@ -60,5 +60,6 @@ sealed class PromoAnalyticsEvent( Sepa("Sepa"), BlackFriday("Black Friday"), OnePlusOne("One-Plus-One"), + YieldPromo("Yield Promo"), } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt index 2f90546c14..55dd5e9a5c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt @@ -108,6 +108,8 @@ internal interface WalletWarningsClickIntents { fun onDenyPermissions() fun onFinishWalletActivationClick(isBackupExists: Boolean) + + fun onYieldPromoTermsAndConditionsClick() } @Suppress("LargeClass", "LongParameterList", "TooManyFunctions") @@ -337,6 +339,11 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( program = Program.OnePlusOne, action = PromotionBannerClicked.BannerAction.Closed(), ) + PromoId.YieldPromo -> PromotionBannerClicked( + source = AnalyticsParam.ScreensSources.Main, + program = Program.YieldPromo, + action = PromotionBannerClicked.BannerAction.Closed(), + ) }, ) @@ -394,6 +401,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( ) urlOpener.openUrl(ONE_PLUS_ONE_PROMO_LINK) } + PromoId.YieldPromo -> Unit // banner is not clickable, only terms and conditions button } } @@ -611,6 +619,17 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( } } + override fun onYieldPromoTermsAndConditionsClick() { + analyticsEventHandler.send( + PromotionBannerClicked( + source = AnalyticsParam.ScreensSources.Main, + program = Program.YieldPromo, + action = PromotionBannerClicked.BannerAction.Clicked(), + ), + ) + urlOpener.openUrl(YIELD_PROMO_TERMS_LINK) + } + private companion object { const val VISA_PROMO_LINK = "https://tangem.com/en/cardwaitlist/?utm_source=tangem-app-banner" + "&utm_medium=banner" + @@ -625,5 +644,6 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( "&utm_source=tangem-app-banner" + "&utm_medium=banner" + "&utm_campaign=BOGO50" + const val YIELD_PROMO_TERMS_LINK = "https://tangem.com/docs/yield-mode-toc.html" } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt index 62dc30de88..3852ada00e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt @@ -66,6 +66,10 @@ internal class WalletWarningsAnalyticsSender @Inject constructor( source = AnalyticsParam.ScreensSources.Main, program = Program.OnePlusOne, ) + is WalletNotification.YieldPromo -> NoticePromotionBanner( + source = AnalyticsParam.ScreensSources.Main, + program = Program.YieldPromo, + ) is WalletNotification.ReferralPromo -> MainScreen.ReferralPromo() is WalletNotification.VisaPresalePromo -> VisaWaitlistPromo() is WalletNotification.UnlockWallets -> null // See [SelectedWalletAnalyticsSender] diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt index ed279ff217..fe3861e0c2 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetMultiWalletWarningsFactory.kt @@ -96,6 +96,8 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( notificationsRepository.getShouldShowNotification(NotificationId.EnablePushesReminderNotification.key) .distinctUntilChanged(), getAccessCodeSkippedUseCase(userWallet.walletId).distinctUntilChanged(), + shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.YieldPromo) + .distinctUntilChanged(), ) { array -> array } .combine(tokenListFlow()) { array, any: Any -> arrayOf(any).plus(elements = array) } .map { array -> @@ -108,6 +110,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( val shouldShowOnePlusOnePromo = array[4] as Boolean val shouldShowEnablePushesReminderNotification = array[5] as Boolean val shouldAccessCodeSkipped = array[6] as Boolean + val shouldShowYieldPromo = array[7] as Boolean buildList { addUsedOutdatedDataNotification(totalFiatBalance) @@ -123,6 +126,8 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( addOnePlusOnePromoNotification(clickIntents, shouldShowOnePlusOnePromo) + addYieldPromoNotification(clickIntents, shouldShowYieldPromo) + addInformationalNotifications(userWallet, cardTypesResolver, flattenCurrencies, clickIntents) addWarningNotifications(cardTypesResolver, flattenCurrencies, isNeedToBackup, clickIntents) @@ -287,6 +292,19 @@ internal class GetMultiWalletWarningsFactory @Inject constructor( ) } + private fun MutableList.addYieldPromoNotification( + clickIntents: WalletClickIntents, + shouldShowPromo: Boolean, + ) { + addIf( + element = WalletNotification.YieldPromo( + onCloseClick = { clickIntents.onClosePromoClick(promoId = PromoId.YieldPromo) }, + onTermsAndConditionsClick = { clickIntents.onYieldPromoTermsAndConditionsClick() }, + ), + condition = shouldShowPromo, + ) + } + // private fun MutableList.addYieldSupplyNotifications( // flattenCurrencies: Lce>, // ) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt index 5d67cf05e5..9abf719a45 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt @@ -396,6 +396,23 @@ sealed class WalletNotification(val config: NotificationConfig) { ), ) + data class YieldPromo( + val onCloseClick: () -> Unit, + val onTermsAndConditionsClick: () -> Unit, + ) : WalletNotification( + config = NotificationConfig( + title = resourceReference(R.string.notification_yield_promo_title), + subtitle = resourceReference(R.string.notification_yield_promo_text), + iconResId = R.drawable.ic_yield_promo_36, + onCloseClick = onCloseClick, + buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig( + text = resourceReference(R.string.notification_yield_promo_button), + onClick = onTermsAndConditionsClick, + ), + iconSize = 36.dp, + ), + ) + data class PushNotifications( val onCloseClick: () -> Unit, val onEnabledClick: () -> Unit, diff --git a/features/wallet/impl/src/main/res/drawable/ic_yield_promo_36.xml b/features/wallet/impl/src/main/res/drawable/ic_yield_promo_36.xml new file mode 100644 index 0000000000..4a4921466d --- /dev/null +++ b/features/wallet/impl/src/main/res/drawable/ic_yield_promo_36.xml @@ -0,0 +1,15 @@ + + + +