From 140629ec06149cde8ee2f3c03515a8ca4a595143 Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Sat, 8 Nov 2025 01:33:12 +0000 Subject: [PATCH] Opportunities API client for frontend cgen-c2a35b6c54174cb1b086c439f1bfdc6e --- client/api/opportunities.ts | 110 ++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 client/api/opportunities.ts diff --git a/client/api/opportunities.ts b/client/api/opportunities.ts new file mode 100644 index 00000000..11f06616 --- /dev/null +++ b/client/api/opportunities.ts @@ -0,0 +1,110 @@ +export interface OpportunityPoster { + id: string; + username: string; + avatar_url: string; + bio?: string; +} + +export interface Opportunity { + id: string; + title: string; + description: string; + job_type: string; + salary_min: number; + salary_max: number; + experience_level: string; + arm_affiliation: string; + posted_by_id: string; + aethex_creators: OpportunityPoster; + status: string; + created_at: string; + updated_at?: string; + aethex_applications?: { count: number }; +} + +export interface OpportunitiesResponse { + data: Opportunity[]; + pagination: { + page: number; + limit: number; + total: number; + pages: number; + }; +} + +export interface CreateOpportunityData { + title: string; + description: string; + job_type: string; + salary_min?: number; + salary_max?: number; + experience_level?: string; + arm_affiliation: string; +} + +const API_BASE = process.env.VITE_API_BASE || ""; + +export async function getOpportunities(filters?: { + arm?: string; + search?: string; + jobType?: string; + experienceLevel?: string; + sort?: "recent" | "oldest"; + page?: number; + limit?: number; +}): Promise { + const params = new URLSearchParams(); + if (filters?.arm) params.append("arm", filters.arm); + if (filters?.search) params.append("search", filters.search); + if (filters?.jobType) params.append("jobType", filters.jobType); + if (filters?.experienceLevel) params.append("experienceLevel", filters.experienceLevel); + if (filters?.sort) params.append("sort", filters.sort); + if (filters?.page) params.append("page", String(filters.page)); + if (filters?.limit) params.append("limit", String(filters.limit)); + + const response = await fetch(`${API_BASE}/api/opportunities?${params}`); + if (!response.ok) throw new Error("Failed to fetch opportunities"); + return response.json(); +} + +export async function getOpportunityById(id: string): Promise { + const response = await fetch(`${API_BASE}/api/opportunities/${id}`); + if (!response.ok) throw new Error("Opportunity not found"); + return response.json(); +} + +export async function createOpportunity(data: CreateOpportunityData): Promise { + const response = await fetch(`${API_BASE}/api/opportunities`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(data), + }); + if (!response.ok) throw new Error("Failed to create opportunity"); + return response.json(); +} + +export async function updateOpportunity( + id: string, + data: Partial +): Promise { + const response = await fetch(`${API_BASE}/api/opportunities/${id}`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(data), + }); + if (!response.ok) throw new Error("Failed to update opportunity"); + return response.json(); +} + +export async function closeOpportunity(id: string): Promise { + const response = await fetch(`${API_BASE}/api/opportunities/${id}/close`, { + method: "POST", + }); + if (!response.ok) throw new Error("Failed to close opportunity"); +} + +export async function getApplicationsForOpportunity(opportunityId: string) { + const response = await fetch(`${API_BASE}/api/opportunities/${opportunityId}/applications`); + if (!response.ok) throw new Error("Failed to fetch applications"); + return response.json(); +}