"use client"; import { useState, useEffect, useMemo } from "react"; import { motion } from "framer-motion"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Progress } from "@/components/ui/progress"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ArrowLeft, Download, Star, Briefcase, GraduationCap, Code, Languages, FolderOpen, Loader2, BookOpen, Users, Award, Trophy, LinkedinIcon, GithubIcon, PenBox, ExternalLink, Sparkles, RefreshCw, Wand2, FileText, FileDown, } from "lucide-react"; import Link from "next/link"; import { useParams, useRouter, useSearchParams } from "next/navigation"; import { useSession } from "next-auth/react"; import { renderMarkdownInline } from "@/lib/markdown-renderer"; import MarkdownRenderer from "@/components/ui/markdown-renderer"; import { useResume } from "@/hooks/queries"; import { EnrichmentModal } from "@/components/enrichment"; import { RegenerateDialog } from "@/components/regeneration"; import { JDEditPanel } from "@/components/jd-editor/jd-edit-panel"; import ExportTab from "@/components/pdf-resume/ExportTab"; import { ResumeEditorTab } from "@/components/resume-editor/resume-editor-tab"; import type { SelectableItem } from "@/types/enrichment"; import type { JDEditResponse } from "@/types/jd-editor"; type WorkspaceTab = | "overview" | "edit" | "enrich" | "improve-by-jd" | "regenerate" | "export"; export default function AnalysisPage() { const params = useParams(); const id = params?.id as string; const router = useRouter(); const searchParams = useSearchParams(); const { data: session, status } = useSession(); const { data: analysisData, isLoading, error, refetch } = useResume(id); // Derive active tab from ?tab= query param; default to "overview" const initialTab = (searchParams.get("tab") as WorkspaceTab | null) ?? "overview"; const [activeTab, setActiveTab] = useState(initialTab); // Modal states (enrichment + regenerate still use modals for now) const [isEnrichmentOpen, setIsEnrichmentOpen] = useState(false); const [isRegenerateOpen, setIsRegenerateOpen] = useState(false); // Pre-fill JD params from URL (from ATS page) const jdParam = searchParams.get("jd") ?? ""; const jdUrlParam = searchParams.get("jdUrl") ?? ""; const companyParam = searchParams.get("company") ?? ""; // Build selectable items for regeneration — must be before any early returns const selectableItems: SelectableItem[] = useMemo(() => { const items: SelectableItem[] = []; const analysis = analysisData?.analysis; if (!analysis) return items; if (analysis.workExperience) { analysis.workExperience.forEach((work: any, index: number) => { items.push({ id: `experience-${index}`, type: "experience", title: work.role || "Untitled Role", subtitle: work.company_and_duration, content: work.bullet_points || [], selected: false, }); }); } if (analysis.projects) { analysis.projects.forEach((project: any, index: number) => { items.push({ id: `project-${index}`, type: "project", title: project.title || "Untitled Project", subtitle: project.technologies_used?.join(", "), content: project.description ? [project.description] : [], selected: false, }); }); } if (analysis.publications) { analysis.publications.forEach((pub: any, index: number) => { const subtitleParts: string[] = []; if (pub.journal_conference) subtitleParts.push(pub.journal_conference); if (pub.year) subtitleParts.push(pub.year); items.push({ id: `publication-${index}`, type: "publication", title: pub.title || "Untitled Publication", subtitle: subtitleParts.length > 0 ? subtitleParts.join(", ") : undefined, content: pub.authors ? [pub.authors] : [], selected: false, }); }); } if (analysis.positionsOfResponsibility) { analysis.positionsOfResponsibility.forEach((pos: any, index: number) => { const subtitleParts: string[] = []; if (pos.organization) subtitleParts.push(pos.organization); if (pos.duration) subtitleParts.push(pos.duration); items.push({ id: `position-${index}`, type: "position", title: pos.title || "Untitled Position", subtitle: subtitleParts.length > 0 ? subtitleParts.join(", ") : undefined, content: pos.description ? [pos.description] : [], selected: false, }); }); } if (analysis.certifications) { analysis.certifications.forEach((cert: any, index: number) => { const subtitleParts: string[] = []; if (cert.issuing_organization) subtitleParts.push(cert.issuing_organization); if (cert.issue_date) subtitleParts.push(cert.issue_date); items.push({ id: `certification-${index}`, type: "certification", title: cert.name || "Untitled Certification", subtitle: subtitleParts.length > 0 ? subtitleParts.join(", ") : undefined, content: cert.credential_id ? [cert.credential_id] : [], selected: false, }); }); } if (analysis.achievements) { analysis.achievements.forEach((ach: any, index: number) => { const subtitleParts: string[] = []; if (ach.year) subtitleParts.push(ach.year); if (ach.category) subtitleParts.push(ach.category); items.push({ id: `achievement-${index}`, type: "achievement", title: ach.title || "Untitled Achievement", subtitle: subtitleParts.length > 0 ? subtitleParts.join(", ") : undefined, content: ach.description ? [ach.description] : [], selected: false, }); }); } if (analysis.education) { analysis.education.forEach((edu: any, index: number) => { items.push({ id: `education-${index}`, type: "education", title: edu.education_detail || "Untitled Education", subtitle: undefined, content: edu.education_detail ? [edu.education_detail] : [], selected: false, }); }); } return items; }, [ analysisData?.analysis?.workExperience, analysisData?.analysis?.projects, analysisData?.analysis?.publications, analysisData?.analysis?.positionsOfResponsibility, analysisData?.analysis?.certifications, analysisData?.analysis?.achievements, analysisData?.analysis?.education, ]); useEffect(() => { if (status === "unauthenticated") { router.push("/auth/signin"); } }, [status, router]); if (status === "loading" || isLoading) { return (

Loading resume workspace…

); } if (error || !analysisData) { return (

{error ? (error as Error).message : "No analysis data found"}

); } const { resume, analysis } = analysisData; const handleEnrichmentComplete = () => refetch(); const handleRegenerateComplete = () => refetch(); const handleJDEditApply = async (_response: JDEditResponse) => { // TODO: persist edited resume to DB (Phase 3 / DB endpoint) // For now just refetch so the workspace reflects any upstream changes await refetch(); }; return (
{/* Sticky header */}
{/* Page header */}

Resume Workspace

{analysis.name || "Candidate"} — {resume.customName}

{/* Tabbed workspace */} setActiveTab(v as WorkspaceTab)} > Overview Edit Enrich Improve by JD Regenerate Export {/* ── Overview ─────────────────────────────────────────────── */}
{/* Main Content */}
{/* Skills Analysis */} Skills Analysis {analysis.skillsAnalysis && analysis.skillsAnalysis.length > 0 ? ( analysis.skillsAnalysis.map((skill: any, index: number) => (
{skill.skill_name} {skill.percentage}%
)) ) : (

No skills analysis available

)}
{/* Work Experience */} Work Experience {analysis.workExperience && analysis.workExperience.length > 0 ? ( analysis.workExperience.map((work: any, index: number) => (

{work.role}

{work.company_and_duration}

{work.bullet_points && work.bullet_points.length > 0 && (
    {work.bullet_points.map((point: string, i: number) => (
  • {renderMarkdownInline(point ?? "")}
  • ))}
)}
)) ) : (

No work experience data available

)}
{/* Projects */} Projects {analysis.projects && analysis.projects.length > 0 ? ( analysis.projects.map((project: any, index: number) => (

{project.title}

{(project.live_link || project.repo_link) && (
{project.live_link && ( )} {project.repo_link && ( )}
)}
{project.technologies_used && project.technologies_used.length > 0 && (
{project.technologies_used.map((tech: string, i: number) => ( {tech} ))}
)}
)) ) : (

No projects data available

)}
{/* Publications */} {analysis.publications && analysis.publications.length > 0 && ( Publications {analysis.publications.map((publication: any, index: number) => (

{publication.title}

{publication.authors &&

Authors: {publication.authors}

} {publication.journal_conference &&

{publication.journal_conference}

} {publication.year &&

Year: {publication.year}

} {publication.doi &&

DOI: {publication.doi}

} {publication.url && View Publication}
))}
)} {/* Positions of Responsibility */} {analysis.positionsOfResponsibility && analysis.positionsOfResponsibility.length > 0 && ( Positions of Responsibility {analysis.positionsOfResponsibility.map((position: any, index: number) => (

{position.title}

{position.organization}

{position.duration &&

{position.duration}

} {position.description && (
)}
))}
)} {/* Certifications */} {analysis.certifications && analysis.certifications.length > 0 && ( Certifications {analysis.certifications.map((certification: any, index: number) => (

{certification.name}

{certification.issuing_organization}

{certification.issue_date &&

Issued: {certification.issue_date}

} {certification.expiry_date &&

Expires: {certification.expiry_date}

} {certification.credential_id &&

ID: {certification.credential_id}

} {certification.url && View Certificate}
))}
)} {/* Achievements */} {analysis.achievements && analysis.achievements.length > 0 && ( Achievements {analysis.achievements.map((achievement: any, index: number) => (

{achievement.title}

{achievement.category && ( {achievement.category} )} {achievement.year &&

{achievement.year}

} {achievement.description && (
)}
))}
)}
{/* Sidebar */}
{/* Candidate Info */} Candidate Information {analysis.name && (
Name:

{analysis.name}

)} {analysis.email && (
Email:

{analysis.email}

)} {analysis.contact && (
Contact:

{analysis.contact}

)} {analysis.predictedField && (
Predicted Field:

{analysis.predictedField}

)} {(analysis.linkedin || analysis.github || analysis.blog || analysis.portfolio) && (
Links:
{analysis.linkedin && ( {(() => { const link = analysis.linkedin!; try { const url = new URL(link); return url.pathname.replace(/^\/+/, "") || url.search.replace(/^\?/, "") || url.hash.replace(/^#/, ""); } catch { const idx = link.indexOf("linkedin.com/"); return idx !== -1 ? link.slice(idx + "linkedin.com/".length) : link; } })()} )} {analysis.github && ( {(() => { const link = analysis.github!; try { const url = new URL(link); return url.pathname.replace(/^\/+/, "") || url.search.replace(/^\?/, "") || url.hash.replace(/^#/, ""); } catch { const idx = link.indexOf("github.com/"); return idx !== -1 ? link.slice(idx + "github.com/".length) : link; } })()} )} {analysis.blog && ( {(() => { const link = analysis.blog!; try { const url = new URL(link); return `${url.host}${url.pathname}${url.search}${url.hash}`.replace(/\/$/, ""); } catch { return link.replace(/^https?:\/\//, "").replace(/\/$/, ""); } })()} )} {analysis.portfolio && ( {(() => { const link = analysis.portfolio!; try { const url = new URL(link); return `${url.host}${url.pathname}${url.search}${url.hash}`.replace(/\/$/, ""); } catch { return link.replace(/^https?:\/\//, "").replace(/\/$/, ""); } })()} )}
)}
{/* Recommended Roles */} Recommended Roles
{analysis.recommendedRoles && analysis.recommendedRoles.length > 0 ? ( analysis.recommendedRoles.map((role: string, index: number) => ( {role} )) ) : (

No role recommendations available

)}
{/* Languages */} Languages
{analysis.languages && analysis.languages.length > 0 ? ( analysis.languages.map((lang: any, index: number) => (
{lang.language}
)) ) : (

No language information available

)}
{/* Education */} Education
{analysis.education && analysis.education.length > 0 ? ( analysis.education.map((edu: any, index: number) => (

{edu.education_detail}

)) ) : (

No education information available

)}
{/* ── Edit ──────────────────────────────────────────────── */} {/* ── Enrich ───────────────────────────────────────────────── */} Enrich Resume

Answer targeted questions to enrich your resume with stronger, more detailed content.

{/* ── Improve by JD ────────────────────────────────────────── */} Improve by Job Description

Paste a job description and we will rewrite your resume to maximize ATS match — without fabricating experience.

{/* ── Regenerate ───────────────────────────────────────────── */} Regenerate Content

Select work experiences or projects to regenerate with stronger, more impactful bullet points.

{/* ── Export ───────────────────────────────────────────────── */}
{/* Enrichment Modal */} setIsEnrichmentOpen(false)} onComplete={handleEnrichmentComplete} /> {/* Regenerate Dialog */} setIsRegenerateOpen(false)} onComplete={handleRegenerateComplete} availableItems={selectableItems} />
); }