feat: Network Matching page - AI-powered client connection suggestions

- New /network page with match cards, score badges, category filters
- Network stats dashboard (clients, matches, avg score, top connectors)
- Category-based filtering (industry, interests, location, business, social)
- Adjustable minimum score threshold
- AI introduction generation button per match
- Added Network to sidebar navigation
- Types: NetworkMatch, NetworkStats
This commit is contained in:
2026-01-29 12:35:33 +00:00
parent b6de50ba5e
commit 0b7bddb81c
5 changed files with 360 additions and 0 deletions

View File

@@ -239,6 +239,31 @@ class ApiClient {
await this.fetch(`/emails/${id}`, { method: 'DELETE' });
}
// Network Matching
async getNetworkMatches(params?: { minScore?: number; limit?: number }): Promise<{ matches: NetworkMatch[]; total: number; clientCount: number }> {
const searchParams = new URLSearchParams();
if (params?.minScore) searchParams.set('minScore', String(params.minScore));
if (params?.limit) searchParams.set('limit', String(params.limit));
const query = searchParams.toString();
return this.fetch(`/network/matches${query ? `?${query}` : ''}`);
}
async getClientMatches(clientId: string, minScore?: number): Promise<{ matches: NetworkMatch[]; client: { id: string; name: string } }> {
const query = minScore ? `?minScore=${minScore}` : '';
return this.fetch(`/network/matches/${clientId}${query}`);
}
async generateIntro(clientAId: string, clientBId: string, reasons: string[], provider?: string): Promise<{ introSuggestion: string }> {
return this.fetch('/network/intro', {
method: 'POST',
body: JSON.stringify({ clientAId, clientBId, reasons, provider }),
});
}
async getNetworkStats(): Promise<NetworkStats> {
return this.fetch('/network/stats');
}
// Admin
async getUsers(): Promise<User[]> {
return this.fetch('/admin/users');