212 lines
9.2 KiB
JavaScript
212 lines
9.2 KiB
JavaScript
import React, { useState } from "react";
|
||
import { Card, CardContent } from "@/components/ui/card";
|
||
import { Button } from "@/components/ui/button";
|
||
import { Progress } from "@/components/ui/progress";
|
||
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
|
||
import { CheckCircle, Clock, Target, PlusCircle, Search } from "lucide-react";
|
||
import { Input } from "@/components/ui/input";
|
||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
|
||
|
||
const careerClusters = [
|
||
"Software Development",
|
||
"Healthcare",
|
||
"Engineering",
|
||
"Finance",
|
||
"Education",
|
||
"Marketing",
|
||
"Cybersecurity",
|
||
"Construction",
|
||
"Legal",
|
||
"Data Science",
|
||
"Sales",
|
||
"Human Resources",
|
||
"Manufacturing",
|
||
"Aviation",
|
||
"Social Work",
|
||
"Design & UX",
|
||
"Hospitality",
|
||
"Retail Management",
|
||
"Real Estate",
|
||
"Transportation",
|
||
"Agriculture",
|
||
"Public Administration",
|
||
"Energy & Environment"
|
||
];
|
||
|
||
const universalPrerequisites = {
|
||
"Software Development": ["Learn a Programming Language", "Build and Deploy a Small Project", "Understand Data Structures & Algorithms"],
|
||
"Healthcare": ["Complete Required Certifications", "Pass Licensing Exam", "Gain Clinical Experience"],
|
||
"Engineering": ["Earn a Relevant Engineering Degree", "Obtain Engineering Certification (PE/EIT)", "Gain Hands-on Experience"],
|
||
"Finance": ["Earn a Bachelor's in Finance or Related Field", "Gain Experience with Financial Modeling", "Obtain CFA or CPA Certification"],
|
||
"Education": ["Complete a Teaching Credential", "Pass State Licensing Exam", "Gain Classroom Experience"],
|
||
"Marketing": ["Learn Digital Marketing Basics", "Build a Portfolio of Campaigns", "Gain Experience in Market Research"],
|
||
"Cybersecurity": ["Learn Network Security Fundamentals", "Obtain CompTIA Security+ or CISSP", "Gain Hands-on Security Experience"],
|
||
"Construction": ["Complete an Apprenticeship Program", "Earn a Safety Certification (OSHA)", "Gain On-Site Experience"],
|
||
"Legal": ["Earn a Law Degree (JD)", "Pass the Bar Exam", "Gain Internship Experience at a Law Firm"],
|
||
"Data Science": ["Learn Python & SQL", "Complete a Machine Learning Course", "Build a Data Science Portfolio"],
|
||
"Sales": ["Develop Strong Communication Skills", "Understand CRM Tools", "Gain Sales Experience"],
|
||
"Human Resources": ["Earn a Bachelor's in HR or Business", "Obtain PHR or SHRM Certification", "Gain HR Generalist Experience"],
|
||
"Manufacturing": ["Learn Manufacturing Processes", "Complete a Safety Training Course", "Gain Hands-on Experience in Production"],
|
||
"Aviation": ["Earn a Pilot’s License", "Pass FAA Certification Exams", "Gain Flight Hours"],
|
||
"Social Work": ["Earn a Social Work Degree", "Obtain State Licensing", "Gain Casework Experience"],
|
||
"Design & UX": ["Learn UI/UX Design Principles", "Build a Portfolio of Designs", "Gain Experience with Design Tools (Figma, Adobe XD)"],
|
||
"Hospitality": ["Gain Customer Service Experience", "Complete Hospitality Management Courses", "Develop Event Planning Skills"],
|
||
"Retail Management": ["Gain Experience in Retail Operations", "Learn Inventory & Budget Management", "Develop Leadership Skills"],
|
||
"Real Estate": ["Earn a Real Estate License", "Develop Sales & Negotiation Skills", "Understand Market Trends"],
|
||
"Transportation": ["Obtain a Commercial Driver's License (CDL)", "Complete Logistics Training", "Gain Hands-on Experience in Transportation"],
|
||
"Agriculture": ["Learn Crop & Soil Science Basics", "Understand Farm Equipment Operation", "Gain Hands-on Farming Experience"],
|
||
"Public Administration": ["Earn a Public Administration Degree", "Understand Government Policies & Regulations", "Gain Leadership Experience"],
|
||
"Energy & Environment": ["Learn Renewable Energy Technologies", "Understand Environmental Regulations", "Gain Fieldwork Experience"]
|
||
};
|
||
|
||
const MilestoneTracker = () => {
|
||
const [activeTab, setActiveTab] = useState("career");
|
||
const [customMilestones, setCustomMilestones] = useState({ career: [], financial: [], retirement: [] });
|
||
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||
const [newMilestone, setNewMilestone] = useState("");
|
||
const [careerSearch, setCareerSearch] = useState("");
|
||
const [filteredCareers, setFilteredCareers] = useState(careerClusters);
|
||
|
||
|
||
useEffect(() => {
|
||
const fetchUserProfile = async () => {
|
||
try {
|
||
const response = await fetch("/api/user/profile", {
|
||
method: "GET",
|
||
credentials: "include", // Ensure cookies/session are sent
|
||
});
|
||
if (response.ok) {
|
||
const data = await response.json();
|
||
setIsPremiumUser(data.is_premium === 1); // Expecting { is_premium: 0 or 1 }
|
||
} else {
|
||
setIsPremiumUser(false); // Default to false if there's an error
|
||
}
|
||
} catch (error) {
|
||
console.error("Error fetching user profile:", error);
|
||
setIsPremiumUser(false);
|
||
}
|
||
};
|
||
fetchUserProfile();
|
||
}, []);
|
||
|
||
if (isPremiumUser === null) {
|
||
return <div className="p-6 text-center">Loading...</div>; // Show loading state while fetching
|
||
}
|
||
|
||
if (!isPremiumUser) {
|
||
return (
|
||
<div className="p-6 text-center">
|
||
<Lock className="mx-auto text-gray-400 w-16 h-16 mb-4" />
|
||
<h2 className="text-xl font-bold">Access Restricted</h2>
|
||
<p className="text-gray-600">Upgrade to Aptiva Premium to access the Milestone Tracker.</p>
|
||
<Button className="mt-4">Upgrade Now</Button>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
const handleAddMilestone = () => {
|
||
if (newMilestone.trim() !== "") {
|
||
setCustomMilestones((prev) => ({
|
||
...prev,
|
||
[activeTab]: [...prev[activeTab], { title: newMilestone, status: "upcoming", progress: 0 }],
|
||
}));
|
||
setNewMilestone("");
|
||
setIsDialogOpen(false);
|
||
}
|
||
};
|
||
|
||
const handleCareerSearch = (e) => {
|
||
const query = e.target.value.toLowerCase();
|
||
setCareerSearch(query);
|
||
setFilteredCareers(
|
||
careerClusters.filter((career) => career.toLowerCase().includes(query))
|
||
);
|
||
};
|
||
|
||
return (
|
||
<div className="p-6">
|
||
<h1 className="text-2xl font-bold mb-4">Milestone Tracker</h1>
|
||
|
||
{/* Career Search Section */}
|
||
<div className="mb-6 p-4 border rounded-lg shadow-md bg-white">
|
||
<h2 className="text-xl font-semibold mb-2">Search for a Career Path</h2>
|
||
<Input
|
||
value={careerSearch}
|
||
onChange={handleCareerSearch}
|
||
placeholder="Search for a career cluster"
|
||
className="mb-2"
|
||
/>
|
||
<div className="max-h-40 overflow-y-auto border rounded p-2">
|
||
{filteredCareers.map((career, index) => (
|
||
<div key={index} className="p-2 hover:bg-gray-200 cursor-pointer rounded">
|
||
<strong>{career}</strong>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Milestone Tracker Section */}
|
||
<Tabs value={activeTab} onValueChange={setActiveTab} className="mb-6">
|
||
<TabsList>
|
||
<TabsTrigger value="career">Career</TabsTrigger>
|
||
<TabsTrigger value="financial">Financial</TabsTrigger>
|
||
<TabsTrigger value="retirement">Retirement</TabsTrigger>
|
||
</TabsList>
|
||
</Tabs>
|
||
|
||
{/* Add Milestone Section */}
|
||
<Button onClick={() => setIsDialogOpen(true)} className="mb-4 flex items-center gap-2">
|
||
<PlusCircle /> Add Milestone
|
||
</Button>
|
||
|
||
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
|
||
<DialogContent>
|
||
<DialogHeader>
|
||
<DialogTitle>Add a New Milestone</DialogTitle>
|
||
</DialogHeader>
|
||
<Input value={newMilestone} onChange={(e) => setNewMilestone(e.target.value)} placeholder="Enter milestone title" />
|
||
<DialogFooter>
|
||
<Button onClick={handleAddMilestone}>Save</Button>
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
|
||
{/* Display User-Added Milestones */}
|
||
<TabsContent value={activeTab}>
|
||
{customMilestones[activeTab].map((milestone, index) => (
|
||
<Card key={index} className="mb-4 p-4">
|
||
<CardContent className="flex justify-between items-center">
|
||
<div className="flex items-center gap-4">
|
||
{milestone.status === "completed" && <CheckCircle className="text-green-500" />}
|
||
{milestone.status === "in-progress" && <Clock className="text-yellow-500" />}
|
||
{milestone.status === "upcoming" && <Target className="text-gray-500" />}
|
||
<h2 className="text-lg font-semibold">{milestone.title}</h2>
|
||
</div>
|
||
<Progress value={milestone.progress} className="w-40" />
|
||
</CardContent>
|
||
</Card>
|
||
))}
|
||
</TabsContent>
|
||
|
||
|
||
<Button onClick={() => setIsDialogOpen(true)} className="mb-4 flex items-center gap-2">
|
||
<PlusCircle /> Add Milestone
|
||
</Button>
|
||
|
||
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
|
||
<DialogContent>
|
||
<DialogHeader>
|
||
<DialogTitle>Add a New Milestone</DialogTitle>
|
||
</DialogHeader>
|
||
<Input value={newMilestone} onChange={(e) => setNewMilestone(e.target.value)} placeholder="Enter milestone title" />
|
||
<DialogFooter>
|
||
<Button onClick={handleAddMilestone}>Save</Button>
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
|
||
export default MilestoneTracker; |