Skip to content

Commit 451dc55

Browse files
committed
Sayali: add search functionality to community members page
1 parent 83459ef commit 451dc55

3 files changed

Lines changed: 101 additions & 22 deletions

File tree

src/components/HGNHelpSkillsDashboard/CommunityMembersPage.jsx

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { useState } from 'react';
22
import { useSelector } from 'react-redux';
3+
import { availablePreferences, availableSkills, formatSkillName } from './FilerData.js';
34
import RankedUserList from './RankedUserList';
45
import styles from './style/CommunityMembersPage.module.css';
5-
import { availableSkills, availablePreferences, formatSkillName } from './FilerData.js';
66

77
function Accordion({ title, children, defaultOpen = false, darkMode }) {
88
const [open, setOpen] = useState(defaultOpen);
@@ -26,6 +26,7 @@ function Accordion({ title, children, defaultOpen = false, darkMode }) {
2626
function CommunityMembersPage() {
2727
const [selectedSkills, setSelectedSkills] = useState([]);
2828
const [selectedPreferences, setSelectedPreferences] = useState([]);
29+
const [searchQuery, setSearchQuery] = useState('');
2930
const darkMode = useSelector(state => state.theme.darkMode);
3031

3132
const toggleItem = (item, selectedArray, setSelectedArray) => {
@@ -44,7 +45,7 @@ function CommunityMembersPage() {
4445
key={skillKey}
4546
onClick={() => toggleItem(skillKey, selectedSkills, setSelectedSkills)}
4647
type="button"
47-
className={`${`${styles.skillButton}`} ${isSelected ? styles.selected : ''}`}
48+
className={`${styles.skillButton} ${isSelected ? styles.selected : ''}`}
4849
>
4950
{formattedName}
5051
</button>
@@ -62,7 +63,7 @@ function CommunityMembersPage() {
6263
key={pref}
6364
onClick={() => toggleItem(pref, selectedPreferences, setSelectedPreferences)}
6465
type="button"
65-
className={`${`${styles.preferenceButton}`} ${isSelected ? styles.selected : ''}`}
66+
className={`${styles.preferenceButton} ${isSelected ? styles.selected : ''}`}
6667
>
6768
{pref}
6869
</button>
@@ -71,10 +72,33 @@ function CommunityMembersPage() {
7172
</div>
7273
);
7374

75+
const hasFilters =
76+
selectedSkills.length > 0 || selectedPreferences.length > 0 || searchQuery.trim().length > 0;
77+
7478
return (
7579
<div className={`${styles.container} ${darkMode ? styles.darkMode : ''}`}>
7680
<h1 className={`${styles.title}`}>Community Member Filters</h1>
7781

82+
{/* Search Bar */}
83+
<div className={`${styles.searchContainer} ${darkMode ? styles.darkSearch : ''}`}>
84+
<input
85+
type="text"
86+
placeholder="Search members by name or skill..."
87+
value={searchQuery}
88+
onChange={e => setSearchQuery(e.target.value)}
89+
className={`${styles.searchInput} ${darkMode ? styles.darkSearchInput : ''}`}
90+
/>
91+
{searchQuery && (
92+
<button
93+
type="button"
94+
className={`${styles.clearButton} ${darkMode ? styles.darkClearButton : ''}`}
95+
onClick={() => setSearchQuery('')}
96+
>
97+
98+
</button>
99+
)}
100+
</div>
101+
78102
<Accordion title="Filter by Skills" defaultOpen darkMode={darkMode}>
79103
{renderSkillButtons()}
80104
</Accordion>
@@ -84,14 +108,15 @@ function CommunityMembersPage() {
84108
</Accordion>
85109

86110
<div>
87-
{selectedSkills.length > 0 || selectedPreferences.length > 0 ? (
111+
{hasFilters ? (
88112
<RankedUserList
89113
selectedSkills={selectedSkills}
90114
selectedPreferences={selectedPreferences}
115+
searchQuery={searchQuery.trim()}
91116
/>
92117
) : (
93118
<p className={`${styles.message}`}>
94-
Select skills or preferences above to see filtered members.
119+
Search or select skills and preferences above to see filtered members.
95120
</p>
96121
)}
97122
</div>

src/components/HGNHelpSkillsDashboard/RankedUserList.jsx

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,55 @@
1-
import { useEffect, useState } from 'react';
21
import axios from 'axios';
3-
import UserCard from './UserCard';
2+
import { useEffect, useState } from 'react';
43
import { useSelector } from 'react-redux';
54
import styles from './style/RankedUserList.module.css';
5+
import UserCard from './UserCard';
66

7-
function RankedUserList({ selectedSkills, selectedPreferences }) {
8-
const [rankedUsers, setRankedUsers] = useState([]);
7+
function RankedUserList({ selectedSkills, selectedPreferences, searchQuery }) {
8+
const [allUsers, setAllUsers] = useState([]);
99
const [loading, setLoading] = useState(true);
1010
const darkMode = useSelector(state => state.theme.darkMode);
11-
useEffect(() => {
12-
if (
13-
(!selectedSkills || selectedSkills.length === 0) &&
14-
(!selectedPreferences || selectedPreferences.length === 0)
15-
)
16-
return;
1711

18-
const fetchRankedUsers = async () => {
12+
useEffect(() => {
13+
const fetchUsers = async () => {
1914
setLoading(true);
2015
try {
2116
const params = {};
22-
if (selectedSkills.length > 0) params.skills = selectedSkills.join(',');
23-
if (selectedPreferences.length > 0) params.preferences = selectedPreferences.join(',');
17+
if (selectedSkills && selectedSkills.length > 0) params.skills = selectedSkills.join(',');
18+
if (selectedPreferences && selectedPreferences.length > 0)
19+
params.preferences = selectedPreferences.join(',');
2420

2521
const response = await axios.get(`${process.env.REACT_APP_APIENDPOINT}/hgnform/ranked`, {
2622
params,
2723
});
28-
setRankedUsers(response.data);
24+
setAllUsers(response.data);
2925
} catch (err) {
26+
// error handled silently
3027
} finally {
3128
setLoading(false);
3229
}
3330
};
3431

35-
fetchRankedUsers();
32+
fetchUsers();
3633
}, [selectedSkills, selectedPreferences]);
3734

35+
// Client-side filter by searchQuery on top of API results
36+
const filteredUsers = searchQuery
37+
? allUsers.filter(user => {
38+
const name = (user.name || '').toLowerCase();
39+
const skills = (user.topSkills || []).join(' ').toLowerCase();
40+
return (
41+
name.includes(searchQuery.toLowerCase()) || skills.includes(searchQuery.toLowerCase())
42+
);
43+
})
44+
: allUsers;
45+
3846
if (loading) return <p className={`${styles.message}`}>Loading ranked users...</p>;
39-
if (!rankedUsers.length) return <p className={`${styles.message}`}>No users found.</p>;
47+
if (!filteredUsers.length) return <p className={`${styles.message}`}>No users found.</p>;
4048

4149
return (
4250
<div className={darkMode ? `${styles.darkMode}` : ''}>
4351
<div className={`${styles.container}`}>
44-
{rankedUsers.map(user => (
52+
{filteredUsers.map(user => (
4553
<div key={user._id} className={`${styles.userWrapper}`}>
4654
<UserCard user={user} />
4755
</div>

src/components/HGNHelpSkillsDashboard/style/CommunityMembersPage.module.css

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,49 @@
124124
border-color: #22c55e;
125125
color: #ffffff;
126126
}
127+
128+
.searchContainer {
129+
display: flex;
130+
align-items: center;
131+
margin-bottom: 16px;
132+
border: 1px solid #ccc;
133+
border-radius: 8px;
134+
padding: 6px 12px;
135+
background: #fff;
136+
}
137+
138+
.searchInput {
139+
flex: 1;
140+
border: none;
141+
outline: none;
142+
font-size: 14px;
143+
background: transparent;
144+
color: #000;
145+
}
146+
147+
.clearButton {
148+
background: none;
149+
border: none;
150+
cursor: pointer;
151+
color: #888;
152+
font-size: 14px;
153+
padding: 0 4px;
154+
}
155+
156+
.darkSearch {
157+
border-color: #555;
158+
background: #2d3748;
159+
}
160+
161+
.darkSearchInput {
162+
color: #fff !important;
163+
background: transparent;
164+
}
165+
166+
.darkSearch .clearButton {
167+
color: #ccc;
168+
}
169+
170+
.darkClearButton {
171+
color: #f2e8e8;
172+
}

0 commit comments

Comments
 (0)