Skip to content

Client Search

Client search interface designed to be embedded in the IPA top feature for quick client lookups across the platform.

Overview

  • Route: /feature/one-place-client-search
  • Framework: Angular 19 (standalone component)
  • Main Component: ClientSearchComponent
  • Feature Type: Top Feature (height: 200px)

Purpose

Provides a lightweight, embedded client search interface that:

  • Appears in the IPA top feature bar
  • Allows searching for clients by name or GCN
  • Updates the active client context platform-wide
  • Can be triggered from any application in the suite

IPA SDK Integration

Setting Active Client

When a client is selected from search results:

typescript
onClientSelect(client: Client) {
  ipaSdk.data.setActiveClient({
    gcn: client.gcn,
    name: client.name,
    // ... other client properties
  });
}

This updates the active client context across all applications in the IPA platform.

Client Context Broadcasting

All applications in the suite listen for these changes:

typescript
// In consuming apps (PFM, Account Visibility, etc.)
ipaSdk.data.listenForActiveClientContextChanges()
  .subscribe((context) => {
    // React to new active client
    this.activeClient = context.gcn;
    this.performSearch();
  });

Top Feature Implementation

Opening from Other Apps

typescript
// Example from PFM Manager or Account Visibility Manager
searchClient() {
  this.isTopFeatureOpen = true;
  
  ipaSdk.platform.sideload.topFeature({
    active: true,
    src: '/feature/one-place-client-search',
    height: 200
  });
}

Closing the Feature

User actions trigger context updates that consuming apps listen for:

typescript
// Consuming app detects client selection
const subscription = ipaSdk.data.listenForActiveClientContextChanges()
  .subscribe(() => {
    this.isTopFeatureOpen = false;
    subscription.unsubscribe();
  });

Component Architecture

Standalone Component

typescript
@Component({
  selector: 'app-client-search',
  standalone: true,
  imports: [CommonModule, ReactiveFormsModule, /* ... */],
  templateUrl: './client-search.component.html',
  styleUrls: ['./client-search.component.scss']
})
export class ClientSearchComponent implements OnInit {
  searchForm!: FormGroup;
  searchResults: Client[] = [];
  loading = false;
}

Search Functionality

typescript
onSearch() {
  const query = this.searchForm.get('searchQuery')?.value;
  
  if (!query || query.length < 2) {
    return;
  }
  
  this.loading = true;
  this.clientService.search(query)
    .pipe(
      finalize(() => this.loading = false)
    )
    .subscribe((results) => {
      this.searchResults = results;
    });
}

Usage Patterns

  1. User clicks "Search Client" button in PFM Manager
  2. PFM Manager opens top feature with Client Search
  3. User searches and selects a client
  4. IPA broadcasts client context change
  5. PFM Manager detects change, re-enables button
  6. PFM Manager fetches GUID for selected client
  1. User clicks feature button in Dashboard that requires client context
  2. Dashboard opens target feature (e.g., PFM Manager)
  3. Target feature automatically opens Client Search in top feature
  4. User selects client
  5. Target feature receives context and begins operation
  6. Dashboard remains in appropriate view (center or left menu)

Event Flow

User Action (Search Button)

Open Top Feature (Client Search)

User Searches & Selects Client

IPA SDK: setActiveClient()

Broadcast: listenForActiveClientContextChanges()

All Apps Receive Update

Apps React (fetch data, update UI, re-enable buttons)

Design Considerations

Height

Fixed at 200px to provide sufficient space for:

  • Search input field
  • Loading indicator
  • Search results list (scrollable)
  • Error messages

Responsiveness

Adapts to IPA top feature container width:

  • Full-width search bar
  • Responsive result cards
  • Touch-friendly on mobile

State Management

Minimal state:

  • Search query
  • Results array
  • Loading flag
  • No persistence needed (ephemeral search)

Best Practices

typescript
// ✅ Good: Track state and listen for context changes
searchClient() {
  this.isTopFeatureOpen = true;
  ipaSdk.platform.sideload.topFeature({
    active: true,
    src: '/feature/one-place-client-search',
    height: 200
  });
  
  const subscription = ipaSdk.data.listenForActiveClientContextChanges()
    .pipe(takeUntil(this.unsubscribe$))
    .subscribe(() => {
      this.isTopFeatureOpen = false;
      subscription.unsubscribe();
    });
}
typescript
// ❌ Bad: No state tracking or cleanup
searchClient() {
  ipaSdk.platform.sideload.topFeature({
    active: true,
    src: '/feature/one-place-client-search',
    height: 200
  });
  // Button stays disabled forever
}

Listening for Client Changes

typescript
// ✅ Good: Proper cleanup with takeUntil
ipaSdk.data.listenForActiveClientContextChanges()
  .pipe(takeUntil(this.unsubscribe$))
  .subscribe((context) => {
    this.handleClientChange(context);
  });
typescript
// ❌ Bad: Memory leak - no cleanup
ipaSdk.data.listenForActiveClientContextChanges()
  .subscribe((context) => {
    this.handleClientChange(context);
  });

Integration Checklist

When integrating Client Search into a new app:

  • [ ] Import IPA SDK
  • [ ] Create button with click handler
  • [ ] Track isTopFeatureOpen state
  • [ ] Call ipaSdk.platform.sideload.topFeature()
  • [ ] Listen for listenForActiveClientContextChanges()
  • [ ] Implement proper cleanup with takeUntil(this.unsubscribe$)
  • [ ] Re-enable button when client is selected
  • [ ] Handle client context in your business logic

Future Enhancements

Potential improvements:

  • Recent searches cache
  • Favorite clients
  • Advanced search filters
  • Keyboard navigation
  • Multi-client selection (if needed)