Repository: Automattic/pocket-casts-android
File: modules/features/account/src/main/java/au/com/shiftyjelly/pocketcasts/account/onboarding/components/SubscriptionPlanRow.kt (Kotlin)

Code before:
            )
        }
    } else {
        Box(
            modifier = modifier.border(
                width = 1.dp,
                color = MaterialTheme.theme.colors.primaryIcon02,
                shape = CircleShape,
            ),
        )
    }
}

private val SubscriptionPlan.pricePerMonth: Float
    get() {
        val pricePerMonth = when (billingCycle) {
            BillingCycle.Monthly -> recurringPrice?.amount?.toFloat() ?: 0f
            BillingCycle.Yearly -> (recurringPrice?.amount?.toFloat() ?: 0f) / 12f
        }
        return pricePerMonth
    }

private val SubscriptionPlan.recurringPrice: Price? get() = when (this) {
    is SubscriptionPlan.Base -> pricingPhase.price
    is SubscriptionPlan.WithOffer -> pricingPhases.find { it.schedule.recurrenceMode is PricingSchedule.RecurrenceMode.Infinite }?.price
}

private val SubscriptionPlan.pricePerWeek: Float
    get() {
        val pricePerWeek = when (billingCycle) {
            BillingCycle.Monthly -> (recurringPrice?.amount?.toFloat() ?: 0f) / 4f
            BillingCycle.Yearly -> (recurringPrice?.amount?.toFloat() ?: 0f) / 52f
        }
        return pricePerWeek
    }

@Composable
private fun SubscriptionPlan.pricePerPeriod(config: RowConfig): String? {
    return if (this.billingCycle == BillingCycle.Yearly) {
        when (config.pricePerPeriod) {
            PricePerPeriod.PRICE_PER_MONTH -> {
                val currencyCode = recurringPrice?.currencyCode
                if (currencyCode == "USD") {
                    stringResource(LR.string.price_per_month_usd, pricePerMonth)
                } else {
                    stringResource(LR.string.price_per_month, pricePerMonth, currencyCode.orEmpty())
                }
            }

            PricePerPeriod.PRICE_PER_WEEK -> {
                val currencyCode = recurringPrice?.currencyCode

Review comment (suggestion):
🛑 `recurringPrice` should never be `null`. Allowing it to be nullable can lead to inconsistent UI and UX if there are issues in our offer mapping logic or in the Play Console configuration.

There are a few possible solutions, but the most sensible one is to move `recurringPrice` to be a property of `SubscriptionPlan`, and derive it based on the selected offer. Something like:

```kotlin
sealed interface SubscriptionPlan {    
    val recurringPrice get() = when (this) {
        is Base -> pricingPhase.price
        is WithOffer -> pricingPhases.last().price // or the logic that you use
    }
}
```

This should be covered with tests for every supported offer to ensure we have the correct prices.

Code after:
    } else {
        Box(
            modifier = modifier.border(
                width = 1.dp,
                color = MaterialTheme.theme.colors.primaryIcon02,
                shape = CircleShape,
            ),
        )
    }
}

private val SubscriptionPlan.pricePerMonth: Float
    get() {
        val pricePerMonth = when (billingCycle) {
            BillingCycle.Monthly -> recurringPrice.amount
            BillingCycle.Yearly -> recurringPrice.amount / monthsInYear
        }
        return pricePerMonth.toFloat()
    }

private val SubscriptionPlan.pricePerWeek: Float
    get() {
        val pricePerWeek = when (billingCycle) {
            BillingCycle.Monthly -> recurringPrice.amount * monthsInYear
            BillingCycle.Yearly -> recurringPrice.amount
        } / weeksInYear
        return pricePerWeek.toFloat()
    }

private val monthsInYear = 12.toBigDecimal()
private val weeksInYear = 52.toBigDecimal()

@Composable
private fun SubscriptionPlan.pricePerPeriod(config: RowConfig): String? {
    return if (this.billingCycle == BillingCycle.Yearly) {
        when (config.pricePerPeriod) {
            PricePerPeriod.PRICE_PER_MONTH -> {
                val currencyCode = recurringPrice.currencyCode
                if (currencyCode == "USD") {
                    stringResource(LR.string.price_per_month_usd, pricePerMonth)
                } else {
                    stringResource(LR.string.price_per_month, pricePerMonth, currencyCode)
                }
            }

            PricePerPeriod.PRICE_PER_WEEK -> {
                val currencyCode = recurringPrice.currencyCode
                if (currencyCode == "USD") {
                    stringResource(LR.string.price_per_week_usd, pricePerWeek)
                } else {
                    stringResource(LR.string.price_per_week, pricePerWeek, currencyCode)