230 lines
6.7 KiB
TypeScript
230 lines
6.7 KiB
TypeScript
import { API_BASE_URL } from '../config/api';
|
|
|
|
export interface JobPosition {
|
|
id: number;
|
|
title: string;
|
|
slug: string;
|
|
department: string;
|
|
employment_type: string;
|
|
location_type: string;
|
|
location: string;
|
|
open_positions: number;
|
|
experience_required?: string;
|
|
salary_min?: number;
|
|
salary_max?: number;
|
|
salary_currency: string;
|
|
salary_period: string;
|
|
salary_additional?: string;
|
|
short_description?: string;
|
|
about_role?: string;
|
|
requirements?: string[];
|
|
responsibilities?: string[];
|
|
qualifications?: string[];
|
|
bonus_points?: string[];
|
|
benefits?: string[];
|
|
start_date: string;
|
|
posted_date: string;
|
|
updated_date: string;
|
|
deadline?: string;
|
|
status: string;
|
|
featured?: boolean;
|
|
}
|
|
|
|
export interface JobApplication {
|
|
job: number;
|
|
first_name: string;
|
|
last_name: string;
|
|
email: string;
|
|
phone?: string;
|
|
current_position?: string;
|
|
current_company?: string;
|
|
years_of_experience?: string;
|
|
cover_letter?: string;
|
|
resume: File;
|
|
portfolio_url?: string;
|
|
linkedin_url?: string;
|
|
github_url?: string;
|
|
website_url?: string;
|
|
available_from?: string;
|
|
notice_period?: string;
|
|
expected_salary?: number;
|
|
salary_currency?: string;
|
|
consent: boolean;
|
|
}
|
|
|
|
class CareerService {
|
|
private baseUrl = `${API_BASE_URL}/api/career`;
|
|
|
|
|
|
/**
|
|
* Get all active job positions
|
|
*/
|
|
async getAllJobs(): Promise<JobPosition[]> {
|
|
try {
|
|
const response = await fetch(`${this.baseUrl}/jobs`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch jobs: ${response.statusText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
// Handle paginated response - extract results array
|
|
return data.results || data;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a single job position by slug
|
|
*/
|
|
async getJobBySlug(slug: string): Promise<JobPosition> {
|
|
try {
|
|
const response = await fetch(`${this.baseUrl}/jobs/${slug}`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch job: ${response.statusText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get featured job positions
|
|
*/
|
|
async getFeaturedJobs(): Promise<JobPosition[]> {
|
|
try {
|
|
const response = await fetch(`${this.baseUrl}/jobs/featured`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch featured jobs: ${response.statusText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
// Handle paginated response - extract results array
|
|
return data.results || data;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Submit a job application
|
|
*/
|
|
async submitApplication(applicationData: JobApplication): Promise<any> {
|
|
try {
|
|
const formData = new FormData();
|
|
|
|
// Required fields
|
|
formData.append('job', applicationData.job.toString());
|
|
formData.append('first_name', applicationData.first_name);
|
|
formData.append('last_name', applicationData.last_name);
|
|
formData.append('email', applicationData.email);
|
|
formData.append('consent', applicationData.consent.toString());
|
|
formData.append('resume', applicationData.resume);
|
|
|
|
// Optional fields (only append if they exist)
|
|
if (applicationData.phone) formData.append('phone', applicationData.phone);
|
|
if (applicationData.current_position) formData.append('current_position', applicationData.current_position);
|
|
if (applicationData.current_company) formData.append('current_company', applicationData.current_company);
|
|
if (applicationData.years_of_experience) formData.append('years_of_experience', applicationData.years_of_experience);
|
|
if (applicationData.cover_letter) formData.append('cover_letter', applicationData.cover_letter);
|
|
if (applicationData.portfolio_url) formData.append('portfolio_url', applicationData.portfolio_url);
|
|
if (applicationData.linkedin_url) formData.append('linkedin_url', applicationData.linkedin_url);
|
|
if (applicationData.github_url) formData.append('github_url', applicationData.github_url);
|
|
if (applicationData.website_url) formData.append('website_url', applicationData.website_url);
|
|
if (applicationData.available_from) formData.append('available_from', applicationData.available_from);
|
|
if (applicationData.notice_period) formData.append('notice_period', applicationData.notice_period);
|
|
if (applicationData.expected_salary !== undefined) formData.append('expected_salary', applicationData.expected_salary.toString());
|
|
if (applicationData.salary_currency) formData.append('salary_currency', applicationData.salary_currency);
|
|
|
|
const response = await fetch(`${this.baseUrl}/applications`, {
|
|
method: 'POST',
|
|
body: formData,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
const errorMessage = errorData.error || errorData.message || errorData.detail || `HTTP ${response.status}: ${response.statusText}`;
|
|
throw new Error(errorMessage);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filter jobs by department
|
|
*/
|
|
async getJobsByDepartment(department: string): Promise<JobPosition[]> {
|
|
try {
|
|
const response = await fetch(`${this.baseUrl}/jobs?department=${department}`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch jobs: ${response.statusText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
// Handle paginated response - extract results array
|
|
return data.results || data;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filter jobs by employment type
|
|
*/
|
|
async getJobsByEmploymentType(employmentType: string): Promise<JobPosition[]> {
|
|
try {
|
|
const response = await fetch(`${this.baseUrl}/jobs?employment_type=${employmentType}`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch jobs: ${response.statusText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
// Handle paginated response - extract results array
|
|
return data.results || data;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
export const careerService = new CareerService();
|
|
|