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 739514fe49..6d851c0067 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 @@ -191,12 +191,12 @@ interface TangemTechApi { suspend fun getPromoBannerDisplays( @Query("walletId") walletId: String, @Query("placeholder") placeholder: String, - @Query("locale") locale: String, + @Query("lang") languageISOCode: String, ): ApiResponse - @PATCH("v1/displays/{displayId}") + @PATCH("v1/banner/displays/{displayId}") suspend fun dismissPromoBannerDisplay( - @Path("displayId") displayId: String, + @Path("displayId") displayId: Int, @Body body: DismissPromoBannerRequest, ): ApiResponse // endregion diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/promobanners/PromoBannerDisplaysResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/promobanners/PromoBannerDisplaysResponse.kt index ca1a8e9e5e..bc69dbf9c8 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/promobanners/PromoBannerDisplaysResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/models/promobanners/PromoBannerDisplaysResponse.kt @@ -5,20 +5,31 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class PromoBannerDisplaysResponse( - @Json(name = "items") val items: List, + @Json(name = "items") + val items: List, ) @Suppress("BooleanPropertyNaming") @JsonClass(generateAdapter = true) data class PromoBannerDisplayDTO( - @Json(name = "id") val id: String, - @Json(name = "placeholder") val placeholder: String, - @Json(name = "priority") val priority: String, - @Json(name = "title") val title: String, - @Json(name = "subtitle") val subtitle: String, - @Json(name = "iconUrl") val iconUrl: String?, - @Json(name = "deeplink") val deeplink: String?, - @Json(name = "buttonEnabled") val buttonEnabled: Boolean, - @Json(name = "buttonText") val buttonText: String?, - @Json(name = "dismissable") val dismissable: Boolean, + @Json(name = "id") + val id: Int, + @Json(name = "placeholder") + val placeholder: String, + @Json(name = "priority") + val priority: String, + @Json(name = "title") + val title: String, + @Json(name = "subtitle") + val subtitle: String, + @Json(name = "iconUrl") + val iconUrl: String?, + @Json(name = "deeplink") + val deeplink: String?, + @Json(name = "buttonEnabled") + val buttonEnabled: Boolean, + @Json(name = "buttonText") + val buttonText: String?, + @Json(name = "dismissable") + val dismissable: Boolean, ) \ No newline at end of file diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/analytics/PromoBannerAnalyticsEvent.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/analytics/PromoBannerAnalyticsEvent.kt index 229e06fcdb..d6ca0f6001 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/analytics/PromoBannerAnalyticsEvent.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/analytics/PromoBannerAnalyticsEvent.kt @@ -8,34 +8,51 @@ internal sealed class PromoBannerAnalyticsEvent( ) : AnalyticsEvent(category = "Promo Banner", event = event, params = params) { data class Shown( - private val displayId: String, + private val displayId: Int, private val placeholder: String, ) : PromoBannerAnalyticsEvent( event = "Banner Shown", - params = mapOf("Display Id" to displayId, "Placeholder" to placeholder), + params = mapOf( + PARAM_DISPLAY_ID to displayId.toString(), + PARAM_PLACEHOLDER to placeholder, + ), ) data class CarouselScrolled( - private val displayId: String, + private val displayId: Int, private val placeholder: String, ) : PromoBannerAnalyticsEvent( event = "Banner Carousel Scrolled", - params = mapOf("Display Id" to displayId, "Placeholder" to placeholder), + params = mapOf( + PARAM_DISPLAY_ID to displayId.toString(), + PARAM_PLACEHOLDER to placeholder, + ), ) data class Clicked( - private val displayId: String, + private val displayId: Int, private val placeholder: String, ) : PromoBannerAnalyticsEvent( event = "Banner Button Clicked", - params = mapOf("Display Id" to displayId, "Placeholder" to placeholder), + params = mapOf( + PARAM_DISPLAY_ID to displayId.toString(), + PARAM_PLACEHOLDER to placeholder, + ), ) data class Dismissed( - private val displayId: String, + private val displayId: Int, private val placeholder: String, ) : PromoBannerAnalyticsEvent( event = "Banner Dismissed", - params = mapOf("Display Id" to displayId, "Placeholder" to placeholder), + params = mapOf( + PARAM_DISPLAY_ID to displayId.toString(), + PARAM_PLACEHOLDER to placeholder, + ), ) + + private companion object { + const val PARAM_DISPLAY_ID = "Display Id" + const val PARAM_PLACEHOLDER = "Placeholder" + } } \ No newline at end of file diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayDTOConverter.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayDTOConverter.kt index 13e19d5361..ef32e2291c 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayDTOConverter.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayDTOConverter.kt @@ -25,7 +25,7 @@ internal class PromoBannerDisplayDTOConverter : Converter PromoBannerPriority.IMPORTANT + "TOP" -> PromoBannerPriority.TOP "HIGH" -> PromoBannerPriority.HIGH "MEDIUM" -> PromoBannerPriority.MEDIUM "LOW" -> PromoBannerPriority.LOW diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayToNotificationConverter.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayToNotificationConverter.kt index 0e81007163..91c29f151a 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayToNotificationConverter.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayToNotificationConverter.kt @@ -10,7 +10,7 @@ internal class PromoBannerDisplayToNotificationConverter { fun convert( banner: PromoBannerDisplay, onDeeplinkClick: (String?) -> Unit, - onDismiss: (String) -> Unit, + onDismiss: (Int) -> Unit, ): PromoBannerNotificationUM { return PromoBannerNotificationUM( displayId = banner.id, diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannerDisplay.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannerDisplay.kt index 6f96a1cf00..15c278cee2 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannerDisplay.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannerDisplay.kt @@ -1,7 +1,7 @@ package com.tangem.features.promobanners.impl.model internal data class PromoBannerDisplay( - val id: String, + val id: Int, val placeholder: String, val priority: PromoBannerPriority, val title: String, diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannerNotificationUM.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannerNotificationUM.kt index 1d244d419c..6003b4e54f 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannerNotificationUM.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannerNotificationUM.kt @@ -3,6 +3,6 @@ package com.tangem.features.promobanners.impl.model import com.tangem.core.ui.components.notifications.NotificationConfig internal data class PromoBannerNotificationUM( - val displayId: String, + val displayId: Int, val config: NotificationConfig, ) \ No newline at end of file diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannerPriority.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannerPriority.kt index 959f3c3b44..bdb0403226 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannerPriority.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannerPriority.kt @@ -1,7 +1,7 @@ package com.tangem.features.promobanners.impl.model internal enum class PromoBannerPriority(val order: Int) { - IMPORTANT(order = 0), + TOP(order = 0), HIGH(order = 1), MEDIUM(order = 2), LOW(order = 3), diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt index 5c596f3fd4..f4f2d505e5 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockModel.kt @@ -12,6 +12,7 @@ import com.tangem.features.promobanners.impl.converters.PromoBannerDisplayToNoti import com.tangem.features.promobanners.impl.repository.PromoBannersRepository import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.runSuspendCatching +import kotlinx.collections.immutable.persistentListOf import com.tangem.utils.logging.TangemLogger import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.* @@ -34,11 +35,12 @@ internal class PromoBannersBlockModel @Inject constructor( private val converter = PromoBannerDisplayToNotificationConverter() private val placeholder: String = params.placeholder.name.lowercase() - private val shownBannerIds: MutableSet = ConcurrentHashMap.newKeySet() + private val shownBannerIds: MutableSet = ConcurrentHashMap.newKeySet() private var wasCarouselScrolled = false + private val savedDisplayIdByWalletId: MutableMap = mutableMapOf() val uiState: StateFlow - field = MutableStateFlow(PromoBannersBlockUM()) + field = MutableStateFlow(getInitialState()) init { subscribeOnSelectedWallet() @@ -59,46 +61,67 @@ internal class PromoBannersBlockModel @Inject constructor( } private suspend fun loadBanners(walletId: String) { - val locale = Locale.getDefault().language + val languageISOCode = Locale.getDefault().language runSuspendCatching { - repository.getBanners(walletId, params.placeholder, locale) + repository.getBanners(walletId, params.placeholder, languageISOCode) }.onSuccess { banners -> + val bannerUMs = banners.map { banner -> + converter.convert( + banner = banner, + onDeeplinkClick = { deeplink -> onButtonClick(banner.id, deeplink) }, + onDismiss = { displayId -> onBannerDismiss(walletId, displayId) }, + ) + }.toImmutableList() + + val savedDisplayId = savedDisplayIdByWalletId[walletId] + val initialPage = if (savedDisplayId != null) { + bannerUMs.indexOfFirst { it.displayId == savedDisplayId }.coerceAtLeast(0) + } else { + 0 + } + uiState.value = PromoBannersBlockUM( - banners = banners.map { banner -> - converter.convert( - banner = banner, - onDeeplinkClick = { deeplink -> onButtonClick(banner.id, deeplink) }, - onDismiss = { displayId -> onBannerDismiss(walletId, displayId) }, - ) - }.toImmutableList(), + userWalletId = walletId, + initialPage = initialPage, + banners = bannerUMs, onBannerShown = ::onBannerShown, onCarouselScrolled = ::onCarouselScrolled, + onPageChanged = { displayId -> savedDisplayIdByWalletId[walletId] = displayId }, ) }.onFailure { error -> TangemLogger.w("Failed to load promo banners", error) } } - private fun onBannerShown(displayId: String) { + private fun onBannerShown(displayId: Int) { if (shownBannerIds.add(displayId)) { analyticsEventHandler.send(PromoBannerAnalyticsEvent.Shown(displayId, placeholder)) } } - private fun onCarouselScrolled(displayId: String) { + private fun onCarouselScrolled(displayId: Int) { if (!wasCarouselScrolled) { wasCarouselScrolled = true analyticsEventHandler.send(PromoBannerAnalyticsEvent.CarouselScrolled(displayId, placeholder)) } } - private fun onButtonClick(displayId: String, deeplink: String?) { + private fun onButtonClick(displayId: Int, deeplink: String?) { analyticsEventHandler.send(PromoBannerAnalyticsEvent.Clicked(displayId, placeholder)) deeplink?.let { deeplinkLauncher.launch(it) } } - private fun onBannerDismiss(walletId: String, displayId: String) { + private fun getInitialState() = PromoBannersBlockUM( + userWalletId = "", + initialPage = 0, + banners = persistentListOf(), + onBannerShown = {}, + onCarouselScrolled = {}, + onPageChanged = {}, + ) + + private fun onBannerDismiss(walletId: String, displayId: Int) { analyticsEventHandler.send(PromoBannerAnalyticsEvent.Dismissed(displayId, placeholder)) uiState.update { state -> state.copy( diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockUM.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockUM.kt index e58b9d432c..0b12f8cf7c 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockUM.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/model/PromoBannersBlockUM.kt @@ -1,10 +1,12 @@ package com.tangem.features.promobanners.impl.model import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf internal data class PromoBannersBlockUM( - val banners: ImmutableList = persistentListOf(), - val onBannerShown: (displayId: String) -> Unit = {}, - val onCarouselScrolled: (displayId: String) -> Unit = {}, + val userWalletId: String, + val initialPage: Int, + val banners: ImmutableList, + val onBannerShown: (displayId: Int) -> Unit, + val onCarouselScrolled: (displayId: Int) -> Unit, + val onPageChanged: (displayId: Int) -> Unit, ) \ No newline at end of file diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/DefaultPromoBannersRepository.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/DefaultPromoBannersRepository.kt index ba193f57e4..9a13d9fab1 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/DefaultPromoBannersRepository.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/DefaultPromoBannersRepository.kt @@ -28,7 +28,7 @@ internal class DefaultPromoBannersRepository( override suspend fun getBanners( walletId: String, placeholder: Placeholder, - locale: String, + languageISOCode: String, ): List { val key = BannersCacheKey(walletId, placeholder) @@ -38,7 +38,7 @@ internal class DefaultPromoBannersRepository( tangemTechApi.getPromoBannerDisplays( walletId = walletId, placeholder = placeholder.toApiValue(), - locale = locale, + languageISOCode = languageISOCode, ).getOrThrow() .items .map(converter::convert) @@ -52,7 +52,7 @@ internal class DefaultPromoBannersRepository( return banners } - override suspend fun dismissBanner(walletId: String, displayId: String) { + override suspend fun dismissBanner(walletId: String, displayId: Int) { cache.update(default = emptyMap()) { current -> current.mapValues { (key, banners) -> if (key.walletId == walletId) { diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/PromoBannersRepository.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/PromoBannersRepository.kt index e4e7430d98..0fd96683b7 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/PromoBannersRepository.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/repository/PromoBannersRepository.kt @@ -5,7 +5,11 @@ import com.tangem.features.promobanners.impl.model.PromoBannerDisplay internal interface PromoBannersRepository { - suspend fun getBanners(walletId: String, placeholder: Placeholder, locale: String): List + suspend fun getBanners( + walletId: String, + placeholder: Placeholder, + languageISOCode: String, + ): List - suspend fun dismissBanner(walletId: String, displayId: String) + suspend fun dismissBanner(walletId: String, displayId: Int) } \ No newline at end of file diff --git a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/ui/PromoBannersBlock.kt b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/ui/PromoBannersBlock.kt index 37b834d756..49cff50a0a 100644 --- a/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/ui/PromoBannersBlock.kt +++ b/features/promo-banners/impl/src/main/kotlin/com/tangem/features/promobanners/impl/ui/PromoBannersBlock.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.key import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -35,12 +36,16 @@ internal fun PromoBannersBlock(state: PromoBannersBlockUM, modifier: Modifier = modifier = modifier, ) } else { - BannersCarousel( - banners = state.banners, - onBannerShown = state.onBannerShown, - onCarouselScroll = state.onCarouselScrolled, - modifier = modifier, - ) + key(state.userWalletId) { + BannersCarousel( + banners = state.banners, + initialPage = state.initialPage, + onBannerShown = state.onBannerShown, + onCarouselScroll = state.onCarouselScrolled, + onPageChange = state.onPageChanged, + modifier = modifier, + ) + } } } @@ -56,16 +61,22 @@ private fun SingleBanner(banner: PromoBannerNotificationUM, modifier: Modifier = @Composable private fun BannersCarousel( banners: List, - onBannerShown: (String) -> Unit, - onCarouselScroll: (String) -> Unit, + initialPage: Int, + onBannerShown: (Int) -> Unit, + onCarouselScroll: (Int) -> Unit, + onPageChange: (Int) -> Unit, modifier: Modifier = Modifier, ) { - val pagerState = rememberPagerState(pageCount = { banners.size }) + val pagerState = rememberPagerState( + initialPage = initialPage, + pageCount = { banners.size }, + ) LaunchedEffect(pagerState, banners) { snapshotFlow { pagerState.currentPage } .collect { page -> banners.getOrNull(page)?.let { banner -> + onPageChange(banner.displayId) onBannerShown(banner.displayId) if (page == 1) { // one-time event when user scrolls from first to second page, diff --git a/features/promo-banners/impl/src/test/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayDTOConverterTest.kt b/features/promo-banners/impl/src/test/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayDTOConverterTest.kt index 91eb08c41a..36d87c263e 100644 --- a/features/promo-banners/impl/src/test/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayDTOConverterTest.kt +++ b/features/promo-banners/impl/src/test/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayDTOConverterTest.kt @@ -12,7 +12,7 @@ class PromoBannerDisplayDTOConverterTest { @Test fun `should convert DTO to domain model`() { val dto = PromoBannerDisplayDTO( - id = "123", + id = 123, placeholder = "MAIN", priority = "HIGH", title = "Test Banner", @@ -26,7 +26,7 @@ class PromoBannerDisplayDTOConverterTest { val result = converter.convert(dto) - assertThat(result.id).isEqualTo("123") + assertThat(result.id).isEqualTo(123) assertThat(result.placeholder).isEqualTo("MAIN") assertThat(result.priority).isEqualTo(PromoBannerPriority.HIGH) assertThat(result.title).isEqualTo("Test Banner") @@ -63,7 +63,7 @@ class PromoBannerDisplayDTOConverterTest { placeholder: String = "MAIN", priority: String = "MEDIUM", ) = PromoBannerDisplayDTO( - id = "1", + id = 1, placeholder = placeholder, priority = priority, title = "Title", diff --git a/features/promo-banners/impl/src/test/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayToNotificationConverterTest.kt b/features/promo-banners/impl/src/test/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayToNotificationConverterTest.kt index fed421aa20..fdae92bc97 100644 --- a/features/promo-banners/impl/src/test/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayToNotificationConverterTest.kt +++ b/features/promo-banners/impl/src/test/kotlin/com/tangem/features/promobanners/impl/converters/PromoBannerDisplayToNotificationConverterTest.kt @@ -13,14 +13,14 @@ class PromoBannerDisplayToNotificationConverterTest { @Test fun `should convert banner with all fields`() { val banner = createBanner( - id = "b1", + id = 1, deeplink = "tangem://wallet", isButtonEnabled = true, buttonText = "Open", isDismissable = true, ) var clickedDeeplink: String? = "not_called" - var dismissedId: String? = null + var dismissedId: Int? = null val result = converter.convert( banner = banner, @@ -28,7 +28,7 @@ class PromoBannerDisplayToNotificationConverterTest { onDismiss = { dismissedId = it }, ) - assertThat(result.displayId).isEqualTo("b1") + assertThat(result.displayId).isEqualTo(1) assertThat(result.config.title).isEqualTo(TextReference.Str("Title")) assertThat(result.config.subtitle).isEqualTo(TextReference.Str("Subtitle")) assertThat(result.config.iconUrl).isEqualTo("https://icon.png") @@ -42,7 +42,7 @@ class PromoBannerDisplayToNotificationConverterTest { assertThat(clickedDeeplink).isEqualTo("tangem://wallet") result.config.onCloseClick!!.invoke() - assertThat(dismissedId).isEqualTo("b1") + assertThat(dismissedId).isEqualTo(1) } @Test @@ -98,7 +98,7 @@ class PromoBannerDisplayToNotificationConverterTest { } private fun createBanner( - id: String = "id", + id: Int = 0, deeplink: String? = "https://example.com", isButtonEnabled: Boolean = false, buttonText: String? = null,