Appearance
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
Scenario 1: PFM Manager Opens Client Search
- User clicks "Search Client" button in PFM Manager
- PFM Manager opens top feature with Client Search
- User searches and selects a client
- IPA broadcasts client context change
- PFM Manager detects change, re-enables button
- PFM Manager fetches GUID for selected client
Scenario 2: Dashboard Opens Client Search
- User clicks feature button in Dashboard that requires client context
- Dashboard opens target feature (e.g., PFM Manager)
- Target feature automatically opens Client Search in top feature
- User selects client
- Target feature receives context and begins operation
- 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
Opening Client Search
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
isTopFeatureOpenstate - [ ] 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)