Refactor JobFeeds state management and add explicit Search button to ensure instant dynamic filtering

This commit is contained in:
2026-07-23 12:29:56 -04:00
parent 8d23a457b5
commit 69d4857d04
2 changed files with 35 additions and 23 deletions
+1 -1
View File
@@ -1 +1 @@
273759 274566
+27 -15
View File
@@ -26,25 +26,19 @@ export const JobFeeds: React.FC<JobFeedsProps> = ({
onQuickApplyFeed onQuickApplyFeed
}) => { }) => {
const [searchTerm, setSearchTerm] = useState(''); const [searchTerm, setSearchTerm] = useState('');
const [activeSearchTerm, setActiveSearchTerm] = useState('');
const [selectedPlatform, setSelectedPlatform] = useState<string>('ALL'); const [selectedPlatform, setSelectedPlatform] = useState<string>('ALL');
const [selectedWorkType, setSelectedWorkType] = useState<string>('ALL'); const [selectedWorkType, setSelectedWorkType] = useState<string>('ALL');
const [selectedLocationFilter, setSelectedLocationFilter] = useState<string>('ALL'); const [selectedLocationFilter, setSelectedLocationFilter] = useState<string>('ALL');
const [minMatch, setMinMatch] = useState<number>(0); const [minMatch, setMinMatch] = useState<number>(0);
const [appliedFeedIds, setAppliedFeedIds] = useState<string[]>([]); const [appliedFeedIds, setAppliedFeedIds] = useState<string[]>([]);
const [isFetchingFeeds, setIsFetchingFeeds] = useState(false); const [isFetchingFeeds, setIsFetchingFeeds] = useState(false);
const [localFeeds, setLocalFeeds] = useState<JobFeedItem[]>(jobFeeds); const [liveFetchedFeeds, setLiveFetchedFeeds] = useState<JobFeedItem[]>([]);
// Synchronize localFeeds whenever jobFeeds prop updates from parent const displayFeeds = liveFetchedFeeds.length > 0 ? liveFetchedFeeds : jobFeeds;
React.useEffect(() => {
if (jobFeeds && jobFeeds.length > 0) {
setLocalFeeds(jobFeeds);
}
}, [jobFeeds]);
const displayFeeds = localFeeds.length > 0 ? localFeeds : jobFeeds;
const filteredFeeds = displayFeeds.filter(feed => { const filteredFeeds = displayFeeds.filter(feed => {
const term = searchTerm.toLowerCase().trim(); const term = (activeSearchTerm || searchTerm).toLowerCase().trim();
const titleMatch = (feed.title || '').toLowerCase().includes(term); const titleMatch = (feed.title || '').toLowerCase().includes(term);
const companyMatch = (feed.company || '').toLowerCase().includes(term); const companyMatch = (feed.company || '').toLowerCase().includes(term);
@@ -90,7 +84,7 @@ export const JobFeeds: React.FC<JobFeedsProps> = ({
if (res.ok) { if (res.ok) {
const data = await res.json(); const data = await res.json();
if (data.success && Array.isArray(data.jobs)) { if (data.success && Array.isArray(data.jobs)) {
setLocalFeeds(data.jobs); setLiveFetchedFeeds(data.jobs);
} }
} }
} catch (e) { } catch (e) {
@@ -137,17 +131,35 @@ export const JobFeeds: React.FC<JobFeedsProps> = ({
{/* Filter Bar */} {/* Filter Bar */}
<div className="p-4 rounded-2xl bg-slate-900 border border-slate-800 flex flex-col md:flex-row md:items-center justify-between gap-4"> <div className="p-4 rounded-2xl bg-slate-900 border border-slate-800 flex flex-col md:flex-row md:items-center justify-between gap-4">
{/* Search */} {/* Search Input with explicit Search & Filter Button */}
<div className="relative flex-1 min-w-[240px]"> <form
onSubmit={(e) => {
e.preventDefault();
setActiveSearchTerm(searchTerm);
}}
className="flex items-center gap-2 flex-1 min-w-[280px]"
>
<div className="relative flex-1">
<Search className="w-4 h-4 absolute left-3.5 top-1/2 -translate-y-1/2 text-slate-400" /> <Search className="w-4 h-4 absolute left-3.5 top-1/2 -translate-y-1/2 text-slate-400" />
<input <input
type="text" type="text"
placeholder="Search feed openings by title, company, or skills..." placeholder="Search by title, company, or skills..."
value={searchTerm} value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => {
setSearchTerm(e.target.value);
setActiveSearchTerm(e.target.value);
}}
className="w-full pl-10 pr-4 py-2 rounded-xl bg-slate-950 border border-slate-800 text-slate-200 text-xs placeholder:text-slate-500 focus:outline-none focus:border-indigo-500" className="w-full pl-10 pr-4 py-2 rounded-xl bg-slate-950 border border-slate-800 text-slate-200 text-xs placeholder:text-slate-500 focus:outline-none focus:border-indigo-500"
/> />
</div> </div>
<button
type="submit"
className="px-3.5 py-2 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white font-semibold text-xs transition shrink-0 flex items-center gap-1 shadow-md shadow-indigo-600/20"
>
<Filter className="w-3.5 h-3.5" />
<span>Search</span>
</button>
</form>
{/* Platform & Work Type & Match Threshold */} {/* Platform & Work Type & Match Threshold */}
<div className="flex items-center flex-wrap gap-2.5 text-xs"> <div className="flex items-center flex-wrap gap-2.5 text-xs">