Create CartUiState.kt — client secret and PaymentSheet
In the code column — CartUiState.kt. The new clientSecret field is a switch: when it becomes non-null, the screen presents the PaymentSheet. totalCents is the amount in Stripe's format (cents).
How does clientSecret turn into a payment dialog? CartScreen uses Stripe's composables:
// 1) prepare the PaymentSheet and describe what to do with the result
val paymentSheet = rememberPaymentSheet { result ->
when (result) {
is PaymentSheetResult.Completed -> viewModel.onEvent(CartEvent.PaymentSucceeded)
is PaymentSheetResult.Canceled -> viewModel.onEvent(CartEvent.PaymentCanceled)
is PaymentSheetResult.Failed -> viewModel.onEvent(CartEvent.PaymentFailed(result.error.message))
}
}
// 2) when a clientSecret appears → present the payment dialog
LaunchedEffect(state.clientSecret) {
state.clientSecret?.let { secret ->
paymentSheet.presentWithPaymentIntent(
secret,
PaymentSheet.Configuration(merchantDisplayName = "Pica")
)
}
}
// 3) order recorded → snackbar and go back
LaunchedEffect(state.orderPlaced) {
if (state.orderPlaced) {
snackbarHostState.showSnackbar("Payment complete! 🍕")
viewModel.onEvent(CartEvent.ClearOrderPlaced)
onOrderPlaced()
}
}
The full cycle: Checkout → startPayment() → clientSecret → LaunchedEffect presents PaymentSheet → the user enters a card → Completed → PaymentSucceeded → completeOrder() → orderPlaced → snackbar.
Verify. Test mode, test card 4242 4242 4242 4242, any future date, any CVC:
1. Cart → "Pay" → briefly ⟳ (a PaymentIntent is created).
2. The Stripe PaymentSheet pops up → enter 4242… → "Pay €X".
3. "Payment complete! 🍕" → the order appears in history (status "paid"/"created").
Gotcha (initialization). If you don't call
PaymentConfiguration.init(...)inApplication.onCreate(or you call it afterPaymentSheet), the app crashes:java.lang.IllegalStateException: PaymentConfiguration was not initialized. Call PaymentConfiguration.init(context, publishableKey)Without the publishable key,
PaymentSheethas no idea which Stripe account to talk to. Initialize it once, early — in theApplicationclass (right wherestartKoinlives).