| | import { authFetch } from "@/lib/api"; |
| | import { FilterFormValues } from "@/types/candidate-table"; |
| |
|
| | |
| | |
| | |
| | export const fetchAllCandidatesForExport = async ( |
| | search: string, |
| | sortConfig: { key: string | null; direction: "asc" | "desc" }, |
| | filters: FilterFormValues, |
| | criteriaId: string | null |
| | ): Promise<any[]> => { |
| | const params = new URLSearchParams() |
| |
|
| | |
| | |
| | params.set("page", "1") |
| | params.set("limit", "10000") |
| |
|
| | if (search) params.set("search", search) |
| | if (sortConfig.key) { |
| | params.set("sortBy", sortConfig.key) |
| | params.set("sortOrder", sortConfig.direction) |
| | } |
| |
|
| | if (filters.domicile) params.set("domicile", filters.domicile) |
| | if (filters.yoe) params.set("yoe", filters.yoe) |
| | filters.educations.forEach((edu, i) => { |
| | const n = i + 1 |
| | if (edu.university) params.set(`univ_edu_${n}`, edu.university) |
| | if (edu.major) params.set(`major_edu_${n}`, edu.major) |
| | if (edu.gpa) params.set(`gpa_${n}`, edu.gpa) |
| | }) |
| | if (filters.softskills) params.append("softskills", filters.softskills) |
| | if (filters.hardskills) params.append("hardskills", filters.hardskills) |
| | if (filters.certifications) params.append("certifications", filters.certifications) |
| | if (filters.businessDomain) params.append("business_domain", filters.businessDomain) |
| | if (criteriaId) params.append("criteria_id", criteriaId) |
| |
|
| | const res = await authFetch(`/api/cv-profile?${params}`) |
| | if (!res.ok) throw new Error("Failed to fetch candidates for export") |
| | |
| | const data = await res.json() |
| | return data.data ?? [] |
| | } |
| |
|
| | |
| | |
| | |
| | export const generateCSVContent = (candidates: any[]): string => { |
| | if (candidates.length === 0) return "" |
| |
|
| | |
| | const columns = [ |
| | "profile_id", |
| | "fullname", |
| | "domicile", |
| | "yoe", |
| | "univ_edu_1", |
| | "major_edu_1", |
| | "gpa_edu_1", |
| | "univ_edu_2", |
| | "major_edu_2", |
| | "gpa_edu_2", |
| | "univ_edu_3", |
| | "major_edu_3", |
| | "gpa_edu_3", |
| | "hardskills", |
| | "softskills", |
| | "certifications", |
| | "business_domain", |
| | "score", |
| | ] |
| |
|
| | |
| | const header = columns.join(",") |
| |
|
| | |
| | const rows = candidates.map((candidate) => |
| | columns |
| | .map((col) => { |
| | const value = candidate[col] |
| |
|
| | |
| | if (Array.isArray(value)) { |
| | return `"${value.join("; ")}"` |
| | } |
| |
|
| | |
| | if (value === null || value === undefined) { |
| | return "" |
| | } |
| |
|
| | |
| | const stringValue = String(value) |
| | if (stringValue.includes(",") || stringValue.includes('"') || stringValue.includes("\n")) { |
| | return `"${stringValue.replace(/"/g, '""')}"` // Escape quotes |
| | } |
| | |
| | return stringValue |
| | }) |
| | .join(",") |
| | ) |
| | |
| | return [header, ...rows].join("\n") |
| | } |
| | |
| | /** |
| | * Trigger CSV download in browser |
| | */ |
| | export const downloadCSV = (content: string, filename: string = "candidates.csv"): void => { |
| | const blob = new Blob([content], { type: "text/csv;charset=utf-8;" }) |
| | const link = document.createElement("a") |
| | const url = URL.createObjectURL(blob) |
| | |
| | link.setAttribute("href", url) |
| | link.setAttribute("download", filename) |
| | link.style.visibility = "hidden" |
| | |
| | document.body.appendChild(link) |
| | link.click() |
| | document.body.removeChild(link) |
| | |
| | URL.revokeObjectURL(url) |
| | } |
| | |
| | /** |
| | * Main export function - orchestrates fetch, generate, and download |
| | */ |
| | export const exportCandidatesToCSV = async ( |
| | search: string, |
| | sortConfig: { key: string | null; direction: "asc" | "desc" }, |
| | filters: FilterFormValues, |
| | criteriaId: string | null, |
| | userId: string |
| | ): Promise<void> => { |
| | try { |
| | const params = new URLSearchParams() |
| | |
| | if (search) params.set("search", search) |
| | if (sortConfig.key) { |
| | params.set("sortBy", sortConfig.key) |
| | params.set("sortOrder", sortConfig.direction) |
| | } |
| | |
| | if (filters.domicile) params.set("domicile", filters.domicile) |
| | if (filters.yoe) params.set("yoe", filters.yoe) |
| | filters.educations.forEach((edu, i) => { |
| | const n = i + 1 |
| | // Handle arrays for university and major |
| | edu.university.forEach((univ) => params.append(`univ_edu_${n}`, univ)) |
| | edu.major.forEach((maj) => params.append(`major_edu_${n}`, maj)) |
| | if (edu.gpa) params.set(`gpa_${n}`, edu.gpa) |
| | }) |
| | // Updated to handle arrays |
| | filters.softskills.forEach((skill) => params.append("softskills", skill)) |
| | filters.hardskills.forEach((skill) => params.append("hardskills", skill)) |
| | filters.certifications.forEach((cert) => params.append("certifications", cert)) |
| | filters.businessDomain.forEach((domain) => params.append("business_domain", domain)) |
| | |
| | if (criteriaId) params.append("criteria_id", criteriaId) |
| | params.append("user_id", userId) |
| | |
| | // Call backend export endpoint |
| | const response = await authFetch(`/api/cv-profile/export?${params}`, { |
| | method: "GET", |
| | headers: { |
| | "Accept": "text/csv", |
| | }, |
| | }) |
| | |
| | if (!response.ok) { |
| | const error = await response.json() |
| | throw new Error(error.error || "Export failed") |
| | } |
| | |
| | // Get blob and trigger download |
| | const blob = await response.blob() |
| | const url = window.URL.createObjectURL(blob) |
| | const link = document.createElement("a") |
| | link.href = url |
| | |
| | // Extract filename from Content-Disposition header |
| | const contentDisposition = response.headers.get("Content-Disposition") |
| | const filename = contentDisposition |
| | ? contentDisposition.split("filename=")[1]?.replace(/"/g, "") |
| | : `candidates-${new Date().toISOString().slice(0, 10)}.csv` |
| | |
| | link.setAttribute("download", filename) |
| | document.body.appendChild(link) |
| | link.click() |
| | |
| | // Cleanup |
| | document.body.removeChild(link) |
| | window.URL.revokeObjectURL(url) |
| | |
| | } catch (error) { |
| | console.error("Export failed:", error) |
| | throw error |
| | } |
| | } |