Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 106 additions & 101 deletions src/components/Collaboration/Collaboration.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { ApiEndpoint } from '~/utils/URL';
import { useSelector } from 'react-redux';
import OneCommunityImage from '../../assets/images/logo2.png';
import WhatWeDoSection from '../WhatWeDo/WhatWeDo';

const ADS_PER_PAGE = 18;

Expand All @@ -20,22 +21,21 @@
const [showCategoryDropdown, setShowCategoryDropdown] = useState(false);
const [showPositionDropdown, setShowPositionDropdown] = useState(false);
const [summaries, setSummaries] = useState(null);
// const [positions, setPositions] = useState([]);

const [selectedPosition, setSelectedPosition] = useState('');
const [selectedCategory, setSelectedCategory] = useState('');
const [selectedJob, setSelectedJob] = useState(null);

Check warning on line 27 in src/components/Collaboration/Collaboration.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the declaration of the unused 'selectedJob' variable.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ6PRrTMp2VFTZekHq88&open=AZ6PRrTMp2VFTZekHq88&pullRequest=5271

Check warning on line 27 in src/components/Collaboration/Collaboration.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this useless assignment to variable "selectedJob".

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ6PRrTMp2VFTZekHq89&open=AZ6PRrTMp2VFTZekHq89&pullRequest=5271

// KEEP ACTIVE TAB (required)
const [activeTab, setActiveTab] = useState('jobPostings');

const categoryRef = useRef(null);
const positionRef = useRef(null);

const darkMode = useSelector(state => state.theme.darkMode);

const slugify = s =>
(s || '')
.toLowerCase()
.replace(/&/g, 'and')
.replace(/[^a-z0-9]+/g, '-')
.replace(/(^-|-$)/g, '');

/* ================= FETCH JOBS ================= */

const fetchJobs = async () => {
try {
const url =
Expand All @@ -61,7 +61,6 @@
}
};

/* ================= EFFECTS ================= */
useEffect(() => {
fetchCategories();
}, []);
Expand All @@ -71,6 +70,8 @@
fetchJobs();
}, [searchTerm, selectedCategory]);

/* ================= FILTER LOGIC ================= */

const filteredJobs = useMemo(() => {
if (!selectedPosition) return allJobs;

Expand Down Expand Up @@ -103,9 +104,7 @@
setTotalPages(Math.max(calculatedPages, 1));
}, [filteredJobs, currentPage]);

useEffect(() => {
// no-op placeholder; keep hook list stable if needed in future
}, []);
/* ================= OUTSIDE CLICK ================= */

useEffect(() => {
const handleClickOutside = event => {
Expand All @@ -119,16 +118,17 @@
};

document.addEventListener('mousedown', handleClickOutside);

return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);

/* ================= HANDLERS ================= */

const handleSubmit = e => {
e.preventDefault();
setSearchTerm(query);

// IMPORTANT: switch to job view automatically
setActiveTab('jobPostings');
};

const handleClearAllFilters = () => {
Expand All @@ -151,6 +151,7 @@
};

/* ================= SUMMARIES VIEW ================= */

if (summaries) {
return (
<div className={`${styles.jobLanding} ${darkMode ? styles.dark : ''}`}>
Expand All @@ -160,12 +161,12 @@
</a>
</div>

<div className={`${styles.userCollaborationContainer} ${darkMode ? styles.dark : ''}`}>
<div className={styles.userCollaborationContainer}>
<h2>Job Summaries</h2>

{summaries.jobs?.length ? (
summaries.jobs.map(job => (
<div key={job._id} className="job-summary-item">
<div key={job._id}>
<h4>
<a href={job.jobDetailsLink}>{job.title}</a>
</h4>
Expand All @@ -185,6 +186,7 @@
}

/* ================= MAIN VIEW ================= */

return (
<div className={`${styles.jobLanding} ${darkMode ? styles.dark : ''}`}>
<div className={styles.jobHeader}>
Expand All @@ -196,6 +198,14 @@
<div className={styles.userCollaborationContainer}>
{/* NAVBAR */}
<nav className={styles.navbar}>
{/* ONLY ONE TAB BUTTON (no Job Postings button UI) */}
<button
className={activeTab === 'whatWeDo' ? styles.activeTab : styles.tabButton}
onClick={() => setActiveTab(prev => (prev === 'whatWeDo' ? 'jobPostings' : 'whatWeDo'))}
>
What We Do
</button>

<form className={styles.searchForm} onSubmit={handleSubmit}>
<input
type="text"
Expand All @@ -206,14 +216,14 @@
<button className="btn btn-secondary">Go</button>
</form>

{/* CATEGORY */}
<div className={styles.dropdownWrapper} ref={categoryRef}>
<button
type="button"
onClick={() => {
setShowCategoryDropdown(prev => !prev);
setShowPositionDropdown(false);
}}
aria-expanded={showCategoryDropdown}
>
{selectedCategory || 'Select Categories'} ▼
</button>
Expand All @@ -224,12 +234,11 @@
<button
key={cat}
type="button"
className={styles.dropdownItem}
onClick={() => {
setSelectedCategory(cat);
setSelectedPosition('');
setShowCategoryDropdown(false);
setCurrentPage(1);
setShowCategoryDropdown(false);
}}
>
{cat}
Expand All @@ -239,6 +248,7 @@
)}
</div>

{/* POSITION */}
<div className={styles.dropdownWrapper} ref={positionRef}>
<button
type="button"
Expand All @@ -248,116 +258,111 @@
setShowPositionDropdown(prev => !prev);
setShowCategoryDropdown(false);
}}
aria-expanded={showPositionDropdown}
>
{selectedPosition || 'Select Positions'} ▼
</button>

{showPositionDropdown && selectedCategory && (
<div className={styles.jobSelect}>
{positions.length > 0 ? (
{positions.length ? (
positions.map(pos => (
<button
key={pos}
type="button"
className={styles.dropdownItem}
onClick={() => {
setSelectedPosition(pos);
setShowPositionDropdown(false);
setCurrentPage(1);
setShowPositionDropdown(false);
}}
>
{pos}
</button>
))
) : (
<div className={styles.dropdownItem}>No positions found</div>
<div>No positions found</div>
)}
</div>
)}
</div>
</nav>

{/* HEADINGS */}
<div className={styles.headings}>
<h1 className={styles.jobHead}>LIKE TO WORK WITH US? APPLY NOW!</h1>
<a className="btn" href="https://www.onecommunityglobal.org/collaboration/">
← Return to One Community Collaboration Page
</a>
</div>
{/* ================= TAB CONTENT ================= */}

{activeTab === 'whatWeDo' ? (
<WhatWeDoSection />
) : (
<>
{/* HEADINGS */}
<div className={styles.headings}>
<h1 className={styles.jobHead}>LIKE TO WORK WITH US? APPLY NOW!</h1>
<a className="btn" href="https://www.onecommunityglobal.org/collaboration/">
← Return to One Community Collaboration Page
</a>
</div>

{/* QUERY TEXT */}
<div className="job-queries">
<p>
{searchTerm
? `Listing results for '${searchTerm}'`
: selectedPosition
? `Listing results for '${selectedPosition}' in '${selectedCategory}'`
: selectedCategory
? `Listing results for '${selectedCategory}'`
: 'Listing all job ads.'}
</p>
<button className="btn btn-secondary" onClick={handleShowSummaries}>
Show Summaries
</button>
</div>
{/* QUERY INFO */}
<div className="job-queries">
<p>
{searchTerm
? `Listing results for '${searchTerm}'`
: selectedPosition
? `Listing results for '${selectedPosition}' in '${selectedCategory}'`
: selectedCategory
? `Listing results for '${selectedCategory}'`
: 'Listing all job ads.'}
</p>

<button className="btn btn-secondary" onClick={handleShowSummaries}>
Show Summaries
</button>
</div>

{/* FILTER CHIPS */}
{(selectedCategory || selectedPosition) && (
<div className={styles.jobQueries}>
{selectedCategory && <span className={styles.chip}>{selectedCategory}</span>}
{selectedPosition && <span className={styles.chip}>{selectedPosition}</span>}
<button className={styles.clearAllButton} onClick={handleClearAllFilters}>
Clear All
</button>
</div>
)}
{/* FILTER CHIPS */}
{(selectedCategory || selectedPosition) && (
<div className={styles.jobQueries}>
<button onClick={handleClearAllFilters}>Clear All Filters</button>
</div>
)}

{/* JOB GRID */}
<div className={styles.jobList}>
{jobAds.length > 0 ? (
jobAds.map(ad => (
<button
key={ad._id}
type="button"
className={styles.jobAd}
onClick={() => setSelectedJob(ad)}
>
<img
src={
ad.imageUrl ||
`/api/placeholder/640/480?text=${encodeURIComponent(ad.category || 'Job')}`
}
alt={ad.title}
/>
<h3>{ad.title}</h3>
</button>
))
) : (
<div className={styles.emptyState}>
<p>No job listings found matching your criteria.</p>
<p>Try clearing filters or adjusting your search terms.</p>
<button className="btn btn-secondary" onClick={handleClearAllFilters}>
Clear All Filters
</button>
{/* JOB GRID */}
<div className={styles.jobList}>
{jobAds.length ? (
jobAds.map(ad => (
<button key={ad._id} className={styles.jobAd} onClick={() => setSelectedJob(ad)}>
<img
src={
ad.imageUrl ||
`/api/placeholder/640/480?text=${encodeURIComponent(ad.category || 'Job')}`
}
alt={ad.title}
/>
<h3>{ad.title}</h3>
</button>
))
) : (
<div className={styles.emptyState}>
<p>No job listings found matching your criteria.</p>
<button onClick={handleClearAllFilters}>Clear All Filters</button>
</div>
)}
</div>
)}
</div>

{/* PAGINATION */}
<div className={styles.pagination}>
{Array.from({ length: totalPages }, (_, i) => (
<button
key={i}
onClick={() => setCurrentPage(i + 1)}
className={
currentPage === i + 1 ? styles.paginationButtonActive : styles.paginationButton
}
>
{i + 1}
</button>
))}
</div>
{/* PAGINATION */}
<div className={styles.pagination}>
{Array.from({ length: totalPages }, (_, i) => (
<button
key={i}
onClick={() => setCurrentPage(i + 1)}
className={
currentPage === i + 1 ? styles.paginationButtonActive : styles.paginationButton
}
>
{i + 1}
</button>
))}
</div>
</>
)}
</div>
</div>
);
Expand Down
Loading
Loading