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()
}
}
}
)
}
}
}