Wallet Screen¶
We provide a complete wallet experience via our WalletScreen
- in both a self-managed capacity and a fully "Ansa-managed" experience.
Ansa Managed UI¶
The Ansa-managed screen utilizes your AnsaClient
and handles ALL internal workings of the screen.
The simplest setup of WalletScreen
is 4 lines.
val ansaClient = AnsaClient.init(
/* initialization params */
)
AnsaTheme {
AnsaWalletScreen(
ansaClient = ansaClient,
customerId = { /* the customer ID provided */ },
merchantId = { /* the merchant ID provided */ },
)
}
The Ansa managed experience also supports being used as a nested destination by providing onNavigateBack
callback. In doing so, a back arrow will be placed in the Top App Bar of the screen.
AnsaWalletScreen(
ansaClient = ansaClient,
customerId = { /* the customer ID provided */ },
merchantId = { /* the merchant ID provided */ },
onNavigateBack = { navigator.pop() }
)
Self Managed UI¶
The WalletScreen
also supports self-management via all knobs you would expect.
AnsaWalletScreen(
title: String = stringResource(Res.string.home_screen_title),
termsAndConditions: TermsAndConditions? = null,
isRefreshing: Boolean,
isSandboxMode: Boolean = false,
merchantCardArt: String? = null,
balance: Balance = Balance(0, LocalCurrencyFormatter.current.localCurrency()),
alertContent: InlineAlertContent? = null,
transactions: List<Transaction> = emptyList(),
autoReloadConfiguration: AutoReloadConfiguration?,
userReloadConfiguration: UserReloadConfiguration?,
onRefresh: () -> Unit,
onSelectPaymentMethod: (() -> Unit),
onAddFunds: () -> Unit,
onAutoReloadClicked: () -> Unit,
onAddCard: (() -> Unit)? = null,
onHowToUseBalance: (() -> Unit)? = null,
onRedeemGiftCard: (() -> Unit)? = null,
onNavigateBack: (() -> Unit)? = null,
endContent: @Composable BoxScope.() -> Unit = { },
)
The data you provide will be rendered as such.
Custom Add Card Handling¶
In both Ansa managed and Self managed UI, we support the ability to handle/override the "Add Card" flow. This is handled by provided the onAddCard
callback. This can be utilized to navigate to another screen, show a modal, etc. Once the card is successfully added via our APIs and you receive a PaymentMethod
from the backend, you can inform the SDK of the change via the LocalPaymentMethodManager
Composition local by calling onPaymentMethodAdded(paymentMethod)
. If the add flow is cancelled, simply call onCancelled
An example of this in action with a BottomSheet:
AnsaTheme {
val paymentMethodUpdateManager = LocalPaymentMethodManager.current
val bottomSheetState =
rememberStandardBottomSheetState(
initialValue = SheetValue.Hidden,
skipHiddenState = false,
)
val scaffoldState =
rememberBottomSheetScaffoldState(bottomSheetState = bottomSheetState)
val composeScope = rememberCoroutineScope()
BottomSheetScaffold(
scaffoldState = scaffoldState,
sheetShadowElevation = 8.dp,
sheetPeekHeight = 0.dp,
sheetContent = {
PrimaryButtonLarge(
modifier = Modifier.navigationBarsPadding(),
text = "Click me",
onClick = {
composeScope.launch {
val paymentMethod =
PaymentMethod(
card =
Card(
brand = "visa",
fingerprint = UUID.randomUUID().toString(),
lastFour = "4890",
firstSix = "123456"
),
id = UUID.randomUUID().toString(),
type = "credit_card"
)
// notify SDK cancelled payment method selection flow
// paymentUpdateManager.onCancelled()
// notify SDK user added payment method
paymentMethodUpdateManager.onPaymentMethodAdded(paymentMethod)
bottomSheetState.hide()
}
}
)
}
) {
BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
AnsaWalletScreen(
ansaClient = ansaClient,
customerId = { BuildConfig.CUSTOMER_ID },
merchantId = { BuildConfig.MERCHANT_ID },
onAddCard = {
composeScope.launch {
bottomSheetState.show()
}
}
)
val maxHeightPx = with(LocalDensity.current) { maxHeight.toPx() }
val scrim by
animateColorAsState(
targetValue =
if (maxHeightPx - bottomSheetState.requireOffset() > 0f)
AnsaTheme.colors.background.scrim
else Color.Transparent
)
Box(
modifier =
Modifier.matchParentSize().background(scrim).addIf(
bottomSheetState.currentValue == SheetValue.Expanded
) {
Modifier.clickable {
composeScope.launch {
bottomSheetState.hide()
delay(300)
paymentMethodUpdateManager.onCancelled()
}
}
}
)
}
}
}
Custom Select Payment Method Handling¶
Similarly, in both Ansa managed and Self managed UI, we support the ability to handle/override the "Select Payment Method" flow. This is handled by provided the onSelectPaymentMethod
callback. This can be utilized to navigate to another screen, show a modal, etc. Once the card is successfully added via our APIs and you receive a PaymentMethod
from the backend, you can inform the SDK of the change via the LocalPaymentMethodManager
Composition local by calling onPaymentMethodAdded(paymentMethod)
. If the add flow is cancelled, simply call onCancelled
An example of this in action with a BottomSheet:
AnsaTheme {
val paymentMethodUpdateManager = LocalPaymentMethodManager.current
val bottomSheetState =
rememberStandardBottomSheetState(
initialValue = SheetValue.Hidden,
skipHiddenState = false,
)
val scaffoldState =
rememberBottomSheetScaffoldState(bottomSheetState = bottomSheetState)
val composeScope = rememberCoroutineScope()
BottomSheetScaffold(
scaffoldState = scaffoldState,
sheetShadowElevation = 8.dp,
sheetPeekHeight = 0.dp,
sheetContent = {
PrimaryButtonLarge(
modifier = Modifier.navigationBarsPadding(),
text = "Click me to select card",
onClick = {
composeScope.launch {
val paymentMethod =
PaymentMethod(
card =
Card(
brand = "visa",
fingerprint = UUID.randomUUID().toString(),
lastFour = "4890",
firstSix = "123456"
),
id = UUID.randomUUID().toString(),
type = "credit_card"
)
// notify SDK cancelled payment method selection flow
// paymentUpdateManager.onCancelled()
// notify SDK user added or selected payment method
paymentMethodUpdateManager.onPaymentMethodAdded(paymentMethod)
bottomSheetState.hide()
}
}
)
}
) {
BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
AnsaWalletScreen(
ansaClient = ansaClient,
customerId = { BuildConfig.CUSTOMER_ID },
merchantId = { BuildConfig.MERCHANT_ID },
onSelectPaymentMethod = {
composeScope.launch {
bottomSheetState.show()
}
}
)
val maxHeightPx = with(LocalDensity.current) { maxHeight.toPx() }
val scrim by
animateColorAsState(
targetValue =
if (maxHeightPx - bottomSheetState.requireOffset() > 0f)
AnsaTheme.colors.background.scrim
else Color.Transparent
)
Box(
modifier =
Modifier.matchParentSize().background(scrim).addIf(
bottomSheetState.currentValue == SheetValue.Expanded
) {
Modifier.clickable {
composeScope.launch {
bottomSheetState.hide()
delay(300)
paymentMethodUpdateManager.onCancelled()
}
}
}
)
}
}
}