import { db, storage } from '../lib/firebase'; import { collection, addDoc, updateDoc, deleteDoc, doc, getDocs, getDoc, query, where, orderBy, limit, increment } from 'firebase/firestore'; import { ref, uploadBytes, getDownloadURL } from 'firebase/storage'; export interface Application { id: string; jobId: string; studentId: string; status: 'applied' | 'shortlisted' | 'interview' | 'offer' | 'hired' | 'rejected'; resumeUrl: string; coverLetter: string; appliedAt: Date; } export const applicationService = { // Apply for a job (Student) applyForJob: async (jobId: string, studentId: string, resumeFile?: File, coverLetter?: string) => { if (!db) throw new Error("Firebase Database not initialized"); // Check if already applied const q = query( collection(db, 'applications'), where('jobId', '==', String(jobId)), where('studentId', '==', studentId) ); const snapshot = await getDocs(q); if (!snapshot.empty) { throw new Error('Already applied to this job'); } let resumeUrl = "https://via.placeholder.com/150?text=Resume+Upload+Disabled"; // Fallback URL // 1. Upload Resume (if Storage is available) if (storage && resumeFile) { try { const storageRef = ref(storage, `resumes/${studentId}/${jobId}_${resumeFile.name}`); await uploadBytes(storageRef, resumeFile); resumeUrl = await getDownloadURL(storageRef); } catch (error) { console.warn("Firebase Storage not available or failed. Using mock resume URL.", error); // Continue without failing, so the application can still be created in DB } } else { console.warn("Firebase Storage is not initialized. Skipping file upload."); } // 2. Save Application to Firestore const application = { jobId: String(jobId), studentId, status: 'applied', resumeUrl, coverLetter: coverLetter || '', appliedAt: new Date() }; const docRef = await addDoc(collection(db, 'applications'), application); // 3. Increment applicants count on job document try { const jobRef = doc(db, 'jobs', String(jobId)); await updateDoc(jobRef, { applicants: increment(1) }); } catch (e) { console.error("Failed to increment applicants count:", e); } return docRef.id; }, // Get applications for a specific job (Employer) getApplicationsForJob: async (jobId: string) => { if (!db) return []; const q = query(collection(db, 'applications'), where('jobId', '==', jobId)); const querySnapshot = await getDocs(q); const apps = querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() } as Application)); return apps.sort((a, b) => { const dateA = a.appliedAt instanceof Date ? a.appliedAt : (a.appliedAt as any)?.toDate?.() || new Date(0); const dateB = b.appliedAt instanceof Date ? b.appliedAt : (b.appliedAt as any)?.toDate?.() || new Date(0); return dateB.getTime() - dateA.getTime(); }); }, // Get my applications (Student) getMyApplications: async (studentId: string) => { if (!db) return []; const q = query(collection(db, 'applications'), where('studentId', '==', studentId)); const querySnapshot = await getDocs(q); const apps = querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() } as Application)); return apps.sort((a, b) => { const dateA = a.appliedAt instanceof Date ? a.appliedAt : (a.appliedAt as any)?.toDate?.() || new Date(0); const dateB = b.appliedAt instanceof Date ? b.appliedAt : (b.appliedAt as any)?.toDate?.() || new Date(0); return dateB.getTime() - dateA.getTime(); }); }, // Get all applications for an employer's jobs getApplicationsForEmployer: async (employerId: string) => { if (!db) return []; // First get all jobs for this employer const jobsQuery = query(collection(db, 'jobs'), where('employerId', '==', employerId)); const jobsSnapshot = await getDocs(jobsQuery); const jobIds = jobsSnapshot.docs.map(doc => doc.id); if (jobIds.length === 0) return []; // Then get applications for these jobs // Note: Firestore 'in' query supports up to 10 values. For more, we need to chunk or query all and filter. // For simplicity, we'll query all applications and filter in memory if jobIds > 10, or just query all and filter. const appsQuery = query(collection(db, 'applications')); const appsSnapshot = await getDocs(appsQuery); const allApps = appsSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() } as Application)); return allApps.filter(app => jobIds.includes(app.jobId)); }, // Update application status (Employer) updateStatus: async (applicationId: string, status: Application['status']) => { if (!db) throw new Error("Firebase not initialized"); const docRef = doc(db, 'applications', applicationId); await updateDoc(docRef, { status }); } };