diff --git a/backend/server3.js b/backend/server3.js index ae14c7c..84732d8 100644 --- a/backend/server3.js +++ b/backend/server3.js @@ -8,11 +8,12 @@ import sqlite3 from 'sqlite3'; import jwt from 'jsonwebtoken'; import { v4 as uuidv4 } from 'uuid'; import path from 'path'; -import fs from 'fs'; +import fs from 'fs/promises'; import multer from 'multer'; import mammoth from 'mammoth'; import { fileURLToPath } from 'url'; -import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.js'; +import pkg from 'pdfjs-dist'; + import OpenAI from 'openai'; // --- Basic file init --- @@ -28,6 +29,7 @@ dotenv.config({ path: envPath }); // Load .env file const app = express(); const PORT = process.env.PREMIUM_PORT || 5002; +const { getDocument } = pkg; let db; const initDB = async () => { @@ -1655,6 +1657,22 @@ ${resumeText} Precisely Tailored, ATS-Optimized Resume: `; +async function extractTextFromPDF(filePath) { + const fileBuffer = await fs.readFile(filePath); + const uint8Array = new Uint8Array(fileBuffer); // Convert Buffer explicitly + const pdfDoc = await getDocument({ data: uint8Array }).promise; + + let text = ''; + for (let pageNum = 1; pageNum <= pdfDoc.numPages; pageNum++) { + const page = await pdfDoc.getPage(pageNum); + const pageText = await page.getTextContent(); + text += pageText.items.map(item => item.str).join(' '); + } + return text; +} + + +// Your corrected endpoint with limits correctly returned: app.post( '/api/premium/resume/optimize', upload.single('resumeFile'), @@ -1668,7 +1686,6 @@ app.post( const userId = req.userId; const now = new Date(); - const currentWeek = getWeekNumber(now); // Function defined below const userProfile = await db.get( `SELECT is_premium, is_pro_premium, resume_optimizations_used, resume_limit_reset, resume_booster_count @@ -1702,16 +1719,20 @@ app.post( } const filePath = req.file.path; - const fileExt = req.file.originalname.split('.').pop().toLowerCase(); + const mimeType = req.file.mimetype; let resumeText = ''; - if (fileExt === 'pdf') { + if (mimeType === 'application/pdf') { resumeText = await extractTextFromPDF(filePath); - } else if (fileExt === 'docx') { + } else if ( + mimeType === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' || + mimeType === 'application/msword' + ) { const result = await mammoth.extractRawText({ path: filePath }); resumeText = result.value; } else { - return res.status(400).json({ error: 'Unsupported file type.' }); + await fs.unlink(filePath); + return res.status(400).json({ error: 'Unsupported or corrupted file upload.' }); } const prompt = buildResumePrompt(resumeText, jobTitle, jobDescription); @@ -1728,12 +1749,16 @@ app.post( `UPDATE user_profile SET resume_optimizations_used = resume_optimizations_used + 1 WHERE user_id = ?`, [userId] ); - - // Calculate remaining optimizations + const remainingOptimizations = totalLimit - (userProfile.resume_optimizations_used + 1); - - fs.unlinkSync(filePath); - res.json({ optimizedResume, remainingOptimizations }); + + await fs.unlink(filePath); + res.json({ + optimizedResume, + remainingOptimizations, + resetDate: resetDate.toISOString() // <-- explicitly returned here! + }); + } catch (err) { console.error('Error optimizing resume:', err); res.status(500).json({ error: 'Failed to optimize resume.' }); diff --git a/src/App.js b/src/App.js index d203acd..93907df 100644 --- a/src/App.js +++ b/src/App.js @@ -236,12 +236,12 @@ function App() { {/* Logout */}
  • - +
  • diff --git a/src/components/ResumeRewrite.js b/src/components/ResumeRewrite.js index af0afc5..b0e1965 100644 --- a/src/components/ResumeRewrite.js +++ b/src/components/ResumeRewrite.js @@ -9,6 +9,7 @@ function ResumeRewrite() { const [error, setError] = useState(''); const [remainingOptimizations, setRemainingOptimizations] = useState(null); const [resetDate, setResetDate] = useState(null); + const [loading, setLoading] = useState(false); // ADDED loading state const handleFileChange = (e) => { setResumeFile(e.target.files[0]); @@ -39,6 +40,8 @@ function ResumeRewrite() { return; } + setLoading(true); // ACTIVATE loading + try { const token = localStorage.getItem('token'); const formData = new FormData(); @@ -55,12 +58,12 @@ function ResumeRewrite() { setOptimizedResume(res.data.optimizedResume || ''); setError(''); - - // Refresh remaining optimizations after optimizing fetchRemainingOptimizations(); } catch (err) { console.error('Resume optimization error:', err); setError(err.response?.data?.error || 'Failed to optimize resume.'); + } finally { + setLoading(false); // DEACTIVATE loading } }; @@ -101,10 +104,22 @@ function ResumeRewrite() { {error &&

    {error}

    } - + + {loading && ( +
    +
    + Optimizing your resume... +
    + )} {optimizedResume && ( diff --git a/uploads/27bb962c438a8ffe986fc7571948bfb7 b/uploads/27bb962c438a8ffe986fc7571948bfb7 new file mode 100644 index 0000000..d1f1847 Binary files /dev/null and b/uploads/27bb962c438a8ffe986fc7571948bfb7 differ diff --git a/uploads/7494904b7764d12ecd6900f9292949f2 b/uploads/7494904b7764d12ecd6900f9292949f2 new file mode 100644 index 0000000..c5b7a08 Binary files /dev/null and b/uploads/7494904b7764d12ecd6900f9292949f2 differ diff --git a/uploads/9fce92f8988efce8891352b7d64b2829 b/uploads/9fce92f8988efce8891352b7d64b2829 new file mode 100644 index 0000000..d1f1847 Binary files /dev/null and b/uploads/9fce92f8988efce8891352b7d64b2829 differ diff --git a/uploads/b4299293be37c7a453d27801078a4efb b/uploads/b4299293be37c7a453d27801078a4efb new file mode 100644 index 0000000..c5b7a08 Binary files /dev/null and b/uploads/b4299293be37c7a453d27801078a4efb differ diff --git a/uploads/d0470483ed235e9d1a88bee2005dd840 b/uploads/d0470483ed235e9d1a88bee2005dd840 new file mode 100644 index 0000000..d1f1847 Binary files /dev/null and b/uploads/d0470483ed235e9d1a88bee2005dd840 differ diff --git a/user_profile.db b/user_profile.db index 36960d4..9aa0302 100644 Binary files a/user_profile.db and b/user_profile.db differ