diff --git a/apps/admin/app/(main)/jobs/new/actions.ts b/apps/admin/app/(main)/jobs/new/actions.ts index e721645..87f6684 100644 --- a/apps/admin/app/(main)/jobs/new/actions.ts +++ b/apps/admin/app/(main)/jobs/new/actions.ts @@ -1,12 +1,14 @@ 'use server'; import { db, companies, jobs } from '@workspace/db'; +import { writeFile, mkdir } from 'fs/promises'; +import { join } from 'path'; export async function createJob(formData: FormData) { const companyIdRaw = formData.get('companyId'); const companyId = companyIdRaw ? Number(companyIdRaw) : undefined; const title = String(formData.get('title') ?? '').trim(); const link = String(formData.get('link') ?? '').trim(); - const description = String(formData.get('description') ?? '').trim() || 'N/A'; + const description = String(formData.get('description') ?? '').trim() || ''; const location = String(formData.get('location') ?? '').trim() || 'N/A'; const imageURL = String(formData.get('imageURL') ?? '').trim() || 'https://via.placeholder.com/100x100?text=Job'; @@ -19,13 +21,49 @@ export async function createJob(formData: FormData) { const allowDeadKT = formData.get('allowDeadKT') === 'on' || formData.get('allowDeadKT') === 'true'; const allowLiveKT = formData.get('allowLiveKT') === 'on' || formData.get('allowLiveKT') === 'true'; + // Handle file upload + const descriptionFile = formData.get('descriptionFile') as File | null; + const fileType = formData.get('fileType') as string | null; + + let fileUrl: string | null = null; + let fileName: string | null = null; + + if (descriptionFile && descriptionFile.size > 0) { + try { + // Create uploads directory if it doesn't exist + const uploadsDir = join(process.cwd(), 'public', 'uploads', 'job-descriptions'); + await mkdir(uploadsDir, { recursive: true }); + + // Generate unique filename + const timestamp = Date.now(); + const originalName = descriptionFile.name.replace(/[^a-zA-Z0-9.-]/g, '_'); + fileName = `${timestamp}_${originalName}`; + const filePath = join(uploadsDir, fileName); + + // Write file to disk + const bytes = await descriptionFile.arrayBuffer(); + await writeFile(filePath, Buffer.from(bytes)); + + // Set file URL for database + fileUrl = `/uploads/job-descriptions/${fileName}`; + } catch (error) { + console.error('Error uploading file:', error); + return { error: 'Failed to upload description file.' }; + } + } + if (!companyId || !title) return { error: 'Company and title are required.' }; + + // Either description text OR file is required + if (!description && !descriptionFile) { + return { error: 'Either description text or description file is required.' }; + } await db.insert(jobs).values({ companyId, title, link, - description, + description: description || null, location, imageURL, salary, @@ -36,18 +74,20 @@ export async function createJob(formData: FormData) { minHSC, allowDeadKT, allowLiveKT, + fileType: fileType || null, + fileUrl: fileUrl || null, + fileName: fileName || null, }); return { success: true }; } export async function createCompany(formData: FormData) { const name = String(formData.get('name') ?? '').trim(); - const email = String(formData.get('email') ?? '').trim(); const link = String(formData.get('link') ?? '').trim(); const description = String(formData.get('description') ?? '').trim(); const imageURL = String(formData.get('imageURL') ?? '').trim() || 'https://via.placeholder.com/100x100?text=Company'; - if (!name || !email || !link || !description) return { error: 'All fields are required.' }; - const [inserted] = await db.insert(companies).values({ name, email, link, description, imageURL }).returning(); + if (!name || !link || !description) return { error: 'Name, link, and description are required.' }; + const [inserted] = await db.insert(companies).values({ name, link, description, imageURL }).returning(); if (!inserted) return { error: 'Failed to add company.' }; return { success: true, company: { id: inserted.id, name: inserted.name } }; } diff --git a/apps/admin/app/(main)/jobs/new/new-job-form.tsx b/apps/admin/app/(main)/jobs/new/new-job-form.tsx index 4246f05..bca5468 100644 --- a/apps/admin/app/(main)/jobs/new/new-job-form.tsx +++ b/apps/admin/app/(main)/jobs/new/new-job-form.tsx @@ -29,6 +29,9 @@ import { CheckCircle, AlertCircle, LinkIcon, + Upload, + FileText, + X, } from "lucide-react" import { cn } from "@workspace/ui/lib/utils" import { Alert, AlertDescription } from "@workspace/ui/components/alert" @@ -62,6 +65,8 @@ function NewJobForm({ companies }: { companies: { id: number; name: string }[] } minHSC: 0, allowDeadKT: true, allowLiveKT: true, + fileType: undefined, + descriptionFile: undefined, }, }) @@ -74,7 +79,7 @@ function NewJobForm({ companies }: { companies: { id: number; name: string }[] } formData.append('companyId', String(data.companyId)) formData.append('title', data.title) formData.append('link', data.link) - formData.append('description', data.description) + formData.append('description', data.description || '') formData.append('location', data.location) formData.append('imageURL', data.imageURL || '') formData.append('salary', data.salary) @@ -89,6 +94,12 @@ function NewJobForm({ companies }: { companies: { id: number; name: string }[] } formData.append('allowDeadKT', String(data.allowDeadKT)) formData.append('allowLiveKT', String(data.allowLiveKT)) + // Handle file upload + if (data.descriptionFile) { + formData.append('descriptionFile', data.descriptionFile) + formData.append('fileType', data.fileType || (data.descriptionFile.type === 'application/pdf' ? 'pdf' : 'text')) + } + const result = await createJob(formData) if (result?.success) { setSuccess(true) @@ -412,23 +423,102 @@ function NewJobForm({ companies }: { companies: { id: number; name: string }[] } /> - ( - - Job Description * - -