1- import { useState , useEffect } from "react" ;
1+ import { useState } from "react" ;
22import { useNavigate } from "react-router-dom" ;
3- import { getAllProfiles , getProfile } from "../api/client.js" ;
4- import useUserId from "../hooks/useUserId.js" ;
5- import MatchCard from "../components/MatchCard.jsx" ;
63
74const LOOKING_FOR_OPTIONS = [ "Co-founder" , "Collaborators" , "Mentorship" , "Investors" , "Customers" , "Employees" , "Advice" ] ;
85const DOMAIN_OPTIONS = [ "AI/ML" , "Hardware" , "FinTech" , "HealthTech" , "EdTech" , "Climate" , "Web3" , "Enterprise SaaS" , "Consumer" , "Developer Tools" ] ;
96const HELP_OPTIONS = [ "Technical advice" , "Product feedback" , "Introductions" , "Funding" , "Design" , "Marketing" , "Legal" ] ;
107const URGENCY_OPTIONS = [ "high" , "medium" , "low" ] ;
118
9+ // Mock profiles for matching
10+ const MOCK_MATCHES = [
11+ {
12+ id : "match-1" ,
13+ name : "Maya Patel" ,
14+ role : "Principal Product Designer" ,
15+ company : "Figma" ,
16+ bio : "Leading design systems and mentoring designers globally." ,
17+ skills : [ "Figma" , "Design Systems" , "User Research" ] ,
18+ domains : [ "Developer Tools" , "Enterprise SaaS" ] ,
19+ score : 82 ,
20+ reason : "Strong alignment with your domain expertise and design collaboration needs" ,
21+ } ,
22+ {
23+ id : "match-2" ,
24+ name : "Jordan Lee" ,
25+ role : "Senior ML Engineer" ,
26+ company : "Anthropic" ,
27+ bio : "Working on AI safety and alignment research." ,
28+ skills : [ "PyTorch" , "RLHF" , "Transformers" ] ,
29+ domains : [ "AI/ML" ] ,
30+ score : 76 ,
31+ reason : "Complementary technical skills in AI/ML with mentorship experience" ,
32+ } ,
33+ {
34+ id : "match-3" ,
35+ name : "Chris Wong" ,
36+ role : "Founding Engineer" ,
37+ company : "Vercel" ,
38+ bio : "Building the future of web development infrastructure." ,
39+ skills : [ "TypeScript" , "React" , "Edge Computing" ] ,
40+ domains : [ "Developer Tools" , "Enterprise SaaS" ] ,
41+ score : 63 ,
42+ reason : "Relevant industry experience with strong technical background" ,
43+ } ,
44+ {
45+ id : "match-4" ,
46+ name : "Taylor Kim" ,
47+ role : "Partner" ,
48+ company : "Sequoia Capital" ,
49+ bio : "Investing in early-stage AI and infrastructure companies." ,
50+ skills : [ "Due Diligence" , "Market Analysis" , "Board Governance" ] ,
51+ domains : [ "AI/ML" , "FinTech" ] ,
52+ score : 58 ,
53+ reason : "Could provide valuable introductions and funding connections" ,
54+ } ,
55+ ] ;
56+
1257const selectStyle = {
1358 padding : "9px 14px" ,
14- border : "1px solid #ddd " ,
59+ border : "1px solid #e2e8f0 " ,
1560 borderRadius : "8px" ,
1661 fontSize : "0.9rem" ,
1762 background : "#fff" ,
@@ -21,79 +66,29 @@ const selectStyle = {
2166
2267export default function SmartQuery ( ) {
2368 const navigate = useNavigate ( ) ;
24- const userId = useUserId ( ) ;
25- const [ allProfiles , setAllProfiles ] = useState ( [ ] ) ;
26- const [ senderProfile , setSenderProfile ] = useState ( null ) ;
2769 const [ query , setQuery ] = useState ( {
2870 looking_for : LOOKING_FOR_OPTIONS [ 0 ] ,
2971 domain : DOMAIN_OPTIONS [ 0 ] ,
3072 urgency : "medium" ,
3173 help_type : HELP_OPTIONS [ 0 ] ,
3274 } ) ;
33- const [ rankings , setRankings ] = useState ( [ ] ) ;
34- const [ profileMap , setProfileMap ] = useState ( { } ) ;
75+ const [ results , setResults ] = useState ( [ ] ) ;
3576 const [ loading , setLoading ] = useState ( false ) ;
36- const [ error , setError ] = useState ( null ) ;
37-
38- useEffect ( ( ) => {
39- getAllProfiles ( ) . then ( setAllProfiles ) . catch ( ( ) => { } ) ;
40- const myId = localStorage . getItem ( "mingle_my_profile_id" ) ;
41- if ( myId ) {
42- getProfile ( myId ) . then ( setSenderProfile ) . catch ( ( ) => { } ) ;
43- }
44- } , [ ] ) ;
77+ const [ searched , setSearched ] = useState ( false ) ;
4578
4679 async function handleSearch ( ) {
47- if ( allProfiles . length === 0 ) {
48- setError ( "No profiles found. Create some profiles first." ) ;
49- return ;
50- }
5180 setLoading ( true ) ;
52- setError ( null ) ;
53- setRankings ( [ ] ) ;
54-
55- // Simulate loading
81+ setSearched ( true ) ;
5682 await new Promise ( resolve => setTimeout ( resolve , 800 ) ) ;
57-
58- try {
59- const myId = localStorage . getItem ( "mingle_my_profile_id" ) ;
60- const candidates = allProfiles . filter ( ( p ) => p . id !== myId ) ;
61- if ( candidates . length === 0 ) {
62- setError ( "No other profiles to match against." ) ;
63- setLoading ( false ) ;
64- return ;
65- }
66-
67- const map = { } ;
68- candidates . forEach ( ( p ) => { map [ p . id ] = p ; } ) ;
69- setProfileMap ( map ) ;
70-
71- // Generate mock rankings with scores from 82% to 58%
72- const scores = [ 82 , 78 , 75 , 71 , 68 , 65 , 62 , 58 ] ;
73- const reasons = [
74- "Strong alignment with your domain expertise and collaboration goals" ,
75- "Complementary skills in product and technical areas" ,
76- "Experienced in your target domain with relevant network" ,
77- "Background matches your mentorship needs" ,
78- "Could provide valuable introductions in your space" ,
79- "Overlapping interests and mutual connection potential" ,
80- "Relevant industry experience and advisory background" ,
81- "Good fit based on shared professional interests"
82- ] ;
83-
84- const mockRankings = candidates . slice ( 0 , 8 ) . map ( ( c , i ) => ( {
85- contact_id : c . id ,
86- score : scores [ i ] || ( 58 - i * 2 ) ,
87- reason : reasons [ i ] || "Potential match based on profile alignment" ,
88- urgency_fit : query . urgency === "high" ? "responsive" : "standard" ,
89- } ) ) ;
90-
91- setRankings ( mockRankings ) ;
92- } catch ( err ) {
93- setError ( err . message ) ;
94- } finally {
95- setLoading ( false ) ;
96- }
83+ setResults ( MOCK_MATCHES ) ;
84+ setLoading ( false ) ;
85+ }
86+
87+ function getScoreColor ( score ) {
88+ if ( score >= 80 ) return "#10b981" ;
89+ if ( score >= 70 ) return "#6366f1" ;
90+ if ( score >= 60 ) return "#f59e0b" ;
91+ return "#64748b" ;
9792 }
9893
9994 return (
@@ -105,12 +100,12 @@ export default function SmartQuery() {
105100
106101 < div style = { {
107102 background : "#fff" ,
108- borderRadius : "14px " ,
103+ borderRadius : "16px " ,
109104 padding : "24px" ,
110- boxShadow : "0 2px 10px rgba(0,0,0,0.07 )" ,
105+ boxShadow : "0 2px 12px rgba(0,0,0,0.06 )" ,
111106 marginBottom : "28px" ,
112107 } } >
113- < p style = { { fontWeight : 600 , marginBottom : "14px" , color : "#444 " } } > Find connections who can help you with…</ p >
108+ < p style = { { fontWeight : 600 , marginBottom : "14px" , color : "#1e293b " } } > Find connections who can help you with…</ p >
114109
115110 < div style = { { display : "flex" , flexWrap : "wrap" , gap : "12px" , alignItems : "flex-end" } } >
116111 < div >
@@ -146,7 +141,8 @@ export default function SmartQuery() {
146141 disabled = { loading }
147142 style = { {
148143 padding : "10px 26px" ,
149- background : loading ? "#a5a0ff" : "#6c63ff" , color : "#fff" ,
144+ background : loading ? "#a5b4fc" : "linear-gradient(135deg, #6366f1 0%, #4f46e5 100%)" ,
145+ color : "#fff" ,
150146 border : "none" , borderRadius : "8px" ,
151147 fontWeight : 700 , cursor : loading ? "default" : "pointer" ,
152148 alignSelf : "flex-end" ,
@@ -157,41 +153,115 @@ export default function SmartQuery() {
157153 </ div >
158154 </ div >
159155
160- { error && (
161- < div style = { { padding : "12px 16px" , background : "#fde8e8" , borderRadius : "8px" , color : "#c0392b" , marginBottom : "16px" } } >
162- { error }
163- </ div >
164- ) }
165-
166- { ! loading && rankings . length === 0 && ! error && (
167- < p style = { { color : "#aaa" , textAlign : "center" , marginTop : "40px" } } >
156+ { ! searched && (
157+ < p style = { { color : "#94a3b8" , textAlign : "center" , marginTop : "40px" } } >
168158 Set your criteria above and click "Find Connections" to see AI-ranked matches.
169159 </ p >
170160 ) }
171161
172- { rankings . map ( ( r ) => (
173- < MatchCard
174- key = { r . contact_id }
175- ranking = { r }
176- profile = { profileMap [ r . contact_id ] }
177- senderProfile = { senderProfile }
178- />
179- ) ) }
162+ { loading && (
163+ < div style = { { textAlign : "center" , padding : "40px" } } >
164+ < div style = { {
165+ width : "40px" ,
166+ height : "40px" ,
167+ border : "3px solid #e2e8f0" ,
168+ borderTopColor : "#6366f1" ,
169+ borderRadius : "50%" ,
170+ margin : "0 auto 16px" ,
171+ animation : "spin 0.8s linear infinite"
172+ } } > </ div >
173+ < p style = { { color : "#64748b" } } > Finding your people...</ p >
174+ < style > { `@keyframes spin { to { transform: rotate(360deg); } }` } </ style >
175+ </ div >
176+ ) }
177+
178+ { ! loading && results . length > 0 && (
179+ < div style = { { display : "flex" , flexDirection : "column" , gap : "16px" } } >
180+ { results . map ( ( match ) => (
181+ < div key = { match . id } style = { {
182+ background : "#fff" ,
183+ borderRadius : "16px" ,
184+ padding : "20px 24px" ,
185+ boxShadow : "0 2px 12px rgba(0,0,0,0.06)" ,
186+ display : "flex" ,
187+ alignItems : "center" ,
188+ gap : "20px" ,
189+ } } >
190+ < div style = { {
191+ width : "56px" ,
192+ height : "56px" ,
193+ borderRadius : "14px" ,
194+ background : "linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)" ,
195+ color : "white" ,
196+ display : "flex" ,
197+ alignItems : "center" ,
198+ justifyContent : "center" ,
199+ fontSize : "22px" ,
200+ fontWeight : 700 ,
201+ flexShrink : 0 ,
202+ } } >
203+ { match . name . charAt ( 0 ) }
204+ </ div >
205+
206+ < div style = { { flex : 1 , minWidth : 0 } } >
207+ < div style = { { display : "flex" , alignItems : "center" , gap : "10px" , marginBottom : "4px" } } >
208+ < h3 style = { { fontSize : "1.1rem" , fontWeight : 700 , color : "#1e293b" } } >
209+ { match . name }
210+ </ h3 >
211+ < span style = { {
212+ background : `${ getScoreColor ( match . score ) } 15` ,
213+ color : getScoreColor ( match . score ) ,
214+ padding : "3px 10px" ,
215+ borderRadius : "999px" ,
216+ fontSize : "0.8rem" ,
217+ fontWeight : 700 ,
218+ } } >
219+ { match . score } % match
220+ </ span >
221+ </ div >
222+ < p style = { { fontSize : "0.9rem" , color : "#64748b" , marginBottom : "6px" } } >
223+ { match . role } @ { match . company }
224+ </ p >
225+ < p style = { { fontSize : "0.85rem" , color : "#94a3b8" , fontStyle : "italic" } } >
226+ "{ match . reason } "
227+ </ p >
228+ </ div >
229+
230+ < button
231+ onClick = { ( ) => navigate ( `/profile/${ match . id } ` ) }
232+ style = { {
233+ padding : "8px 18px" ,
234+ background : "linear-gradient(135deg, #6366f1 0%, #4f46e5 100%)" ,
235+ color : "#fff" ,
236+ border : "none" ,
237+ borderRadius : "8px" ,
238+ cursor : "pointer" ,
239+ fontSize : "0.85rem" ,
240+ fontWeight : 600 ,
241+ flexShrink : 0 ,
242+ } }
243+ >
244+ View
245+ </ button >
246+ </ div >
247+ ) ) }
248+ </ div >
249+ ) }
180250 </ div >
181251 ) ;
182252}
183253
184254const backBtn = {
185255 padding : "6px 14px" , background : "none" ,
186- border : "1px solid #ddd " , borderRadius : "8px" ,
187- cursor : "pointer" , color : "#555 " , fontSize : "0.85rem" ,
256+ border : "1px solid #e2e8f0 " , borderRadius : "8px" ,
257+ cursor : "pointer" , color : "#64748b " , fontSize : "0.85rem" ,
188258} ;
189259
190260const labelStyle = {
191261 display : "block" ,
192262 fontSize : "0.78rem" ,
193263 fontWeight : 600 ,
194- color : "#888 " ,
264+ color : "#94a3b8 " ,
195265 textTransform : "uppercase" ,
196266 letterSpacing : "0.05em" ,
197267 marginBottom : "4px" ,
0 commit comments