skillsync-cli / frontend /src /components /pages /WorkflowPage.tsx
Mr-Haseeb786
Sanitized Production Build
56c7b6d
Raw History Blame Contribute Delete
9.58 kB
import React from "react";
import { motion } from "framer-motion";
import { Upload, Search, Check, ArrowRight } from "lucide-react";
import { Card, Button } from "@/components/common";
import Header from "@/components/sections/Header";
import CVUpload from "@/components/sections/CVUpload";
import { AutoApplyProfile } from "@/components/sections/AutoApplyProfile";
import JobSearch from "@/components/sections/JobSearch";
import { useJobStore } from "@/store/appStore";
type StepValue = "upload" | "search" | "review";
interface WorkflowPageProps {
onJobsFound?: () => void;
onSettingsClick?: () => void;
onHomeClick?: () => void;
}
const WorkflowPage: React.FC<WorkflowPageProps> = ({
onJobsFound,
onSettingsClick,
onHomeClick,
}) => {
const [currentStep, setCurrentStep] = React.useState<StepValue>("upload");
const { cvTemplate, jobs } = useJobStore();
const steps = [
{
value: "upload" as StepValue,
label: "Upload CV",
icon: Upload,
completed: !!cvTemplate,
},
{
value: "search" as StepValue,
label: "Search Jobs",
icon: Search,
completed: jobs.length > 0,
},
{
value: "review" as StepValue,
label: "Review & Generate",
icon: Check,
completed: false,
},
];
return (
<div className="min-h-screen bg-gradient-saas">
<Header onSettingsClick={onSettingsClick} onHomeClick={onHomeClick} />
<div className="px-4 sm:px-6 lg:px-8 py-12 max-w-6xl mx-auto">
{/* Progress Steps */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="mb-12"
>
<div className="flex items-center justify-between mb-8">
{steps.map((step, index) => (
<React.Fragment key={step.value}>
<motion.button
whileHover={{ scale: 1.05 }}
onClick={() => setCurrentStep(step.value)}
className={`flex flex-col items-center gap-2 cursor-pointer transition-all ${
currentStep === step.value
? "opacity-100"
: "opacity-60 hover:opacity-80"
}`}
>
<div
className={`w-12 h-12 rounded-full flex items-center justify-center transition-all ${
step.completed || currentStep === step.value
? "bg-gradient-emerald text-white"
: "bg-slate-700 text-slate-300"
}`}
>
{step.completed && currentStep !== step.value ? (
<Check className="w-6 h-6" />
) : (
<step.icon className="w-6 h-6" />
)}
</div>
<span className="text-sm font-medium text-slate-300">
{step.label}
</span>
</motion.button>
{index < steps.length - 1 && (
<div className="flex-1 h-1 mx-4 bg-slate-700 rounded-full overflow-hidden">
<motion.div
layoutId="progress"
className="h-full bg-gradient-emerald"
initial={{ width: 0 }}
animate={{
width:
currentStep === steps[index + 1].value
? "100%"
: "0%",
}}
transition={{ duration: 0.5 }}
/>
</div>
)}
</React.Fragment>
))}
</div>
</motion.div>
{/* Content */}
<motion.div
key={currentStep}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3 }}
>
{currentStep === "upload" && (
// <div>
// <Card className="mb-8">
// <h2 className="text-2xl font-bold text-white mb-2">
// Upload Your CV
// </h2>
// <p className="text-slate-400 mb-6">
// Start by uploading your base CV template. We'll use this to
// create tailored versions for each job.
// </p>
// <CVUpload
// onSuccess={() => {
// // Auto-proceed to next step
// setTimeout(() => {
// setCurrentStep('search');
// }, 500);
// }}
// onError={() => {
// // Stay on current step on error
// }}
// />
// </Card>
// {cvTemplate && (
// <motion.div
// initial={{ opacity: 0, y: 10 }}
// animate={{ opacity: 1, y: 0 }}
// className="flex justify-end"
// >
// <Button
// onClick={() => setCurrentStep('search')}
// icon={<ArrowRight className="w-4 h-4" />}
// iconPosition="right"
// >
// Proceed to Job Search
// </Button>
// </motion.div>
// )}
// </div>
<div className="space-y-6">
{" "}
{/* Added spacing container */}
<Card>
<h2 className="text-2xl font-bold text-white mb-2">
Upload Your CV
</h2>
<p className="text-slate-400 mb-6">
Start by uploading your base CV template. We'll use this to
create tailored versions for each job.
</p>
<CVUpload
onSuccess={() => {
// REMOVED the setTimeout auto-proceed!
// We want the user to stay here so they can optionally setup Auto-Apply.
console.log("CV Uploaded Successfully");
}}
onError={() => {
// Stay on current step on error
}}
/>
</Card>
{/* --- NEW OPTIONAL AUTO-APPLY SECTION --- */}
<AutoApplyProfile />
{/* PROCEED BUTTON */}
{cvTemplate && (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
className="flex justify-end pt-4"
>
<Button
onClick={() => setCurrentStep("search")}
icon={<ArrowRight className="w-4 h-4" />}
iconPosition="right"
>
Proceed to Job Search
</Button>
</motion.div>
)}
</div>
)}
{currentStep === "search" && (
<div>
<Card className="mb-8">
<h2 className="text-2xl font-bold text-white mb-2">
Search for Jobs
</h2>
<p className="text-slate-400 mb-6">
Find job opportunities that match your skills and interests.
</p>
<JobSearch
onJobsFound={() => {
onJobsFound?.();
// Auto-proceed to next step after small delay
setTimeout(() => {
setCurrentStep("review");
}, 800);
}}
/>
</Card>
</div>
)}
{currentStep === "review" && (
<div>
<Card>
<h2 className="text-2xl font-bold text-white mb-2">
Ready to Generate CVs
</h2>
<p className="text-slate-400 mb-6">
You have {jobs.length} jobs ready. Select the ones you want to
generate tailored CVs for and download them all at once.
</p>
{jobs.length > 0 ? (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
>
<Button
fullWidth
size="lg"
icon={<ArrowRight className="w-5 h-5" />}
iconPosition="right"
onClick={() => {
console.log(
"View Jobs button clicked! Jobs count:",
jobs.length
);
onJobsFound?.();
}}
>
View Jobs & Generate CVs
</Button>
</motion.div>
) : (
<div className="p-4 bg-slate-800/30 border border-slate-700 rounded-lg text-center">
<p className="text-slate-400 text-sm">
No jobs found. Please try searching again.
</p>
</div>
)}
</Card>
</div>
)}
</motion.div>
</div>
</div>
);
};
export default WorkflowPage;