VETERAN CAREER BUILDER

Skip to main content
Career Path Tools — $15/mo My Account / Login Career Tools Job Match Analyzer Federal Resume Builder Interview Simulator LinkedIn Optimizer Salary Negotiator Certification Advisor DD-214 Decoder MOS Translator 🔴 Live Federal Jobs VCP PathFinder™ Pro Transition Planner PathFinder Lite (Free) 🎖️ MOS & Branch Guides Army MOS Careers Marine Corps MOS Navy Rate Careers Air Force AFSC Coast Guard Space Force 🏛️ Transition & Federal Transition Guide First 90 Days Guide Civilian Culture Guide TAP Guide ETS Checklist SkillBridge ASI/ASQ/NEC Guide Military Records Guide Emergency Assistance Homeless Assistance Forms Directory Veteran Discounts Soft Skills Guide USAJobs Guide Veterans' Preference Military → GS Pay GS Grade Estimator Top 100 Employers 💼 Career Pathways Cybersecurity Healthcare Law Enforcement Gov Contracting Project Management Freelancing & Remote Trade Schools Apprenticeships Entrepreneurship Cleared Jobs Intelligence Data Analytics Aviation Construction Mgmt Emergency Mgmt Energy Financial Services Human Resources Manufacturing Supply Chain 🧮 Calculators PCS / DITY Calculator Reenlist vs Separate Retirement Pay VA Disability Calc GI Bill BAH GI Bill vs VR&E 🏥 VA Benefits & Claims Disability Rating Schedule Disability Guide Claims Appeal Guide C&P Exam Guide PACT Act / Presumptive Secondary Conditions Aid & Attendance Community Care (MISSION Act) VA Home Loan CHAMPVA TRICARE VR&E Chapter 31 Mental Health Caregiver Support Substance Abuse Resources Burial & Death Benefits VA Debt & Overpayment Veteran Tax Guide Blended Retirement TSP Guide 📝 Blog & Resources Blog — All Articles 68W Careers Guide 11B Careers Guide Resources Directory Success Stories Contact 🗺️ State Benefits All 50 States Guide Alabama Alaska Arizona Arkansas California Colorado Connecticut Delaware Florida Georgia Hawaii Idaho Illinois Indiana Iowa Kansas Kentucky Louisiana Maine Maryland Massachusetts Michigan Minnesota Mississippi Missouri Montana Nebraska Nevada New Hampshire New Jersey New Mexico New York North Carolina North Dakota Ohio Oklahoma Oregon Pennsylvania Rhode Island South Carolina South Dakota Tennessee Texas Utah Vermont Virginia Washington Washington DC West Virginia Wisconsin Wyoming

Admin Setup

Enter your Anthropic API key to enable AI features.
Get one free at console.anthropic.com

");win.document.close();}}>🖨 Print ); } function CareerDetailView(props) { const {selectedCareer,setSelectedCareer,careerDetail,loading,currentUser,setShowAuth,showToast,tab,setTab,target,targetLocation,upT,DI} = props; if (!selectedCareer||loading.careers) return null; return (
{selectedCareer.sector==="Government"?"🏛️":selectedCareer.sector===DI?"🛡️":"💼"}

{selectedCareer.title}

{selectedCareer.match} Match {selectedCareer.clearanceBonus&&🔐 Clearance Advantage}
{selectedCareer.sector} · {selectedCareer.industry||"Multiple Industries"}
{selectedCareer.salaryRange}
{selectedCareer.outlook==="High Growth"?"📈":selectedCareer.outlook==="Emerging"?"🔄":"📊"} {selectedCareer.outlook}
{loading.careerDetail&&
Loading full career profile...
} {careerDetail&&!loading.careerDetail&&( )}
); } function CareerTab(props) { const {careers,careerFilter,setCareerFilter,selectedCareer,setSelectedCareer,careerDetail,loading,careerError,openCareerDetail,findCareers,tab,setTab,target,upT,targetLocation,milExperiences,civExperiences,education,currentUser,showToast,setShowAuth,DI,RG,filterCareers,matchesSector,hasAccess,setShowPaywall,skills,personal} = props; if (tab!==1) return null; return (
Your Civilian Qualifications Profile. Before finding your career matches, review what your service actually unlocks in the civilian world. Every MOS, clearance, ASI, SQI, and additional duty is an asset — here's what each one means to a civilian employer.
{milExperiences.map(exp=>(

{window.BRANCH_LOGOS&&window.BRANCH_LOGOS[exp.branch] ? React.createElement("img",{src:window.BRANCH_LOGOS[exp.branch],alt:exp.branch,width:32,height:32,style:{borderRadius:"50%",flexShrink:0},onError:function(e){e.target.style.display="none";}}) : "🎖️" } {exp.branch} {exp.rank ? "— "+exp.rank : ""}

{exp.serviceType}{exp.tos ? " · "+exp.tos : ""}
{exp.mos||"—"} {exp.mosTitle&&{exp.mosTitle}} {exp.unit&&· {exp.unit}}
{exp.tos&&⏱ {exp.tos} Time in Service} {exp.startDate&&📅 {exp.startDate} – {exp.current?"Present":exp.endDate||"?"}}
{/* ── CIVILIAN TRANSLATION BOX ── */}
🔄
Your Military Experience → Civilian Translation
{exp.mos ? (<>
In civilian terms, you were: { (function(){ var r = exp.rank || ""; var isNCO = r.indexOf("E-5")!==-1||r.indexOf("E-6")!==-1||r.indexOf("E-7")!==-1||r.indexOf("E-8")!==-1||r.indexOf("E-9")!==-1; var isSrNCO = r.indexOf("E-7")!==-1||r.indexOf("E-8")!==-1||r.indexOf("E-9")!==-1; var isOfficer = r.indexOf("O-")!==-1||r.indexOf("W-")!==-1; var title = exp.mosTitle || exp.mos; if(isOfficer) return "A department director or senior program manager leading " + (exp._unitSize||"multiple teams of") + " personnel, responsible for strategic planning, resource allocation, and mission execution in a " + (exp.branch||"military") + " " + title + " organization."; if(isSrNCO) return "A senior operations manager supervising " + (exp._leaderCount||"multiple") + " direct reports and " + (exp._unitSize||"a team of") + " personnel, with full accountability for training, performance, equipment worth " + (exp._equipValue||"significant assets") + ", and day-to-day execution of " + title + " operations."; if(isNCO) return "A team lead / front-line supervisor managing " + (exp._leaderCount||"a team of") + " personnel, responsible for training, task execution, quality control, and operational readiness in " + title + " operations."; return "A trained specialist in " + title + " operations with hands-on experience in mission execution, technical procedures, teamwork, and accountability under pressure."; })() }
{exp.duties && (
What companies see when they read your background: { (exp.duties||"").replace(/led/gi,"managed").replace(/soldiers|Marines|sailors|airmen|service members/gi,"team members").replace(/platoon/gi,"division").replace(/squad/gi,"team").replace(/company/gi,"department").replace(/battalion/gi,"organization").replace(/mission/gi,"project").replace(/field exercise/gi,"operational exercise").replace(/PT\b/g,"fitness training").replace(/NCOIC/gi,"supervisor").replace(/OIC/gi,"manager").replace(/COP|FOB|base/gi,"facility").substring(0,300) + (exp.duties.length>300?"...":"") }
)} {(exp._leaderCount || exp._unitSize || exp._equipValue || exp._trainedCount) && (
{exp._leaderCount && Led {exp._leaderCount} personnel} {exp._unitSize && {exp._unitSize}-person organization} {exp._equipValue && {exp._equipValue} in assets} {exp._trainedCount && Trained {exp._trainedCount} personnel}
)} ) : (
Enter your MOS code on the Profile tab to see your civilian translation.
)}

🔐 Security Clearance
{exp.clearanceLevel==="None" ?
No clearance listed. Many civilian roles don't require one — your skills still transfer.
:
{exp.clearanceLevel} {exp.clearanceStatus} {exp.polygraph!=="None"&&{exp.polygraph}}
{exp.clearanceLevel.includes("SCI")||exp.clearanceLevel.includes("Poly") ? "🏆 Premium Asset: TS/SCI clearances unlock high-paying roles in intelligence agencies (CIA, NSA, DIA), defense contractors (Booz Allen, SAIC, Leidos), and federal IT. Cleared professionals command 10–30% salary premiums. Your clearance alone can be worth $20,000–$50,000 more per year." : exp.clearanceLevel==="Top Secret" ? "⭐ High Value: Top Secret clearance opens doors to defense contracting, federal law enforcement, DHS, and government IT roles. Actively sought by employers — investigation costs $50,000+ to initiate." : exp.clearanceLevel==="Secret" ? "✅ Solid Asset: Secret clearance qualifies you for thousands of defense, federal, and contractor positions. Most DoD contractor roles require this as a baseline." : "✅ Clearance noted. Even Confidential/Public Trust clearances help with federal and contractor employment."}
}
{exp.asi.length>0&&(<>
Additional Skill Identifiers (ASI) — What They Unlock
{exp.asi.map(a=>(
{a.code}
{a.desc}
{a.code==="2S"||a.code==="R" ? "Ranger qualification signals elite physical conditioning, leadership under extreme stress, and small-unit tactics mastery. Highly valued in law enforcement special units, federal agencies, private security, and defense contracting." : a.code==="8A" ? "Airborne qualification demonstrates ability to operate in austere environments and adapt to rapidly changing conditions. Valued in emergency management, aviation, and special operations support roles." : a.code==="B3" ? "Linguist qualification is a premium asset in intelligence, federal law enforcement (FBI/CIA/DEA), international business, diplomacy, and translation services." : a.code==="P1" ? "Master Parachutist with 65+ jumps signals elite special operations background, exceptional risk management, and advanced military training. Top-tier for SOF support, government contracting, and security consulting." : a.code==="X3" ? "Military Instructor qualification translates directly to corporate training, learning & development roles, academic instruction, and leadership coaching — all high-demand civilian fields." : a.code==="G4" ? "Combatives instructor certification demonstrates advanced physical training expertise. Directly applicable to law enforcement training, personal protection, and defense sector roles." : a.code==="V5" ? "Battle Staff qualification means you've planned and coordinated complex multi-element operations. This maps directly to senior project management, operations director, and strategic planning roles." : a.code==="W1" ? "SERE training signals resilience, high-stress decision-making, and classified operations knowledge — valuable in intelligence, security, and government contracting." : (a.desc)+" represents specialized military training that differentiates you from typical civilian applicants. Highlight this on your resume and in interviews."}
))}
)} {exp.sqi.length>0&&(<>
Skill Qualification Identifiers (SQI) — What They Unlock
{exp.sqi.map(s=>(
{s.code}
{s.desc}
{s.code==="F"||s.code==="Q" ? "Special Forces background is among the most valued military credentials in civilian employment. Opens doors to intelligence agencies, Tier 1 defense contractors, private military consulting, federal law enforcement leadership, and executive protection. Salary premiums of 20–40% are common." : s.code==="R" ? "Ranger-tabbed service members are highly sought in law enforcement, federal agencies, and security consulting for their demonstrated leadership, physical toughness, and tactical expertise." : s.code==="P" ? "Parachutist qualification demonstrates willingness to operate in high-risk environments and comfort with complex technical procedures — valued in aviation, emergency services, and government contracting." : s.code==="X" ? "Instructor/Faculty SQI means you've been certified to teach and develop others in the military's most rigorous training environment. This maps directly to corporate L&D, technical training, academic instruction, and coaching careers." : s.code==="V" ? "Aviation background unlocks commercial aviation, drone operations, air traffic control, aviation management, and aerospace industry roles." : s.code==="S" ? "Special Operations support experience is premium in defense contracting, intelligence support, and government program management." : (s.desc)+" SQI represents a specialized role that distinguishes you from standard applicants. Leverage this credential prominently."}
))}
)} {exp.additionalDuties.length>0&&(<>
Additional Duty Qualifications — Civilian Value
{exp.additionalDuties.map(d=>(
{d}
{d.includes("Armorer") ? "Maps to: Firearms compliance, asset management, inventory control" : d.includes("Safety") ? "Maps to: EHS Officer, Workplace Safety Manager, OSHA compliance" : d.includes("SHARP")||d.includes("Equal Opportunity") ? "Maps to: HR Business Partner, DEI Coordinator, Employee Relations" : d.includes("COR")||d.includes("Contracting") ? "Maps to: Procurement Specialist, Contract Manager, Acquisition Analyst" : d.includes("OPSEC")||d.includes("Information Security") ? "Maps to: Information Security Analyst, Cybersecurity, Risk Management" : d.includes("UPL")||d.includes("Prevention") ? "Maps to: Employee Assistance Programs, HR Compliance, Wellness Coordinator" : d.includes("Training Room")||d.includes("Records") ? "Maps to: HR Specialist, Records Manager, Compliance Officer" : d.includes("Property Book")||d.includes("Supply") ? "Maps to: Logistics Coordinator, Asset Manager, Supply Chain Analyst" : d.includes("Master Driver") ? "Maps to: Fleet Manager, Transportation Supervisor, Logistics Lead" : d.includes("Battle Staff")||d.includes("Master Gunner") ? "Maps to: Operations Manager, Senior Project Lead, Strategic Planner" : d.includes("Recruiter")||d.includes("Career Counselor") ? "Maps to: Talent Acquisition, HR Recruiter, Career Coach" : d.includes("Family Readiness") ? "Maps to: Community Liaison, Employee Engagement, HR Programs" : d.includes("NBC")||d.includes("CBRN") ? "Maps to: Hazmat Specialist, Environmental Health & Safety, Emergency Management" : "Maps to: Program management, compliance, and organizational leadership roles"}
))}
)} {(exp.deployments||exp.awards)&&(<>
{exp.deployments&&
Combat / Operational Experience
{exp.deployments}
Demonstrates: adaptability, crisis leadership, cross-cultural operations, mission execution under pressure
} {(exp.awards||[]).length>0&&
Awards & Decorations
{exp.awards}
Demonstrates: recognized performance, leadership, valor, and professional excellence
}
)}
))} {civExperiences.map(exp=>(

💼 {exp.type}

{exp.jobTitle||""}{exp.employer?" · "+exp.employer:""}
{exp.startDate&&📅 {exp.startDate} – {exp.current?"Present":exp.endDate||"?"}} {exp.clearanceLevel!=="None"&&{exp.clearanceLevel} — {exp.clearanceStatus}}
{exp.duties&&
"{exp.duties.slice(0,180)}{exp.duties.length>180?"...":""}"
} {exp.type===RG&&
⭐ Dual-career advantage: Simultaneously maintaining civilian employment and military service demonstrates exceptional time management, discipline, and commitment — a top-tier signal to civilian employers.
}
))}

Refine Your Target (optional)

upT("title",e.target.value)}/>
upT("industry",e.target.value)}/>
upT("keywords",e.target.value)}/>
setTargetLocation(e.target.value)} onKeyUp={e=>setTargetLocation(e.target.value)} style={{width:"100%"}} /> Used to filter job search results by location
upT("interests",e.target.value)}/> Help us find careers matching your passions — not just your MOS
{["Entrepreneurship","Government / Federal","Defense / Intel","Tech / Cybersecurity","Trades / Skilled Labor","Healthcare","Law Enforcement","Education / Coaching","Nonprofit / Veteran Services","Remote Work","Part-time / Flexible"].map(opt=>( ))}
Click to select — expands career matches beyond your MOS
{hasAccess?( ):( )} {loading.careers&&
Analyzing your qualifications and finding career matches...
} {careerError&&!loading.careers&&(
Career match error: {careerError}
)} {careers&&!loading.careers&&!selectedCareer&&()} {selectedCareer&&!loading.careers&&()}
); } function RankInsignia({branch,grade,color}) { const c = color||"#c8a951"; const g = grade||""; if (g.startsWith("E-")) { const n = parseInt(g.slice(2))||1; const chevs = n<=3?n:n<=6?3:n<=8?3:3; const rockers = n>=7?n-6:0; const hasDiamond = n===8; const stars = n>=9?n-8:0; const h = 36; const paths = []; for(let ci=0;ciReact.createElement("rect",{key:bi,x:2+(bi*7),y:8,width:5,height:14,rx:1,fill:bi%2===0?c:"rgba(255,255,255,.2)"})); return React.createElement("svg",{viewBox:"0 0 36 24",width:32,height:24,style:{flexShrink:0}}, React.createElement("rect",{x:2,y:18,width:32,height:4,rx:1,fill:c}),...bars); } if (g.startsWith("O-")) { const n = parseInt(g.slice(2))||1; if(n===1) return React.createElement("svg",{viewBox:"0 0 36 14",width:32,height:14,style:{flexShrink:0}},React.createElement("rect",{x:4,y:3,width:28,height:8,rx:2,fill:c})); if(n===2) return React.createElement("svg",{viewBox:"0 0 36 14",width:32,height:14,style:{flexShrink:0}},React.createElement("rect",{x:4,y:3,width:28,height:8,rx:2,fill:"#d8d8d8"})); if(n===3) return React.createElement("svg",{viewBox:"0 0 36 14",width:32,height:14,style:{flexShrink:0}},React.createElement("rect",{x:2,y:3,width:13,height:8,rx:2,fill:"#d8d8d8"}),React.createElement("rect",{x:21,y:3,width:13,height:8,rx:2,fill:"#d8d8d8"})); if(n<=5) return React.createElement("svg",{viewBox:"0 0 36 20",width:32,height:20,style:{flexShrink:0}},React.createElement("path",{d:"M18,2 C11,2 5,7 5,13 C5,17 8,19 12,18 L18,22 L24,18 C28,19 31,17 31,13 C31,7 25,2 18,2Z",fill:n===4?c:"#d8d8d8"})); if(n===6) return React.createElement("svg",{viewBox:"0 0 36 22",width:32,height:22,style:{flexShrink:0}},React.createElement("ellipse",{cx:18,cy:14,rx:5,ry:4,fill:c}),React.createElement("path",{d:"M4,12 L18,5 L32,12",fill:"none",stroke:c,strokeWidth:2.5}),React.createElement("polygon",{points:"18,2 20,7 18,6 16,7",fill:c})); const ns = n-6; const sp = [{x:18,y:11},{x:10,y:16},{x:26,y:16},{x:8,y:8},{x:28,y:8}].slice(0,ns); return React.createElement("svg",{viewBox:"0 0 36 22",width:32,height:22,style:{flexShrink:0}},...sp.map((p,si)=>React.createElement("text",{key:si,x:p.x,y:p.y,textAnchor:"middle",fontSize:11,fill:c},"★"))); } if (window.BRANCH_LOGOS && window.BRANCH_LOGOS[branch]) { return React.createElement("img",{src:window.BRANCH_LOGOS[branch],alt:branch,width:44,height:44,style:{borderRadius:"50%",verticalAlign:"middle",display:"block"},onError:function(e){e.target.style.display="none";}}); } return React.createElement("span",{style:{fontSize:"1.2rem"}},BRANCH_EMBLEMS[branch]||"⭐"); } function MyProfileHero(props) { const {tab,currentUser,personal,hasAccess,hasUnsaved,milExperiences,BRANCH_EMBLEMS,BRANCH_COLORS,RANKS,RankInsignia,careers,openCareerDetail,setTab,resume,savedResumes,handleDeleteResume,savedCoverLetters,savedEmails,savedScores,handleDeleteSaved,handleLogout,handleSaveProfile,showToast,setShowPaywall,savedPaths,setSavedPaths} = props; return (<>
{personal.name||(currentUser&¤tUser.name)||"Veteran"}
{personal.email||(currentUser&¤tUser.email)||""}
Service Record
{milExperiences.filter(e=>e.branch).map((exp,ri)=>{ const bRanks = RANKS[exp.branch]||RANKS["Army"]; const allR = [...(bRanks.enlisted||[]),...(bRanks.warrant||[]),...(bRanks.officer||[])]; const rankObj = allR.find(r=>r.abbr===exp.rank)||null; const bColor = BRANCH_COLORS[exp.branch]||BRANCH_COLORS["Army"]; return (
{window.BRANCH_LOGOS&&window.BRANCH_LOGOS[exp.branch] ?React.createElement("img",{src:window.BRANCH_LOGOS&&window.BRANCH_LOGOS[exp.branch],alt:exp.branch,width:24,height:24,style:{borderRadius:"50%",flexShrink:0},onError:function(e){e.target.style.display="none";}}) :null} {exp.branch}
Status:{exp.serviceType||"—"}
{exp.rank&&
Rank:{exp.rank}{rankObj?" — "+rankObj.title:""}
} {(exp.startDate||exp.endDate)&&
Served:{exp.startDate||"?"} – {exp.currently?"Present":(exp.endDate||"?")}
} {exp.tos&&
{exp.tos} total
}
); })} {milExperiences.filter(e=>e.branch).length===0&&(
Add service history in Profile & Qualifications to see your record here.
)}
{careers&&careers.length>0&&(

Your Career Matches

{careers.length} matches · click any to explore
{careers.map((c,ci)=>(
{setTab(1);setTimeout(()=>openCareerDetail(c),100);}}>
{c.title}
{c.match}
{c.industry}
{c.salaryRange}
))}
)} ); } function MyProfileSaved(props) { const {tab,hasAccess,setTab,resume,savedResumes,handleDeleteResume,savedCoverLetters,savedEmails,savedScores,handleDeleteSaved,handleLogout,handleSaveProfile,handleSaveResume,showToast,setShowPaywall,savedPaths,setSavedPaths} = props; // Fallback for handleSaveResume const _hsr = handleSaveResume || window.__vcp_saveResume || (()=>{}); return (<>

Saved Resumes

{resume&&}
{savedResumes.length===0?(
📄
No saved resumes yet. Generate one on the Build Resume tab.
):( savedResumes.map(r=>(
{r.title}
{r.title||r.job||"Saved Resume"}
{r.date}{r.industry?" · "+r.industry:""}
)) )}

📝 Saved Cover Letters

{savedCoverLetters.length} saved
{savedCoverLetters.length===0?(
No saved cover letters yet. Generate one on the Cover Letter tab.
):( savedCoverLetters.map(r=>(
{r.job}{r.company?" @ "+r.company:""}
{r.date}
)) )}

✉️ Saved Emails

{savedEmails.length} saved
{savedEmails.length===0?(
No saved emails yet. Generate follow-up emails on the Job Search tab.
):( savedEmails.map(r=>(
{r.type}
{r.date}
)) )}

📊 Saved Score Reports

{savedScores.length} saved
{savedScores.length===0?(
No saved scores yet. Score your resume on the Cover Letter & Review tab.
):( savedScores.map(r=>(
=80?"#1a7a40":r.score>=65?"#e67e22":"#c0392b"}}>{r.score} {r.label}
{r.date}
)) )}

Quick Links

{[ {label:"Profile & Qualifications",icon:"📋",tab:0}, {label:"Career Pathways",icon:"🎯",tab:1}, {label:"Build Resume",icon:"📄",tab:2}, {label:"Cover Letter & Review",icon:"📝",tab:3}, {label:"Job Search Tools",icon:"🔍",tab:4}, {label:"Resources Hub",icon:"🏛️",tab:6} ].map((link,i)=>( ))}

Account & Subscription

{hasAccess?(
Full Access Active {(()=>{try{const d=JSON.parse(localStorage.getItem("vcb_access")||"null");if(d&&d.expiry)return React.createElement("span",{style:{fontSize:".75rem",color:"#5a7090",fontWeight:400}}," — expires "+new Date(d.expiry).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"}));if(d&&d.type==="code")return React.createElement("span",{style:{fontSize:".75rem",color:"#5a7090",fontWeight:400}}," — Access Code");return null;}catch(e){return null;}})()}
):(
No active subscription
Unlock all 16 AI-powered career tools
)}

🧭 Saved Assessment Results

Career Assessments
{(()=>{ let assessmentResult = null; try { assessmentResult = JSON.parse(localStorage.getItem("vcb_assessment_result")||"null"); } catch(e){} if (!assessmentResult) { return (
🧭
No saved assessment results yet.
); } return (
{assessmentResult.type||"Career Assessment"}
{assessmentResult.date ? new Date(assessmentResult.date).toLocaleDateString() : "Date unknown"}
{(assessmentResult.topCareers||assessmentResult.results||[]).length>0&&(
Top Career Matches
{(assessmentResult.topCareers||assessmentResult.results||[]).slice(0,6).map((c,i)=>(
{typeof c==="string"?c:(c.title||c.name||"Career "+(i+1))}
{c.match&&
{c.match}% Match
} {c.sector&&
{c.sector}
}
))}
)} {assessmentResult.summary&&(
{assessmentResult.summary}
)}
); })()}

⭐ Saved Career Paths

{(savedPaths||[]).length} saved
{(!savedPaths||savedPaths.length===0)?(
🎯
No saved career paths yet. Go to Career Pathways and click 💾 Save Path on any career.
):(
{(savedPaths||[]).map((p,i)=>(
{p.title}
{p.sector&&
{p.sector}{p.industry?" · "+p.industry:""}
} {p.salaryRange&&
{p.salaryRange}
} {p.match&&{p.match} Match} {p.whyFit&&
{p.whyFit}
}
))}
)}
); } function MyProfileContent(props) { const {tab,currentUser,personal,hasAccess,hasUnsaved,milExperiences,BRANCH_EMBLEMS,BRANCH_COLORS,RANKS,RankInsignia,careers,openCareerDetail,setTab,resume,savedResumes,handleDeleteResume,savedCoverLetters,savedEmails,savedScores,handleDeleteSaved,handleLogout,handleSaveProfile,handleSaveResume,showToast,setShowPaywall,savedPaths,setSavedPaths} = props; // Fallback: if handleSaveResume wasn't passed as prop, use window version const _handleSaveResume = handleSaveResume || window.__vcp_saveResume || (()=>{}); return (
); } function MyProfileTab(props) { const {tab,currentUser,setShowAuth,personal,hasAccess,hasUnsaved,milExperiences,BRANCH_EMBLEMS,BRANCH_COLORS,RANKS,RankInsignia,careers,openCareerDetail,setTab,resume,savedResumes,handleDeleteResume,savedCoverLetters,savedEmails,savedScores,handleDeleteSaved,handleLogout,handleSaveProfile,handleSaveResume,showToast,setShowPaywall,savedPaths,setSavedPaths} = props; if (tab!==5) return null; return (
); } function App() { // ── APP STATE (must be declared first) ── const [tab, setTab] = useState(0); const [personal, setPersonal] = useState({ name:"", email:"", phone:"", location:"", linkedin:"" }); const [milExperiences, setMilExperiences] = useState([newMilExp()]); const [civExperiences, setCivExperiences] = useState([]); // Keep a unified "experiences" for backwards compatibility with AI prompts const experiences = [...milExperiences, ...civExperiences]; const [education, setEducation] = useState([{ id:1, institution:"", degree:"", field:"", year:"", pme:"" }]); const [skills, setSkills] = useState({ technical:"", leadership:"", languages:"", certs:"" }); const [target, setTarget] = useState({ title:"", industry:"", keywords:"", interests:"", openTo:"" }); const [targetLocation, setTargetLocation] = useState(""); const [collapsed, setCollapsed] = useState({}); const [mosOut, setMosOut] = useState(""); const [careers, setCareers] = useState(null); const [serviceRecords, setServiceRecords] = useState([{ id:1, branch:"Army", rank:"", status:"Veteran" }]); const [coverLetter, setCoverLetter] = useState(""); const [coverLetterJob, setCoverLetterJob] = useState({ title:"", company:"", description:"" }); const [resumeScore, setResumeScore] = useState(null); const [resumeReview, setResumeReview] = useState(null); const [coverLetterLoading, setCoverLetterLoading] = useState(false); const [reviewLoading, setReviewLoading] = useState(false); const [uploadedResumeText, setUploadedResumeText] = useState(""); const [uploadedFileName, setUploadedFileName] = useState(""); const [uploadProcessing, setUploadProcessing] = useState(false); const [copiedCL, setCopiedCL] = useState(false); // ── RETENTION FEATURE STATE ─────────────────────────────────────────────── // Job Tracker const [jobApps, setJobApps] = useState(() => { try { return JSON.parse(localStorage.getItem("vcb_jobs")||"[]"); } catch(e){ return []; } }); const [newJob, setNewJob] = useState({ company:"", title:"", date:"", status:"Applied", notes:"", link:"",source:"" }); const [showAddJob, setShowAddJob] = useState(false); const saveJobs = (jobs) => { setJobApps(jobs); localStorage.setItem("vcb_jobs", JSON.stringify(jobs)); }; // Interview Prep const [prepJob, setPrepJob] = useState({ title:"", company:"", type:"behavioral" }); const [prepQuestions, setPrepQuestions] = useState([]); const [prepLoading, setPrepLoading] = useState(false); // Follow-up Email const [followupCtx, setFollowupCtx] = useState({ company:"", role:"", interviewerName:"", date:"", outcome:"thank-you" }); const [followupEmail, setFollowupEmail] = useState(""); const [followupJob, setFollowupJob] = useState({title:"",company:""}); const [showClipboardModal, setShowClipboardModal] = useState(false); const [showHomelessForm, setShowHomelessForm] = useState(false); const [homelessForm, setHomelessForm] = useState({name:"",branch:"",location:"",situation:"",email:"",phone:""}); const [homelessSubmitted, setHomelessSubmitted] = useState(false); const [clipboardParsed, setClipboardParsed] = useState({title:"",company:"",link:""}); const [followupLoading, setFollowupLoading] = useState(false); const [copiedFollowup, setCopiedFollowup] = useState(false); // Transition Timeline const [tlChecks, setTlChecks] = useState(() => { try { return JSON.parse(localStorage.getItem("vcb_timeline")||"{}"); } catch(e){ return {}; } }); const saveTl = (key, val) => { const updated = {...tlChecks, [key]: val}; setTlChecks(updated); localStorage.setItem("vcb_timeline", JSON.stringify(updated)); if (currentUser && fbDb) { try { fbDb.collection("profiles").doc((currentUser&¤tUser.uid)).set({ timeline: updated, updatedAt: Date.now() }, { merge: true }); } catch(e) {} } }; // Dashboard tab sub-view const [retentionTab, setRetentionTab] = useState("tracker"); const [savedPaths, setSavedPaths] = useState(() => { try { return JSON.parse(localStorage.getItem("vcb_saved_paths")||"[]"); } catch(e){ return []; } }); const refreshSavedPaths = () => { try { setSavedPaths(JSON.parse(localStorage.getItem("vcb_saved_paths")||"[]")); } catch(e){} }; const [resFilter, setResFilter] = useState("All"); const [selectedCareer, setSelectedCareer] = useState(null); const [careerDetail, setCareerDetail] = useState(null); const [careerFilter, setCareerFilter] = useState("All"); const [resume, setResume] = useState(""); const [resumeFormat, setResumeFormat] = useState("ats_chrono"); const [translationData, setTranslationData] = useState(null); const [loading, setLoading] = useState({ translate:false, careers:false, resume:false, careerDetail:false }); const [apiError, setApiError] = useState(""); const [showAdminSetup, setShowAdminSetup] = useState(false); const [adminKeyInput, setAdminKeyInput] = useState(""); const [adminKeySet, setAdminKeySet] = useState(() => { if (PROXY_URL && PROXY_URL.length > 10) return true; const k = localStorage.getItem("vcb_admin_key")||(typeof sessionStorage!=="undefined"&&sessionStorage.getItem("vcb_admin_key"))||""; return k.length > 20; }); const [careerError, setCareerError] = useState(""); const [resumeData, setResumeData] = useState(null); const [resumeTemplate, setResumeTemplate] = useState("ats_chrono"); const [profileMode, setProfileMode] = useState("guided"); const [resumeVisualStyle, setResumeVisualStyle] = useState("classic"); const VISUAL_STYLES = { classic: { name:"Classic", accent:"#000000", accent2:"#333333", headerBg:"#ffffff", headerText:"#000000", font:"Georgia,Times New Roman,serif", sectionBorder:"2px solid #000", preview:"#000" }, navy: { name:"Navy Professional", accent:"#1a3a6b", accent2:"#c8960a", headerBg:"#1a3a6b", headerText:"#ffffff", font:"Arial,Helvetica,sans-serif", sectionBorder:"2px solid #1a3a6b", preview:"#1a3a6b" }, slate: { name:"Slate Modern", accent:"#475569", accent2:"#0ea5e9", headerBg:"#f8fafc", headerText:"#0f172a", font:"Calibri,Segoe UI,sans-serif", sectionBorder:"1px solid #cbd5e1", preview:"#475569" }, amber: { name:"Warm Amber", accent:"#92400e", accent2:"#d97706", headerBg:"#fffbeb", headerText:"#78350f", font:"Cambria,Georgia,serif", sectionBorder:"2px solid #d97706", preview:"#92400e" }, midnight: { name:"Midnight", accent:"#1e293b", accent2:"#6366f1", headerBg:"#1e293b", headerText:"#f8fafc", font:"Inter,Helvetica Neue,sans-serif", sectionBorder:"2px solid #6366f1", preview:"#1e293b" } }; const vs = VISUAL_STYLES[resumeVisualStyle] || VISUAL_STYLES.classic; const [resumeError, setResumeError] = useState(""); const [copied, setCopied] = useState(false); const [includeClearance, setIncludeClearance] = useState(true); // ── RESUME SECTIONS CHECKLIST ── const [resumeSections, setResumeSections] = useState({ summary: true, military: true, civilian: true, education: true, certifications: true, clearance: true, awards: true, volunteer: false, technicalSkills: true, languages: false }); const toggleResumeSection = (key) => setResumeSections(prev => ({...prev, [key]: !prev[key]})); // ── RESUME TARGET ENHANCEMENTS ── const [targetCompany, setTargetCompany] = useState(""); const [experienceLevel, setExperienceLevel] = useState("mid"); const [jobDescription, setJobDescription] = useState(""); // ── ATS ANALYSIS STATE ── const [atsAnalysis, setAtsAnalysis] = useState(null); const [atsLoading, setAtsLoading] = useState(false); // ── JOB URL ANALYZER STATE ── const [jobAnalyzerUrl, setJobAnalyzerUrl] = useState(""); const [jobAnalyzerResult, setJobAnalyzerResult] = useState(null); const [jobAnalyzerLoading, setJobAnalyzerLoading] = useState(false); // ── AUTH STATE ── const [authMode, setAuthMode] = useState("login"); const [showAuth, setShowAuth] = useState(false); const [authForm, setAuthForm] = useState({ username:"", password:"", confirmPassword:"", name:"" }); const [authErr, setAuthErr] = useState(""); const [authOk, setAuthOk] = useState(""); const [currentUser, setCurrentUser] = useState(null); const [saveToast, setSaveToast] = useState(""); const [hasUnsaved, setHasUnsaved] = useState(false); const [savedResumes, setSavedResumes] = useState([]); const [savedCoverLetters, setSavedCoverLetters] = useState([]); const [savedEmails, setSavedEmails] = useState([]); const [savedScores, setSavedScores] = useState([]); const [viewingResume, setViewingResume] = useState(null); // ── PAYWALL STATE ───────────────────────────────────────────────────────── // ── ACCESS CODE SYSTEM ────────────────────────────────────────────────────── // Format: CODE -> expiry timestamp (ms). 0 = never expires. // Add new codes here. Date.UTC(year, month-1, day) for expiry. // ACCESS_CODES, isCodeValid, checkAccess defined at module level (see below component) // They are referenced here as module-level vars so useState initializer can call them const [hasAccess, setHasAccess] = useState(() => checkAccess()); const [showPaywall, setShowPaywall] = useState(false); const [pwPlan, setPwPlan] = useState("monthly"); const [pwCode, setPwCode] = useState(""); const [pwCodeStatus, setPwCodeStatus] = useState("idle"); const [pwCodeMsg, setPwCodeMsg] = useState(""); const redeemCode = () => { const code = pwCode.trim().toUpperCase(); const check = isCodeValid(code); // calls module-level function if (check.valid) { localStorage.setItem("vcb_access", JSON.stringify({ type:"code", code })); // Persist code to Firestore for cross-session access try { if (window.fbAuth && window.fbDb) { const u = window.fbAuth.currentUser; if (u) { window.fbDb.collection("profiles").doc(u.uid).set( { accessCode: code, updatedAt: Date.now() }, { merge: true } ); } } } catch(e) {} const expMsg = check.reason === "permanent" ? "✓ Code accepted! You have permanent access." : "✓ Code accepted! Access expires " + new Date(check.expiry).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"}) + "."; setPwCodeStatus("valid"); setPwCodeMsg(expMsg); setTimeout(() => { setHasAccess(true); setShowPaywall(false); }, 900); } else if (check.reason === "expired") { setPwCodeStatus("invalid"); setPwCodeMsg("This code has expired. Please subscribe or contact support for a new code."); } else { setPwCodeStatus("invalid"); setPwCodeMsg("That code isn't valid. Check spelling or contact support."); } }; const grantPaidAccess = (planMonths) => { const expiry = Date.now() + planMonths * 30 * 24 * 60 * 60 * 1000; localStorage.setItem("vcb_access", JSON.stringify({ type:"paid", stripeSession:"direct", expiry, plan: planMonths===1?"monthly":"annual" })); setHasAccess(true); setShowPaywall(false); }; // Access validation handled in checkAccess() // ── FIREBASE STORAGE HELPERS ──────────────────────────────────────────────── const openClipboardCapture = async () => { let text = ""; try { text = await navigator.clipboard.readText(); } catch(e) { // Clipboard permission denied - open with empty fields } // Try to parse job info from clipboard text let title = ""; let company = ""; let link = ""; if (text) { // If it looks like a URL if (text.startsWith("http")) { link = text.trim(); // Try to extract from common URL patterns if (text.includes("indeed.com")) company = "Indeed Job"; if (text.includes("linkedin.com")) company = "LinkedIn Job"; if (text.includes("usajobs.gov")) company = "U.S. Government"; if (text.includes("ziprecruiter.com")) company = "ZipRecruiter Job"; if (text.includes("clearancejobs.com")) company = "ClearanceJobs"; } else { // Try to parse "Job Title - Company" or "Job Title at Company" const atMatch = text.match(/^(.+?)\s+at\s+(.+?)$/i); const dashMatch = text.match(/^(.+?)\s*[-–]\s*(.+?)$/); if (atMatch) { title = atMatch[1].trim(); company = atMatch[2].trim(); } else if (dashMatch) { title = dashMatch[1].trim(); company = dashMatch[2].trim(); } else { title = text.slice(0, 80).trim(); } } } setClipboardParsed({ title, company, link }); setShowClipboardModal(true); setTab(4); setRetentionTab("tracker"); }; const showToast = (msg) => { setSaveToast(msg); setTimeout(() => setSaveToast(""), 2800); }; // ── LISTEN FOR FIREBASE AUTH STATE ── // ── BOOKMARKLET URL HANDLER ── useEffect(() => { const params = new URLSearchParams(window.location.search); if (params.get("addjob") === "1") { const title = decodeURIComponent(params.get("title")||""); const company = decodeURIComponent(params.get("company")||""); const link = decodeURIComponent(params.get("link")||""); if (title || company) { const entry = {id:Date.now(), title, company, link, date: new Date().toISOString().slice(0,10), status:"Applied", notes:"", source:"Bookmarklet"}; setJobApps(prev => { const updated = [entry, ...prev]; localStorage.setItem("vcb_jobs", JSON.stringify(updated)); return updated; }); setTab(4); setRetentionTab("tracker"); showToast("Job saved to tracker ✓ — "+(title||company)); window.history.replaceState({}, "", window.location.pathname); } } }, []); useEffect(() => { if (!fbAuth) return; const unsubscribe = fbAuth.onAuthStateChanged(async (firebaseUser) => { if (firebaseUser) { // User is signed in const initials = (firebaseUser.displayName || firebaseUser.email) .split(" ").map(w => w[0]).join("").toUpperCase().slice(0, 2); const user = { uid: firebaseUser.uid, name: firebaseUser.displayName || firebaseUser.email.split("@")[0], email: firebaseUser.email, initials, }; setCurrentUser(user); setHasUnsaved(false); // Load their saved profile try { const doc = await fbDb.collection("profiles").doc(firebaseUser.uid).get(); if (doc.exists) { const data = doc.data(); if (data.personal) setPersonal(data.personal); if ((data.milExperiences && data.milExperiences.length)) setMilExperiences(data.milExperiences); if ((data.civExperiences && data.civExperiences.length)) setCivExperiences(data.civExperiences); // backwards compat if (!data.milExperiences && (data.experiences && data.experiences.length)) setMilExperiences(data.experiences); if ((data.education && data.education.length)) setEducation(data.education); if (data.skills) setSkills(data.skills); if (data.target) setTarget(data.target); // Cache profile to localStorage so standalone tool pages can read it // without needing their own Firebase init try { localStorage.setItem("vcb_profile", JSON.stringify(data)); } catch(e) {} // Re-hydrate vcb_access from Firestore if localStorage was cleared // This keeps tools unlocked across refreshes for paying users try { const currentAccess = localStorage.getItem("vcb_access"); let needsRehydrate = !currentAccess; if (currentAccess) { const parsed = JSON.parse(currentAccess); if (parsed.type === "paid" && parsed.expiry <= Date.now()) needsRehydrate = true; } if (needsRehydrate && data.stripeSession) { const expiry = data.accessExpiry || (Date.now() + 365*24*60*60*1000); localStorage.setItem("vcb_access", JSON.stringify({ type:"paid", stripeSession: data.stripeSession, expiry, plan: data.plan || "monthly" })); setHasAccess(true); setShowPaywall(false); } else if (needsRehydrate && data.accessCode) { localStorage.setItem("vcb_access", JSON.stringify({ type:"code", code: data.accessCode })); setHasAccess(true); setShowPaywall(false); } else if (!needsRehydrate) { // localStorage still valid, make sure React state reflects it if (checkAccess()) { setHasAccess(true); setShowPaywall(false); // Sync localStorage access to Firestore if Firestore is missing it try { const acc = JSON.parse(localStorage.getItem("vcb_access")||"{}"); if (acc.stripeSession && !data.stripeSession) { fbDb.collection("profiles").doc(firebaseUser.uid).set({ stripeSession: acc.stripeSession, accessExpiry: acc.expiry, plan: acc.plan || "monthly", updatedAt: Date.now() }, { merge: true }); } else if (acc.code && !data.accessCode) { fbDb.collection("profiles").doc(firebaseUser.uid).set({ accessCode: acc.code, updatedAt: Date.now() }, { merge: true }); } } catch(e) {} } } } catch(e) {} } // Load saved resumes const resumesSnap = await fbDb.collection("profiles").doc(firebaseUser.uid) .collection("resumes").orderBy("createdAt","desc").limit(20).get(); setSavedResumes(resumesSnap.docs.map(d => d.data())); const clSnap = await fbDb.collection("profiles").doc(firebaseUser.uid).collection("coverLetters").orderBy("id","desc").limit(20).get(); setSavedCoverLetters(clSnap.docs.map(d=>d.data())); const emSnap = await fbDb.collection("profiles").doc(firebaseUser.uid).collection("emails").orderBy("id","desc").limit(20).get(); setSavedEmails(emSnap.docs.map(d=>d.data())); const scSnap = await fbDb.collection("profiles").doc(firebaseUser.uid).collection("scores").orderBy("id","desc").limit(10).get(); setSavedScores(scSnap.docs.map(d=>d.data())); } catch(e) { console.warn("Profile load error:", e); } } else { setCurrentUser(null); setSavedResumes([]); setJobApps([]); setTlChecks({}); setSavedCoverLetters([]); setSavedEmails([]); setSavedScores([]); } }); return () => unsubscribe(); }, []); // Mark unsaved when key fields change useEffect(() => { if (!currentUser || !fbDb) { setHasUnsaved(false); return; } setHasUnsaved(true); const timer = setTimeout(async () => { try { await fbDb.collection("profiles").doc((currentUser&¤tUser.uid)).set({ personal, milExperiences, civExperiences, education, skills, target, serviceRecords, targetLocation, updatedAt: Date.now() }, { merge: true }); setHasUnsaved(false); } catch(e) { /* silent fail */ } }, 1800); return () => clearTimeout(timer); }, [personal, milExperiences, civExperiences, education, skills, target, targetLocation, serviceRecords]); // ── AUTH HANDLERS (Firebase) ── const handleRegister = async () => { setAuthErr(""); setAuthOk(""); if (!authForm.name.trim()) return setAuthErr("Full name is required."); if (!authForm.username.trim()) return setAuthErr("Email is required."); if (authForm.password.length < 6) return setAuthErr("Password must be at least 6 characters."); if (authForm.password !== authForm.confirmPassword) return setAuthErr("Passwords do not match."); try { const cred = await fbAuth.createUserWithEmailAndPassword(authForm.username.trim(), authForm.password); await cred.user.updateProfile({ displayName: authForm.name.trim() }); setAuthOk("Account created! Signing you in..."); setShowAuth(false); // Check access before redirecting to Stripe if(window._pendingStripe){ delete window._pendingStripe; if(!checkAccess()){setShowPaywall(true);} } else if(!checkAccess()){setShowPaywall(true);} showToast("Welcome, " + authForm.name.split(" ")[0] + "! ✓"); setAuthForm({ username:"", password:"", confirmPassword:"", name:"" }); } catch(e) { if (e.code === "auth/email-already-in-use") setAuthErr("An account with this email already exists."); else if (e.code === "auth/invalid-email") setAuthErr("Please enter a valid email address."); else setAuthErr(e.message); } }; const handleLogin = async () => { if (!fbAuth) { setAuthErr("Authentication is not configured yet. Contact the site owner."); return; } setAuthErr(""); setAuthOk(""); if (!authForm.username.trim()) { setAuthErr("Please enter your email address."); return; } if (!authForm.password) { setAuthErr("Please enter your password."); return; } try { await fbAuth.signInWithEmailAndPassword(authForm.username.trim(), authForm.password); setShowAuth(false); // Check access before redirecting to Stripe - prevent double charges if(window._pendingStripe){ delete window._pendingStripe; if(!checkAccess()){setShowPaywall(true);} } else if(!checkAccess()){setShowPaywall(true);} setAuthForm({ username:"", password:"", confirmPassword:"", name:"" }); } catch(e) { if (e.code === "auth/user-not-found" || e.code === "auth/invalid-credential") setAuthErr("No account found. Check your email or create an account."); else if (e.code === "auth/wrong-password") setAuthErr("Incorrect password. Try again or reset it below."); else if (e.code === "auth/invalid-email") setAuthErr("Please enter a valid email address."); else if (e.code === "auth/too-many-requests") setAuthErr("Too many attempts. Please wait a moment and try again."); else setAuthErr("Sign in failed: " + (e.message||"Unknown error")); } }; const handleLogout = async () => { await fbAuth.signOut(); setCurrentUser(null); setSavedResumes([]); setHasUnsaved(false); // Clear localStorage caches try { localStorage.removeItem("vcb_profile"); localStorage.removeItem("vcb_access"); localStorage.removeItem("vcp_pf_user"); localStorage.removeItem("vcp_pathfinder_result"); localStorage.removeItem("vcb_assessment_result"); localStorage.removeItem("vcp_scout_data"); localStorage.removeItem("vcp_scout_resume"); localStorage.removeItem("vcp_scout_wizard"); } catch(e) {} setHasAccess(false); setShowPaywall(false); // Reset form fields setPersonal({ name:"", email:"", phone:"", location:"", linkedin:"" }); setMilExperiences([newMilExp()]); setEducation([{ id:1, institution:"", degree:"", field:"", year:"", pme:"" }]); setSkills({ technical:"", leadership:"", languages:"", certs:"" }); }; const handleSaveProfile = async () => { if (!currentUser) { setShowAuth(true); return; } try { const profileData = { personal, milExperiences, civExperiences, education, skills, target, updatedAt: new Date().toISOString() }; await fbDb.collection("profiles").doc((currentUser&¤tUser.uid)).set( profileData, { merge: true } ); // Cache profile in localStorage so standalone tool pages can read it // without needing their own Firebase init try { localStorage.setItem("vcb_profile", JSON.stringify(profileData)); } catch(e) {} showToast("Profile saved ✓"); setHasUnsaved(false); } catch(e) { showToast("Save failed — check connection"); } }; const handleSaveResume = async () => { if (!currentUser) { setShowAuth(true); return; } if (!resume) return; try { const resumeTitle = window.prompt("Give this resume a name so you can find it later:", target.title || "My Resume") || target.title || "Saved Resume"; const id = Date.now().toString(); const entry = { id, title: resumeTitle, industry: target.industry || "", format: resumeFormat, template: resumeTemplate, visualStyle: resumeVisualStyle, resumeData: resumeData || null, date: new Date().toLocaleDateString("en-US", { year:"numeric", month:"short", day:"numeric" }), preview: resume.slice(0, 120) + "...", content: resume, createdAt: new Date().toISOString(), }; await fbDb.collection("profiles").doc((currentUser&¤tUser.uid)) .collection("resumes").doc(id).set(entry); setSavedResumes(prev => [entry, ...prev].slice(0, 20)); showToast("Resume saved to your profile ✓"); } catch(e) { showToast("Save failed — check connection"); } }; // Safety: expose on window so components with broken prop threading can still call it window.__vcp_saveResume = handleSaveResume; const handleDeleteResume = async (id) => { if (!currentUser) return; try { await fbDb.collection("profiles").doc((currentUser&¤tUser.uid)) .collection("resumes").doc(id.toString()).delete(); setSavedResumes(prev => prev.filter(r => r.id !== id)); showToast("Resume deleted"); } catch(e) { showToast("Delete failed"); } }; const saveCoverLetter = async () => { const entry = {id:Date.now(), date:new Date().toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"}), job:coverLetterJob.title||"Cover Letter", company:coverLetterJob.company||"", content:coverLetter}; setSavedCoverLetters(prev=>[entry,...prev].slice(0,20)); if(currentUser&&fbDb){try{await fbDb.collection("profiles").doc((currentUser&¤tUser.uid)).collection("coverLetters").doc(entry.id.toString()).set(entry);}catch(e){}} showToast("Cover letter saved to My Profile ✓"); }; const saveEmail = async () => { const entry = {id:Date.now(), date:new Date().toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"}), type:followupCtx.outcome||"Follow-Up Email", content:followupEmail}; setSavedEmails(prev=>[entry,...prev].slice(0,20)); if(currentUser&&fbDb){try{await fbDb.collection("profiles").doc((currentUser&¤tUser.uid)).collection("emails").doc(entry.id.toString()).set(entry);}catch(e){}} showToast("Email saved to My Profile ✓"); }; const saveScore = async () => { const entry = {id:Date.now(), date:new Date().toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"}), score:resumeScore, label:resumeScore>=85?"Excellent":resumeScore>=75?"Strong":resumeScore>=65?"Good":"Needs Work", summary:resumeReview.summary||"", grades:resumeReview.grades||{}}; setSavedScores(prev=>[entry,...prev].slice(0,10)); if(currentUser&&fbDb){try{await fbDb.collection("profiles").doc((currentUser&¤tUser.uid)).collection("scores").doc(entry.id.toString()).set(entry);}catch(e){}} showToast("Score report saved to My Profile ✓"); }; const handleDeleteSaved = async (type,id) => { if(type==="cl") setSavedCoverLetters(prev=>prev.filter(x=>x.id!==id)); else if(type==="em") setSavedEmails(prev=>prev.filter(x=>x.id!==id)); else if(type==="sc") setSavedScores(prev=>prev.filter(x=>x.id!==id)); if(currentUser&&fbDb){ const col=type==="cl"?"coverLetters":type==="em"?"emails":"scores"; try{await fbDb.collection("profiles").doc((currentUser&¤tUser.uid)).collection(col).doc(id.toString()).delete();}catch(e){} } showToast("Deleted"); }; const handleLoadResume = (r) => { setResume(r.content); setTarget(t => ({ ...t, title: r.title, industry: r.industry })); setTab(2); showToast("Resume loaded ✓"); }; const setL = (k,v) => setLoading(l=>({...l,[k]:v})); const upP = (k,v) => setPersonal(p=>({...p,[k]:v})); const upT = (k,v) => setTarget(p=>({...p,[k]:v})); const upMilExp = (id,k,v) => setMilExperiences(es=>es.map(e=>e.id===id ? {...e,[k]:v,...(k==="mos"?{mosTitle:(MOS_DATA[v.toUpperCase()] && MOS_DATA[v.toUpperCase()].title)||""}:{})} : e)); const upCivExp = (id,k,v) => setCivExperiences(es=>es.map(e=>e.id===id ? {...e,[k]:v} : e)); const upExp = (id,k,v) => { if (milExperiences.find(e=>e.id===id)) upMilExp(id,k,v); else upCivExp(id,k,v); }; // ASI helpers const addAsi = (id) => { const exp = experiences.find(e=>e.id===id); if (!exp) return; const code = exp.customAsiCode.trim().toUpperCase(); const desc = exp.customAsiDesc.trim() || (COMMON_ASI.find(a=>a.code===code) ? COMMON_ASI.find(a=>a.code===code).desc : undefined) || ""; if (!code) return; if (exp.asi.find(a=>a.code===code)) return; upExp(id,"asi",[...exp.asi,{code,desc}]); upExp(id,"customAsiCode",""); upExp(id,"customAsiDesc",""); }; const addAsiCommon = (id,asi) => { const exp = experiences.find(e=>e.id===id); if (!exp||exp.asi.find(a=>a.code===asi.code)) return; upExp(id,"asi",[...exp.asi,asi]); }; const rmAsi = (id,code) => { const exp=experiences.find(e=>e.id===id); upExp(id,"asi",exp.asi.filter(a=>a.code!==code)); }; // SQI helpers const addSqi = (id) => { const exp = experiences.find(e=>e.id===id); if (!exp) return; const code = exp.customSqiCode.trim().toUpperCase(); const desc = exp.customSqiDesc.trim() || (COMMON_SQI.find(s=>s.code===code) ? COMMON_SQI.find(s=>s.code===code).desc : undefined) || ""; if (!code) return; if (exp.sqi.find(s=>s.code===code)) return; upExp(id,"sqi",[...exp.sqi,{code,desc}]); upExp(id,"customSqiCode",""); upExp(id,"customSqiDesc",""); }; const addSqiCommon = (id,sqi) => { const exp = experiences.find(e=>e.id===id); if (!exp||exp.sqi.find(s=>s.code===sqi.code)) return; upExp(id,"sqi",[...exp.sqi,sqi]); }; const rmSqi = (id,code) => { const exp=experiences.find(e=>e.id===id); upExp(id,"sqi",exp.sqi.filter(s=>s.code!==code)); }; // Duty helpers const addDuty = (id, duty) => { const exp = experiences.find(e=>e.id===id); if (!exp||!duty.trim()||exp.additionalDuties.includes(duty.trim())) return; upExp(id,"additionalDuties",[...exp.additionalDuties,duty.trim()]); upExp(id,"customDuty",""); }; const rmDuty = (id,d) => { const exp=experiences.find(e=>e.id===id); upExp(id,"additionalDuties",exp.additionalDuties.filter(x=>x!==d)); }; const addMilExp = () => setMilExperiences(es=>[...es,newMilExp()]); const addCivExp = () => setCivExperiences(es=>[...es,newCivExp()]); const addExp = () => setCivExperiences(es=>[...es,newCivExp()]); const rmExp = id => { setMilExperiences(es=>es.filter(e=>e.id!==id)); setCivExperiences(es=>es.filter(e=>e.id!==id)); }; const upEdu = (id,k,v) => setEducation(eds=>eds.map(e=>e.id===id?{...e,[k]:v}:e)); const addEdu = () => setEducation(eds=>[...eds,{id:Date.now(),institution:"",degree:"",field:"",year:"",pme:""}]); const rmEdu = id => setEducation(eds=>eds.filter(e=>e.id!==id)); const toggleCollapse = id => setCollapsed(c=>({...c,[id]:!c[id]})); // ── BUILD SUMMARIES ──────────────────────────────────────────────────────── const buildExpSummary = () => { const milParts = milExperiences.map(e=>{ const rolesStr = (e.mosRoles||[]).length ? "Positions held: "+(e.mosRoles.map(r=>[r.title,r.rankAtRole,r.fromYear&&r.toYear?r.fromYear+"-"+r.toYear:"",r.keyDuty].filter(Boolean).join(", ")).join(" | ")) : ""; const awardsStr = (e.awards||[]).length ? "Awards: "+((e.awards||[]).join(", ")) : ""; const qualStr = [ (e.asi && e.asi.length)?"ASIs: "+(e.asi.map(a=>a.code+"("+a.desc+")").join(", ")):null, (e.sqi && e.sqi.length)?"SQIs: "+(e.sqi.map(s=>s.code+"("+s.desc+")").join(", ")):null, (e.additionalDuties && e.additionalDuties.length)?"Additional Duties: "+(e.additionalDuties.join(", ")):null, ].filter(Boolean).join(" | "); const clearStr = e.clearanceLevel!=="None" ? `Clearance: ${e.clearanceLevel} (${e.clearanceStatus})${e.polygraph!=="None"?" + "+e.polygraph+" Poly":""}` : "No clearance"; return `[MILITARY] ${e.branch} | ${e.rank} | MOS: ${e.mos}${e.mosTitle?" ("+e.mosTitle+")":""} | ${e.serviceType} | Unit: ${e.unit} | TOS: ${e.tos||"not listed"} | ${e.startDate||"?"}–${e.current?"Present":e.endDate||"?"} | ${clearStr}${qualStr?" | "+qualStr:""} | Duties: ${e.duties||"not listed"}${rolesStr?" | "+rolesStr:""}${awardsStr?" | "+awardsStr:""}${e.deployments?" | Deployments: "+e.deployments:""}`; }); const civParts = civExperiences.map(e=>{ const clearStr = (e.clearanceLevel&&e.clearanceLevel!=="None") ? "Clearance: "+(e.clearanceLevel):""; return `[${e.type.toUpperCase()}] ${e.jobTitle||"Role"} at ${e.employer||"Unknown"} | ${e.startDate||"?"}–${e.current?"Present":e.endDate||"?"} | Duties: ${e.duties||"not listed"}${clearStr?" | "+clearStr:""}`; }); return [...milParts,...civParts].join("\n"); }; // ── TRANSLATE ────────────────────────────────────────────────────────────── const translateMOS = async () => { if (!hasAccess) { setShowPaywall(true); return; } if (!isApiKeySet()) { setShowAdminSetup(true); return; } if (!milExperiences.length) return; setApiError(""); setTranslationData(null); setMosOut(""); setL("translate", true); try { const lines = milExperiences.map(e => { const parts = [ "MOS/Rate: " + (e.mos||"unknown") + " (" + (e.mosTitle||"see title") + ")", "Branch: " + e.branch + " | Rank: " + (e.rank||"not listed") + " | Service: " + (e.serviceType||"Active Duty") + " | TOS: " + (e.tos||"unknown"), (e.asi&&e.asi.length) ? "ASIs: " + e.asi.map(a=>a.code+" - "+a.desc).join(", ") : null, (e.sqi&&e.sqi.length) ? "SQIs: " + e.sqi.map(s=>s.code+" - "+s.desc).join(", ") : null, (e.additionalDuties&&e.additionalDuties.length) ? "Additional Duties: " + e.additionalDuties.join(", ") : null, (e.mosRoles&&e.mosRoles.length) ? "Career progression: " + e.mosRoles.map(r=>(r.fromYear?r.fromYear:"")+(r.toYear?"-"+r.toYear:"")+" "+r.rankAtRole+" "+r.title+(r.keyDuty?": "+r.keyDuty:"")).filter(s=>s.trim()).join(" → ") : null, (e.awards&&e.awards.length) ? "Awards: " + e.awards.join(", ") : null, (e.clearanceLevel&&e.clearanceLevel!=="None") ? "Clearance: " + e.clearanceLevel + " " + (e.clearanceStatus||"Active") : null, "Duties: " + (e.duties||"not described"), ]; return parts.filter(Boolean).join("\n"); }).join("\n\n---\n\n"); const prompt = "A veteran has this military background:\n\n" + lines + "\n\n" + "Please provide a detailed civilian translation. Return ONLY a JSON object with NO markdown, no backticks, no extra text. Start with { and end with }.\n\n" + "The JSON must have these exact keys:\n" + "summary: a 3-sentence professional civilian summary paragraph\n" + "roles: array of objects, one per military role, each with: mos (string), title (string), whatYouDid (string, 2-3 plain English sentences), transferableSkills (array of 6 strings), resumeBullets (array of 4 strong resume bullet points starting with action verbs)\n" + "qualifications: array of objects for each ASI/SQI, each with: code, name, civilianMeaning, unlocks\n" + "additionalDuties: array of objects for each additional duty, each with: duty, civilianEquivalent, value"; const raw = await callClaude( prompt, "You are an expert military-to-civilian career translator. RULES: 1) ZERO military jargon — translate everything to civilian language. 2) EMPLOYER/BRANCH NAME: Never change U.S. Army, U.S. Navy, U.S. Marine Corps, U.S. Air Force, U.S. Coast Guard, U.S. Space Force — keep exactly as written. 3) UNIT NAME: Never translate unit names — keep exactly as the veteran typed (e.g. 126 CTC stays 126 CTC). 4) RANK TRANSLATIONS: E5-E6=Supervisor, E7=Operations Manager, E8=Senior Manager, E9=Director, O3=Program Manager, O4=Senior PM, O5=Director, O6=Executive Director. 5) TITLE TRANSLATIONS: NCO=Supervisor, NCOIC=Operations Lead, Armorer=Equipment Inventory Manager, SHARP Rep=HR Compliance Coordinator, Retention NCO=Talent Acquisition Specialist, Supply Sgt=Logistics Manager, Motor Transport=Fleet Operations Manager. 6) METRICS: Only use numbers the veteran explicitly provided — never fabricate metrics. 7) Security clearances: ONLY include if the veteran selected to include it. If not selected, omit entirely. 8) Every bullet starts with a civilian action verb: Led, Managed, Directed, Coordinated, Developed, Implemented, Oversaw, Delivered.", 2000 ); // Robust JSON extraction const start = raw.indexOf("{"); const end = raw.lastIndexOf("}"); if (start === -1 || end === -1) { throw new Error("Response did not contain valid JSON. Raw: " + raw.slice(0,200)); } const parsed = JSON.parse(raw.slice(start, end + 1)); // Ensure required fields exist with fallbacks const result = { summary: parsed.summary || "Your military background demonstrates strong leadership, discipline, and mission-focused expertise.", roles: Array.isArray(parsed.roles) ? parsed.roles : [], qualifications: Array.isArray(parsed.qualifications) ? parsed.qualifications : [], additionalDuties: Array.isArray(parsed.additionalDuties) ? parsed.additionalDuties : [], }; setTranslationData(result); } catch(err) { console.error("translateMOS error:", err); setMosOut("Translation failed: " + (err.message || "Unknown error. Check your API key and try again.")); } setL("translate", false); }; // ── CAREERS ─────────────────────────────────────────────────────────────── const findCareers = async () => { if (!hasAccess) { setShowPaywall(true); return; } if (!isApiKeySet()) { setShowAdminSetup(true); return; } setApiError(""); setCareerError(""); setL("careers",true); setCareers(null); setSelectedCareer(null); setCareerDetail(null); const summary = buildExpSummary(); const branch = (milExperiences[0]||{}).branch||"Army"; const mos = (milExperiences[0]||{}).mos||""; const rank = (milExperiences[0]||{}).rank||""; const tos = (milExperiences[0]||{}).tos||""; const clearance = (milExperiences[0]||{}).clearanceLevel||"None"; const hasClearance = clearance && clearance!=="None"; const system = "You are the world's best military-to-civilian career counselor. You know EVERY civilian job sector including skilled trades, retail management, transportation, agriculture, maritime, aviation, hospitality, fitness, education, social work, nonprofits, entrepreneurship, real estate, financial services, and more. Return ONLY valid minified JSON. No markdown, no backticks, no line breaks inside strings, no trailing commas. The JSON must parse with JSON.parse() on the first try."; const mosDetail = milExperiences.map(e=>(e.mos||(e.branch+' service'))+(e.mosTitle?' ('+e.mosTitle+')':'')+', '+e.branch+(e.rank?' '+e.rank:'')+', '+(e.tos||'unknown TIS')+' TIS').join('; '); const civDetail = civExperiences.filter(e=>e.jobTitle).map(e=>e.jobTitle+(e.employer?' at '+e.employer:'')).join(', '); const awardsDetail = milExperiences.flatMap(e=>e.awards||[]).slice(0,6).join(', '); const asiDetail = milExperiences.flatMap(e=>(e.asi||[]).map(a=>a.code+': '+a.desc)).slice(0,4).join('; '); const clearances = milExperiences.map(e=>e.clearanceLevel).filter(c=>c&&c!=='None').join(', '); const dutiesDetail = milExperiences.flatMap(e=>e.duties?[e.duties.slice(0,100)]:[]).join(' | ').slice(0,300); const eduDetail = education.map(e=>e.degree+' '+e.field).filter(Boolean).join(', '); const prompt = `You are an expert military transition counselor. Generate 12 PERSONALIZED career paths for this specific veteran. THIS VETERAN'S ACTUAL BACKGROUND: Military: ${mosDetail||'military background'} Civilian Work: ${civDetail||'none yet'} Duties/Responsibilities: ${dutiesDetail||'standard military duties'} Specialty Quals: ${asiDetail||'none listed'} Awards: ${awardsDetail||'none listed'} Clearance: ${clearances||'None'} Education: ${eduDetail||'military training'} Career Goal: ${target.title||'open'} in ${target.industry||'any sector'} Interests & Hobbies: ${target.interests||'not specified'} Open To: ${target.openTo||'flexible'} Location: ${targetLocation||'flexible'} RULES — follow strictly: 1. Top 8 paths must directly match their MOS/rate and civilian work history 2. Use their interests/hobbies to find 3-4 meaningful career connections 3. Clearances unlock intel, defense contractor, and federal roles — include them 4. ASI/SQI specialties must appear directly in titles and whyFit 5. Include entry-level ($40k-$60k) AND senior paths ($80k+) 6. NO generic roles unless directly tied to their specific background 7. whyFit MUST cite something specific from their profile — not generic veteran praise 8. salaryRange format: '$XX,000-$XX,000' only, no special chars 9. Return ONLY minified JSON, no markdown [{"title":"Specific Title","sector":"Civilian|Government|Defense\/Intel","industry":"Field","salaryRange":"$X-$Y","match":"Excellent|Strong|Good","whyFit":"cite specific background","topSkills":["s1","s2","s3"],"nextStep":"first action"}]` try { const raw = await callClaude(prompt, system, 2500); // Aggressively clean the response let cleaned = raw .replace(/```json/gi,"").replace(/```/g,"") .replace(/,\s*}/g,"}").replace(/,\s*]/g,"]") .trim(); const arrStart = cleaned.indexOf("["); const arrEnd = cleaned.lastIndexOf("]"); if (arrStart === -1 || arrEnd === -1) throw new Error("No JSON array found"); cleaned = cleaned.slice(arrStart, arrEnd + 1); // Fix common JSON issues const parsed = JSON.parse(cleaned); if (!Array.isArray(parsed) || parsed.length === 0) throw new Error("Empty array"); setCareers(parsed); } catch(err) { console.error("findCareers error:", err); setCareerError("Career match failed: " + (err.message||"Try again.")); // Rich fallback covering all sectors setCareers([ {title:"CDL Truck Driver",sector:"Civilian",industry:"Transportation / Logistics",salaryRange:"$55,000-$90,000",match:"Excellent",outlook:"High Growth",why:"Military discipline and vehicle operation translate directly. CDL license obtainable in 4-8 weeks.",clearanceBonus:false,entryPath:"Enroll in CDL school using GI Bill or Helmets to Hardhats",education:"CDL-A License"}, {title:"Police Officer",sector:"Government",industry:"Law Enforcement",salaryRange:"$55,000-$85,000",match:"Excellent",outlook:"Stable",why:"Military veterans are preferred candidates at most agencies. Physical fitness and command presence are direct assets.",clearanceBonus:false,entryPath:"Apply to local or federal agency, most waive written exam for veterans",education:"Police Academy (3-6 months)"}, {title:"Electrician Apprentice",sector:"Civilian",industry:"Skilled Trades / Construction",salaryRange:"$48,000-$95,000",match:"Excellent",outlook:"High Growth",why:"High demand, strong union wages, GI Bill covers apprenticeship programs.",clearanceBonus:false,entryPath:"Register with IBEW or IEC apprenticeship program",education:"4-year apprenticeship"}, {title:"Firefighter",sector:"Government",industry:"Fire & Emergency Services",salaryRange:"$52,000-$80,000",match:"Excellent",outlook:"Stable",why:"Military teamwork, physical fitness, and emergency response experience are exactly what fire departments seek.",clearanceBonus:false,entryPath:"Apply to local fire department, use veterans preference points",education:"Fire Academy + EMT cert"}, {title:"Federal Law Enforcement Officer",sector:"Government",industry:"Federal Agency",salaryRange:"$60,000-$100,000",match:"Strong",outlook:"Stable",why:"FBI, DEA, CBP, Secret Service all actively recruit veterans with military police or combat experience.",clearanceBonus:true,entryPath:"Apply via USAJobs.gov with veterans preference",education:"Agency-specific training"}, {title:"Operations Manager",sector:"Civilian",industry:"Logistics / Manufacturing",salaryRange:"$65,000-$100,000",match:"Strong",outlook:"Stable",why:"Military NCOs and officers run complex operations daily — this is the same skill set.",clearanceBonus:false,entryPath:"Translate leadership experience on resume, target Walmart, Amazon, FedEx hiring programs",education:"PMP cert helpful"}, {title:"HVAC Technician",sector:"Civilian",industry:"Skilled Trades",salaryRange:"$50,000-$85,000",match:"Strong",outlook:"High Growth",why:"Strong demand, excellent wages, military mechanical experience is valued.",clearanceBonus:false,entryPath:"Enroll in HVAC program via GI Bill, apprenticeship or trade school",education:"EPA 608 Cert"}, {title:"Cybersecurity Analyst",sector:"Civilian",industry:"Technology / Defense",salaryRange:"$70,000-$115,000",match:"Strong",outlook:"High Growth",why:"DOD cybersecurity experience and clearances are extremely valuable in the private sector.",clearanceBonus:true,entryPath:"CompTIA Security+ certification (study 2-3 months), apply to defense contractors",education:"Security+ / CEH cert"}, {title:"Government Contractor (DoD)",sector:"Defense/Intel",industry:"Defense Contracting",salaryRange:"$75,000-$130,000",match:"Excellent",outlook:"Stable",why:"Your military experience and clearance make you immediately valuable to Booz Allen, SAIC, Leidos, and others.",clearanceBonus:true,entryPath:"Apply directly to major defense contractors on LinkedIn or ClearanceJobs.com",education:"Clearance required"}, {title:"EMT / Paramedic",sector:"Civilian",industry:"Emergency Medical Services",salaryRange:"$38,000-$65,000",match:"Strong",outlook:"High Growth",why:"Combat medics (68W, HM, 18D) can often test out of EMT requirements.",clearanceBonus:false,entryPath:"Enroll in EMT-Basic course, advance to Paramedic in 1-2 years",education:"EMT-B cert (4-8 weeks)"}, {title:"Project Manager",sector:"Civilian",industry:"Construction / Technology / Healthcare",salaryRange:"$70,000-$110,000",match:"Strong",outlook:"High Growth",why:"Military planning experience maps directly to project management.",clearanceBonus:false,entryPath:"Earn PMP certification, target companies with veteran hiring programs",education:"PMP Certification"}, {title:"TSA Officer / Border Patrol",sector:"Government",industry:"Homeland Security",salaryRange:"$45,000-$75,000",match:"Excellent",outlook:"Stable",why:"Direct pipeline from military service, veterans preference applies.",clearanceBonus:false,entryPath:"Apply on USAJobs.gov, process takes 3-6 months",education:"Federal training provided"}, {title:"Welder",sector:"Civilian",industry:"Manufacturing / Oil & Gas / Shipbuilding",salaryRange:"$48,000-$80,000",match:"Strong",outlook:"Stable",why:"High demand across shipbuilding, pipeline, and manufacturing. Overtime opportunities are substantial.",clearanceBonus:false,entryPath:"AWS welding cert via trade school or community college using GI Bill",education:"AWS Certification"}, {title:"Intelligence Analyst",sector:"Defense/Intel",industry:"Intelligence Community",salaryRange:"$70,000-$115,000",match:"Strong",outlook:"Stable",why:"Military intelligence experience and clearances are the #1 requirement for these roles.",clearanceBonus:true,entryPath:"Apply to CIA, NSA, DIA or defense contractors via ClearanceJobs.com",education:"Clearance + BA preferred"}, {title:"Heavy Equipment Operator",sector:"Civilian",industry:"Construction / Mining / Oil & Gas",salaryRange:"$55,000-$90,000",match:"Strong",outlook:"Stable",why:"Military combat engineers and motor transport operators have directly transferable skills.",clearanceBonus:false,entryPath:"NCCER certification via apprenticeship or Helmets to Hardhats program",education:"NCCER Operator Cert"}, {title:"Logistics Coordinator",sector:"Civilian",industry:"Supply Chain / Freight",salaryRange:"$50,000-$75,000",match:"Excellent",outlook:"High Growth",why:"Military logistics (92A, 88M, Storekeeper) is identical to civilian supply chain work.",clearanceBonus:false,entryPath:"Apply to Amazon, FedEx, UPS, or freight brokerages",education:"None required"}, {title:"Diesel Mechanic",sector:"Civilian",industry:"Transportation / Fleet Maintenance",salaryRange:"$52,000-$80,000",match:"Strong",outlook:"Stable",why:"Military vehicle mechanics (91B, 63 series, DC) are highly sought after.",clearanceBonus:false,entryPath:"ASE certification, apply to trucking companies or transit agencies",education:"ASE Cert"}, {title:"Safety Manager / EHS Specialist",sector:"Civilian",industry:"Construction / Manufacturing / Oil & Gas",salaryRange:"$60,000-$95,000",match:"Strong",outlook:"High Growth",why:"Military safety protocols and risk management experience are directly valuable.",clearanceBonus:false,entryPath:"OSHA 30 cert + CSP or CHST certification",education:"OSHA 30 cert"}, {title:"Corrections Officer",sector:"Government",industry:"State / Federal Corrections",salaryRange:"$45,000-$70,000",match:"Strong",outlook:"Stable",why:"Military discipline and physical fitness are exactly what the correctional system needs.",clearanceBonus:false,entryPath:"Apply to state DOC or Bureau of Prisons, veterans preference applies",education:"Academy training provided"}, {title:"IT Systems Administrator",sector:"Civilian",industry:"Technology",salaryRange:"$60,000-$95,000",match:"Strong",outlook:"High Growth",why:"Military IT and communications (25 series, IT rating) translates directly.",clearanceBonus:false,entryPath:"CompTIA A+ and Network+ certs, apply to IT staffing firms",education:"CompTIA A+ / Network+"}, {title:"Plumber / Pipefitter",sector:"Civilian",industry:"Skilled Trades",salaryRange:"$55,000-$100,000",match:"Strong",outlook:"High Growth",why:"Extremely high demand, strong union wages, GI Bill covers apprenticeship.",clearanceBonus:false,entryPath:"UA Plumbers & Pipefitters apprenticeship via Helmets to Hardhats",education:"5-year apprenticeship"}, {title:"Training Specialist / Instructional Designer",sector:"Civilian",industry:"Corporate / Government",salaryRange:"$55,000-$85,000",match:"Excellent",outlook:"Stable",why:"Military instructors (Drill Sergeants, MOS trainers) are natural training specialists.",clearanceBonus:false,entryPath:"ATD certification, apply to corporate L&D departments or government training contractors",education:"ATD cert helpful"}, {title:"Postal Inspector / Mail Carrier",sector:"Government",industry:"United States Postal Service",salaryRange:"$50,000-$85,000",match:"Strong",outlook:"Stable",why:"USPS offers veterans preference and career advancement paths.",clearanceBonus:false,entryPath:"Apply at usps.com/careers, veterans preference gives significant advantage",education:"None required"}, {title:"Real Estate Agent",sector:"Civilian",industry:"Real Estate",salaryRange:"$45,000-$120,000",match:"Good",outlook:"High Growth",why:"Veterans understand the military relocation process and connect well with the 1.3M military families moving annually.",clearanceBonus:false,entryPath:"State real estate license (3-6 months), target military communities near bases",education:"State RE License"} ]); } setL("careers",false); }; // ── CAREER DETAIL ────────────────────────────────────────────────────────── const openCareerDetail = async (career) => { if (!hasAccess) { setShowPaywall(true); return; } setSelectedCareer(career); setCareerDetail(null); setL("careerDetail",true); const summary = buildExpSummary(); const prompt = `A veteran with this background: ${summary || "general military service"} is considering the career: "${career.title}" in the ${career.sector} sector. You MUST return ONLY a valid JSON object. No text before or after. No markdown. No backticks. Start your response with { and end with }. Use this exact structure: {"about":"3-4 sentences about this career","salaryBreakdown":{"entry":"$X – $Y","mid":"$X – $Y","senior":"$X – $Y","cleared":"$X – $Y or null","notes":"what drives salary variation"},"careerPath":[{"title":"Job Title","salary":"$X – $Y","description":"one sentence","timeframe":"Years 0-2"},{"title":"Next Role","salary":"$X – $Y","description":"one sentence","timeframe":"Years 2-5"},{"title":"Senior Role","salary":"$X – $Y","description":"one sentence","timeframe":"Years 5-10"},{"title":"Expert/Leadership","salary":"$X – $Y","description":"one sentence","timeframe":"Years 10+"}],"whyYouFit":["reason 1","reason 2","reason 3","reason 4"],"requiredSkills":["skill 1","skill 2","skill 3","skill 4","skill 5"],"gaps":["gap 1","gap 2"],"certifications":["cert 1","cert 2","cert 3"],"actionSteps":["step 1","step 2","step 3","step 4","step 5"]}`; try { const raw = await callClaude(prompt, "You are a military career transition expert. Return ONLY valid JSON starting with { and ending with }. Never include markdown, backticks, or explanatory text outside the JSON."); // Robust JSON extraction — find first { to last } const start = raw.indexOf("{"); const end = raw.lastIndexOf("}"); if (start === -1 || end === -1) throw new Error("No JSON found"); const jsonStr = raw.slice(start, end + 1); const parsed = JSON.parse(jsonStr); // Ensure all expected fields exist with fallbacks setCareerDetail({ about: parsed.about || (career.title)+" is a "+(career.sector||"")+" career well-suited for veterans.", salaryBreakdown: { entry: (parsed.salaryBreakdown && parsed.salaryBreakdown.entry) || career.salaryRange, mid: (parsed.salaryBreakdown && parsed.salaryBreakdown.mid) || "", senior: (parsed.salaryBreakdown && parsed.salaryBreakdown.senior) || "", cleared: (parsed.salaryBreakdown && parsed.salaryBreakdown.cleared) || null, notes: (parsed.salaryBreakdown && parsed.salaryBreakdown.notes) || "", }, careerPath: Array.isArray(parsed.careerPath) ? parsed.careerPath : [], whyYouFit: Array.isArray(parsed.whyYouFit) ? parsed.whyYouFit : [career.whyFit || "Your military background is directly transferable."], requiredSkills: Array.isArray(parsed.requiredSkills) ? parsed.requiredSkills : (career.topSkills || []), gaps: Array.isArray(parsed.gaps) ? parsed.gaps : [], certifications: Array.isArray(parsed.certifications) ? parsed.certifications : [], actionSteps: Array.isArray(parsed.actionSteps) ? parsed.actionSteps : [career.nextStep || "Research this career field further."], }); } catch(err) { // Fallback: build a useful detail view from the data we already have setCareerDetail({ about: (career.title)+" is a "+(career.sector||"")+" role in "+(career.industry||"multiple industries")+". "+(career.description||"")+" Veterans are well-positioned for this career due to their disciplined work ethic, leadership experience, and mission-focused mindset.", salaryBreakdown: { entry: career.salaryRange, mid: "", senior: "", cleared: null, notes: "Salary varies by location, experience, and certifications." }, careerPath: [ { title: "Entry-Level "+(career.title), salary: career.salaryRange, description: "Build foundational civilian experience and professional network.", timeframe: "Years 0–2" }, { title: "Mid-Level "+(career.title), salary: "", description: "Take on increased responsibility and specialize in a sub-field.", timeframe: "Years 2–5" }, { title: "Senior "+(career.title), salary: "", description: "Lead teams, mentor junior staff, manage larger programs.", timeframe: "Years 5–10" }, { title: "Director / Principal", salary: "", description: "Strategic leadership, executive decision-making, organizational impact.", timeframe: "Years 10+" }, ], whyYouFit: [career.whyFit || "Your military background provides strong transferable skills.", "Veterans bring leadership and discipline that civilian employers highly value.", "Your service demonstrates mission focus and the ability to perform under pressure."], requiredSkills: career.topSkills || [], gaps: ["Consider gaining civilian industry certifications to complement your military training.", "Building a professional civilian network through LinkedIn and industry events will accelerate your transition."], certifications: ["Research industry-specific certifications for this field.", "Consider PMP (Project Management Professional) as a broad credential.", "Check if your military training credits toward any civilian licenses."], actionSteps: [career.nextStep || "Research job postings in this field on USAJOBS, LinkedIn, and Indeed.", "Update your resume to target this specific role using the Resume tab.", "Connect with veterans already working in this field through LinkedIn.", "Research employers who actively recruit veterans in this sector.", "Schedule informational interviews with professionals in this career."], }); } setL("careerDetail",false); }; // ── RESUME ───────────────────────────────────────────────────────────────── const genResume = async () => { if (!hasAccess) { setShowPaywall(true); return; } if (!isApiKeySet()) { setShowAdminSetup(true); return; } setApiError(""); setL("resume",true); setResume(""); setResumeData(null); const expText = buildExpSummary(); const milSum = milExperiences.map(e => (e.branch||"Military") + " " + (e.rank||"") + " MOS:" + (e.mos||"") + " " + (e.mosTitle||"") + " TOS:" + (e.tos||"unknown") + ((e.asi&&e.asi.length) ? " ASIs:"+e.asi.map(a=>a.code+"-"+a.desc).join(",") : "") + ((e.sqi&&e.sqi.length) ? " SQIs:"+e.sqi.map(s=>s.code+"-"+s.desc).join(",") : "") + ((e.awards&&e.awards.length) ? " Awards:"+e.awards.join(",") : "") + ((e.additionalDuties&&e.additionalDuties.length) ? " Duties:"+e.additionalDuties.join(",") : "") + ((e.mosRoles&&e.mosRoles.length) ? " Progression:"+e.mosRoles.map(r=>(r.fromYear||"")+"-"+(r.toYear||"")+" "+r.rankAtRole+" "+r.title).join(" → ") : "") + " Clearance:" + (e.clearanceLevel||"None") + " Deployments:" + (e.deployments||"none") + " Duties:" + (e.duties||"not described") ).join(" | "); const eduText = education.map(e=>(e.degree)+" in "+(e.field||"")+" — "+(e.institution||"")+" ("+(e.year||"")+")").join("; "); try { const formatInstructions = { ats_chrono: "ATS CHRONOLOGICAL FORMAT: Simple clean layout. Standard section headers (Summary, Experience, Education, Skills, Certifications). Reverse chronological work history. No tables, no text boxes, no columns. Keyword-rich. ATS-safe fonts and structure.", ats_combo: "ATS COMBINATION FORMAT: Open with a Skills Summary section listing 8-10 core competencies as keywords. Then reverse-chronological experience. Then education. ATS-optimized throughout with no tables or columns.", functional: "FUNCTIONAL (SKILLS-FIRST) FORMAT: Section order: 1) Professional Profile (3 sentences), 2) Core Competencies (10-12 keywords), 3) Functional Skill Groups — create 2-3 sections named after skill categories (Leadership & Management, Technical Operations, Medical/Healthcare, etc.) with 3-4 bullets each, 4) Employment History (brief: title, org, dates only — no bullets), 5) Education. This format de-emphasizes employment gaps and career pivots by leading with what the veteran CAN DO.", traditional: "TRADITIONAL FORMAT: Conservative black and white. Clean serif-style formatting. Standard sections. No color, no design elements. Appropriate for government, legal, and formal industries.", modern: "MODERN PROFESSIONAL FORMAT: Clean contemporary layout. Use subtle section dividers (——). Bold role titles. Clean hierarchy. Professional but polished. Suitable for corporate and private sector.", executive: "EXECUTIVE FORMAT: Open with a strong executive profile paragraph. Follow with Core Competencies as two columns of keywords. Then Career Highlights with 3-4 major achievements with metrics. Then abbreviated experience. Emphasize leadership scope, P&L, team size, and strategic impact.", federal: "FEDERAL/USAJOBS FORMAT: Extremely detailed. Include GS pay scale equivalent where applicable. List all positions with full addresses of employers, hours per week, supervisor names. Include detailed KSAs. Often 3-5 pages. List all training, awards, and certifications in full.", harvard: "HARVARD STYLE: Single column, clean conservative layout. Name and contact centered at top with a line beneath. Section headers in small caps or bold with a line rule. Clean consistent formatting with strong use of white space.", wharton: "WHARTON/MBA STYLE: Name bold and prominent. One-line title/brand statement. Experience entries lead with company and bold achievement metrics. Emphasis on quantified results, revenue impact, team sizes, and scope. Sharp and results-focused.", minimalist: "MINIMALIST FORMAT: Maximum white space. Simple clean typography. Minimal use of dividers. Let content breathe. Easy to scan. Clean hierarchy with role, company, dates on one line.", creative: "CREATIVE FORMAT: Use tasteful formatting with section color accents (use ASCII/text characters to simulate). Clear visual hierarchy. Creative but readable. Appropriate for design, media, and branding roles.", }; const formatGuide = formatInstructions[resumeFormat] || formatInstructions.ats_chrono; const contact = (personal.name||"") + " | " + (personal.email||"") + " | " + (personal.phone||"") + " | " + (personal.location||"") + (personal.linkedin ? " | " + personal.linkedin : ""); const eduText2 = education.map(e => (e.degree||"") + " " + (e.field||"") + " " + (e.institution||"") + " " + (e.year||"")).join("; "); const sectionsToInclude = Object.entries(resumeSections).filter(([k,v])=>v).map(([k])=>k).join(", "); const expLevelGuide = { entry: "ENTRY LEVEL: Focus on transferable skills, training certifications, leadership potential. Emphasize trainability and work ethic.", mid: "MID-CAREER: Balance military achievements with growing expertise. Show progression and increasing responsibility.", senior: "SENIOR LEVEL: Lead with strategic impact, team/org size, budget authority. Show cross-functional leadership.", executive: "EXECUTIVE LEVEL: Emphasize org-wide transformations, P&L ownership, strategic vision, enterprise-level decisions." }; const prompt = "You are a military-to-civilian resume expert and ATS optimization specialist. Create a PREMIUM, ATS-optimized professional resume.\n\n" + "VETERAN MILITARY PROFILE:\n" + milSum + "\n\n" + "CIVILIAN EXPERIENCE:\n" + expText + "\n\n" + "EDUCATION:\n" + eduText2 + "\n\n" + "SKILLS: " + (skills.technical||"") + "\n" + "LEADERSHIP: " + (skills.leadership||"") + "\n" + "LANGUAGES: " + (skills.languages||"") + "\n" + "CERTIFICATIONS: " + (skills.certs||"") + "\n" + (target.interests ? "INTERESTS/HOBBIES: " + target.interests + "\n" : "") + "TARGET ROLE: " + (target.title||"open") + " | Industry: " + (target.industry||"any") + "\n" + (targetCompany ? "TARGET COMPANY: " + targetCompany + " — tailor language and culture fit to this company\n" : "") + "EXPERIENCE LEVEL: " + (expLevelGuide[experienceLevel] || expLevelGuide.mid) + "\n" + (jobDescription ? "\nJOB DESCRIPTION TO MATCH:\n" + jobDescription.slice(0,2000) + "\n\nCRITICAL: Extract exact keywords from this job description and mirror them in the resume. Match qualifications, skills, and terminology exactly as written in the posting.\n" : "") + "SECTIONS TO INCLUDE: " + sectionsToInclude + "\n\n" + "CONTACT: " + contact + "\n\n" + "ATS OPTIMIZATION RULES:\n" + "1. Use EXACT keywords from the job description (if provided). ATS systems do literal string matching.\n" + "2. Include industry-standard civilian keywords for " + (target.industry||"this field") + ": " + (target.title||"operations management, leadership") + "\n" + "3. Use standard section headers that ATS systems recognize (Professional Summary, Experience, Education, Skills, Certifications).\n" + "4. No tables, columns, text boxes, headers/footers, or images — pure text hierarchy.\n" + "5. Spell out acronyms the first time, then abbreviate: 'Project Management Professional (PMP)'\n\n" + "PROFESSIONAL SUMMARY RULES:\n" + "Write a compelling 3-sentence Professional Summary that: (a) opens with years of experience + core expertise, (b) highlights 2-3 quantified signature achievements, (c) ends with the value proposition for the target role. Make it specific and powerful — not generic.\n\n" + "ACHIEVEMENT RULES:\n" + "1. Every bullet MUST follow the format: [Action Verb] + [What You Did] + [Quantified Result]\n" + "2. Include numbers wherever possible: team sizes, budget amounts ($), percentages (%), time saved, efficiency gains\n" + "3. Quantify ONLY using numbers the veteran explicitly provided. NEVER invent or fabricate metrics. If they gave no numbers, write a strong qualitative bullet.\n" + "4. Start every bullet with a powerful civilian action verb: Spearheaded, Orchestrated, Streamlined, Optimized, Transformed, Directed, Launched, Pioneered, Delivered, Accelerated\n\n" + "CRITICAL RULES — ZERO MILITARY JARGON ALLOWED:\n" + "ABSOLUTE RULE: The resume must read as if written by a civilian professional. A civilian hiring manager should not be able to tell this person was in the military unless they choose to mention it. Every single military term MUST be replaced with civilian language.\n" + "BANNED WORDS — never use these: NCO, NCOIC, OIC, MOS, AFSC, NEC, SGT, SSG, SFC, MSG, CSM, PFC, SPC, CPL, E-4, E-5, O-3, Soldier, Airman, Marine, Sailor, Guardian, Troop, Unit, Battalion, Brigade, Company, Platoon, Squad, TOC, SITREP, AAR, OPORD, TDY, PCS, ETS, TAD, SHARP (spell it out), Armorer (say Weapons Inventory Manager), Retention NCO (say Talent Acquisition Specialist), Drill Sergeant (say Training Instructor/Leadership Development Specialist), Airborne (say Parachute Operations Certified), MRE, Battle Rhythm, Hooah, Oorah, Hard Charger.\n" + "FULL JARGON TRANSLATION TABLE — translate ALL of these:\n" + "- NCO / Sergeant / Staff Sergeant = Team Leader / Operations Supervisor\n" + "- NCOIC = Operations Lead / Team Supervisor\n" + "- OIC = Program Manager / Department Lead\n" + "- 1SG/First Sergeant = Senior Operations Manager\n" + "- CSM/Command Sergeant Major = Chief of Staff / Senior Director\n" + "- Platoon Leader = Team Manager (30-50 personnel)\n" + "- Company Commander = Department Director (100-200 personnel)\n" + "- Battalion Commander = Division Director (500-800 personnel)\n" + "- S1/G1/J1 = Human Resources / Personnel Management\n" + "- S2/G2/J2 = Intelligence / Security Analysis\n" + "- S3/G3/J3 = Operations Management\n" + "- S4/G4/J4 = Logistics / Supply Chain Management\n" + "- S6/G6/J6 = Information Technology / Communications\n" + "- Unit Armorer = Weapons & Equipment Inventory Manager\n" + "- SHARP Representative = Employee Relations & Compliance Coordinator\n" + "- Retention NCO = Talent Acquisition & Career Development Specialist\n" + "- Drill Sergeant = Leadership Development Instructor\n" + "- Airborne qualified = Parachute Operations Certified (or just omit if not relevant)\n" + "- Supply Sergeant = Inventory & Logistics Manager\n" + "- Motor Transport = Fleet Operations & Vehicle Maintenance Manager\n" + "- Battalion / Brigade = Organization / Division\n" + "- Platoon of 40 soldiers = Team of 40 personnel\n" + "- TOC = Operations Center\n" + "- SITREP = Status Report / Progress Update\n" + "- AAR = After-Action Review / Post-Project Debrief\n" + "- OPORD = Operations Plan / Project Plan\n" + "- COR = Contract Oversight Manager\n" + "- PMCS = Preventive Maintenance Inspection Program\n" + "- SOP = Standard Operating Procedure / Process Documentation\n" + "- PT = Physical Fitness / Wellness Program\n" + "- FOB = Forward Operating Base / Remote Facility\n" + "- Deployed = Worked in austere / international / remote environment\n" + "- Secret clearance = Active Secret Security Clearance (keep this — it is valuable)\n" + "- TS/SCI = Active Top Secret/SCI Security Clearance (keep this — premium asset)\n\n" + "Return ONLY valid JSON, no markdown, starting with { ending with }.\n" + "Keys: name, contact (string), summary (2-3 sentence COMPELLING professional paragraph — not generic), " + "experience (array of {employer, title, dates, bullets:[4-6 strong civilian achievement bullets with quantified results]}), " + "education (array of {degree, school, year}), " + "skills (array of max 12 ATS-optimized skill strings matching the target industry), " + "certifications (array of strings), " + "clearance (string or null), " + "awards (array of strings), " + (resumeSections.volunteer ? "volunteer (array of {org, role, description}), " : "") + (resumeSections.languages ? "languages (array of strings), " : "") + "atsKeywords (array of 10-15 relevant keywords used in the resume)"; const raw = await callClaude( prompt, "You are an expert military-to-civilian career translator. RULES: 1) ZERO military jargon — translate everything to civilian language. 2) EMPLOYER/BRANCH NAME: Never change U.S. Army, U.S. Navy, U.S. Marine Corps, U.S. Air Force, U.S. Coast Guard, U.S. Space Force — keep exactly as written. 3) UNIT NAME: Never translate unit names — keep exactly as the veteran typed (e.g. 126 CTC stays 126 CTC). 4) RANK TRANSLATIONS: E5-E6=Supervisor, E7=Operations Manager, E8=Senior Manager, E9=Director, O3=Program Manager, O4=Senior PM, O5=Director, O6=Executive Director. 5) TITLE TRANSLATIONS: NCO=Supervisor, NCOIC=Operations Lead, Armorer=Equipment Inventory Manager, SHARP Rep=HR Compliance Coordinator, Retention NCO=Talent Acquisition Specialist, Supply Sgt=Logistics Manager, Motor Transport=Fleet Operations Manager. 6) METRICS: Only use numbers the veteran explicitly provided — never fabricate metrics. 7) Security clearances: ONLY include if the veteran selected to include it. If not selected, omit entirely. 8) Every bullet starts with a civilian action verb: Led, Managed, Directed, Coordinated, Developed, Implemented, Oversaw, Delivered.", 3500 ); const rStart = raw.indexOf("{"); const rEnd = raw.lastIndexOf("}"); if (rStart > -1 && rEnd > -1) { try { const rd = JSON.parse(raw.slice(rStart, rEnd + 1)); delete rd.careerPath; setResumeData(rd); } catch(pe) { console.warn("Resume JSON parse failed, using text mode:", pe.message); } } setResume(raw); setL("resume",false); // Auto-run ATS analysis after successful generation if (rStart > -1 && rEnd > -1) { runAtsAnalysis(raw.slice(rStart, rEnd + 1)); } } catch(e) { console.error("Resume generation failed:", e); setResume("Error generating resume: " + (e.message || "Please check your API key and try again.")); setL("resume",false); } }; // ── ATS ANALYSIS ────────────────────────────────────────────────────────── const runAtsAnalysis = async (resumeJson) => { setAtsLoading(true); setAtsAnalysis(null); try { const jdText = jobDescription ? "\nJOB DESCRIPTION:\n" + jobDescription.slice(0,1500) : ""; const atsPrompt = "Analyze this resume for ATS (Applicant Tracking System) optimization.\n\n" + "RESUME:\n" + (resumeJson||resume).slice(0,2500) + "\n" + "TARGET ROLE: " + (target.title||"general") + " | Industry: " + (target.industry||"any") + (targetCompany ? " | Company: " + targetCompany : "") + jdText + "\n\n" + "Return ONLY valid JSON:\n" + '{"atsScore": 0-100, "scoreBreakdown": {"keywordMatch": 0-100, "formatting": 0-100, "quantifiedAchievements": 0-100, "jargonFree": 0-100, "readability": 0-100}, ' + '"keywordsFound": ["keyword1","keyword2",...], "keywordsMissing": ["keyword1","keyword2",...], ' + '"improvements": [{"priority":"high|medium|low","suggestion":"specific improvement"},...], ' + '"verdict": "One sentence overall assessment"}'; const raw = await callClaude(atsPrompt, "You are an ATS optimization expert. Return ONLY valid JSON.", 1200); const clean = raw.replace(/```json|```/g,"").trim(); const s = clean.indexOf("{"); const e = clean.lastIndexOf("}"); if (s > -1 && e > -1) { setAtsAnalysis(JSON.parse(clean.slice(s, e + 1))); } } catch(err) { console.warn("ATS analysis failed:", err); } setAtsLoading(false); }; // ── JOB URL ANALYZER ───────────────────────────────────────────────────── const analyzeJobUrl = async () => { if (!hasAccess) { setShowPaywall(true); return; } if (!isApiKeySet()) { setShowAdminSetup(true); return; } if (!jobAnalyzerUrl.trim()) return; setJobAnalyzerLoading(true); setJobAnalyzerResult(null); const milSummary = milExperiences.map(e=>(e.branch||"")+" "+(e.rank||"")+" MOS:"+(e.mos||"")+" "+(e.mosTitle||"")+" TOS:"+(e.tos||"")).join("; "); const prompt = "I want you to analyze a job posting URL and compare it against a veteran's profile.\n\n" + "JOB POSTING URL: " + jobAnalyzerUrl.trim() + "\n\n" + "NOTE: You cannot actually visit URLs, so extract what you can from the URL structure (company name, job title hints) and provide your best analysis. If the URL contains company/title info, use that. Otherwise, ask the user to paste the job description instead.\n\n" + "VETERAN PROFILE:\n" + "Military: " + milSummary + "\n" + "Skills: " + (skills.technical||"none listed") + "\n" + "Leadership: " + (skills.leadership||"none listed") + "\n" + "Certifications: " + (skills.certs||"none") + "\n" + "Education: " + education.map(e=>(e.degree||"")+" "+(e.field||"")+" "+(e.institution||"")).join("; ") + "\n" + "Target Role: " + (target.title||"open") + " | Industry: " + (target.industry||"any") + "\n\n" + "Return ONLY valid JSON:\n" + '{"jobTitle":"extracted or inferred title","company":"extracted company","matchScore":0-100,' + '"strengths":["strength1","strength2","strength3"],' + '"gaps":["gap1","gap2"],' + '"actionItems":["action1","action2","action3"],' + '"keyQualifications":["qual1","qual2","qual3"],' + '"salaryEstimate":"estimated range or unknown",' + '"verdict":"honest 2-sentence assessment"}'; try { const raw = await callClaude(prompt, "You are a veteran career counselor and job matching expert. Be honest about gaps. Return ONLY valid JSON.", 1500); const clean = raw.replace(/```json|```/g,"").trim(); const s = clean.indexOf("{"); const e = clean.lastIndexOf("}"); if (s > -1 && e > -1) { setJobAnalyzerResult(JSON.parse(clean.slice(s, e + 1))); } } catch(err) { setJobAnalyzerResult({ error: "Could not analyze this job. Try pasting the job description in the Resume Builder instead." }); } setJobAnalyzerLoading(false); }; // ── COVER LETTER GENERATOR ──────────────────────────────────────────────── const genCoverLetter = async () => { if (!hasAccess) { setShowPaywall(true); return; } if (!isApiKeySet()) { setShowAdminSetup(true); return; } if (!resume && !resumeData && !uploadedResumeText) { alert("Please upload a resume file or generate one on the Build Resume tab."); return; } setCoverLetterLoading(true); setCoverLetter(""); const milSummary = milExperiences.map(e=>(e.branch)+" "+(e.rank||"")+" ("+(e.tos||"")+"), MOS: "+(e.mos||"")).join("; "); const resumeText = uploadedResumeText || resume || (resumeData ? JSON.stringify(resumeData) : ""); const prompt = `You are an expert military-to-civilian career counselor writing a compelling cover letter. VETERAN PROFILE: - Service: ${milSummary} - Name: ${personal.name||"[Name]"} TARGET JOB: - Title: ${coverLetterJob.title||"[Position]"} - Company: ${coverLetterJob.company||"[Company]"} - Job Description: ${coverLetterJob.description||"Not provided"} RESUME SUMMARY: ${resumeText.slice(0,1500)} Write a professional, warm, and compelling 3-paragraph cover letter that: 1. Opens with a strong hook connecting military service to the role 2. Highlights 2-3 specific achievements from their service that directly apply 3. Closes with confidence and a clear call to action 4. Translates ALL military jargon into civilian language 5. Is addressed to the hiring manager (use "Dear Hiring Manager" if no name given) 6. Is between 250-350 words Return ONLY the cover letter text, no subject line, no extra commentary.`; try { const raw = await callClaude(prompt, "You are an expert military-to-civilian career translator. RULES: 1) ZERO military jargon — translate everything to civilian language. 2) EMPLOYER/BRANCH NAME: Never change U.S. Army, U.S. Navy, U.S. Marine Corps, U.S. Air Force, U.S. Coast Guard, U.S. Space Force — keep exactly as written. 3) UNIT NAME: Never translate unit names — keep exactly as the veteran typed (e.g. 126 CTC stays 126 CTC). 4) RANK TRANSLATIONS: E5-E6=Supervisor, E7=Operations Manager, E8=Senior Manager, E9=Director, O3=Program Manager, O4=Senior PM, O5=Director, O6=Executive Director. 5) TITLE TRANSLATIONS: NCO=Supervisor, NCOIC=Operations Lead, Armorer=Equipment Inventory Manager, SHARP Rep=HR Compliance Coordinator, Retention NCO=Talent Acquisition Specialist, Supply Sgt=Logistics Manager, Motor Transport=Fleet Operations Manager. 6) METRICS: Only use numbers the veteran explicitly provided — never fabricate metrics. 7) Security clearances: ONLY include if the veteran selected to include it. If not selected, omit entirely. 8) Every bullet starts with a civilian action verb: Led, Managed, Directed, Coordinated, Developed, Implemented, Oversaw, Delivered.", 1500); setCoverLetter(raw); } catch(e) { setCoverLetter("Error generating cover letter. Please try again."); } setCoverLetterLoading(false); }; // ── INTERVIEW PREP GENERATOR ────────────────────────────────────────────── const genInterviewPrep = async () => { if (!hasAccess) { setShowPaywall(true); return; } if (!isApiKeySet()) { setShowAdminSetup(true); return; } setPrepLoading(true); setPrepQuestions([]); const milSummary = milExperiences.map(e=>(e.branch)+" "+(e.rank||"")+" MOS "+(e.mos||"")+" ("+(e.tos||"")+")").join("; "); const prompt = `You are an elite interview coach for military veterans transitioning to civilian careers. VETERAN: ${milSummary} APPLYING FOR: ${prepJob.title||"a civilian role"} at ${prepJob.company||"a company"} INTERVIEW TYPE: ${prepJob.type} Generate 8 interview questions they will likely be asked, with a tailored answer strategy using their military background. Return ONLY valid JSON array: [{ "question": "Tell me about yourself.", "whyAsked": "Sets the tone, they want your career story", "answerStrategy": "Start with military service, bridge to civilian value, end with why this role", "starExample": "Situation: As a [rank] in [branch]... Task: I was responsible for... Action: I implemented... Result: This led to...", "tip": "Keep it under 2 minutes. Practice out loud." }] Make answers specific to their MOS and rank. Use the STAR method. Translate all military jargon.`; try { const raw = await callClaude(prompt, "You are an expert military-to-civilian career translator. RULES: 1) ZERO military jargon — translate everything to civilian language. 2) EMPLOYER/BRANCH NAME: Never change U.S. Army, U.S. Navy, U.S. Marine Corps, U.S. Air Force, U.S. Coast Guard, U.S. Space Force — keep exactly as written. 3) UNIT NAME: Never translate unit names — keep exactly as the veteran typed (e.g. 126 CTC stays 126 CTC). 4) RANK TRANSLATIONS: E5-E6=Supervisor, E7=Operations Manager, E8=Senior Manager, E9=Director, O3=Program Manager, O4=Senior PM, O5=Director, O6=Executive Director. 5) TITLE TRANSLATIONS: NCO=Supervisor, NCOIC=Operations Lead, Armorer=Equipment Inventory Manager, SHARP Rep=HR Compliance Coordinator, Retention NCO=Talent Acquisition Specialist, Supply Sgt=Logistics Manager, Motor Transport=Fleet Operations Manager. 6) METRICS: Only use numbers the veteran explicitly provided — never fabricate metrics. 7) Security clearances: ONLY include if the veteran selected to include it. If not selected, omit entirely. 8) Every bullet starts with a civilian action verb: Led, Managed, Directed, Coordinated, Developed, Implemented, Oversaw, Delivered.", 3000); const clean = raw.replace(/```json|```/g,"").trim(); const s = clean.indexOf("["); const e = clean.lastIndexOf("]"); if(s===-1||e===-1) throw new Error("No array"); setPrepQuestions(JSON.parse(clean.slice(s,e+1))); } catch(err) { setPrepQuestions([{ question:"Tell me about yourself.", whyAsked:"Opens the interview and sets the tone", answerStrategy:"Lead with your military service, highlight your top 2-3 skills, connect to this specific role, end with your excitement about the opportunity.", starExample:"I served "+milSummary+". I built strong skills in leadership and operations that I am excited to bring to this role.", tip:"Practice this until it feels natural. This is your elevator pitch." }]); } setPrepLoading(false); }; // ── FOLLOW-UP EMAIL GENERATOR ───────────────────────────────────────────── const genFollowupEmail = async () => { if (!hasAccess) { setShowPaywall(true); return; } if (!isApiKeySet()) { setShowAdminSetup(true); return; } setFollowupLoading(true); setFollowupEmail(""); const milSum = milExperiences.map(e=>(e.branch)+" "+(e.rank||"")).join(", "); const emailTypes = { "thank-you": "a warm, professional thank-you email after an interview", "follow-up": "a polite follow-up email checking on application status after 1 week of silence", "negotiation": "a professional salary negotiation email asking for a higher offer", "withdraw": "a gracious email withdrawing from consideration while keeping the door open" }; const prompt = `Write ${emailTypes[followupCtx.outcome]||"a professional email"}. Veteran: ${personal.name||"[Name]"} | Service: ${milSum} Role: ${followupCtx.role||"the position"} at ${followupCtx.company||"your company"} Interviewer: ${followupCtx.interviewerName||"Hiring Manager"} Interview date: ${followupCtx.date||"recently"} Write a genuine, professional email that: - Is NOT overly formal or stiff - References something specific from the conversation if possible (be generic if no details) - Subtly reinforces their military background as an asset - Is under 150 words - Has a clear subject line on the first line starting with "Subject: " Return ONLY the email text including the subject line. No extra commentary.`; try { const raw = await callClaude(prompt, "You are an expert military-to-civilian career translator. RULES: 1) ZERO military jargon — translate everything to civilian language. 2) EMPLOYER/BRANCH NAME: Never change U.S. Army, U.S. Navy, U.S. Marine Corps, U.S. Air Force, U.S. Coast Guard, U.S. Space Force — keep exactly as written. 3) UNIT NAME: Never translate unit names — keep exactly as the veteran typed (e.g. 126 CTC stays 126 CTC). 4) RANK TRANSLATIONS: E5-E6=Supervisor, E7=Operations Manager, E8=Senior Manager, E9=Director, O3=Program Manager, O4=Senior PM, O5=Director, O6=Executive Director. 5) TITLE TRANSLATIONS: NCO=Supervisor, NCOIC=Operations Lead, Armorer=Equipment Inventory Manager, SHARP Rep=HR Compliance Coordinator, Retention NCO=Talent Acquisition Specialist, Supply Sgt=Logistics Manager, Motor Transport=Fleet Operations Manager. 6) METRICS: Only use numbers the veteran explicitly provided — never fabricate metrics. 7) Security clearances: ONLY include if the veteran selected to include it. If not selected, omit entirely. 8) Every bullet starts with a civilian action verb: Led, Managed, Directed, Coordinated, Developed, Implemented, Oversaw, Delivered.", 800); setFollowupEmail(raw.trim()); } catch(err) { setFollowupEmail("Subject: Thank You - " + (followupCtx.role||"Position") + " Interview\n\nDear " + (followupCtx.interviewerName||"Hiring Manager") + ",\n\nThank you for taking the time to meet with me regarding the " + (followupCtx.role||"position") + " role at " + (followupCtx.company||"your organization") + ". I enjoyed learning more about the team and am excited about the opportunity to bring my military leadership experience to your organization.\n\nPlease let me know if you need any additional information.\n\nBest regards,\n" + (personal.name||"[Your Name]")); } setFollowupLoading(false); }; // ── RESUME REVIEW / SCORE ───────────────────────────────────────────────── const runResumeReview = async () => { if (!hasAccess) { setShowPaywall(true); return; } if (!isApiKeySet()) { setShowAdminSetup(true); return; } if (!resume && !resumeData && !uploadedResumeText) { alert("Please upload a resume file or generate one first."); return; } setReviewLoading(true); setResumeScore(null); setResumeReview(null); const resumeText = uploadedResumeText || resume || JSON.stringify(resumeData||{}); const prompt = `You are an expert resume reviewer for military-to-civilian career transitions. Analyze this resume and return ONLY valid JSON. RESUME: ${resumeText.slice(0,2000)} TARGET JOB: ${target.title||"General civilian role"} Return this exact JSON structure: { "overallScore": 82, "grades": { "impact": { "score": 85, "label": "Impact & Achievements" }, "clarity": { "score": 78, "label": "Clarity & Civilian Language" }, "keywords": { "score": 80, "label": "Keywords & ATS" }, "formatting": { "score": 88, "label": "Format & Length" }, "military": { "score": 72, "label": "Military Translation" } }, "strengths": ["strength 1", "strength 2", "strength 3"], "improvements": [ { "priority": "HIGH", "issue": "Issue title", "fix": "Specific fix to make" }, { "priority": "MEDIUM", "issue": "Issue title", "fix": "Specific fix to make" }, { "priority": "LOW", "issue": "Issue title", "fix": "Specific fix to make" } ], "missingKeywords": ["keyword1", "keyword2", "keyword3"], "verdict": "One sentence overall assessment" }`; try { const raw = await callClaude(prompt, "You are an expert resume reviewer. Return ONLY valid JSON, no markdown, no commentary.", 1500); const clean = raw.replace(/```json|```/g,"").trim(); const data = JSON.parse(clean); setResumeScore(data.overallScore); setResumeReview(data); } catch(e) { setResumeReview({ error: "Could not analyze resume. Make sure your resume is generated first." }); } setReviewLoading(false); }; const copy = () => { navigator.clipboard.writeText(resume); setCopied(true); setTimeout(()=>setCopied(false),2200); }; const TABS = ["My Service Record","Career Pathways","Build Resume","Cover Letter & Review","Job Search Hub","My Profile"]; const TAB_ICONS = ["\u{1F396}\uFE0F","\u{1F3AF}","\u{1F4C4}","\u{2709}\uFE0F","\u{1F50D}","\u{1F464}"]; const AI_TABS = [2,3,4]; // tabs that are AI-powered tools const isMilType = t => t==="Military Service"||t==="Reserve/Guard (concurrent with civilian)"; const DI = "Defense/Intel"; const RG = "Reserve/Guard (concurrent with civilian)"; const matchesSector = (c, filter) => filter==="All" || c.sector===filter || (filter===DI && c.sector===DI); const filterCareers = (careers, filter) => careers.filter(c => matchesSector(c, filter)); // Hide loading skeleton on first render useEffect(() => { const skel = document.getElementById('app-skeleton'); if (skel) skel.style.display = 'none'; }, []); // Profile dropdown state const [profileOpen, setProfileOpen] = useState(false); const [showAccountSettings, setShowAccountSettings] = useState(false); const profileRef = useRef(null); useEffect(() => { const handler = (e) => { if (profileRef.current && !profileRef.current.contains(e.target)) setProfileOpen(false); }; document.addEventListener('mousedown', handler); return () => document.removeEventListener('mousedown', handler); }, []); return ( <>
{/* ── PROFILE ICON (top-right) ── */}
{profileOpen&¤tUser&&(
{personal.name||currentUser.displayName||"Veteran"}
{personal.email||currentUser.email||""}
)}
{/* ── ACCOUNT SETTINGS MODAL ── */} {showAccountSettings&¤tUser&&(()=>{ let accessData = null; try { accessData = JSON.parse(localStorage.getItem("vcb_access")||"null"); } catch(e){} const isSubscribed = hasAccess; const planLabel = accessData ? (accessData.type==="paid" ? (accessData.plan==="annual"?"Annual Plan":"Monthly Plan") : accessData.type==="code" ? "Access Code" : "Active") : null; const expiryDate = accessData && accessData.expiry ? new Date(accessData.expiry).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"}) : null; return (
{if(e.target===e.currentTarget)setShowAccountSettings(false);}}>
Account Settings
Account Info
{(()=>{const m=milExperiences&&milExperiences[0];const g=m&&m.rank?(m.rank.match(/[EWO]-\d+/)||[""])[0]:"";return g?React.createElement(RankInsignia,{branch:m.branch,grade:g,color:"#1a3a6b"}):null;})()} {(()=>{const m=milExperiences&&milExperiences[0];const r=m&&m.rank?m.rank.split(" - ").pop().split(" (")[0]:"";const isRet=m&&(m.serviceType==="Retired"||m.status==="Retired"||(m.endDate&&!m.currently));return (r?r+" ":"")+(personal.name||currentUser.displayName||"Veteran")+(isRet?" (Ret.)":"");})()}
{personal.email||currentUser.email||""}
Subscription Status
{isSubscribed?(
Active {planLabel&&{planLabel}}
{expiryDate&&
Access expires: {expiryDate}
}
):(
No active subscription
Subscribe to unlock all 16 AI-powered career tools.
)}
Quick Stats
{savedResumes.length}
Resumes
{savedCoverLetters.length}
Cover Letters
{savedScores.length}
Score Reports
{savedEmails.length}
Emails
); })()} {showPaywall&&(
e.target===e.currentTarget&&null}>
Veteran Career Path

AI-powered tools to translate your service into a civilian career

$15
Monthly Subscription
$15/month — 16 AI tools
{["AI Career Matching","Military Language Translator","AI Resume Builder","5 Resume Templates","Cover Letter Generator","Resume Score & Review","Job Application Tracker","Interview Prep Generator","Follow-Up Email Generator","Transition Timeline","Weekly Progress Dashboard","Veteran Resources Hub"].map((f,i)=>(
{f}
))}
OR ENTER ACCESS CODE
{setPwCode(e.target.value.toUpperCase());setPwCodeStatus("idle");setPwCodeMsg("");}} onKeyDown={e=>e.key==="Enter"&&redeemCode()} style={{textTransform:"uppercase",letterSpacing:".1em",fontWeight:600}} />
{pwCodeMsg&&(
{pwCodeMsg}
)}
{(!fbAuth||!fbAuth.currentUser)&&( )}
$15/month · 16 AI tools · cancel anytime
Already have an account?{" "}
)} {showAuth&&(
e.target===e.currentTarget&&setShowAuth(false)}>
🎖
Veteran Career Path
Free account — save your profile and resumes
{authErr&&
{authErr}
} {authOk&&
{authOk}
}
OR EMAIL
{authMode==="register"&&(
setAuthForm(f=>({...f,name:e.target.value}))}/>
)}
setAuthForm(f=>({...f,username:e.target.value}))} onKeyDown={e=>e.key==="Enter"&&(authMode==="login"?handleLogin():handleRegister())}/>
setAuthForm(f=>({...f,password:e.target.value}))} onKeyDown={e=>e.key==="Enter"&&(authMode==="login"?handleLogin():handleRegister())}/>
{authMode==="register"&&(
setAuthForm(f=>({...f,confirmPassword:e.target.value}))}/>
)} {authMode==="login"&&(
)}
)} {showAdminSetup&&(
⚙ Site Owner Setup
This panel is only for the site owner — not visible to users
{adminKeySet?(
✓ API key is configured — AI features are enabled
):(
AI features are enabled via the Vercel proxy. If you need to override with a direct API key, enter it below.
)}
setAdminKeyInput(e.target.value)} style={{width:"100%",background:"rgba(255,255,255,.92)",border:"1.5px solid rgba(201,168,76,.5)",borderRadius:"3px",color:"#1a1a2e",padding:".65rem .85rem",fontFamily:"monospace",fontSize:".9rem"}} />
{adminKeySet&&( )}
)} {currentUser?(
{(()=>{ const latestMil = milExperiences && milExperiences[0]; const rank = latestMil && latestMil.rank; const grade = rank ? (rank.match(/[EWO]-\d+/)||[""])[0] : ""; const branch = latestMil && latestMil.branch; const isRetired = latestMil && (latestMil.serviceType==="Retired" || latestMil.status==="Retired" || (latestMil.endDate && !latestMil.currently)); const rankAbbr = rank || ""; const displayName = rankAbbr ? (rankAbbr.split(" - ").pop().split(" (")[0] + " " + (personal.name||currentUser.name||"").split(" ").pop()) : (personal.name||currentUser.name||"Veteran"); const insigniaUrl = (grade && window.VCP_INSIGNIA) ? window.VCP_INSIGNIA.get(branch||"Army",grade) : null; return React.createElement("div",{style:{display:"flex",alignItems:"center",gap:".4rem"}}, insigniaUrl ? React.createElement("img",{src:insigniaUrl,alt:grade+" insignia",style:{height:"28px",width:"auto",flexShrink:0,filter:"drop-shadow(0 1px 2px rgba(0,0,0,.3))"}}) : React.createElement("div",{className:"user-avatar"},(currentUser&¤tUser.initials)), React.createElement("span",null, "Welcome Back, ", React.createElement("strong",null,displayName), isRetired ? React.createElement("span",{style:{fontSize:".72rem",color:"rgba(240,192,64,.7)",marginLeft:".25rem",fontStyle:"italic"}},"(Ret.)") : null ) ); })()} {hasUnsaved&&}
{!hasAccess&&} {window.location.search.indexOf("admin=1")>-1&&}
):(
Not signed in — your progress won't be saved
)}
Veteran to Civilian Career Transitions
{TABS.map((t,i)=>( {i===2&&
AI
} {i===5&&
·
}
))}
{TABS.map((_,i)=>
)}
{tab===0 &&
{/* ── SCOUT DATA CODE IMPORT ── */}
🔑 Have a Scout Data Code? Import your profile

If you previously used the Scout Resume Builder or Cover Letter Builder, enter your email and 6-digit data code to automatically import your military experience, skills, and career data into your profile.

{/* ── GUIDED WIZARD LAUNCH BUTTON ── */} {profileMode==="manual"&&
} {profileMode==="guided"&&
} {/* ══ GUIDED WIZARD ══ */} {profileMode==="guided" && ( )} {/* ══ MANUAL ENTRY (existing form) ══ */} {profileMode==="manual" && <>
Your service matters. Fill in your background below — your military experience, civilian work, education, and skills. The more you add, the better your career matches and resume will be. Take your time and be as detailed as you like.
toggleCollapse("personal")}>

Personal Information

{!collapsed.personal &&
upP("name",e.target.value)}/>
upP("email",e.target.value)}/>
upP("phone",e.target.value)}/>
upP("location",e.target.value)}/>
upP("linkedin",e.target.value)}/>
}

Military Service History

All Branches Served
OPSEC WARNING
Do not include identifying information about your unit, personnel, equipment, or operations that is not public knowledge. Be vague with specifics. Present yourself as the asset you are without violating OPSEC.
DoD OPSEC Guidelines
{milExperiences.map((exp)=>(
{exp.branch||"Military Service"} · {exp.serviceType||"Active Duty"} {milExperiences.length>1&&}
{ const val = e.target.value.toUpperCase(); upMilExp(exp.id,"mos",val); }} style={{paddingRight:"2.5rem"}} /> {exp.mosTitle&&( ✓ {exp.mosTitle} )}
Type your code above — it auto-fills the title. Or browse by branch:
Browse {exp.branch} {exp.branch==="Navy"?"Rates":exp.branch==="Air Force"||exp.branch==="Space Force"?"AFSCs":"MOS codes"} {getMosByBranch(exp.branch).length} codes ›
{ const q=e.target.value.toLowerCase(); const items=document.querySelectorAll(`.mos-lookup-item-${exp.id}`); items.forEach(item=>{ item.style.display=(item.dataset.code.toLowerCase().includes(q)||item.dataset.title.toLowerCase().includes(q))?"flex":"none"; }); }} />
{getMosByBranch(exp.branch).map(m=>( ))}
upMilExp(exp.id,"tos",e.target.value)}/>
upMilExp(exp.id,"unit",e.target.value)}/>
upMilExp(exp.id,"startDate",v)} placeholder="Select start date"/>
{exp.current ?
Present
: upMilExp(exp.id,"endDate",v)} placeholder="Select end date"/> }
upMilExp(exp.id,"current",e.target.checked)} style={{width:"auto"}}/>

Roles Held Under This MOS
Add each official position you held under this MOS — even within the same contract. Example: 88M as Operator (E-4, 2020-2022) → Dispatcher (E-5, 2022-2024) → Platoon Sergeant (E-6, 2024-2026). This shows career progression, not just time served.
{(exp.mosRoles||[]).map((role,ri)=>(
Position {ri+1}
{ const updated=[...(exp.mosRoles||[])]; updated[ri]={...updated[ri],title:e.target.value}; upMilExp(exp.id,"mosRoles",updated); }}/>
{ const updated=[...(exp.mosRoles||[])]; updated[ri]={...updated[ri],rankAtRole:e.target.value}; upMilExp(exp.id,"mosRoles",updated); }}/>
{ const updated=[...(exp.mosRoles||[])]; updated[ri]={...updated[ri],fromYear:e.target.value}; upMilExp(exp.id,"mosRoles",updated); }}/>
{ const updated=[...(exp.mosRoles||[])]; updated[ri]={...updated[ri],toYear:e.target.value}; upMilExp(exp.id,"mosRoles",updated); }}/>
{ const updated=[...(exp.mosRoles||[])]; updated[ri]={...updated[ri],keyDuty:e.target.value}; upMilExp(exp.id,"mosRoles",updated); }}/>
))}

🔐 Security Clearance

{exp.clearanceLevel!=="None"&&{exp.clearanceLevel}}

{(BRANCH_QUALS[exp.branch]||BRANCH_QUALS["Army"]).label}
Browse common qualifiers {(BRANCH_QUALS[exp.branch]||BRANCH_QUALS["Army"]).items.length} options ›
{(BRANCH_QUALS[exp.branch]||BRANCH_QUALS["Army"]).items.map(a=>( ))}
{(exp.asi||[]).length>0&&(
{(exp.asi||[]).map(a=>( {a.code} {a.desc} upMilExp(exp.id,"asi",(exp.asi||[]).filter(x=>x.code!==a.code))}>✕ ))}
)}
upMilExp(exp.id,"customAsiCode",e.target.value)}/>
upMilExp(exp.id,"customAsiDesc",e.target.value)}/>

{(BRANCH_QUALS[exp.branch]||BRANCH_QUALS["Army"]).sqiLabel}
Browse qualifiers {(BRANCH_QUALS[exp.branch]||BRANCH_QUALS["Army"]).sqi.length} options ›
{(BRANCH_QUALS[exp.branch]||BRANCH_QUALS["Army"]).sqi.map(s=>( ))}
{(exp.sqi||[]).length>0&&(
{(exp.sqi||[]).map(s=>( {s.code} {s.desc} upMilExp(exp.id,"sqi",(exp.sqi||[]).filter(x=>x.code!==s.code))}>✕ ))}
)}

Additional Duty Qualifications
{[ {cat:"Command & Admin",items:["Unit Armorer","Unit Fund Custodian","Property Book Officer","Inspector General Representative","Records Management","Battle Staff NCO"]}, {cat:"Training & Safety",items:["Training Room NCO","Safety Officer/NCO","Master Driver","Master Gunner","Physical Fitness Leader","NBC/CBRN Officer"]}, {cat:"Personnel & HR",items:["Equal Opportunity Leader","Sexual Harassment/Assault Response (SHARP) Coordinator","Casualty Notification Officer","Family Readiness Officer/NCO","Retention NCO","Recruiter/Career Counselor"]}, {cat:"Operations",items:["Operations Security (OPSEC) Coordinator","Information Security Officer","Physical Security Officer","Supply Sergeant (additional duty)","Contracting Officer Representative (COR)","Unit Prevention Leader (UPL/Drug Testing)"]}, {cat:"Community & Liaison",items:["Casualty Liaison Officer","Community Outreach Coordinator","Voting Assistance Officer","Religious Affairs NCO"]}, ].map(grp=>(
{grp.cat} {grp.items.length} options ›
{grp.items.map(d=>( ))}
))} {(exp.additionalDuties||[]).length>0&&(
{(exp.additionalDuties||[]).map(d=>( {d} upMilExp(exp.id,"additionalDuties",(exp.additionalDuties||[]).filter(x=>x!==d))}>✕ ))}
)}
upMilExp(exp.id,"customDuty",e.target.value)} onKeyDown={e=>{ if(e.key==="Enter"&&(exp.customDuty||"").trim()){ upMilExp(exp.id,"additionalDuties",[...(exp.additionalDuties||[]),exp.customDuty.trim()]); upMilExp(exp.id,"customDuty",""); }}}/>
Awards & Decorations
Select from the library or type your own. Awards are pulled from the {exp.branch} awards list.
{(exp.awards||[]).length>0&&(
{(exp.awards||[]).map((a,i)=>( 🎖 {a} upMilExp(exp.id,"awards",(exp.awards||[]).filter((_,j)=>j!==i))}>✕ ))}
)}
upMilExp(exp.id,"customAward",e.target.value)} onKeyDown={e=>{ if(e.key==="Enter"&&(exp.customAward||"").trim()){ upMilExp(exp.id,"awards",[...(exp.awards||[]),exp.customAward.trim()]); upMilExp(exp.id,"customAward",""); } }}/>