Skip to content

Commit

Permalink
Add test mode toggle and simplify playground logic (#8416)
Browse files Browse the repository at this point in the history
  • Loading branch information
tillh-stripe committed May 6, 2024
1 parent 12ef08f commit 299f56e
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -311,21 +311,22 @@ internal class FinancialConnectionsPlaygroundViewModel(
}
}

@Suppress("Unused")
enum class Merchant(val apiValue: String) {
Test("testmode"),
PartnerM("partner_m"),
PartnerF("partner_f"),
PartnerD("partner_d"),
enum class Merchant(
val apiValue: String,
val canSwitchBetweenTestAndLive: Boolean = true,
) {
Default("default"),
PartnerD("partner_d", canSwitchBetweenTestAndLive = false),
PartnerF("partner_f", canSwitchBetweenTestAndLive = false),
PartnerM("partner_m", canSwitchBetweenTestAndLive = false),
PlatformC("strash"),
App2App("app2app"),
Networking("networking"),
NetworkingTestMode("networking_testmode"),
Livetesting("live_testing"),
Other("other");
Custom("other");

companion object {
fun fromApiValue(apiValue: String): Merchant = entries.first { it.apiValue == apiValue }
fun fromApiValue(apiValue: String): Merchant {
return entries.firstOrNull { it.apiValue == apiValue } ?: Default
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@ data class LinkAccountSessionBody(
@SerialName("customer_email")
val customerEmail: String? = null,
@SerialName("test_environment")
val testEnvironment: String? = null
val testEnvironment: String? = null,
@SerialName("test_mode")
val testMode: Boolean? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ data class PaymentIntentBody(
@SerialName("customer_email")
val customerEmail: String? = null,
@SerialName("test_environment")
val testEnvironment: String? = null
val testEnvironment: String? = null,
@SerialName("test_mode")
val testMode: Boolean? = null,
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.stripe.android.financialconnections.example.settings

import com.stripe.android.financialconnections.example.Flow
import com.stripe.android.financialconnections.example.Merchant
import com.stripe.android.financialconnections.example.data.model.LinkAccountSessionBody
import com.stripe.android.financialconnections.example.data.model.PaymentIntentBody

Expand All @@ -26,6 +28,10 @@ data class ConfirmIntentSetting(
return replace(currentSettings, this.copy(selectedOption = value))
}

override fun shouldDisplay(merchant: Merchant, flow: Flow): Boolean {
return flow == Flow.PaymentIntent
}

override fun convertToValue(value: String): Boolean = value.toBoolean()

override fun convertToString(value: Boolean): String = value.toString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,6 @@ data class FlowSetting(
}

override fun valueUpdated(currentSettings: List<Setting<*>>, value: Flow): List<Setting<*>> {
val flowSettings = listOfNotNull(
copy(selectedOption = value),
ConfirmIntentSetting().takeIf { value == Flow.PaymentIntent },
)
val updatedSettings = currentSettings
.filter { it !is ConfirmIntentSetting }
.flatMap { setting ->
when (setting) {
is FlowSetting -> flowSettings
else -> listOf(setting)
}
}

return if (currentSettings.none { it is FlowSetting }) {
updatedSettings + flowSettings
} else {
updatedSettings
}
return replace(currentSettings, this.copy(selectedOption = value))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.stripe.android.financialconnections.example.data.model.LinkAccountSes
import com.stripe.android.financialconnections.example.data.model.PaymentIntentBody

data class MerchantSetting(
override val selectedOption: Merchant = Merchant.Test,
override val selectedOption: Merchant = Merchant.Default,
override val key: String = "merchant"
) : Saveable<Merchant>, SingleChoiceSetting<Merchant>(
displayName = "Merchant",
Expand All @@ -21,25 +21,7 @@ data class MerchantSetting(
)

override fun valueUpdated(currentSettings: List<Setting<*>>, value: Merchant): List<Setting<*>> {
val merchantSettings = listOfNotNull(
copy(selectedOption = value),
PublicKeySetting("").takeIf { value == Merchant.Other },
PrivateKeySetting("").takeIf { value == Merchant.Other }
)
val updatedSettings = currentSettings
.filter { it !is PublicKeySetting && it !is PrivateKeySetting }
.flatMap { setting ->
when (setting) {
is MerchantSetting -> merchantSettings
else -> listOf(setting)
}
}

return if (currentSettings.none { it is MerchantSetting }) {
updatedSettings + merchantSettings
} else {
updatedSettings
}
return replace(currentSettings, this.copy(selectedOption = value))
}

override fun convertToString(value: Merchant): String = value.apiValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ internal data class PlaygroundSettings(
val settings: List<Setting<*>>
) {

val displayableSettings: List<Setting<*>> by lazy {
val merchant = get<MerchantSetting>()
val flow = get<FlowSetting>()
settings.filter {
it.shouldDisplay(
merchant = merchant.selectedOption,
flow = flow.selectedOption,
)
}
}

fun <T> withValue(
setting: Setting<T>,
value: T
Expand All @@ -28,11 +39,11 @@ internal data class PlaygroundSettings(

fun lasRequest(): LinkAccountSessionBody = settings.toList().fold(
LinkAccountSessionBody(testEnvironment = BuildConfig.TEST_ENVIRONMENT)
) { acc, setting: Setting<*> -> (setting as Setting<Any?>).lasRequest(acc) }
) { acc, setting: Setting<*> -> setting.lasRequest(acc) }

fun paymentIntentRequest(): PaymentIntentBody = settings.toList().fold(
PaymentIntentBody(testEnvironment = BuildConfig.TEST_ENVIRONMENT)
) { acc, setting: Setting<*> -> (setting as Setting<Any?>).paymentIntentRequest(acc) }
) { acc, setting: Setting<*> -> setting.paymentIntentRequest(acc) }

fun asJsonString(): String {
val json = settings
Expand Down Expand Up @@ -95,32 +106,31 @@ internal data class PlaygroundSettings(
}

fun createFromDefaults(): PlaygroundSettings {
return PlaygroundSettings(
allSettings
.filter { it.selectedOption != null }
.toList()
)
return PlaygroundSettings(allSettings)
}

private fun createFromJsonString(jsonString: String): PlaygroundSettings {
private fun createFromJsonString(jsonString: String): PlaygroundSettings? {
var settings = PlaygroundSettings(emptyList())
val jsonObject: JsonObject = Json.decodeFromString(JsonObject.serializer(), jsonString)

allSettings.map {
@Suppress("UNCHECKED_CAST")
it as Setting<Any?>
}.forEach { setting ->
val saveable = setting.saveable()
val savedValue = saveable?.key?.let { jsonObject[it] as? JsonPrimitive }
if (savedValue?.isString == true) {
// add item to mutable list
settings = settings.withValue(setting, saveable.convertToValue(savedValue.content))
} else if (setting.selectedOption != null) {
settings = settings.withValue(setting, setting.selectedOption)
return runCatching {
val jsonObject: JsonObject = Json.decodeFromString(JsonObject.serializer(), jsonString)

allSettings.map {
@Suppress("UNCHECKED_CAST")
it as Setting<Any?>
}.forEach { setting ->
val saveable = setting.saveable()
val savedValue = saveable?.key?.let { jsonObject[it] as? JsonPrimitive }
settings = if (savedValue?.isString == true) {
// add item to mutable list
settings.withValue(setting, saveable.convertToValue(savedValue.content))
} else {
settings.withValue(setting, setting.selectedOption)
}
}
}

return settings
settings
}.getOrNull()
}

fun createFromDeeplinkUri(uri: Uri): PlaygroundSettings {
Expand All @@ -146,10 +156,11 @@ internal data class PlaygroundSettings(
MerchantSetting(),
PublicKeySetting(),
PrivateKeySetting(),
TestModeSetting(),
FlowSetting(),
ConfirmIntentSetting(),
NativeSetting(),
PermissionsSetting(),
ConfirmIntentSetting(),
EmailSetting(),
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.stripe.android.financialconnections.example.settings

import com.stripe.android.financialconnections.example.Flow
import com.stripe.android.financialconnections.example.Merchant
import com.stripe.android.financialconnections.example.data.model.LinkAccountSessionBody
import com.stripe.android.financialconnections.example.data.model.PaymentIntentBody

internal data class PrivateKeySetting(
override val selectedOption: String? = null,
override val selectedOption: String = "",
override val key: String = "sk"
) : Saveable<String?>, SingleChoiceSetting<String?>(
) : Saveable<String>, SingleChoiceSetting<String>(
displayName = "Private Key",
options = emptyList(),
selectedOption = selectedOption
Expand All @@ -21,12 +23,16 @@ internal data class PrivateKeySetting(

override fun valueUpdated(
currentSettings: List<Setting<*>>,
value: String?
value: String
): List<Setting<*>> {
return replace(currentSettings, this.copy(selectedOption = value))
}

override fun convertToString(value: String?): String? = value
override fun shouldDisplay(merchant: Merchant, flow: Flow): Boolean {
return merchant == Merchant.Custom
}

override fun convertToString(value: String): String = value

override fun convertToValue(value: String): String = value
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.stripe.android.financialconnections.example.settings

import com.stripe.android.financialconnections.example.Flow
import com.stripe.android.financialconnections.example.Merchant
import com.stripe.android.financialconnections.example.data.model.LinkAccountSessionBody
import com.stripe.android.financialconnections.example.data.model.PaymentIntentBody

internal data class PublicKeySetting(
override val selectedOption: String? = null,
override val selectedOption: String = "",
override val key: String = "pk"
) : Saveable<String?>, SingleChoiceSetting<String?>(
) : Saveable<String>, SingleChoiceSetting<String>(
displayName = "Publishable Key",
options = emptyList(),
selectedOption = selectedOption
Expand All @@ -22,12 +24,16 @@ internal data class PublicKeySetting(

override fun valueUpdated(
currentSettings: List<Setting<*>>,
value: String?
value: String
): List<Setting<*>> {
return replace(currentSettings, this.copy(selectedOption = value))
}

override fun convertToString(value: String?): String? = value
override fun shouldDisplay(merchant: Merchant, flow: Flow): Boolean {
return merchant == Merchant.Custom
}

override fun convertToString(value: String): String = value

override fun convertToValue(value: String): String = value
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.stripe.android.financialconnections.example.settings

import com.stripe.android.financialconnections.example.Flow
import com.stripe.android.financialconnections.example.Merchant
import com.stripe.android.financialconnections.example.data.model.LinkAccountSessionBody
import com.stripe.android.financialconnections.example.data.model.PaymentIntentBody

Expand All @@ -19,6 +21,8 @@ sealed class Setting<T> {
return this as? Saveable<T>?
}

open fun shouldDisplay(merchant: Merchant, flow: Flow): Boolean = true

abstract val displayName: String
abstract val selectedOption: T
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.stripe.android.financialconnections.example.settings

import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
Expand Down Expand Up @@ -41,11 +43,12 @@ internal fun SettingsUi(
playgroundSettings: PlaygroundSettings,
onSettingsChanged: (PlaygroundSettings) -> Unit,
) {
Column {
for (setting in playgroundSettings.settings) {
Row(modifier = Modifier.padding(bottom = 16.dp)) {
SingleSelectSetting(setting, playgroundSettings, onSettingsChanged)
}
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.animateContentSize(),
) {
for (setting in playgroundSettings.displayableSettings) {
SingleSelectSetting(setting, playgroundSettings, onSettingsChanged)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.stripe.android.financialconnections.example.settings

import com.stripe.android.financialconnections.example.Flow
import com.stripe.android.financialconnections.example.Merchant
import com.stripe.android.financialconnections.example.data.model.LinkAccountSessionBody
import com.stripe.android.financialconnections.example.data.model.PaymentIntentBody

data class TestModeSetting(
override val selectedOption: Boolean = false,
override val key: String = "financial_connections_test_mode",
) : Saveable<Boolean>, SingleChoiceSetting<Boolean>(
displayName = "Enable Test Mode",
options = listOf(
Option("On", true),
Option("Off", false),
),
selectedOption = selectedOption
) {
override fun lasRequest(
body: LinkAccountSessionBody,
): LinkAccountSessionBody = body.copy(testMode = selectedOption)

override fun paymentIntentRequest(
body: PaymentIntentBody,
): PaymentIntentBody = body.copy(testMode = selectedOption)

override fun valueUpdated(currentSettings: List<Setting<*>>, value: Boolean): List<Setting<*>> {
return replace(currentSettings, this.copy(selectedOption = value))
}

override fun shouldDisplay(merchant: Merchant, flow: Flow): Boolean {
return merchant != Merchant.Custom && merchant.canSwitchBetweenTestAndLive
}

override fun convertToValue(value: String): Boolean = value.toBoolean()

override fun convertToString(value: Boolean): String = value.toString()
}

0 comments on commit 299f56e

Please sign in to comment.