# Click-once

Learn about customisation options for the click-once component.

## Styling

```kotlin
val clickOnceComponentConfig = ClickOnceComponentConfig(
    headerTitle = String,
    submitText = String?,
    submitProcessingText = String?,
    selectCardText = String,
    expiredText = String?,
    validThruText = String?,
    hideCardBrandLogo = Boolean,
    disableCardSelection = Boolean,
    isRenderLastPurchaseCard = Boolean,
    isRenderLastPayoutCard = Boolean,
    isCvcRequired = Boolean,
    useTransparentCardBrandImage = Boolean,
    isProcessNextStepOnCardClick = Boolean,
    cvcComponentConfig = CardCvcComponentConfig?,
    cardSubmitComponentConfig = CardSubmitComponentConfig?,
    notificationConfig = NotificationConfig,
    cardBrandImages = CardBrandImages?,
    filterBy = CardTokenFilter,
    orderBy = CardTokenOrder,
    limitTokens = Int?,
    style = ClickOnceStyle
)
```

| Property | Description |
|  --- | --- |
| `headerTitle`String | Title text displayed at the top of the component. Defaults to default header title. |
| `submitText`String? | Text displayed on the submit button. |
| `submitProcessingText`String? | Text displayed during processing/loading state. Defaults to default processing text. |
| `selectCardText`String | Text for card selection prompt. Defaults to "Select Card". |
| `expiredText`String? | Text displayed for expired cards. |
| `validThruText`String? | Text displayed before expiry date (e.g., "Valid Thru"). Defaults to "Valid Thru". |
| `hideCardBrandLogo`Boolean | Whether to hide the card brand logo/icon. Defaults to `false`. |
| `disableCardSelection`Boolean | Whether to disable card selection functionality. Defaults to `false`. |
| `isRenderLastPurchaseCard`Boolean | Whether to render cards used for last purchase. Defaults to `true`. |
| `isRenderLastPayoutCard`Boolean | Whether to display cards previously used for successful payouts. When `true`, cards with a `lastSuccessfulPayoutDate` will be shown even if they haven't been used for purchases. Recommended for payout flows (`IntentType.Payout`) to show recipients their familiar payout cards. Defaults to `true`. |
| `isCvcRequired`Boolean | Whether CVC input is required for card selection. Defaults to `true`. |
| `useTransparentCardBrandImage`Boolean | Whether to use transparent background for card brand images. Defaults to `true`. |
| `isProcessNextStepOnCardClick`Boolean | Whether to automatically process next step when card is clicked. Defaults to `true`. |
| `cvcComponentConfig`CardCvcComponentConfig? | Configuration for the CVC input component. |
| `cardSubmitComponentConfig`CardSubmitComponentConfig? | Configuration for the card submit component. |
| `notificationConfig`NotificationConfig | Configuration for notifications display. Defaults to default configuration. |
| `cardBrandImages`CardBrandImages? | Custom card brand images configuration. |
| `filterBy`CardTokenFilter | Filter criteria for card tokens. Defaults to default filter. |
| `orderBy`CardTokenOrder | Sorting/ordering criteria for card tokens. Defaults to default order. |
| `limitTokens`Int? | Maximum number of tokens to display (null = no limit). |
| `style`ClickOnceStyle | Visual styling configuration for the component. Defaults to default style. |
| `onOnceCardClick`(() -> Unit)? | Callback triggered when a card is clicked. |
| `onPreRenderTokens`((List<CardToken>) -> List<CardTokenMapping>)? | Callback for custom token processing before rendering. |


## Callbacks

```kotlin
data class ClickOnceComponentConfig(
    val onValidationPassed: ((List<ValidationResult>) -> Unit)? = null,
    val onValidationFailed: ((List<ValidationResult>) -> Unit)? = null,
    val onTriggerFieldValidation: ((ValidationResult) -> Unit)? = null,
    val onOnceCardClick: (() -> Unit)? = null,
    val onPreRenderTokens: ((List<CardToken>) -> List<CardTokenMapping>)? = null
)
```

| Callback | Description |
|  --- | --- |
| `onValidationPassed: ((List<ValidationResult>) -> Unit)?` | Event handler for when validation passes. Inherited from ComponentConfigImpl. |
| `onValidationFailed: ((List<ValidationResult>) -> Unit)?` | Event handler for when validation fails. Inherited from ComponentConfigImpl. |
| `onTriggerFieldValidation: ((ValidationResult) -> Unit)?` | Event handler for when field validation is triggered individually. Inherited from ComponentConfigImpl. |
| `onOnceCardClick: (() -> Unit)?` | Event handler triggered when a card is clicked. |
| `onPreRenderTokens: ((List<CardToken>) -> List<CardTokenMapping>)?` | Event handler for custom token processing before rendering. |


For more information about callbacks, see [Events](/guides/checkout/components/android/card/events).

When using click-once with card submit, you can leverage the `onCustomValidation` callback via `cardSubmitComponentConfig` to implement custom business rule validation before payment submission. See [Card submit](/guides/checkout/components/android/card/card-submit) for details.

**Payout support:** The click-once component supports card payouts (also called disbursements or withdrawals) where funds are sent from your merchant account to a cardholder's card. This is commonly used for:

- Marketplace seller payments
- Insurance claim settlements
- Refunds and reimbursements
- Competition prizes and rewards


When using `intent = IntentType.Payout`, configure `isRenderLastPayoutCard = true` to display cards previously used for successful payouts, providing a familiar payout experience for returning recipients.

## Example

```kotlin
import com.pxp.checkout.components.clickonce.ClickOnceComponent
import com.pxp.checkout.components.clickonce.ClickOnceComponentConfig
import com.pxp.checkout.components.cardcvc.CardCvcComponentConfig
import com.pxp.checkout.components.cardsubmit.CardSubmitComponentConfig
import com.pxp.checkout.models.CardTokenFilter
import com.pxp.checkout.models.CardTokenOrder
import com.pxp.checkout.styles.ClickOnceStyle

// Optional: Create custom CVC configuration
val cvcConfig = CardCvcComponentConfig(
    label = "CVC",
    placeholder = "123",
    showMaskToggle = true
)

// Optional: Create custom submit configuration
val submitConfig = CardSubmitComponentConfig(
    buttonText = "Pay Now",
    loadingText = "Processing..."
)

// Optional: Create custom filtering and ordering
val tokenFilter = CardTokenFilter(
    excludeExpired = true,
    includeBrands = listOf(CardBrand.VISA, CardBrand.MASTERCARD)
)

val tokenOrder = CardTokenOrder(
    sortByLastUsed = true,
    sortByExpiryDate = false
)

// Optional: Create custom styling
val customStyle = ClickOnceStyle(
    colors = ClickOnceColors(
        primaryColor = Color.Blue,
        surfaceColor = Color.White,
        onSurfaceColor = Color.Black
    ),
    textStyles = ClickOnceTextStyles(
        cardNumberStyle = TextStyle(
            fontSize = 16.sp,
            fontWeight = FontWeight.SemiBold
        )
    )
)

val config = ClickOnceComponentConfig(
    // Display text configuration
    headerTitle = "Select Payment Method",
    submitText = "Pay Now",
    submitProcessingText = "Processing Payment...",
    selectCardText = "Choose your card",
    validThruText = "Valid Thru",
    
    // Behaviour configuration
    hideCardBrandLogo = false,
    disableCardSelection = false,
    isRenderLastPurchaseCard = true,
    isRenderLastPayoutCard = true,
    isCvcRequired = true,
    useTransparentCardBrandImage = true,
    isProcessNextStepOnCardClick = true,
    
    // Component integrations
    cvcComponentConfig = cvcConfig,
    cardSubmitComponentConfig = submitConfig,
    
    // Data management
    filterBy = tokenFilter,
    orderBy = tokenOrder,
    limitTokens = 5,
    
    // Styling
    style = customStyle,
    
    // Event handlers
    onOnceCardClick = {
        println("Card clicked for quick payment")
    },
    onPreRenderTokens = { tokens ->
        // Custom processing of tokens before display
        tokens.map { token ->
            CardTokenMapping(
                token = token,
                displayLabel = "•••• ${token.lastFourDigits}"
            )
        }
    }
)

val clickOnceComponent = checkout.createComponent<ClickOnceComponent, ClickOnceComponentConfig>(
    type = ComponentType.CLICK_ONCE,
    config = config
)
```

### Payout/disbursement flow

Use the click-once component to send funds to a cardholder's card (common for marketplace payouts, refunds, or prize disbursements):

```kotlin
val transactionData = TransactionData(
    amount = 150.00,
    currency = "USD",
    entryType = EntryType.Ecom,
    intent = IntentType.Payout,  // Critical: Set to Payout for disbursements
    merchantTransactionId = "payout-${System.currentTimeMillis()}",
    merchantTransactionDate = Date()
)

val config = ClickOnceComponentConfig(
    headerTitle = "Select payout card",
    submitText = "Send funds",
    submitProcessingText = "Processing payout...",
    
    // Enable payout-specific features
    isRenderLastPayoutCard = true,  // Show cards used for previous payouts
    isRenderLastPurchaseCard = false,  // Optionally hide purchase-only cards
    
    // Sort by most recent payout activity
    orderBy = CardTokenOrder(
        sortByField = LastUsageField.PAYOUT_DATE,
        direction = SortDirection.DESC
    ),
    
    isCvcRequired = true,
    limitTokens = 5,
    
    cardSubmitComponentConfig = CardSubmitComponentConfig(
        onPreAuthorisation = { data ->
            // Add any payout-specific data
            TransactionInitiationData(
                riskScreeningData = RiskScreeningData(
                    performRiskScreening = true,
                    userIp = "192.168.1.100",
                    account = RiskScreeningAccount(
                        id = "recipient_12345",
                        creationDateTime = "2024-01-15T10:30:00.000Z"
                    ),
                    fulfillments = listOf(
                        RiskScreeningFulfillment(
                            type = FulfillmentType.SHIPPED,
                            recipientPerson = RiskScreeningRecipientPerson(
                                phoneNumber = "+1234567890"
                            )
                        )
                    )
                )
            )
        },
        onPostAuthorisation = { result ->
            Log.d("Payout", "Completed: ${result.merchantTransactionId}")
            navigateToPayoutConfirmation()
        }
    ),
    
    onOnceCardClick = {
        Log.d("Payout", "Card selected for payout")
    }
)

val clickOnceComponent = checkout.createComponent<ClickOnceComponent, ClickOnceComponentConfig>(
    type = ComponentType.CLICK_ONCE,
    config = config
)
```

When using `IntentType.Payout`, funds move from your merchant account to the cardholder's card. Ensure you have sufficient balance in your account and use appropriate messaging ("withdraw", "receive", "send to your card"). Note that not all cards support payouts.