import React, { useState } from 'react'; import { UserProfile } from '../types'; import { User, Mail, Phone, MapPin, FileText, Briefcase, Plus, Trash2, Save, CheckCircle2, Tag, Building2, GraduationCap, Sparkles, Cpu, Zap, RefreshCw, AlertCircle, Server } from 'lucide-react'; interface ProfileSettingsProps { userProfile: UserProfile; onSaveProfile: (profile: UserProfile) => Promise; } export const ProfileSettings: React.FC = ({ userProfile, onSaveProfile }) => { const [profile, setProfile] = useState(userProfile); const [skillInput, setSkillInput] = useState(''); const [isSaving, setIsSaving] = useState(false); const [savedSuccess, setSavedSuccess] = useState(false); // LM Studio Test state const [isTestingLLM, setIsTestingLLM] = useState(false); const [llmTestResult, setLlmTestResult] = useState<{ success: boolean; message: string } | null>(null); const llmConfig = profile.llmConfig || { primaryProvider: 'gemini', fallbackToLocal: true, lmStudioBaseUrl: 'http://localhost:1234/v1', lmStudioModel: 'local-model' }; const handleUpdateLLMConfig = (key: string, val: any) => { setProfile(prev => ({ ...prev, llmConfig: { ...llmConfig, [key]: val } })); }; const handleTestLocalLLM = async () => { setIsTestingLLM(true); setLlmTestResult(null); try { const res = await fetch('/api/llm/test-connection', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ baseUrl: llmConfig.lmStudioBaseUrl, modelName: llmConfig.lmStudioModel, apiKey: llmConfig.customApiKey }) }); const data = await res.json(); if (data.success) { setLlmTestResult({ success: true, message: data.message }); } else { setLlmTestResult({ success: false, message: data.error || 'Could not connect to Local LLM server.' }); } } catch (err: any) { setLlmTestResult({ success: false, message: `Connection error: ${err.message}` }); } finally { setIsTestingLLM(false); } }; const handleUpdateField = (key: keyof UserProfile, val: any) => { setProfile(prev => ({ ...prev, [key]: val })); }; const handleAddSkill = () => { if (!skillInput.trim()) return; const updated = [...profile.skills, skillInput.trim()]; handleUpdateField('skills', updated); setSkillInput(''); }; const handleRemoveSkill = (skill: string) => { const updated = profile.skills.filter(s => s !== skill); handleUpdateField('skills', updated); }; const [isParsingResume, setIsParsingResume] = useState(false); const [parseError, setParseError] = useState(null); const handleResumeFileUpload = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; setIsParsingResume(true); setParseError(null); try { let bodyData: any = { fileName: file.name, llmConfig: profile.llmConfig }; if (file.name.endsWith('.docx') || file.name.endsWith('.doc')) { const arrayBuffer = await file.arrayBuffer(); const base64 = btoa( new Uint8Array(arrayBuffer).reduce((data, byte) => data + String.fromCharCode(byte), '') ); bodyData.resumeBase64 = base64; } else { bodyData.resumeText = await file.text(); } const res = await fetch('/api/gemini/parse-resume', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(bodyData) }); const data = await res.json(); if (data.success && data.profile) { const parsed = data.profile; setProfile(prev => ({ ...prev, fullName: parsed.fullName || prev.fullName, email: parsed.email || prev.email, phone: parsed.phone || prev.phone, location: parsed.location || prev.location, linkedinUrl: parsed.linkedinUrl || prev.linkedinUrl, githubUrl: parsed.githubUrl || prev.githubUrl, portfolioUrl: parsed.portfolioUrl || prev.portfolioUrl, summary: parsed.summary || prev.summary, skills: Array.isArray(parsed.skills) && parsed.skills.length > 0 ? parsed.skills : prev.skills, experience: Array.isArray(parsed.experience) && parsed.experience.length > 0 ? parsed.experience : prev.experience, education: Array.isArray(parsed.education) && parsed.education.length > 0 ? parsed.education : prev.education })); } else { setParseError(data.error || 'Failed to parse resume content.'); } } catch (err: any) { setParseError(`Failed to read/parse file: ${err.message}`); } finally { setIsParsingResume(false); } }; const handleSave = async () => { setIsSaving(true); try { await onSaveProfile(profile); setSavedSuccess(true); setTimeout(() => setSavedSuccess(false), 3000); } catch (err) { console.error('Error saving profile:', err); } finally { setIsSaving(false); } }; return (
{/* Top Banner */}

Master Resume & Profile Configuration

This master profile serves as the foundational knowledge base that Gemini AI uses to tailor your resumes and cover letters for every application.

{parseError && (
{parseError}
)} {/* Main Profile Forms */}
{/* Personal Details */}

Personal Details

handleUpdateField('fullName', e.target.value)} className="w-full px-3 py-2 rounded-xl bg-slate-950 border border-slate-800 text-slate-200" />
handleUpdateField('email', e.target.value)} className="w-full px-3 py-2 rounded-xl bg-slate-950 border border-slate-800 text-slate-200" />
handleUpdateField('phone', e.target.value)} className="w-full px-3 py-2 rounded-xl bg-slate-950 border border-slate-800 text-slate-200" />
handleUpdateField('location', e.target.value)} className="w-full px-3 py-2 rounded-xl bg-slate-950 border border-slate-800 text-slate-200" />
handleUpdateField('linkedinUrl', e.target.value)} className="w-full px-3 py-2 rounded-xl bg-slate-950 border border-slate-800 text-slate-200" />
{/* Master Professional Summary & Technical Skills */}

Master Executive Summary