import { PayerSearchCombobox } from "@samplehc/ui/components";
import { useState } from "react";
import { Button } from "@samplehc/ui/components/ui";
import { X } from "lucide-react";

function MultiplePayerSelection() {
  const [selectedPayers, setSelectedPayers] = useState([]);

  const handleAddPayer = (payer) => {
    if (payer && !selectedPayers.find(p => p.stediId === payer.stediId)) {
      setSelectedPayers([...selectedPayers, payer]);
    }
  };

  const handleRemovePayer = (payerId) => {
    setSelectedPayers(selectedPayers.filter(p => p.stediId !== payerId));
  };

  return (
    <div className="space-y-4">
      <div>
        <label className="block text-sm font-medium mb-2">
          Add Insurance Providers
        </label>
        <PayerSearchCombobox
          onSelect={handleAddPayer}
          placeholder="Search and add payers..."
        />
      </div>
      
      {selectedPayers.length > 0 && (
        <div className="space-y-2">
          <h3 className="text-sm font-medium">Selected Payers:</h3>
          {selectedPayers.map((payer) => (
            <div
              key={payer.stediId}
              className="flex items-center justify-between p-3 bg-muted rounded-md"
            >
              <div>
                <span className="font-medium">{payer.displayName}</span>
                <span className="text-sm text-muted-foreground ml-2">
                  ({payer.primaryPayerId})
                </span>
              </div>
              <Button
                variant="ghost"
                size="sm"
                onClick={() => handleRemovePayer(payer.stediId)}
              >
                <X className="h-4 w-4" />
              </Button>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

Overview

The PayerSearchCombobox provides a powerful search interface for finding healthcare payers and insurance providers. It features real-time search, autocomplete suggestions, alias support, and integration with the SampleHC clearinghouse database.

Basic Usage

import { PayerSearchCombobox } from "@samplehc/ui/components";
import { useState } from "react";

function PayerSelection() {
  const [selectedPayer, setSelectedPayer] = useState(null);

  return (
    <div className="space-y-4">
      <PayerSearchCombobox
        placeholder="Search for insurance provider..."
        onSelect={setSelectedPayer}
        value={selectedPayer}
      />
      
      {selectedPayer && (
        <div className="p-4 bg-muted rounded-md">
          <h3 className="font-semibold">{selectedPayer.displayName}</h3>
          <p className="text-sm text-muted-foreground">
            Payer ID: {selectedPayer.primaryPayerId}
          </p>
        </div>
      )}
    </div>
  );
}

API Reference

PayerSearchComboboxProps

onSelect
function

Callback function called when a payer is selected or cleared.

onSelect?: (item: PayerSearchItem | null) => void
value
PayerSearchItem | null

Currently selected payer item for controlled component behavior.

disabled
boolean

Disable the combobox interaction. Defaults to false.

required
boolean

Mark the field as required for form validation. Defaults to false.

className
string

Additional CSS classes to apply to the trigger element.

placeholder
string

Placeholder text shown when no payer is selected. Defaults to “Search payers…”.

id
string

HTML id attribute for the combobox. Defaults to “payer-search-combobox”.

PayerSearchItem

stediId
string
required

Unique identifier for the payer in the Stedi clearinghouse system.

displayName
string
required

Primary display name for the payer (e.g., “Blue Cross Blue Shield”).

primaryPayerId
string
required

Primary payer identifier used for claims submission.

aliases
string[]
required

Array of alternative names and aliases for the payer.

names
string[]
required

Array of all known names for the payer, including official names.

Search Hook

You can also use the search functionality independently with the usePayerSearch hook:

import { usePayerSearch } from "@samplehc/ui/components";
import { useState } from "react";
import { useDebounce } from "@samplehc/ui/lib/hooks";

function CustomPayerSearch() {
  const [query, setQuery] = useState("");
  const debouncedQuery = useDebounce(query, 300);
  
  const { data: searchResults, isLoading, error } = usePayerSearch(
    debouncedQuery,
    { enabled: debouncedQuery.length >= 2 }
  );

  return (
    <div className="space-y-4">
      <input
        type="text"
        placeholder="Search payers..."
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        className="w-full p-2 border rounded"
      />
      
      {isLoading && <p>Searching...</p>}
      
      {error && (
        <p className="text-red-500">
          Search failed: {error.message}
        </p>
      )}
      
      {searchResults && (
        <div className="space-y-2">
          {searchResults.map((payer) => (
            <div key={payer.stediId} className="p-3 border rounded">
              <h3 className="font-semibold">{payer.displayName}</h3>
              <p className="text-sm text-gray-600">
                ID: {payer.primaryPayerId}
              </p>
              {payer.aliases.length > 0 && (
                <p className="text-xs text-gray-500">
                  Also known as: {payer.aliases.join(", ")}
                </p>
              )}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

Advanced Examples

Multiple Payer Selection

import { PayerSearchCombobox } from "@samplehc/ui/components";
import { useState } from "react";
import { Button } from "@samplehc/ui/components/ui";
import { X } from "lucide-react";

function MultiplePayerSelection() {
  const [selectedPayers, setSelectedPayers] = useState([]);

  const handleAddPayer = (payer) => {
    if (payer && !selectedPayers.find(p => p.stediId === payer.stediId)) {
      setSelectedPayers([...selectedPayers, payer]);
    }
  };

  const handleRemovePayer = (payerId) => {
    setSelectedPayers(selectedPayers.filter(p => p.stediId !== payerId));
  };

  return (
    <div className="space-y-4">
      <div>
        <label className="block text-sm font-medium mb-2">
          Add Insurance Providers
        </label>
        <PayerSearchCombobox
          onSelect={handleAddPayer}
          placeholder="Search and add payers..."
        />
      </div>
      
      {selectedPayers.length > 0 && (
        <div className="space-y-2">
          <h3 className="text-sm font-medium">Selected Payers:</h3>
          {selectedPayers.map((payer) => (
            <div
              key={payer.stediId}
              className="flex items-center justify-between p-3 bg-muted rounded-md"
            >
              <div>
                <span className="font-medium">{payer.displayName}</span>
                <span className="text-sm text-muted-foreground ml-2">
                  ({payer.primaryPayerId})
                </span>
              </div>
              <Button
                variant="ghost"
                size="sm"
                onClick={() => handleRemovePayer(payer.stediId)}
              >
                <X className="h-4 w-4" />
              </Button>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

Validation and Error Handling

import { PayerSearchCombobox } from "@samplehc/ui/components";
import { useState } from "react";

function ValidatedPayerForm() {
  const [selectedPayer, setSelectedPayer] = useState(null);
  const [error, setError] = useState("");

  const validatePayer = (payer) => {
    if (!payer) {
      setError("Please select an insurance provider");
      return false;
    }
    
    // Custom validation logic
    if (!payer.primaryPayerId) {
      setError("Selected payer has invalid configuration");
      return false;
    }
    
    setError("");
    return true;
  };

  const handleSubmit = () => {
    if (validatePayer(selectedPayer)) {
      console.log("Valid payer selected:", selectedPayer);
      // Proceed with form submission
    }
  };

  return (
    <div className="space-y-4">
      <div>
        <label className="block text-sm font-medium mb-2">
          Primary Insurance Provider *
        </label>
        <PayerSearchCombobox
          onSelect={(payer) => {
            setSelectedPayer(payer);
            if (payer) setError(""); // Clear error when selection made
          }}
          value={selectedPayer}
          required
          className={error ? "border-red-500" : ""}
        />
        {error && (
          <p className="text-sm text-red-500 mt-1">{error}</p>
        )}
      </div>
      
      <Button 
        onClick={handleSubmit}
        disabled={!selectedPayer}
      >
        Continue
      </Button>
    </div>
  );
}

Features

  • Debounced Input: Search queries are debounced to reduce API calls
  • Minimum Query Length: Search begins after 2+ characters
  • Live Results: Results update as you type

Smart Matching

  • Primary Names: Matches against official payer names
  • Aliases: Searches through known aliases and alternative names
  • Fuzzy Matching: Handles minor spelling variations and typos

User Experience

  • Keyboard Navigation: Full keyboard support with arrow keys and Enter
  • Loading States: Visual feedback during search operations
  • Error Handling: Graceful error handling with retry options
  • Accessibility: ARIA labels and screen reader support

Visual Features

  • Alias Display: Shows number of aliases with tooltip details
  • Clear Selection: Easy-to-use clear button for selected items
  • Responsive Design: Works on mobile and desktop devices

Error Handling

The component includes comprehensive error handling:

// Automatic retry for temporary network issues
{
  retry: (failureCount, error) => {
    // Don't retry authentication errors
    if (error.message.includes("Authentication")) {
      return false;
    }
    return failureCount < 2;
  }
}

Integration Notes

Backend Integration: The component automatically uses the configured backend URL and authentication from the workflow context.

Performance: Search results are cached for 30 seconds to improve performance for repeated queries.

API Requirements: Requires valid API credentials and access to the SampleHC clearinghouse endpoints.

Styling

The component inherits your application’s theme and can be customized:

<PayerSearchCombobox
  className="w-full border-2 border-primary"
  // Applies custom styling to the trigger element
/>

All styling is compatible with Tailwind CSS classes and follows the shadcn/ui design system.