Spaces:
Sleeping
Sleeping
| /** | |
| * @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> | |
| ); | |
| } | |