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)