@cardql/react-native-tap
Version:
CardQL SDK for React Native tap-to-pay for secure in-person payments
300 lines (278 loc) • 8.17 kB
text/typescript
import type { Payment, CreatePaymentInput } from "@cardql/core";
import type {
Reader,
Cart,
PaymentIntent,
SetupIntent,
Location,
PaymentMethod as StripePaymentMethod,
} from "@stripe/stripe-terminal-react-native";
// Stripe Terminal specific types
export interface StripeTerminalConfig {
tokenProvider: () => Promise<string>;
logLevel?: "verbose" | "info" | "warn" | "error";
simulated?: boolean;
}
export interface StripeReaderConfig {
discoveryMethod: "bluetoothScan" | "localMobile" | "internet";
simulated?: boolean;
locationId?: string;
enableCustomerCancellation?: boolean;
skipTipping?: boolean;
updatePaymentIntent?: boolean;
}
// NFC and Device Capabilities (enhanced for Stripe Terminal)
export interface NFCCapabilities {
isNFCSupported: boolean;
isNFCEnabled: boolean;
canProcessPayments: boolean;
supportedCardTypes: CardType[];
maxTransactionAmount?: string;
supportsLocalMobile: boolean;
supportsBluetoothReaders: boolean;
}
export interface DeviceCapabilities {
nfc: NFCCapabilities;
hasSecureElement: boolean;
supportsTapToPay: boolean;
supportsStripeTerminal: boolean;
deviceModel: string;
osVersion: string;
stripeTerminalVersion?: string;
}
// Card and Payment Types (aligned with Stripe Terminal)
export type CardType =
| "visa"
| "mastercard"
| "amex"
| "discover"
| "diners"
| "jcb"
| "unionpay"
| "maestro"
| "contactless"
| "unknown";
export type PaymentMethod =
| "card_present"
| "contactless_card"
| "mobile_wallet"
| "apple_pay"
| "google_pay"
| "samsung_pay"
| "interac_present"
| "unknown";
// Transaction States (enhanced for Stripe Terminal workflow)
export type TapTransactionState =
| "idle"
| "initializing"
| "discovering_readers"
| "reader_connected"
| "waiting_for_input"
| "processing_payment_method"
| "processing_payment"
| "capturing_payment"
| "requires_confirmation"
| "requires_action"
| "success"
| "failed"
| "cancelled"
| "timeout";
// Transaction Data (enhanced with Stripe Terminal data)
export interface TapTransactionData {
id: string;
state: TapTransactionState;
amount: string;
currency: string;
cardType?: CardType;
paymentMethod?: PaymentMethod;
lastFourDigits?: string;
cardholderName?: string;
applicationId?: string;
transactionId?: string;
paymentIntentId?: string;
stripePaymentIntentId?: string;
authorizationCode?: string;
receiptNumber?: string;
timestamp: Date;
stripePaymentIntent?: PaymentIntent;
stripePaymentMethod?: StripePaymentMethod;
reader?: Reader;
metadata?: Record<string, any>;
}
// Configuration (enhanced for Stripe Terminal)
export interface TapToPayConfig {
merchantID: string;
acceptedCardTypes?: CardType[];
maxAmount?: string;
currency?: string;
requireSignature?: boolean;
requirePin?: boolean;
timeout?: number; // in milliseconds
enableTips?: boolean;
enablePartialPayments?: boolean;
skipReceipt?: boolean;
stripeConfig: StripeTerminalConfig;
captureMethod?: "automatic" | "manual";
customBranding?: {
primaryColor?: string;
logo?: string;
merchantName?: string;
};
}
// Reader Configuration (enhanced for Stripe Terminal)
export interface CardReaderConfig extends StripeReaderConfig {
autoConnect?: boolean;
autoStart?: boolean;
vibrationEnabled?: boolean;
soundEnabled?: boolean;
animationEnabled?: boolean;
showAmount?: boolean;
showInstructions?: boolean;
instructionText?: string;
successMessage?: string;
errorMessage?: string;
enableTipping?: boolean;
tipEligibleAmount?: number;
skipTipping?: boolean;
}
// Transaction Input (enhanced for Stripe)
export interface CreateTapPaymentInput
extends Omit<CreatePaymentInput, "amount"> {
amount: string;
currency: string;
merchantID: string;
tipAmount?: string;
cashbackAmount?: string;
taxAmount?: string;
applicationFeeAmount?: string;
onBehalfOf?: string;
transferGroup?: string;
paymentMethodOptions?: Record<string, any>;
metadata?: Record<string, any>;
captureMethod?: "automatic" | "manual";
setupFutureUsage?: "off_session" | "on_session";
}
// Transaction Result (enhanced with Stripe data)
export interface TapPaymentResult {
success: boolean;
payment?: Payment;
transactionData?: TapTransactionData;
stripePaymentIntent?: PaymentIntent;
stripePaymentMethod?: StripePaymentMethod;
error?: TapToPayError;
receiptData?: ReceiptData;
needsConfirmation?: boolean;
requiresAction?: boolean;
nextAction?: string;
}
// Receipt Data (enhanced with Stripe data)
export interface ReceiptData {
transactionId: string;
stripePaymentIntentId?: string;
merchantName: string;
merchantAddress?: string;
amount: string;
currency: string;
tipAmount?: string;
totalAmount: string;
cardType?: CardType;
lastFourDigits?: string;
paymentMethod?: PaymentMethod;
authorizationCode?: string;
timestamp: Date;
signature?: string;
readerSerialNumber?: string;
applicationCryptogram?: string;
applicationPreferredName?: string;
additionalInfo?: Record<string, any>;
}
// Error Types (enhanced for Stripe Terminal)
export type TapToPayErrorCode =
| "TERMINAL_NOT_SUPPORTED"
| "TERMINAL_NOT_INITIALIZED"
| "READER_CONNECTION_FAILED"
| "READER_DISCOVERY_FAILED"
| "PAYMENT_INTENT_CREATION_FAILED"
| "PAYMENT_COLLECTION_FAILED"
| "PAYMENT_CONFIRMATION_FAILED"
| "CARD_READ_ERROR"
| "CARD_NOT_SUPPORTED"
| "TRANSACTION_DECLINED"
| "TRANSACTION_TIMEOUT"
| "TRANSACTION_CANCELLED"
| "AMOUNT_TOO_HIGH"
| "AMOUNT_TOO_LOW"
| "DEVICE_NOT_COMPATIBLE"
| "SECURITY_ERROR"
| "NETWORK_ERROR"
| "VALIDATION_ERROR"
| "STRIPE_ERROR"
| "UNKNOWN_ERROR";
export interface TapToPayError {
code: TapToPayErrorCode;
message: string;
details?: any;
stripeError?: any;
userFriendlyMessage?: string;
canRetry?: boolean;
suggestedAction?: string;
}
// Event Types (enhanced for Stripe Terminal)
export interface TapToPayEvents {
onTransactionStateChange: (
state: TapTransactionState,
data?: TapTransactionData
) => void;
onReaderDiscovered: (readers: Reader[]) => void;
onReaderConnected: (reader: Reader) => void;
onReaderDisconnected: (reason?: string) => void;
onPaymentMethodCollected: (paymentMethod: StripePaymentMethod) => void;
onPaymentIntentCreated: (paymentIntent: PaymentIntent) => void;
onPaymentIntentUpdated: (paymentIntent: PaymentIntent) => void;
onDisplayMessage: (message: string) => void;
onReaderInputPrompt: (prompt: string) => void;
onError: (error: TapToPayError) => void;
onSuccess: (result: TapPaymentResult) => void;
onCancel: () => void;
onTimeout: () => void;
}
// Hook Options (enhanced for Stripe Terminal)
export interface UseTapToPayOptions {
config?: TapToPayConfig;
readerConfig?: CardReaderConfig;
events?: Partial<TapToPayEvents>;
autoInit?: boolean;
autoDiscoverReaders?: boolean;
autoConnectReader?: boolean;
}
// Hook Result (enhanced for Stripe Terminal)
export interface UseTapToPayResult {
// State
isSupported: boolean;
isInitialized: boolean;
isDiscoveringReaders: boolean;
discoveredReaders: Reader[];
connectedReader?: Reader;
isCollectingPayment: boolean;
currentTransaction?: TapTransactionData;
deviceCapabilities?: DeviceCapabilities;
// Actions
initialize: () => Promise<void>;
discoverReaders: (config?: StripeReaderConfig) => Promise<void>;
connectReader: (reader: Reader) => Promise<void>;
disconnectReader: () => Promise<void>;
createPaymentIntent: (input: CreateTapPaymentInput) => Promise<PaymentIntent>;
collectPaymentMethod: (
paymentIntent: PaymentIntent
) => Promise<PaymentIntent>;
confirmPayment: (paymentIntent: PaymentIntent) => Promise<TapPaymentResult>;
processPayment: (input: CreateTapPaymentInput) => Promise<TapPaymentResult>;
cancelPayment: () => Promise<void>;
// Utilities
checkTerminalStatus: () => Promise<DeviceCapabilities>;
formatReceipt: (receiptData: ReceiptData) => string;
getConnectionStatus: () => Reader.ConnectionStatus;
// Error handling
lastError?: TapToPayError;
clearError: () => void;
}