diff --git a/components/resume/#1_issue-fixed b/components/resume/#1_issue-fixed new file mode 100644 index 00000000..2c21f461 --- /dev/null +++ b/components/resume/#1_issue-fixed @@ -0,0 +1,604 @@ +"use client"; + +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Textarea } from "@/components/ui/textarea"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { ResumePreview } from "@/components/resume/resume-preview"; +import { ResumeTemplates } from "@/components/resume/resume-templates"; +import { GuidedResumeGenerator } from "@/components/resume/guided-resume-generator"; +import { useToast } from "@/hooks/use-toast"; +import { + File as FileIcon, + Loader2, + Sparkles, + Maximize2, + Minimize2, + Download, + User, + Mail, + Wand2, + Palette, + Brain, + Target, + Zap, +} from "lucide-react"; +import { useSubscription } from "@/hooks/use-subscription"; +import { TooltipWithShortcut } from "../ui/tooltip"; +import html2canvas from 'html2canvas'; +import jsPDF from 'jspdf'; + +export function ResumeGenerator() { + const [prompt, setPrompt] = useState(""); + const [name, setName] = useState(""); + const [email, setEmail] = useState(""); + const [isGenerating, setIsGenerating] = useState(false); + const [resumeData, setResumeData] = useState(null); + const [selectedTemplate, setSelectedTemplate] = useState("professional"); + const [isFullView, setIsFullView] = useState(false); + const [isExporting, setIsExporting] = useState(false); + const { toast } = useToast(); + const { isPro } = useSubscription(); + + const generateResume = async () => { + if (!prompt.trim()) { + toast({ + title: "Please enter a prompt", + description: "Describe the resume you want to generate", + variant: "destructive", + }); + return; + } + + if (!name.trim() || !email.trim()) { + toast({ + title: "Missing information", + description: "Please enter your name and email", + variant: "destructive", + }); + return; + } + + setIsGenerating(true); + + try { + const response = await fetch("/api/generate/resume", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + prompt, + name, + email, + }), + }); + + if (!response.ok) { + throw new Error("Failed to generate resume"); + } + + const data = await response.json(); + setResumeData(data); + + toast({ + title: "Resume generated! ✨", + description: "Your tailored resume is ready to preview and download", + }); + } catch (error) { + toast({ + title: "Error", + description: "Failed to generate resume. Please try again.", + variant: "destructive", + }); + } finally { + setIsGenerating(false); + } + }; + + const handleGuidedResumeGenerated = (resume: any) => { + setResumeData(resume); + }; + + const exportToPDF = async () => { + if (!resumeData) { + toast({ + title: "No resume to export", + description: "Please generate a resume first.", + variant: "destructive", + }); + return; + } + + setIsExporting(true); + + try { + const element = document.getElementById('resume-content'); + if (!element) throw new Error('Resume content element not found'); + + const canvas = await html2canvas(element, { + scale: 2, + useCORS: true, + allowTaint: true, + backgroundColor: '#ffffff' + }); + + const imgData = canvas.toDataURL('image/png'); + + // A4 dimensions in mm: 210 x 297 + const pdf = new jsPDF('p', 'mm', 'a4'); + const pdfWidth = pdf.internal.pageSize.getWidth(); + const pdfHeight = pdf.internal.pageSize.getHeight(); + + // Calculate ratio to fit the image within the PDF + const imgWidth = canvas.width; + const imgHeight = canvas.height; + const ratio = Math.min(pdfWidth / imgWidth, pdfHeight / imgHeight); + + const imgX = (pdfWidth - imgWidth * ratio) / 2; + const imgY = 0; + + pdf.addImage(imgData, 'PNG', imgX, imgY, imgWidth * ratio, imgHeight * ratio); + pdf.save(`${resumeData.name?.replace(/\s+/g, '-').toLowerCase() || 'resume'}.pdf`); + + toast({ + title: "Resume exported!", + description: "Your resume has been downloaded as a PDF.", + }); + } catch (error) { + console.error('Error exporting to PDF:', error); + toast({ + title: "Export failed", + description: "Failed to export resume to PDF. Please try again.", + variant: "destructive", + }); + } finally { + setIsExporting(false); + } + }; + + + + return ( +
+ +
+ + + + Smart Builder + Smart + + + + Quick Generate + Quick + + + + Templates + Templates + + +
+ + +
+
+
+ + 100% ATS-Optimized + +
+

+ Build Your ATS-Friendly Resume +

+

+ Our AI-powered guided builder creates resumes that pass + Applicant Tracking Systems with perfect keyword optimization and + professional formatting +

+
+ +
+
+
+ +
+
+
+ + {resumeData && ( +
+
+
+
+ + + ATS-Optimized Resume + +
+

+ Preview +

+
+ + +
+ +
+
+
+ +
+
+ + {/* Download Options */} +
+

+ + Download Options +

+
+ + + {isPro && ( + + )} +
+
+
+ )} +
+ + +
+ {/* Left Side - Form */} +
+
+
+ + + Quick AI Resume Generator + +
+

+ Generate Your Resume +

+

+ Fill in your details and let AI craft the perfect resume +

+
+ +
+ {/* Personal Information */} +
+ + setName(e.target.value)} + className="glass-effect border-yellow-400/30 focus:border-yellow-400/60 focus:ring-yellow-400/20 w-full text-base px-3 py-2" + disabled={isGenerating} + /> +
+ +
+ + setEmail(e.target.value)} + className="glass-effect border-yellow-400/30 focus:border-yellow-400/60 focus:ring-yellow-400/20 w-full text-base px-3 py-2" + disabled={isGenerating} + /> +
+ + {/* Prompt */} +
+ +