Add Work Environment & Location designation (Remote, Hybrid, Onsite) across Profile, Autonomous Engine, and Job Feeds
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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"]
|
||||||
|
|||||||
@@ -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[];
|
||||||
|
|||||||
Reference in New Issue
Block a user