Add Work Environment & Location designation (Remote, Hybrid, Onsite) across Profile, Autonomous Engine, and Job Feeds

This commit is contained in:
2026-07-23 12:18:47 -04:00
parent f4566645f7
commit 1e61798c13
5 changed files with 70 additions and 8 deletions
+1 -1
View File
@@ -1 +1 @@
271040 271577
+32
View File
@@ -248,6 +248,38 @@ export const AutonomousEngine: React.FC<AutonomousEngineProps> = ({
</div> </div>
</div> </div>
{/* Preferred Locations & Work Type (Remote / Hybrid / Onsite) */}
<div>
<label className="block text-xs font-semibold text-slate-300 mb-1.5">Preferred Work Locations & Remote Status</label>
<div className="flex items-center gap-3 text-xs mb-2">
{['Remote', 'Hybrid', 'Onsite'].map((type) => {
const workTypes = criteria.preferredWorkTypes || ['Remote', 'Hybrid'];
const isSelected = workTypes.includes(type as any);
return (
<button
key={type}
type="button"
onClick={() => {
const updated = isSelected
? workTypes.filter(t => t !== type)
: [...workTypes, type as any];
handleUpdateCriteria('preferredWorkTypes', updated);
}}
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-xl border text-xs font-medium transition ${
isSelected
? 'bg-indigo-950 border-indigo-500/50 text-indigo-300 font-bold'
: 'bg-slate-950 border-slate-800 text-slate-400 hover:text-slate-200'
}`}
>
<span className={`w-2 h-2 rounded-full ${isSelected ? 'bg-indigo-400' : 'bg-slate-600'}`}></span>
<span>{type}</span>
</button>
);
})}
</div>
<p className="text-[10px] text-slate-500">Designates work environment preferences for autonomous matching.</p>
</div>
{/* Excluded Companies */} {/* Excluded Companies */}
<div> <div>
<label className="block text-xs font-semibold text-slate-300 mb-1.5">Excluded / Blacklisted Companies</label> <label className="block text-xs font-semibold text-slate-300 mb-1.5">Excluded / Blacklisted Companies</label>
+34 -6
View File
@@ -27,6 +27,7 @@ export const JobFeeds: React.FC<JobFeedsProps> = ({
}) => { }) => {
const [searchTerm, setSearchTerm] = useState(''); const [searchTerm, setSearchTerm] = useState('');
const [selectedPlatform, setSelectedPlatform] = useState<string>('ALL'); const [selectedPlatform, setSelectedPlatform] = useState<string>('ALL');
const [selectedWorkType, setSelectedWorkType] = 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);
@@ -43,7 +44,6 @@ export const JobFeeds: React.FC<JobFeedsProps> = ({
const filteredFeeds = displayFeeds.filter(feed => { const filteredFeeds = displayFeeds.filter(feed => {
const term = searchTerm.toLowerCase().trim(); const term = searchTerm.toLowerCase().trim();
if (!term && selectedPlatform === 'ALL' && minMatch === 0) return true;
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);
@@ -54,9 +54,22 @@ export const JobFeeds: React.FC<JobFeedsProps> = ({
const matchesSearch = !term || titleMatch || companyMatch || locationMatch || platformMatchStr || descMatch || skillsMatch; const matchesSearch = !term || titleMatch || companyMatch || locationMatch || platformMatchStr || descMatch || skillsMatch;
const matchesPlatform = selectedPlatform === 'ALL' || feed.platform === selectedPlatform; const matchesPlatform = selectedPlatform === 'ALL' || feed.platform === selectedPlatform;
// Work Type / Remote Status Filter
const feedLoc = (feed.location || '').toLowerCase();
const feedDesc = (feed.description || '').toLowerCase();
let matchesWorkType = true;
if (selectedWorkType === 'Remote') {
matchesWorkType = feedLoc.includes('remote') || feedDesc.includes('remote');
} else if (selectedWorkType === 'Hybrid') {
matchesWorkType = feedLoc.includes('hybrid') || feedDesc.includes('hybrid');
} else if (selectedWorkType === 'Onsite') {
matchesWorkType = !feedLoc.includes('remote') && !feedDesc.includes('remote');
}
const matchesMatch = (feed.estimatedMatch ?? 80) >= minMatch; const matchesMatch = (feed.estimatedMatch ?? 80) >= minMatch;
return matchesSearch && matchesPlatform && matchesMatch; return matchesSearch && matchesPlatform && matchesWorkType && matchesMatch;
}); });
const handleFetchLiveFeeds = async () => { const handleFetchLiveFeeds = async () => {
@@ -125,8 +138,22 @@ export const JobFeeds: React.FC<JobFeedsProps> = ({
/> />
</div> </div>
{/* Platform & Match Threshold */} {/* Platform & Work Type & Match Threshold */}
<div className="flex items-center gap-3 text-xs"> <div className="flex items-center flex-wrap gap-2.5 text-xs">
{/* Work Type Filter Dropdown */}
<select
value={selectedWorkType}
onChange={(e) => setSelectedWorkType(e.target.value)}
className="px-3 py-2 rounded-xl bg-slate-950 border border-slate-800 text-indigo-300 font-semibold text-xs focus:outline-none focus:border-indigo-500"
>
<option value="ALL">All Work Types (Remote/Onsite/Hybrid)</option>
<option value="Remote">🌐 Remote Only</option>
<option value="Hybrid">🏢 Hybrid Only</option>
<option value="Onsite">📍 Onsite Only</option>
</select>
{/* Platform Dropdown */}
<select <select
value={selectedPlatform} value={selectedPlatform}
onChange={(e) => setSelectedPlatform(e.target.value)} onChange={(e) => setSelectedPlatform(e.target.value)}
@@ -154,14 +181,15 @@ export const JobFeeds: React.FC<JobFeedsProps> = ({
/> />
</div> </div>
{(searchTerm || selectedPlatform !== 'ALL' || minMatch > 0) && ( {(searchTerm || selectedPlatform !== 'ALL' || selectedWorkType !== 'ALL' || minMatch > 0) && (
<button <button
onClick={() => { onClick={() => {
setSearchTerm(''); setSearchTerm('');
setSelectedPlatform('ALL'); setSelectedPlatform('ALL');
setSelectedWorkType('ALL');
setMinMatch(0); setMinMatch(0);
}} }}
className="px-3 py-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-300 text-xs font-semibold transition" className="px-3 py-2 rounded-xl bg-indigo-950 border border-indigo-500/40 text-indigo-300 text-xs font-semibold hover:bg-indigo-900 transition"
> >
Reset Filters Reset Filters
</button> </button>
+2 -1
View File
@@ -26,7 +26,8 @@ export const INITIAL_USER_PROFILE: UserProfile = {
targetRoles: [], targetRoles: [],
minMatchScore: 80, minMatchScore: 80,
maxDailyApplications: 10, maxDailyApplications: 10,
preferredLocations: [], preferredLocations: ["Remote US", "Connecticut", "New York"],
preferredWorkTypes: ["Remote", "Hybrid"],
minSalary: 100000, minSalary: 100000,
excludedCompanies: [], excludedCompanies: [],
preferredPlatforms: ["LinkedIn", "Greenhouse", "Lever", "Workday", "Indeed", "Direct"] preferredPlatforms: ["LinkedIn", "Greenhouse", "Lever", "Workday", "Indeed", "Direct"]
+1
View File
@@ -121,6 +121,7 @@ export interface UserProfile {
minMatchScore: number; minMatchScore: number;
maxDailyApplications: number; maxDailyApplications: number;
preferredLocations: string[]; preferredLocations: string[];
preferredWorkTypes?: ('Remote' | 'Onsite' | 'Hybrid')[];
minSalary: number; minSalary: number;
excludedCompanies: string[]; excludedCompanies: string[];
preferredPlatforms: PlatformType[]; preferredPlatforms: PlatformType[];