UI Components

Pre-built React Native components for promo code entry

ReferralCodeInput

A complete, production-ready component for promo code entry with validation, auto-prefill, and full customization support.

Installation

import { ReferralCodeInput } from '@influto/react-native-sdk/ui';

// Note: Separate import to keep main SDK bundle small

Basic Usage

<ReferralCodeInput
  onValidated={(result) => {
    if (result.valid) {
      navigation.navigate('Paywall');
    }
  }}
  onSkip={() => navigation.navigate('Paywall')}
/>

Props Reference

Behavior Props

PropTypeDefaultDescription
autoPrefillbooleantrueAuto-fill code if user clicked link
autoValidatebooleanfalseAuto-validate prefilled codes
showSkipButtonbooleantrueShow skip button
validateOnBlurbooleantrueValidate when user leaves input
appUserIdstring-User ID for attribution

Callback Props

PropTypeDescription
onValidated(result) => voidCalled when validation completes
onApplied(result) => voidCalled when code successfully applied
onSkip() => voidCalled when user skips

Styling Props - Colors (8 options)

colors={{
  primary: '#3B82F6',           // Main brand color
  success: '#10B981',           // Valid state
  error: '#EF4444',             // Invalid/error state
  text: '#1F2937',              // Primary text
  textSecondary: '#6B7280',     // Secondary text
  background: '#FFFFFF',        // Container background
  border: '#D1D5DB',            // Input border
  inputBackground: '#F9FAFB'    // Input field background
}}

Styling Props - Fonts (4 options)

fonts={{
  family: 'YourCustomFont-Regular',  // Font family
  sizeTitle: 20,                     // Title size
  sizeInput: 18,                     // Input text size
  sizeButton: 16,                    // Button text size
  sizeMessage: 14                    // Message text size
}}

Styling Props - Labels (10 customizable strings)

labels={{
  title: 'Have a promo code?',
  subtitle: 'Enter your referral code',
  placeholder: 'Enter code',
  validateButton: 'Apply Code',
  skipButton: 'Skip',
  validatingMessage: 'Checking...',
  validMessage: 'Code applied!',
  invalidMessage: 'Invalid code',
  errorMessage: 'Connection error',
  prefilledMessage: 'Code detected from link'
}}

Styling Props - Style Objects (13 options)

style={{
  container: { padding: 24, borderRadius: 16 },
  titleContainer: { marginBottom: 20 },
  title: { fontSize: 22, fontWeight: 'bold' },
  subtitle: { fontSize: 14, color: '#666' },
  inputContainer: { marginBottom: 16 },
  input: { height: 56, borderWidth: 2 },
  buttonContainer: { flexDirection: 'row', gap: 12 },
  validateButton: { flex: 1, borderRadius: 12 },
  validateButtonText: { fontSize: 17 },
  skipButton: { paddingHorizontal: 20 },
  skipButtonText: { fontSize: 15 },
  messageContainer: { padding: 12 },
  messageText: { textAlign: 'center' }
}}

Complete Example

import { ReferralCodeInput } from '@influto/react-native-sdk/ui';

<ReferralCodeInput
  // Behavior
  autoPrefill={true}
  autoValidate={false}
  showSkipButton={true}
  validateOnBlur={true}
  appUserId={user.id}

  // Callbacks
  onValidated={(result) => {
    if (result.valid) {
      console.log('Valid code!');
      console.log('Campaign:', result.campaign);
      console.log('Influencer:', result.influencer);

      // Custom logic based on campaign
      if (result.campaign.commission_percentage >= 30) {
        showPremiumOffer();
      } else {
        showStandardOffer();
      }
    } else {
      console.log('Invalid:', result.error);
    }
  }}

  onApplied={(result) => {
    // Code successfully set in RevenueCat
    analytics.track('promo_code_applied', {
      code: result.code,
      campaign: result.campaign.name
    });
  }}

  onSkip={() => {
    navigation.navigate('Paywall');
  }}

  // Branding
  colors={{
    primary: '#FF6B00',      // Your orange
    success: '#10B981',
    error: '#EF4444'
  }}

  fonts={{
    family: 'YourApp-Bold',
    sizeInput: 18
  }}

  // Internationalization
  labels={{
    title: '¿Tienes un código?',
    placeholder: 'Código promocional',
    validateButton: 'Aplicar',
    skipButton: 'Omitir'
  }}

  // Fine-grained styling
  style={{
    container: {
      padding: 24,
      borderRadius: 16,
      backgroundColor: '#FFFFFF'
    },
    input: {
      height: 56,
      borderWidth: 2.5
    }
  }}
/>

Component States

State: Idle

  • Default state
  • Input enabled
  • Button enabled
  • No message shown

State: Validating

  • Loading spinner shown
  • Input disabled
  • Button shows validatingMessage

State: Valid

  • Green checkmark icon
  • Green border on input
  • Success message shown
  • Campaign info displayed
  • onValidated callback fired
  • onApplied callback fired

State: Invalid

  • Red X icon
  • Red border on input
  • Error message shown
  • onValidated callback fired with error

State: Error

  • Network/system error
  • Error message shown
  • User can retry

Accessibility

  • ✓ Screen reader labels
  • ✓ Keyboard navigation
  • ✓ Focus management
  • ✓ High contrast support

Performance

  • Bundle size: ~16 KB (compressed)
  • Dependencies: Only React Native built-ins
  • Renders: Optimized with React.memo
  • Network: Debounced validation

Examples

Minimal (2 lines)

<ReferralCodeInput
  onValidated={(r) => r.valid && navigate('Paywall')}
/>

Onboarding Integration

function OnboardingStep3() {
  return (
    <View>
      <Text>Almost done!</Text>

      <ReferralCodeInput
        autoPrefill={true}
        onValidated={(result) => {
          if (result.valid) {
            setUserData({ campaign: result.campaign });
            goToStep(4);
          }
        }}
        onSkip={() => goToStep(4)}
      />
    </View>
  );
}

Settings Page

function SettingsScreen() {
  return (
    <ReferralCodeInput
      autoPrefill={false}  // Don't prefill in settings
      showSkipButton={false}  // No skip in settings
      appUserId={user.id}
      labels={{
        title: 'Add Referral Code',
        validateButton: 'Add to Account'
      }}
      onValidated={(result) => {
        if (result.valid) {
          closeModal();
          showToast('Code added successfully!');
        }
      }}
    />
  );
}

Next Steps

  1. View all TypeScript types
  2. See complete integration example