"use server"; import { createAdminClient } from "@/lib/supabase/server"; import { auth } from "@clerk/nextjs/server"; import type { PositionWithRelations, Applicant, CreatePositionInput, UpdatePositionInput, CreateApplicantInput, } from "./recruitment-types"; // ── Helpers ────────────────────────────────────────────────── async function getOrgAndUserId(): Promise<{ orgId: string; userId: string }> { const { userId } = await auth(); if (!userId) throw new Error("Unauthenticated"); const supabase = await createAdminClient(); const { data } = await supabase .from("organisation_members") .select("organisation_id, role") .eq("user_id", userId) .single(); if (!data) throw new Error("No org found"); return { orgId: data.organisation_id, userId }; } // ── Open Positions ────────────────────────────────────────── export async function fetchPositions(): Promise { const { orgId } = await getOrgAndUserId(); const supabase = await createAdminClient(); const { data } = await supabase .from("job_postings") .select( ` *, department:departments(name), applicants:applicants(count) ` ) .eq("organisation_id", orgId) .order("created_at", { ascending: false }); return (data || []).map((jp: PositionWithRelations & { applicants: { count: number }[] }) => ({ ...jp, applicant_count: jp.applicants?.[0]?.count || 0, })); } export async function createPosition( input: CreatePositionInput ): Promise<{ success: boolean; id?: string; error?: string }> { const { orgId, userId } = await getOrgAndUserId(); const supabase = await createAdminClient(); const { data, error } = await supabase .from("job_postings") .insert({ ...input, organisation_id: orgId, created_by: userId, }) .select("id") .single(); if (error) return { success: false, error: error.message }; return { success: true, id: data.id }; } export async function updatePosition( id: string, input: UpdatePositionInput ): Promise<{ success: boolean; error?: string }> { const { orgId } = await getOrgAndUserId(); const supabase = await createAdminClient(); const { error } = await supabase .from("job_postings") .update(input) .eq("id", id) .eq("organisation_id", orgId); if (error) return { success: false, error: error.message }; return { success: true }; } export async function fetchPosition(id: string): Promise { const { orgId } = await getOrgAndUserId(); const supabase = await createAdminClient(); const { data } = await supabase .from("job_postings") .select( ` *, department:departments(name), applicants:applicants(count) ` ) .eq("id", id) .eq("organisation_id", orgId) .single(); if (!data) return null; return { ...data, applicant_count: data.applicants?.[0]?.count || 0, }; } // ── Applicants ─────────────────────────────────────────────── export async function fetchApplicants(positionId: string): Promise { const { orgId } = await getOrgAndUserId(); const supabase = await createAdminClient(); const { data } = await supabase .from("applicants") .select("*") .eq("organisation_id", orgId) .eq("job_posting_id", positionId) .order("created_at", { ascending: false }); return data || []; } export async function createApplicant( input: CreateApplicantInput ): Promise<{ success: boolean; error?: string }> { const { orgId } = await getOrgAndUserId(); const supabase = await createAdminClient(); const { error } = await supabase .from("applicants") .insert({ ...input, organisation_id: orgId }); if (error) return { success: false, error: error.message }; return { success: true }; } export async function updateApplicantStage( id: string, stage: string ): Promise<{ success: boolean; error?: string }> { const { orgId } = await getOrgAndUserId(); const supabase = await createAdminClient(); const { error } = await supabase .from("applicants") .update({ stage }) .eq("id", id) .eq("organisation_id", orgId); if (error) return { success: false, error: error.message }; return { success: true }; } export async function updateApplicantNotes( id: string, notes: string ): Promise<{ success: boolean; error?: string }> { const { orgId } = await getOrgAndUserId(); const supabase = await createAdminClient(); const { error } = await supabase .from("applicants") .update({ notes }) .eq("id", id) .eq("organisation_id", orgId); if (error) return { success: false, error: error.message }; return { success: true }; } export async function deleteApplicant( id: string ): Promise<{ success: boolean; error?: string }> { const { orgId } = await getOrgAndUserId(); const supabase = await createAdminClient(); const { error } = await supabase .from("applicants") .delete() .eq("id", id) .eq("organisation_id", orgId); if (error) return { success: false, error: error.message }; return { success: true }; } // ── Resume Upload ──────────────────────────────────────────── export async function uploadResume( file: File ): Promise<{ success: boolean; url?: string; error?: string }> { const { orgId, userId } = await getOrgAndUserId(); const supabase = await createAdminClient(); const ext = file.name.split(".").pop(); const filePath = `${orgId}/${userId}/${Date.now()}-resume.${ext}`; const { error: uploadError } = await supabase.storage .from("resumes") .upload(filePath, file); if (uploadError) return { success: false, error: uploadError.message }; const { data } = await supabase.storage .from("resumes") .createSignedUrl(filePath, 86400 * 365); return { success: true, url: data?.signedUrl }; } // ── Departments ────────────────────────────────────────────── export async function fetchDepartments(): Promise<{ id: string; name: string }[]> { const { orgId } = await getOrgAndUserId(); const supabase = await createAdminClient(); const { data } = await supabase .from("departments") .select("id, name") .eq("organisation_id", orgId) .order("name", { ascending: true }); return data || []; }