1+ import React , { useState } from 'react' ;
2+ import { useQuery , useMutation , useQueryClient } from '@tanstack/react-query' ;
3+ import { base44 } from '@/api/base44Client' ;
4+ import { Card , CardContent , CardHeader , CardTitle } from '@/components/ui/card' ;
5+ import { Button } from '@/components/ui/button' ;
6+ import { Badge } from '@/components/ui/badge' ;
7+ import { Avatar } from '@/components/ui/avatar' ;
8+ import { Users , Sparkles , MessageCircle , UserPlus } from 'lucide-react' ;
9+ import { toast } from 'sonner' ;
10+
11+ export default function AIConnectionSuggestions ( { user } ) {
12+ const [ loading , setLoading ] = useState ( false ) ;
13+ const queryClient = useQueryClient ( ) ;
14+
15+ const { data : suggestions , isLoading } = useQuery ( {
16+ queryKey : [ 'ai-connection-suggestions' , user ?. email ] ,
17+ queryFn : async ( ) => {
18+ setLoading ( true ) ;
19+ try {
20+ const response = await base44 . integrations . Core . InvokeLLM ( {
21+ prompt : `As a new employee joining a remote-first company, suggest 3-5 teammates this person should connect with.
22+
23+ User Role: ${ user . role === 'admin' ? 'admin' : user . user_type || 'participant' }
24+ User Email: ${ user . email }
25+
26+ Provide practical connection suggestions with reasons why they should connect.` ,
27+ response_json_schema : {
28+ type : 'object' ,
29+ properties : {
30+ suggestions : {
31+ type : 'array' ,
32+ items : {
33+ type : 'object' ,
34+ properties : {
35+ role : { type : 'string' } ,
36+ reason : { type : 'string' } ,
37+ suggested_action : { type : 'string' }
38+ }
39+ }
40+ }
41+ }
42+ }
43+ } ) ;
44+ return response . suggestions ;
45+ } finally {
46+ setLoading ( false ) ;
47+ }
48+ } ,
49+ enabled : ! ! user ?. email ,
50+ staleTime : 3600000 // 1 hour
51+ } ) ;
52+
53+ // Fetch actual users matching these roles
54+ const { data : allUsers } = useQuery ( {
55+ queryKey : [ 'all-users-for-connections' ] ,
56+ queryFn : ( ) => base44 . entities . User . list ( 'full_name' , 100 ) ,
57+ enabled : ! ! suggestions
58+ } ) ;
59+
60+ const createBuddyMatchMutation = useMutation ( {
61+ mutationFn : async ( buddyEmail ) => {
62+ await base44 . entities . BuddyMatch . create ( {
63+ user_email : user . email ,
64+ buddy_email : buddyEmail ,
65+ match_type : 'peer_buddy' ,
66+ status : 'pending' ,
67+ match_score : 80
68+ } ) ;
69+ } ,
70+ onSuccess : ( ) => {
71+ queryClient . invalidateQueries ( [ 'buddy-matches' ] ) ;
72+ toast . success ( 'Connection request sent!' ) ;
73+ } ,
74+ onError : ( error ) => toast . error ( 'Failed to send request: ' + error . message )
75+ } ) ;
76+
77+ return (
78+ < Card className = "border-indigo-200 bg-gradient-to-br from-indigo-50 to-purple-50" >
79+ < CardHeader >
80+ < CardTitle className = "flex items-center gap-2" >
81+ < Sparkles className = "h-5 w-5 text-indigo-600" />
82+ Suggested Connections
83+ </ CardTitle >
84+ </ CardHeader >
85+
86+ < CardContent className = "space-y-4" >
87+ { loading && (
88+ < div className = "flex items-center gap-2 text-sm text-slate-500" >
89+ < Sparkles className = "h-4 w-4 animate-pulse" />
90+ Finding great connections for you...
91+ </ div >
92+ ) }
93+
94+ { suggestions ?. map ( ( suggestion , idx ) => {
95+ // Try to match with actual users
96+ const matchedUser = allUsers ?. find ( u =>
97+ u . role === suggestion . role ||
98+ u . user_type === suggestion . role . toLowerCase ( )
99+ ) ;
100+
101+ return (
102+ < div
103+ key = { idx }
104+ className = "p-4 bg-white rounded-lg border border-slate-200 hover:border-indigo-300 transition-all"
105+ >
106+ < div className = "flex items-start gap-3" >
107+ < div className = "w-10 h-10 rounded-full bg-indigo-100 flex items-center justify-center" >
108+ < Users className = "h-5 w-5 text-indigo-600" />
109+ </ div >
110+ < div className = "flex-1" >
111+ < div className = "flex items-center gap-2 mb-1" >
112+ < h4 className = "font-medium text-slate-900" >
113+ { matchedUser ?. full_name || `${ suggestion . role } Team Member` }
114+ </ h4 >
115+ < Badge variant = "outline" className = "text-xs" >
116+ { suggestion . role }
117+ </ Badge >
118+ </ div >
119+
120+ { matchedUser && (
121+ < p className = "text-sm text-slate-500 mb-2" > { matchedUser . email } </ p >
122+ ) }
123+
124+ < p className = "text-sm text-slate-600 mb-3" > { suggestion . reason } </ p >
125+
126+ < div className = "bg-blue-50 border border-blue-200 rounded p-2 mb-3" >
127+ < p className = "text-xs text-blue-900" >
128+ < strong > Suggested:</ strong > { suggestion . suggested_action }
129+ </ p >
130+ </ div >
131+
132+ < div className = "flex gap-2" >
133+ { matchedUser && (
134+ < >
135+ < Button
136+ size = "sm"
137+ variant = "outline"
138+ onClick = { ( ) => createBuddyMatchMutation . mutate ( matchedUser . email ) }
139+ disabled = { createBuddyMatchMutation . isPending }
140+ >
141+ < UserPlus className = "h-3 w-3 mr-1" />
142+ Connect
143+ </ Button >
144+ < Button
145+ size = "sm"
146+ variant = "outline"
147+ onClick = { ( ) => window . location . href = `/pages/Channels` }
148+ >
149+ < MessageCircle className = "h-3 w-3 mr-1" />
150+ Message
151+ </ Button >
152+ </ >
153+ ) }
154+ </ div >
155+ </ div >
156+ </ div >
157+ </ div >
158+ ) ;
159+ } ) }
160+
161+ { ! isLoading && ! suggestions ?. length && (
162+ < div className = "text-center py-8 text-slate-500" >
163+ < Users className = "h-12 w-12 text-slate-300 mx-auto mb-2" />
164+ < p className = "text-sm" > Connection suggestions will appear here</ p >
165+ </ div >
166+ ) }
167+ </ CardContent >
168+ </ Card >
169+ ) ;
170+ }
0 commit comments