Spaces:
Running
Running
/** | |
* @license | |
* SPDX-License-Identifier: Apache-2.0 | |
*/ | |
import React, { useState, ChangeEvent } from 'react'; | |
import type { InitialInput } from '../lib/types'; | |
import { getDocument, GlobalWorkerOptions } from 'pdfjs-dist'; | |
import mammoth from 'mammoth'; | |
// Set workerSrc for pdf.js. This is crucial for it to work. | |
GlobalWorkerOptions.workerSrc = 'pdfjs-dist/build/pdf.worker.min.js'; | |
interface InitialInputFormProps { | |
onSubmit: (formData: InitialInput) => void; | |
onClear: () => void; | |
disabled: boolean; | |
isLoading: boolean; | |
} | |
const initialFormState: InitialInput = { | |
fullName: '', | |
jobTitle: '', | |
careerGoal: '', | |
jobDescription: '', | |
uploadedResumeContent: '', | |
yearsOfExperience: '2-4 Years', | |
keySkills: '', | |
previousRoles: '', | |
education: '', | |
}; | |
export default function InitialInputForm({ onSubmit, onClear, disabled, isLoading }: InitialInputFormProps) { | |
const [formData, setFormData] = useState<InitialInput>(initialFormState); | |
const [selectedFileName, setSelectedFileName] = useState<string>(''); | |
const [fileError, setFileError] = useState<string | null>(null); | |
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => { | |
const { name, value } = e.target; | |
setFormData(prev => ({ ...prev, [name]: value })); | |
}; | |
const handleFileChange = async (e: ChangeEvent<HTMLInputElement>) => { | |
const file = e.target.files?.[0]; | |
setFileError(null); | |
setSelectedFileName(''); | |
setFormData(prev => ({ ...prev, uploadedResumeContent: '' })); | |
if (file) { | |
setSelectedFileName(file.name); | |
try { | |
let text = ''; | |
if (file.name.toLowerCase().endsWith('.txt')) { | |
text = await file.text(); | |
} else if (file.name.toLowerCase().endsWith('.pdf')) { | |
const arrayBuffer = await file.arrayBuffer(); | |
const pdf = await getDocument({ data: arrayBuffer }).promise; | |
let pdfText = ''; | |
for (let i = 1; i <= pdf.numPages; i++) { | |
const page = await pdf.getPage(i); | |
const textContent = await page.getTextContent(); | |
pdfText += textContent.items.map((item: any) => item.str).join(' ') + '\n'; | |
} | |
text = pdfText; | |
} else if (file.name.toLowerCase().endsWith('.docx')) { | |
const arrayBuffer = await file.arrayBuffer(); | |
const result = await mammoth.extractRawText({ arrayBuffer }); | |
text = result.value; | |
} else { | |
setFileError("Unsupported file type. Please use .txt, .pdf, or .docx."); | |
return; | |
} | |
setFormData(prev => ({ ...prev, uploadedResumeContent: text })); | |
} catch (error) { | |
setFileError(`Error processing file: ${error instanceof Error ? error.message : "Unknown error"}.`); | |
} | |
} | |
}; | |
const handleSubmit = (e: React.FormEvent) => { | |
e.preventDefault(); | |
if (fileError) { | |
alert(`Cannot submit: Please resolve the file error first. ${fileError}`); | |
return; | |
} | |
onSubmit(formData); | |
}; | |
const handleClear = () => { | |
setFormData(initialFormState); | |
setSelectedFileName(''); | |
setFileError(null); | |
const fileInput = document.getElementById('resumeUpload') as HTMLInputElement; | |
if (fileInput) fileInput.value = ''; | |
onClear(); | |
}; | |
return ( | |
<form onSubmit={handleSubmit} className="initial-input-form"> | |
<h2>Initial Setup</h2> | |
{/* Form groups for all inputs */} | |
<div className="form-group"> | |
<label htmlFor="fullName">Full Name</label> | |
<input type="text" id="fullName" name="fullName" value={formData.fullName} onChange={handleChange} placeholder="e.g., Jane Doe" required disabled={disabled}/> | |
</div> | |
<div className="form-group"> | |
<label htmlFor="jobTitle">Current or Target Job Title</label> | |
<input type="text" id="jobTitle" name="jobTitle" value={formData.jobTitle} onChange={handleChange} placeholder="e.g., Senior Software Engineer" required disabled={disabled}/> | |
</div> | |
<div className="form-group"> | |
<label htmlFor="jobDescription">Target Job Description (Crucial for Scoring)</label> | |
<textarea id="jobDescription" name="jobDescription" value={formData.jobDescription} onChange={handleChange} placeholder="Paste the job description here..." rows={6} disabled={disabled}/> | |
</div> | |
<div className="form-group"> | |
<label htmlFor="resumeUpload">Upload Existing Resume (Optional)</label> | |
<input type="file" id="resumeUpload" name="resumeUpload" accept=".txt,.pdf,.docx" onChange={handleFileChange} disabled={disabled}/> | |
<small className="form-text text-muted">{selectedFileName ? `Selected: ${selectedFileName}` : "Upload for richer context."}</small> | |
{fileError && <p role="alert" style={{color:'var(--color-error)',fontSize:'0.9em',marginTop:'0.5em'}}>{fileError}</p>} | |
</div> | |
<div className="form-group"> | |
<label htmlFor="keySkills">Key Skills (to supplement resume)</label> | |
<textarea id="keySkills" name="keySkills" value={formData.keySkills} onChange={handleChange} placeholder="List skills not detailed in your resume..." rows={3} disabled={disabled}/> | |
</div> | |
{/* Additional fields like careerGoal, yearsOfExperience etc. can be added here if needed */} | |
<div className="form-actions" style={{marginTop: '1.5rem', display: 'flex', gap: '1rem'}}> | |
<button type="submit" className={`submit-button ${isLoading ? 'is-loading' : ''}`} disabled={disabled}> | |
<span>{isLoading ? 'Generating...' : 'Generate Resume'}</span> | |
</button> | |
<button type="button" className="clear-button" onClick={handleClear} disabled={disabled}> | |
Clear All | |
</button> | |
</div> | |
</form> | |
); | |
} | |