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
+34 -22
View File
@@ -26,25 +26,19 @@ export const JobFeeds: React.FC<JobFeedsProps> = ({
onQuickApplyFeed
}) => {
const [searchTerm, setSearchTerm] = useState('');
const [activeSearchTerm, setActiveSearchTerm] = useState('');
const [selectedPlatform, setSelectedPlatform] = useState<string>('ALL');
const [selectedWorkType, setSelectedWorkType] = useState<string>('ALL');
const [selectedLocationFilter, setSelectedLocationFilter] = useState<string>('ALL');
const [minMatch, setMinMatch] = useState<number>(0);
const [appliedFeedIds, setAppliedFeedIds] = useState<string[]>([]);
const [isFetchingFeeds, setIsFetchingFeeds] = useState(false);
const [localFeeds, setLocalFeeds] = useState<JobFeedItem[]>(jobFeeds);
const [liveFetchedFeeds, setLiveFetchedFeeds] = useState<JobFeedItem[]>([]);
// Synchronize localFeeds whenever jobFeeds prop updates from parent
React.useEffect(() => {
if (jobFeeds && jobFeeds.length > 0) {
setLocalFeeds(jobFeeds);
}
}, [jobFeeds]);
const displayFeeds = localFeeds.length > 0 ? localFeeds : jobFeeds;
const displayFeeds = liveFetchedFeeds.length > 0 ? liveFetchedFeeds : jobFeeds;
const filteredFeeds = displayFeeds.filter(feed => {
const term = searchTerm.toLowerCase().trim();
const term = (activeSearchTerm || searchTerm).toLowerCase().trim();
const titleMatch = (feed.title || '').toLowerCase().includes(term);
const companyMatch = (feed.company || '').toLowerCase().includes(term);
@@ -90,7 +84,7 @@ export const JobFeeds: React.FC<JobFeedsProps> = ({
if (res.ok) {
const data = await res.json();
if (data.success && Array.isArray(data.jobs)) {
setLocalFeeds(data.jobs);
setLiveFetchedFeeds(data.jobs);
}
}
} catch (e) {
@@ -137,17 +131,35 @@ export const JobFeeds: React.FC<JobFeedsProps> = ({
{/* 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">
{/* Search */}
<div className="relative flex-1 min-w-[240px]">
<Search className="w-4 h-4 absolute left-3.5 top-1/2 -translate-y-1/2 text-slate-400" />
<input
type="text"
placeholder="Search feed openings by title, company, or skills..."
value={searchTerm}
onChange={(e) => setSearchTerm(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"
/>
</div>
{/* Search Input with explicit Search & Filter Button */}
<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" />
<input
type="text"
placeholder="Search by title, company, or skills..."
value={searchTerm}
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"
/>
</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 */}
<div className="flex items-center flex-wrap gap-2.5 text-xs">