Skip to content

Commit 0afb552

Browse files
one-communityNeeraj-Kondaveeti
authored andcommitted
Merge pull request #4503 from OneCommunityGlobal/aryan_show_team_members
Aryan Updated team members components
2 parents 933fcee + 9b679f7 commit 0afb552

6 files changed

Lines changed: 161 additions & 265 deletions

File tree

src/components/Collaboration/Collaboration.jsx

Lines changed: 35 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ function Collaboration() {
5858
/** FETCH JOB ADS */
5959
const fetchJobAds = async (search, cats, page) => {
6060
const adsPerPage = 20;
61-
6261
const categoryParam = cats.length ? encodeURIComponent(cats.join(',')) : '';
6362

6463
try {
@@ -107,7 +106,6 @@ function Collaboration() {
107106

108107
const handleSubmit = e => {
109108
e.preventDefault();
110-
111109
setSearchTerm(query);
112110
setShowSearchResults(true);
113111
setSummaries(null);
@@ -116,10 +114,9 @@ function Collaboration() {
116114

117115
/** CATEGORY SELECTION */
118116
const toggleCategory = category => {
119-
setSelectedCategories(prev => {
120-
return prev.includes(category) ? prev.filter(c => c !== category) : [...prev, category];
121-
});
122-
117+
setSelectedCategories(prev =>
118+
prev.includes(category) ? prev.filter(c => c !== category) : [...prev, category],
119+
);
123120
setCurrentPage(1);
124121
};
125122

@@ -166,10 +163,6 @@ function Collaboration() {
166163

167164
const toggleReorderModal = () => setIsReorderModalOpen(prev => !prev);
168165

169-
const handleJobsReordered = () => {
170-
fetchJobAds(query, selectedCategories, currentPage);
171-
};
172-
173166
/** RENDER HELPERS */
174167
const renderFilters = () => (
175168
<CollaborationJobFilters
@@ -191,58 +184,26 @@ function Collaboration() {
191184
/>
192185
);
193186

194-
const renderCategoryChips = () => (
195-
<div className={styles.chipContainer}>
196-
{selectedCategories.map(cat => (
197-
<div key={cat} className={`${styles.chip} btn btn-secondary`}>
198-
{cat}
199-
<button className={styles.chipClose} onClick={() => removeCategory(cat)}>
200-
201-
</button>
202-
</div>
203-
))}
204-
</div>
205-
);
206-
207-
/** SUMMARY VIEW */
208-
if (summaries) {
209-
return (
210-
<div className={`${styles.jobLanding} ${darkMode ? styles.darkMode : ''}`}>
211-
<div className={styles.jobHeader}>
212-
<a
213-
href="https://www.onecommunityglobal.org/collaboration/"
214-
target="_blank"
215-
rel="noreferrer"
216-
>
217-
<img src={OneCommunityImage} alt="One Community Logo" />
218-
</a>
219-
</div>
220-
221-
<div className={styles.jobContainer}>
222-
{renderFilters()}
223-
{renderCategoryChips()}
224-
225-
<div className={styles.jobsSummariesList}>
226-
{summaries.jobs?.length > 0 ? (
227-
summaries.jobs.map(summary => (
228-
<div key={summary._id} className={styles.jobSummaryItem}>
229-
<h3>
230-
<a href={summary.jobDetailsLink}>{summary.title}</a>
231-
</h3>
232-
<div className={styles.jobSummaryContent}>
233-
<p>{summary.description}</p>
234-
<p>Date Posted: {new Date(summary.datePosted).toLocaleDateString()}</p>
235-
</div>
236-
</div>
237-
))
238-
) : (
239-
<p>No summaries found.</p>
240-
)}
241-
</div>
187+
const renderCategoryChips = () =>
188+
selectedCategories.length > 0 && (
189+
<>
190+
<p className={styles.selectedLabel}>Selected Categories:</p>
191+
<div className={styles.chipContainer}>
192+
{selectedCategories.map(cat => (
193+
<div key={cat} className={`${styles.chip} btn btn-secondary`}>
194+
{cat}
195+
<button
196+
type="button"
197+
className={styles.chipClose}
198+
onClick={() => removeCategory(cat)}
199+
>
200+
201+
</button>
202+
</div>
203+
))}
242204
</div>
243-
</div>
205+
</>
244206
);
245-
}
246207

247208
/** MAIN VIEW */
248209
return (
@@ -264,14 +225,21 @@ function Collaboration() {
264225
{showSearchResults ? (
265226
<div className={styles.jobDetails}>
266227
<div className={styles.jobQueries}>
267-
{searchTerm.length || selectedCategories.length ? (
228+
{searchTerm || selectedCategories.length ? (
268229
<p className={styles.jobQuery}>
269-
Listing results for{' '}
270-
<strong>
271-
{searchTerm && `'${searchTerm}' `}
272-
{selectedCategories.length > 0 &&
273-
selectedCategories.map(c => `'${c}'`).join(', ')}
274-
</strong>
230+
Listing results
231+
{searchTerm && (
232+
<>
233+
{' '}
234+
for <strong>&apos;{searchTerm}&apos;</strong>
235+
</>
236+
)}
237+
{selectedCategories.length > 0 && (
238+
<>
239+
{' '}
240+
for <strong>{selectedCategories.length}</strong> selected categories
241+
</>
242+
)}
275243
</p>
276244
) : (
277245
<p className={styles.jobQuery}>Listing all job ads.</p>
@@ -280,15 +248,6 @@ function Collaboration() {
280248
<button className="btn btn-secondary" onClick={handleShowSummaries}>
281249
Show Summaries
282250
</button>
283-
284-
{searchTerm && (
285-
<div className={`${styles.chip} btn btn-secondary`}>
286-
{searchTerm}
287-
<button className={styles.chipClose} onClick={() => setSearchTerm('')}>
288-
289-
</button>
290-
</div>
291-
)}
292251
</div>
293252

294253
{jobAds.length ? (

src/components/Collaboration/Collaboration.module.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,3 +482,8 @@
482482
background: linear-gradient(135deg, #23272a, #181a1b);
483483
}
484484

485+
.selectedLabel {
486+
font-weight: 600;
487+
color: gray;
488+
margin-top: 10px;
489+
}

src/components/HGNHelpSkillsDashboard/CommunityMembersPage.jsx

Lines changed: 14 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,154 +1,43 @@
1-
import { useEffect, useMemo, useState } from 'react';
2-
import axios from 'axios';
1+
import React, { useState, useMemo } from 'react';
32
import RankedUserList from './RankedUserList';
4-
import styles from './style/CommunityMembersPage.module.css';
53

64
const availableSkills = ['React', 'Redux', 'HTML', 'CSS', 'MongoDB', 'Database', 'Agile'];
7-
const RANKED_USERS_ENDPOINT = 'http://localhost:4500/api/hgnform/ranked';
85

96
function CommunityMembersPage() {
107
const [selectedSkills, setSelectedSkills] = useState([]);
11-
const [searchTerm, setSearchTerm] = useState('');
12-
const [sortOrder, setSortOrder] = useState('asc');
13-
const [showFilters, setShowFilters] = useState(false);
14-
const [rankedUsers, setRankedUsers] = useState([]);
15-
const [loading, setLoading] = useState(true);
16-
const [error, setError] = useState(null);
17-
18-
useEffect(() => {
19-
const fetchRankedUsers = async () => {
20-
setLoading(true);
21-
try {
22-
const params = {
23-
skills: (selectedSkills.length ? selectedSkills : availableSkills).join(','),
24-
};
25-
const response = await axios.get(RANKED_USERS_ENDPOINT, { params });
26-
setRankedUsers(response.data);
27-
setError(null);
28-
} catch (err) {
29-
setError('Unable to load community members right now. Please try again later.');
30-
} finally {
31-
setLoading(false);
32-
}
33-
};
34-
35-
fetchRankedUsers();
36-
}, [selectedSkills]);
378

389
const handleCheckboxChange = skill => {
3910
setSelectedSkills(prev =>
4011
prev.includes(skill) ? prev.filter(s => s !== skill) : [...prev, skill],
4112
);
4213
};
4314

44-
const toggleSortOrder = () => {
45-
setSortOrder(prev => (prev === 'asc' ? 'desc' : 'asc'));
46-
};
47-
48-
const clearFilters = () => {
49-
setSelectedSkills([]);
50-
};
51-
52-
const filteredUsers = useMemo(() => {
53-
const normalizedSearch = searchTerm.trim().toLowerCase();
54-
const normalizedSelectedSkills = selectedSkills.map(skill => skill.toLowerCase());
55-
let result = rankedUsers;
56-
57-
if (normalizedSearch) {
58-
result = rankedUsers.filter(user => {
59-
const nameMatches = user.name?.toLowerCase().includes(normalizedSearch);
60-
const skillMatches = Array.isArray(user.topSkills)
61-
? user.topSkills.some(skill => skill.toLowerCase().includes(normalizedSearch))
62-
: false;
63-
return nameMatches || skillMatches;
64-
});
65-
}
66-
67-
if (normalizedSelectedSkills.length) {
68-
result = result.filter(user => {
69-
if (!Array.isArray(user.topSkills) || user.topSkills.length === 0) return false;
70-
return user.topSkills.some(skill =>
71-
normalizedSelectedSkills.includes((skill || '').toLowerCase()),
72-
);
73-
});
74-
}
75-
76-
return [...result].sort((a, b) => {
77-
const first = a.name || '';
78-
const second = b.name || '';
79-
return sortOrder === 'asc' ? first.localeCompare(second) : second.localeCompare(first);
80-
});
81-
}, [rankedUsers, searchTerm, sortOrder, selectedSkills]);
82-
83-
const emptyMessage =
84-
searchTerm || selectedSkills.length
85-
? 'No community members match your current filters.'
86-
: 'No community members available yet.';
15+
// EFFECTIVE SKILLS = what we pass to RankedUserList
16+
const effectiveSkills = useMemo(() => {
17+
return selectedSkills.length > 0 ? selectedSkills : availableSkills;
18+
}, [selectedSkills]);
8719

8820
return (
89-
<div className={styles.container}>
90-
<h1 className={styles.heading}>One Community Members</h1>
91-
<div className={styles.controlsRow}>
92-
<div className={styles.searchWrapper}>
93-
<input
94-
type="search"
95-
value={searchTerm}
96-
onChange={event => setSearchTerm(event.target.value)}
97-
placeholder="Search by team member name or skills"
98-
className={styles.searchInput}
99-
aria-label="Search community members"
100-
/>
101-
</div>
102-
<button
103-
type="button"
104-
className={styles.filterButton}
105-
onClick={() => setShowFilters(prev => !prev)}
106-
>
107-
{showFilters ? 'Hide Filters' : 'Filter'}
108-
</button>
109-
<button type="button" className={styles.sortButton} onClick={toggleSortOrder}>
110-
{sortOrder === 'asc' ? 'A→Z Sort' : 'Z→A Sort'}
111-
</button>
112-
{(selectedSkills.length > 0 || searchTerm) && (
113-
<button
114-
type="button"
115-
className={styles.clearButton}
116-
onClick={() => {
117-
clearFilters();
118-
setSearchTerm('');
119-
}}
120-
>
121-
Clear All
122-
</button>
123-
)}
124-
</div>
21+
<div>
22+
<h1>Community Members</h1>
12523

126-
{showFilters && (
127-
<div className={styles.filtersPanel}>
24+
<div style={{ marginBottom: 16 }}>
25+
<strong>Filter by skills:</strong>
26+
<div style={{ display: 'flex', gap: 10, marginTop: 8, flexWrap: 'wrap' }}>
12827
{availableSkills.map(skill => (
129-
<label key={skill} className={styles.filterOption}>
28+
<label key={skill} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
13029
<input
13130
type="checkbox"
13231
checked={selectedSkills.includes(skill)}
13332
onChange={() => handleCheckboxChange(skill)}
13433
/>
135-
<span>{skill}</span>
34+
{skill}
13635
</label>
13736
))}
13837
</div>
139-
)}
140-
141-
<p className={styles.helperText}>
142-
When multiple filters are selected, the score represents the average value, and the options
143-
are ranked based on their scoring. Click each profile to learn more details.
144-
</p>
38+
</div>
14539

146-
<RankedUserList
147-
users={filteredUsers}
148-
loading={loading}
149-
error={error}
150-
emptyMessage={emptyMessage}
151-
/>
40+
<RankedUserList selectedSkills={effectiveSkills} />
15241
</div>
15342
);
15443
}

0 commit comments

Comments
 (0)