Skip to content

Commit f1dbfce

Browse files
author
Hannah Yan
committed
Find my people: 4 curated matches (82%, 76%, 63%, 58%)
1 parent 35aafa2 commit f1dbfce

File tree

1 file changed

+160
-90
lines changed

1 file changed

+160
-90
lines changed

mingle/frontend/src/pages/SmartQuery.jsx

Lines changed: 160 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,62 @@
1-
import { useState, useEffect } from "react";
1+
import { useState } from "react";
22
import { 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

74
const LOOKING_FOR_OPTIONS = ["Co-founder", "Collaborators", "Mentorship", "Investors", "Customers", "Employees", "Advice"];
85
const DOMAIN_OPTIONS = ["AI/ML", "Hardware", "FinTech", "HealthTech", "EdTech", "Climate", "Web3", "Enterprise SaaS", "Consumer", "Developer Tools"];
96
const HELP_OPTIONS = ["Technical advice", "Product feedback", "Introductions", "Funding", "Design", "Marketing", "Legal"];
107
const 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+
1257
const 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

2267
export 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

184254
const 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

190260
const 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

Comments
 (0)