Repository: wordpress-mobile/WordPress-Android (language: kotlin)

Issue:
[Android] Display a card on Site domain
Apply same conditions for displaying plans card on My site dashboard

![Image](https://github.com/wordpress-mobile/WordPress-Android/assets/990349/056ba2b3-cdc4-4d11-8ac1-155374b7c8cb)




Discussion hints:

<!--
  1 failure:  Please add a type...
  0 warning: 
  
  
  DangerID: danger-id-Peril;
-->

<table>
  <thead>
    <tr>
      <th width="50"></th>
      <th width="100%" data-danger-table="true">Fails</th>
    </tr>
  </thead>
  <tbody><tr>
      <td>:no_entry_sign:</td>
      <td>

  Please add a type label to this issue. e.g. '[Type] Enhancement'
  </td>
    </tr>
  </tbody>
</table>




<p align="right">
  Generated by :no_entry_sign: <a href="https://danger.systems/js">dangerJS</a>
</p>


Pull request: Plans on site domain display updated card
Fixes #19807, #19808, #19809   

Updates card with `upgrade to a plan` CTA, besides existing `get a domain` CTA on domains dashboard for those on free plan .

| Before | After |
|--------|--------|
| ![Screenshot_20231219_193130](https://github.com/wordpress-mobile/WordPress-Android/assets/990349/1a127106-0ed5-495e-ba72-22b9e91294e8) |![Screenshot_20231220_112652](https://github.com/wordpress-mobile/WordPress-Android/assets/990349/63988d4a-defd-4d28-b6ca-953d2470b362) | 

-----

## To Test:

Test 1
- Launch JP app
- `Select` a site with a free plan, have admin role
- `Go` to **Domains** (My site -> domains or My site -> More... -> domain)
- Verify a new card is displayed as in second image above
- `Tap` on **Upgrade to a plan**
- `Verify` it launches plans purchase flow like plans card on dashboard
- Return to domains
- `Tap` on **Just search for a domain**
- `Verify` it launches domain purchase flow as before

Test 2
- For completeness, also verify with a site that has a paid plan
- `Verify` it doesn't display the card above, but the card as before

Test 3
- `Verify` analytics tracker in AS like 
🔵 Tracked: domains_dashboard_get_plan_tapped, Properties: {"blog_id":196875124,"site_type":"blog","is_jetpack":false}
-----

## Regression Notes

1. Potential unintended areas of impact

    - None

2. What I did to test those areas of impact (or what existing automated tests I relied on)

    - Manual, and unit tests

3. What automated tests I added (or what prevented me from doing so)

    - Updated unit tests

-----

## PR Submission Checklist:

- [x] I have completed the Regression Notes.
- [x] I have considered adding accessibility improvements for my changes.
- [x] I have considered if this change warrants user-facing release notes and have added them to `RELEASE-NOTES.txt` if necessary.


Test command: ./gradlew :WordPress:testWordpressVanillaDebugUnitTest --tests "org.wordpress.android.ui.domains.DomainsDashboardViewModelTest"

Fix patch:
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 6fd3d4672b24..1b72edaa59ee 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -3,6 +3,7 @@
 24.0
 -----
 * [*] Filter media types when sharing files to the editor [https://github.com/wordpress-mobile/WordPress-Android/pull/19754]
+* [***] [Jetpack-only] Plans: Upgrade to a Plan from domains dashboard in Jetpack app [https://github.com/wordpress-mobile/WordPress-Android/pull/19818]
 * [**] [internal] Removes unused resources and code [https://github.com/wordpress-mobile/WordPress-Android/pull/19788]
 
 23.9
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardAdapter.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardAdapter.kt
index a160888254d9..5ca9b2d869cb 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardAdapter.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardAdapter.kt
@@ -10,12 +10,14 @@ import org.wordpress.android.ui.domains.DomainsDashboardItem.ManageDomains
 import org.wordpress.android.ui.domains.DomainsDashboardItem.PurchaseDomain
 import org.wordpress.android.ui.domains.DomainsDashboardItem.SiteDomains
 import org.wordpress.android.ui.domains.DomainsDashboardItem.SiteDomainsHeader
+import org.wordpress.android.ui.domains.DomainsDashboardItem.PurchasePlan
 import org.wordpress.android.ui.domains.DomainsDashboardItem.Type
 import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.ADD_DOMAIN
 import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.DOMAIN_BLURB
 import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.MANAGE_DOMAINS
 import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.PRIMARY_DOMAIN
 import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.PURCHASE_DOMAIN
+import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.PURCHASE_PLAN
 import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.SITE_DOMAINS
 import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.SITE_DOMAINS_HEADER
 import org.wordpress.android.ui.domains.DomainsDashboardViewHolder.AddDomainViewHolder
@@ -25,6 +27,7 @@ import org.wordpress.android.ui.domains.DomainsDashboardViewHolder.ManageDomains
 import org.wordpress.android.ui.domains.DomainsDashboardViewHolder.PurchaseDomainViewHolder
 import org.wordpress.android.ui.domains.DomainsDashboardViewHolder.SiteDomainsHeaderViewHolder
 import org.wordpress.android.ui.domains.DomainsDashboardViewHolder.SiteDomainsViewHolder
+import org.wordpress.android.ui.domains.DomainsDashboardViewHolder.PurchasePlanViewHolder
 import org.wordpress.android.ui.utils.UiHelpers
 import javax.inject.Inject
 
@@ -40,6 +43,7 @@ class DomainsDashboardAdapter @Inject constructor(
             MANAGE_DOMAINS -> ManageDomainsViewHolder(parent)
             PURCHASE_DOMAIN -> PurchaseDomainViewHolder(parent, uiHelpers)
             DOMAIN_BLURB -> DomainBlurbViewHolder(parent, uiHelpers)
+            PURCHASE_PLAN -> PurchasePlanViewHolder(parent, uiHelpers)
         }
     }
 
@@ -53,6 +57,7 @@ class DomainsDashboardAdapter @Inject constructor(
             is ManageDomainsViewHolder -> holder.onBind(item as ManageDomains)
             is PurchaseDomainViewHolder -> holder.onBind(item as PurchaseDomain)
             is DomainBlurbViewHolder -> holder.onBind(item as DomainBlurb)
+            is PurchasePlanViewHolder -> holder.onBind(item as PurchasePlan)
         }
     }
 
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardFragment.kt
index ce46ee60a279..bb60d9f91380 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardFragment.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardFragment.kt
@@ -21,8 +21,10 @@ import org.wordpress.android.ui.ActivityLauncher
 import org.wordpress.android.ui.RequestCodes.DOMAIN_REGISTRATION
 import org.wordpress.android.ui.domains.DomainRegistrationActivity.DomainRegistrationPurpose.CTA_DOMAIN_CREDIT_REDEMPTION
 import org.wordpress.android.ui.domains.DomainRegistrationActivity.DomainRegistrationPurpose.DOMAIN_PURCHASE
+import org.wordpress.android.ui.domains.DomainRegistrationActivity.DomainRegistrationPurpose.FREE_DOMAIN_WITH_ANNUAL_PLAN
 import org.wordpress.android.ui.domains.DomainsDashboardNavigationAction.ClaimDomain
 import org.wordpress.android.ui.domains.DomainsDashboardNavigationAction.GetDomain
+import org.wordpress.android.ui.domains.DomainsDashboardNavigationAction.GetPlan
 import org.wordpress.android.ui.utils.UiHelpers
 import org.wordpress.android.util.config.DomainManagementFeatureConfig
 import org.wordpress.android.util.extensions.getSerializableExtraCompat
@@ -103,6 +105,11 @@ class DomainsDashboardFragment : Fragment(R.layout.domains_dashboard_fragment),
             action.site,
             CTA_DOMAIN_CREDIT_REDEMPTION
         )
+        is GetPlan -> ActivityLauncher.viewDomainRegistrationActivityForResult(
+            this,
+            action.site,
+            FREE_DOMAIN_WITH_ANNUAL_PLAN
+        )
     }
 
     @Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardItem.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardItem.kt
index 6bf01edec646..20fc8e283c66 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardItem.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardItem.kt
@@ -8,6 +8,7 @@ import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.DOMAIN_BLURB
 import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.MANAGE_DOMAINS
 import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.PRIMARY_DOMAIN
 import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.PURCHASE_DOMAIN
+import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.PURCHASE_PLAN
 import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.SITE_DOMAINS
 import org.wordpress.android.ui.domains.DomainsDashboardItem.Type.SITE_DOMAINS_HEADER
 import org.wordpress.android.ui.utils.ListItemInteraction
@@ -21,7 +22,8 @@ sealed class DomainsDashboardItem(val type: Type) {
         ADD_DOMAIN,
         MANAGE_DOMAINS,
         PURCHASE_DOMAIN,
-        DOMAIN_BLURB
+        DOMAIN_BLURB,
+        PURCHASE_PLAN
     }
 
     data class FreeDomain(
@@ -49,6 +51,14 @@ sealed class DomainsDashboardItem(val type: Type) {
         val onClick: ListItemInteraction
     ) : DomainsDashboardItem(PURCHASE_DOMAIN)
 
+    data class PurchasePlan(
+        @DrawableRes val image: Int?,
+        val title: UiString,
+        val body: UiString,
+        val onUpgradeClick: ListItemInteraction,
+        val onDomainClick: ListItemInteraction
+    ) : DomainsDashboardItem(PURCHASE_PLAN)
+
     data class DomainBlurb(val blurb: UiString) : DomainsDashboardItem(DOMAIN_BLURB)
 
     enum class Action(@IdRes val itemId: Int) {
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardNavigationAction.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardNavigationAction.kt
index 733ceff0ebe9..60d32b8105d5 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardNavigationAction.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardNavigationAction.kt
@@ -5,4 +5,5 @@ import org.wordpress.android.fluxc.model.SiteModel
 sealed class DomainsDashboardNavigationAction {
     data class GetDomain(val site: SiteModel) : DomainsDashboardNavigationAction()
     data class ClaimDomain(val site: SiteModel) : DomainsDashboardNavigationAction()
+    data class GetPlan(val site: SiteModel) : DomainsDashboardNavigationAction()
 }
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardViewHolder.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardViewHolder.kt
index 9aaeca1cf0b4..02e5db36518b 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardViewHolder.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardViewHolder.kt
@@ -10,6 +10,7 @@ import org.wordpress.android.R
 import org.wordpress.android.databinding.DomainAddDomainCtaBinding
 import org.wordpress.android.databinding.DomainFreeSiteAddressCardBinding
 import org.wordpress.android.databinding.DomainManageDomainsCtaBinding
+import org.wordpress.android.databinding.DomainPlanPurchaseCardBinding
 import org.wordpress.android.databinding.DomainPurchaseCardBinding
 import org.wordpress.android.databinding.DomainSiteDomainsBlurbBinding
 import org.wordpress.android.databinding.DomainSiteDomainsCardBinding
@@ -21,6 +22,7 @@ import org.wordpress.android.ui.domains.DomainsDashboardItem.ManageDomains
 import org.wordpress.android.ui.domains.DomainsDashboardItem.PurchaseDomain
 import org.wordpress.android.ui.domains.DomainsDashboardItem.SiteDomains
 import org.wordpress.android.ui.domains.DomainsDashboardItem.SiteDomainsHeader
+import org.wordpress.android.ui.domains.DomainsDashboardItem.PurchasePlan
 import org.wordpress.android.ui.utils.UiHelpers
 import org.wordpress.android.util.extensions.viewBinding
 
@@ -109,6 +111,21 @@ sealed class DomainsDashboardViewHolder<T : ViewBinding>(
         }
     }
 
+    class PurchasePlanViewHolder(
+        parent: ViewGroup,
+        private val uiHelpers: UiHelpers
+    ) : DomainsDashboardViewHolder<DomainPlanPurchaseCardBinding>(
+        parent.viewBinding(DomainPlanPurchaseCardBinding::inflate)
+    ) {
+        fun onBind(item: PurchasePlan) = with(binding) {
+            uiHelpers.setImageOrHide(purchasePlanImage, item.image)
+            uiHelpers.setTextOrHide(purchasePlanTitle, item.title)
+            uiHelpers.setTextOrHide(purchasePlanCaption, item.body)
+            upgradePlanButton.setOnClickListener { item.onUpgradeClick.click() }
+            justSearchDomainButton.setOnClickListener { item.onDomainClick.click() }
+        }
+    }
+
     class DomainBlurbViewHolder(
         parent: ViewGroup,
         private val uiHelpers: UiHelpers
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardViewModel.kt
index 2fb9f16c5e69..2f2305005aa9 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardViewModel.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/domains/DomainsDashboardViewModel.kt
@@ -7,6 +7,7 @@ import kotlinx.coroutines.async
 import org.wordpress.android.R
 import org.wordpress.android.analytics.AnalyticsTracker.Stat.DOMAINS_DASHBOARD_ADD_DOMAIN_TAPPED
 import org.wordpress.android.analytics.AnalyticsTracker.Stat.DOMAINS_DASHBOARD_GET_DOMAIN_TAPPED
+import org.wordpress.android.analytics.AnalyticsTracker.Stat.DOMAINS_DASHBOARD_GET_PLAN_TAPPED
 import org.wordpress.android.analytics.AnalyticsTracker.Stat.DOMAINS_DASHBOARD_VIEWED
 import org.wordpress.android.analytics.AnalyticsTracker.Stat.DOMAIN_CREDIT_REDEMPTION_TAPPED
 import org.wordpress.android.fluxc.model.PlanModel
@@ -22,8 +23,10 @@ import org.wordpress.android.ui.domains.DomainsDashboardItem.FreeDomain
 import org.wordpress.android.ui.domains.DomainsDashboardItem.PurchaseDomain
 import org.wordpress.android.ui.domains.DomainsDashboardItem.SiteDomains
 import org.wordpress.android.ui.domains.DomainsDashboardItem.SiteDomainsHeader
+import org.wordpress.android.ui.domains.DomainsDashboardItem.PurchasePlan
 import org.wordpress.android.ui.domains.DomainsDashboardNavigationAction.ClaimDomain
 import org.wordpress.android.ui.domains.DomainsDashboardNavigationAction.GetDomain
+import org.wordpress.android.ui.domains.DomainsDashboardNavigationAction.GetPlan
 import org.wordpress.android.ui.domains.usecases.FetchPlansUseCase
 import org.wordpress.android.ui.plans.isDomainCreditAvailable
 import org.wordpress.android.ui.utils.HtmlMessageUtils
@@ -156,15 +159,11 @@ class DomainsDashboardViewModel @Inject constructor(
                     ListItemInteraction.create(this::onGetDomainClick)
                 )
             } else {
-                PurchaseDomain(
-                    R.drawable.img_illustration_domains_card_header,
+                PurchasePlan(
+                    R.drawable.browser_address_bar,
                     UiStringRes(R.string.domains_free_plan_get_your_domain_title),
-                    UiStringText(
-                        htmlMessageUtils.getHtmlMessageFromStringFormatResId(
-                            R.string.domains_free_plan_get_your_domain_caption,
-                            freeDomainUrl
-                        )
-                    ),
+                    UiStringRes(R.string.domains_upgrade_to_plan_caption),
+                    ListItemInteraction.create(this::onGetPlanClick),
                     ListItemInteraction.create(this::onGetDomainClick)
                 )
             }
@@ -207,6 +206,11 @@ class DomainsDashboardViewModel @Inject constructor(
         _onNavigation.value = Event(GetDomain(site))
     }
 
+    private fun onGetPlanClick() {
+        analyticsTrackerWrapper.track(DOMAINS_DASHBOARD_GET_PLAN_TAPPED, site)
+        _onNavigation.value = Event(GetPlan(site))
+    }
+
     private fun onClaimDomainClick() {
         analyticsTrackerWrapper.track(DOMAIN_CREDIT_REDEMPTION_TAPPED, site)
         _onNavigation.value = Event(ClaimDomain(site))
diff --git a/WordPress/src/main/res/layout/domain_plan_purchase_card.xml b/WordPress/src/main/res/layout/domain_plan_purchase_card.xml
new file mode 100644
index 000000000000..7f1f651e50b2
--- /dev/null
+++ b/WordPress/src/main/res/layout/domain_plan_purchase_card.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/purchase_plan_card"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_margin="@dimen/margin_extra_large"
+    app:cardCornerRadius="@dimen/margin_medium_large"
+    app:cardElevation="0dp"
+    app:layout_constraintBottom_toBottomOf="parent"
+    app:layout_constraintEnd_toEndOf="parent"
+    app:layout_constraintStart_toStartOf="parent"
+    app:layout_constraintTop_toTopOf="parent"
+    app:strokeColor="@color/on_surface_disabled_primary_selector"
+    app:strokeWidth="1dp">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/margin_extra_large">
+
+        <ImageView
+            android:id="@+id/purchase_plan_image"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:adjustViewBounds="true"
+            android:contentDescription="@null"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:src="@drawable/browser_address_bar" />
+
+        <com.google.android.material.textview.MaterialTextView
+            android:id="@+id/purchase_plan_title"
+            style="@style/DomainsPlanPurchaseCardTitle"
+            android:layout_marginTop="@dimen/domain_plan_card_title_top_margin"
+            android:text="@string/domains_free_plan_get_your_domain_title"
+            app:layout_constraintBottom_toTopOf="@id/purchase_plan_caption"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="@id/purchase_plan_image" />
+
+        <com.google.android.material.textview.MaterialTextView
+            android:id="@+id/purchase_plan_caption"
+            style="@style/DomainsPlanPurchaseCardSubTitle"
+            android:layout_marginTop="@dimen/margin_small"
+            android:text="@string/domains_upgrade_to_plan_caption"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/purchase_plan_title" />
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/upgrade_plan_button"
+            style="@style/DomainsPlanPurchaseCardPrimaryButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/margin_medium_large"
+            android:text="@string/domains_upgrade_to_a_plan_button"
+            app:layout_constraintBottom_toTopOf="@id/just_search_domain_button"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/purchase_plan_caption" />
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/just_search_domain_button"
+            style="@style/DomainsPlanPurchaseCardSecondaryButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/domains_just_search_for_a_domain_button"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/upgrade_plan_button" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</com.google.android.material.card.MaterialCardView>
+
diff --git a/WordPress/src/main/res/values-land/dimens.xml b/WordPress/src/main/res/values-land/dimens.xml
index c32c067b9c5d..0a2ec43b918c 100644
--- a/WordPress/src/main/res/values-land/dimens.xml
+++ b/WordPress/src/main/res/values-land/dimens.xml
@@ -14,4 +14,6 @@
     <dimen name="dashboard_card_plans_top_margin">16dp</dimen>
     <dimen name="dashboard_card_plans_done_button_bottom_margin">12dp</dimen>
 
+    <dimen name="domain_plan_card_title_top_margin">160dp</dimen>
+
 </resources>
diff --git a/WordPress/src/main/res/values/dimens.xml b/WordPress/src/main/res/values/dimens.xml
index 68d8991ff905..c2d8a90dadce 100644
--- a/WordPress/src/main/res/values/dimens.xml
+++ b/WordPress/src/main/res/values/dimens.xml
@@ -571,6 +571,8 @@
     <dimen name="domain_suggestions_intro_header_bottom_padding">8dp</dimen>
     <dimen name="domain_suggestions_progress_indicator_size">24dp</dimen>
 
+    <dimen name="domain_plan_card_title_top_margin">78dp</dimen>
+
     <dimen name="keyline_second">72dp</dimen>
 
     <dimen name="toolbar_navigation_ripple_radius">20dp</dimen>
diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml
index b7c35003e809..b036fa7c7437 100644
--- a/WordPress/src/main/res/values/strings.xml
+++ b/WordPress/src/main/res/values/strings.xml
@@ -2709,6 +2709,9 @@
     <string name="domains_free_plan_get_your_domain_title">Get your domain</string>
     <string name="domains_free_plan_get_your_domain_caption">Domains purchased on this site will redirect visitors to &lt;b&gt;%s&lt;/b&gt;</string>
     <string name="domains_search_for_a_domain_button">Search for a domain</string>
+    <string name="domains_upgrade_to_plan_caption">Get a free one-year domain registration or transfer with any annual paid plan.</string>
+    <string name="domains_upgrade_to_a_plan_button">Upgrade to a plan</string>
+    <string name="domains_just_search_for_a_domain_button">Just search for a domain</string>
 
     <!-- Domain Management -->
     <string name="domain_management_expires">Expires %1$s</string>
diff --git a/WordPress/src/main/res/values/styles.xml b/WordPress/src/main/res/values/styles.xml
index 72fd2d6e1719..c02c05e96af6 100644
--- a/WordPress/src/main/res/values/styles.xml
+++ b/WordPress/src/main/res/values/styles.xml
@@ -1608,6 +1608,38 @@
         <item name="android:textAlignment">viewStart</item>
     </style>
 
+    <style name="DomainsPlanPurchaseCardTitle">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:textAlignment">center</item>
+        <item name="android:layout_gravity">center</item>
+        <item name="android:textAppearance">?attr/textAppearanceHeadline6</item>
+        <item name="android:textColor">?attr/colorOnSurface</item>
+    </style>
+
+    <style name="DomainsPlanPurchaseCardSubTitle">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:textAlignment">center</item>
+        <item name="android:layout_gravity">center</item>
+        <item name="android:textAppearance">?attr/textAppearanceBody2</item>
+        <item name="android:textColor">?attr/wpColorOnSurfaceMedium</item>
+    </style>
+
+    <style name="DomainsPlanPurchaseCardPrimaryButton" parent="WordPress.Button.Primary.Unelevated">
+        <item name="materialThemeOverlay">@style/ThemeOverlay.WordPress.Domains.Button.Primary.Unelevated</item>
+        <item name="cornerRadius">5dp</item>
+    </style>
+
+    <style name="ThemeOverlay.WordPress.Domains.Button.Primary.Unelevated" parent="">
+        <item name="colorPrimary">?attr/colorOnSurface</item>
+    </style>
+
+    <style name="DomainsPlanPurchaseCardSecondaryButton" parent="Widget.Material3.Button.TextButton">
+        <item name="android:textSize">@dimen/text_sz_medium</item>
+        <item name="cornerRadius">5dp</item>
+    </style>
+
     <!-- Blogging prompts onboarding dialog styles -->
     <style name="BloggingPromptsOnboardingTitle">
         <item name="android:textSize">@dimen/text_sz_double_extra_large</item>
diff --git a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java
index 56ff41c58fa8..77eec02ca812 100644
--- a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java
+++ b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java
@@ -718,6 +718,7 @@ public enum Stat {
         DOMAIN_CREDIT_NAME_SELECTED,
         DOMAINS_DASHBOARD_VIEWED,
         DOMAINS_DASHBOARD_GET_DOMAIN_TAPPED,
+        DOMAINS_DASHBOARD_GET_PLAN_TAPPED,
         DOMAINS_DASHBOARD_ADD_DOMAIN_TAPPED,
         DOMAINS_SEARCH_SELECT_DOMAIN_TAPPED,
         DOMAINS_REGISTRATION_FORM_VIEWED,
diff --git a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java
index 6be5f8310383..76e1853782a9 100644
--- a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java
+++ b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java
@@ -1929,6 +1929,8 @@ public static String getEventNameForStat(AnalyticsTracker.Stat stat) {
                 return "domains_dashboard_viewed";
             case DOMAINS_DASHBOARD_GET_DOMAIN_TAPPED:
                 return "domains_dashboard_get_domain_tapped";
+            case DOMAINS_DASHBOARD_GET_PLAN_TAPPED:
+                return "domains_dashboard_get_plan_tapped";
             case DOMAINS_DASHBOARD_ADD_DOMAIN_TAPPED:
                 return "domains_dashboard_add_domain_tapped";
             case DOMAINS_SEARCH_SELECT_DOMAIN_TAPPED:


Test patch:
diff --git a/WordPress/src/test/java/org/wordpress/android/ui/domains/DomainsDashboardViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/domains/DomainsDashboardViewModelTest.kt
index 2f474eb5c510..e7dc96542b70 100644
--- a/WordPress/src/test/java/org/wordpress/android/ui/domains/DomainsDashboardViewModelTest.kt
+++ b/WordPress/src/test/java/org/wordpress/android/ui/domains/DomainsDashboardViewModelTest.kt
@@ -4,8 +4,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
 import org.assertj.core.api.Assertions.assertThat
 import org.junit.Before
 import org.junit.Test
-import org.mockito.kotlin.any
-import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.whenever
 import org.wordpress.android.BaseUnitTest
@@ -20,6 +18,7 @@ import org.wordpress.android.ui.domains.DomainsDashboardItem.AddDomain
 import org.wordpress.android.ui.domains.DomainsDashboardItem.DomainBlurb
 import org.wordpress.android.ui.domains.DomainsDashboardItem.FreeDomain
 import org.wordpress.android.ui.domains.DomainsDashboardItem.PurchaseDomain
+import org.wordpress.android.ui.domains.DomainsDashboardItem.PurchasePlan
 import org.wordpress.android.ui.domains.DomainsDashboardItem.SiteDomains
 import org.wordpress.android.ui.domains.DomainsDashboardItem.SiteDomainsHeader
 import org.wordpress.android.ui.domains.usecases.FetchPlansUseCase
@@ -33,9 +32,7 @@ import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper
 class DomainsDashboardViewModelTest : BaseUnitTest() {
     private val siteStore: SiteStore = mock()
     private val analyticsTracker: AnalyticsTrackerWrapper = mock()
-    private val htmlMessageUtils: HtmlMessageUtils = mock {
-        on { getHtmlMessageFromStringFormatResId(any(), any()) } doReturn ""
-    }
+    private val htmlMessageUtils: HtmlMessageUtils = mock()
     private val fetchPlansUseCase: FetchPlansUseCase = mock()
 
     private lateinit var viewModel: DomainsDashboardViewModel
@@ -87,8 +84,8 @@ class DomainsDashboardViewModelTest : BaseUnitTest() {
         assertThat(dashboardItems).hasSize(2)
 
         assertThat(dashboardItems[0]).isInstanceOf(FreeDomain::class.java)
-        assertThat(dashboardItems[1]).isInstanceOf(PurchaseDomain::class.java)
-        assertThat((dashboardItems[1] as PurchaseDomain).title)
+        assertThat(dashboardItems[1]).isInstanceOf(PurchasePlan::class.java)
+        assertThat((dashboardItems[1] as PurchasePlan).title)
             .isEqualTo(UiStringRes(R.string.domains_free_plan_get_your_domain_title))
     }