214 lines
11 KiB
PHP
214 lines
11 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('title', 'Browse Jobs - JobifyGarden | ' . number_format($jobs->total()) . ' Opportunities')
|
|
@section('description', 'Browse ' . number_format($jobs->total()) . ' job opportunities. Filter by location, job type, experience level, and more to find your perfect role.')
|
|
@section('canonical', route('jobs.index'))
|
|
|
|
@push('structured_data')
|
|
<script type="application/ld+json">
|
|
{!! json_encode(app(\App\Services\SeoService::class)->generateBreadcrumbStructuredData([
|
|
['name' => 'Home', 'url' => route('home')],
|
|
['name' => 'Jobs', 'url' => route('jobs.index')]
|
|
]), JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) !!}
|
|
</script>
|
|
|
|
<script type="application/ld+json">
|
|
{
|
|
"{{ '@' }}context": "https://schema.org",
|
|
"{{ '@' }}type": "CollectionPage",
|
|
"name": "Browse Jobs",
|
|
"description": "Browse thousands of job opportunities from multiple sources",
|
|
"url": "{{ route('jobs.index') }}"
|
|
}
|
|
</script>
|
|
@endpush
|
|
|
|
@section('content')
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<!-- Page Header -->
|
|
<div class="py-8">
|
|
<h1 class="text-3xl font-bold text-gray-900 mb-2">Browse Jobs</h1>
|
|
<p class="text-gray-600">{{ $jobs->total() }} jobs found</p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-4 gap-8">
|
|
<!-- Filters Sidebar -->
|
|
<aside class="lg:col-span-1">
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6 sticky top-4"
|
|
x-data="{
|
|
showFilters: true,
|
|
jobType: '{{ $filters['job_type'] ?? '' }}',
|
|
experienceLevel: '{{ $filters['experience_level'] ?? '' }}',
|
|
remote: {{ ($filters['remote'] ?? false) ? 'true' : 'false' }}
|
|
}">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h2 class="text-lg font-semibold text-gray-900">Filters</h2>
|
|
@if(!empty(array_filter($filters)))
|
|
<a href="{{ route('jobs.index') }}" class="text-sm text-emerald-600 hover:text-emerald-700">Clear all</a>
|
|
@endif
|
|
</div>
|
|
|
|
<form action="{{ route('jobs.index') }}" method="GET" class="space-y-6">
|
|
<!-- Keywords -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">Keywords</label>
|
|
<input type="text"
|
|
name="keywords"
|
|
value="{{ $filters['keywords'] ?? '' }}"
|
|
placeholder="Job title, skills..."
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-emerald-500 focus:border-emerald-500">
|
|
</div>
|
|
|
|
<!-- Location -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">Location</label>
|
|
<input type="text"
|
|
name="location"
|
|
value="{{ $filters['location'] ?? '' }}"
|
|
placeholder="City, state, or country"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-emerald-500 focus:border-emerald-500">
|
|
</div>
|
|
|
|
<!-- Category -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">Category</label>
|
|
<select name="category_id"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-emerald-500 focus:border-emerald-500">
|
|
<option value="">All Categories</option>
|
|
@foreach($categories as $category)
|
|
<option value="{{ $category->id }}" {{ ($filters['category_id'] ?? '') == $category->id ? 'selected' : '' }}>
|
|
{{ $category->name }} ({{ $category->jobs_count }})
|
|
</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Job Type -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">Job Type</label>
|
|
<select name="job_type"
|
|
x-model="jobType"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-emerald-500 focus:border-emerald-500">
|
|
<option value="">All Types</option>
|
|
@foreach($filterOptions['job_types'] ?? [] as $type)
|
|
<option value="{{ $type }}">{{ ucfirst(str_replace('_', ' ', $type)) }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Experience Level -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">Experience Level</label>
|
|
<select name="experience_level"
|
|
x-model="experienceLevel"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-emerald-500 focus:border-emerald-500">
|
|
<option value="">All Levels</option>
|
|
@foreach($filterOptions['experience_levels'] ?? [] as $level)
|
|
<option value="{{ $level }}">{{ ucfirst(str_replace('_', ' ', $level)) }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Remote -->
|
|
<div>
|
|
<label class="flex items-center">
|
|
<input type="checkbox"
|
|
name="remote"
|
|
value="1"
|
|
x-model="remote"
|
|
{{ ($filters['remote'] ?? false) ? 'checked' : '' }}
|
|
class="rounded border-gray-300 text-emerald-600 focus:ring-emerald-500">
|
|
<span class="ml-2 text-sm text-gray-700">Remote jobs only</span>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Salary Range -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">Minimum Salary</label>
|
|
<input type="number"
|
|
name="salary_min"
|
|
value="{{ $filters['salary_min'] ?? '' }}"
|
|
placeholder="e.g., 50000"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-emerald-500 focus:border-emerald-500">
|
|
</div>
|
|
|
|
<!-- Posted Within -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">Posted Within</label>
|
|
<select name="posted_within"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-emerald-500 focus:border-emerald-500">
|
|
<option value="">Any time</option>
|
|
<option value="1" {{ ($filters['posted_within'] ?? '') == '1' ? 'selected' : '' }}>Last 24 hours</option>
|
|
<option value="7" {{ ($filters['posted_within'] ?? '') == '7' ? 'selected' : '' }}>Last 7 days</option>
|
|
<option value="30" {{ ($filters['posted_within'] ?? '') == '30' ? 'selected' : '' }}>Last 30 days</option>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Submit Button -->
|
|
<button type="submit"
|
|
class="w-full px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white font-medium rounded-md transition-colors duration-200">
|
|
Apply Filters
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- Jobs List -->
|
|
<div class="lg:col-span-3">
|
|
<!-- Sort Options -->
|
|
<div class="mb-6 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
|
|
<div class="text-sm text-gray-600">
|
|
Showing {{ $jobs->firstItem() ?? 0 }} - {{ $jobs->lastItem() ?? 0 }} of {{ $jobs->total() }} jobs
|
|
</div>
|
|
<form action="{{ route('jobs.index') }}" method="GET" class="flex items-center gap-2">
|
|
<!-- Preserve existing filters -->
|
|
@foreach($filters as $key => $value)
|
|
@if($key !== 'sort' && $value)
|
|
<input type="hidden" name="{{ $key }}" value="{{ $value }}">
|
|
@endif
|
|
@endforeach
|
|
|
|
<label class="text-sm text-gray-700">Sort by:</label>
|
|
<select name="sort"
|
|
onchange="this.form.submit()"
|
|
class="px-3 py-1.5 border border-gray-300 rounded-md text-sm focus:ring-emerald-500 focus:border-emerald-500">
|
|
<option value="posted_at_desc" {{ ($filters['sort'] ?? 'posted_at_desc') === 'posted_at_desc' ? 'selected' : '' }}>Newest First</option>
|
|
<option value="posted_at_asc" {{ ($filters['sort'] ?? '') === 'posted_at_asc' ? 'selected' : '' }}>Oldest First</option>
|
|
<option value="salary_desc" {{ ($filters['sort'] ?? '') === 'salary_desc' ? 'selected' : '' }}>Highest Salary</option>
|
|
<option value="salary_asc" {{ ($filters['sort'] ?? '') === 'salary_asc' ? 'selected' : '' }}>Lowest Salary</option>
|
|
</select>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Job Listings -->
|
|
@if($jobs->count() > 0)
|
|
<div class="space-y-4">
|
|
@foreach($jobs as $job)
|
|
<x-job-card :job="$job" />
|
|
@endforeach
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
<div class="mt-8">
|
|
{{ $jobs->appends($filters)->links() }}
|
|
</div>
|
|
@else
|
|
<div class="bg-white rounded-lg border border-gray-200 p-12 text-center">
|
|
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
</svg>
|
|
<h3 class="mt-2 text-sm font-medium text-gray-900">No jobs found</h3>
|
|
<p class="mt-1 text-sm text-gray-500">Try adjusting your search or filter criteria.</p>
|
|
<div class="mt-6">
|
|
<a href="{{ route('jobs.index') }}"
|
|
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-emerald-700 bg-emerald-100 hover:bg-emerald-200">
|
|
Clear all filters
|
|
</a>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|