2024-09-21 15:35:38 -05:00
|
|
|
import React, { useState, useEffect } from 'react';
|
2024-09-20 12:22:42 -05:00
|
|
|
import { ProgressBar } from 'primereact/progressbar';
|
2024-09-21 15:35:38 -05:00
|
|
|
import { Accordion, AccordionTab } from 'primereact/accordion';
|
2024-12-09 12:43:33 -06:00
|
|
|
import { useSession, signIn, getSession } from 'next-auth/react';
|
|
|
|
import { useRouter } from 'next/router';
|
2024-12-06 18:47:05 -06:00
|
|
|
import GenericButton from '@/components/buttons/GenericButton';
|
2024-12-11 11:23:14 -06:00
|
|
|
import UserProgressFlow from './UserProgressFlow';
|
2024-12-11 18:04:22 -06:00
|
|
|
import { Tooltip } from 'primereact/tooltip';
|
2024-09-20 12:22:42 -05:00
|
|
|
|
2024-09-27 13:33:27 -05:00
|
|
|
const allTasks = [
|
2024-12-06 13:04:21 -06:00
|
|
|
{
|
|
|
|
status: 'Connect GitHub',
|
|
|
|
completed: false,
|
|
|
|
tier: 'Pleb',
|
|
|
|
courseId: null,
|
|
|
|
subTasks: [
|
2024-12-10 16:44:34 -06:00
|
|
|
{ status: 'Create Your First GitHub Repo', completed: false },
|
2024-12-06 13:04:21 -06:00
|
|
|
]
|
|
|
|
},
|
2024-09-27 13:33:27 -05:00
|
|
|
{
|
2024-09-27 16:30:04 -05:00
|
|
|
status: 'PlebDevs Starter',
|
2024-09-27 13:33:27 -05:00
|
|
|
completed: false,
|
2024-12-10 16:44:34 -06:00
|
|
|
tier: 'Plebdev',
|
2024-12-06 18:47:05 -06:00
|
|
|
// courseId: "f538f5c5-1a72-4804-8eb1-3f05cea64874",
|
2024-12-11 11:23:14 -06:00
|
|
|
courseId: "5664e78f-c618-410d-a7cc-f3393b021fdf",
|
2024-09-27 13:33:27 -05:00
|
|
|
subTasks: [
|
2024-12-06 18:47:05 -06:00
|
|
|
{ status: 'Complete the course', completed: false },
|
2024-09-27 13:33:27 -05:00
|
|
|
]
|
|
|
|
},
|
2024-12-06 13:04:21 -06:00
|
|
|
{
|
|
|
|
status: 'Frontend Course',
|
|
|
|
completed: false,
|
2024-12-10 16:44:34 -06:00
|
|
|
tier: 'Frontend Dev',
|
2024-11-26 13:51:08 -06:00
|
|
|
courseId: 'f73c37f4-df2e-4f7d-a838-dce568c76136',
|
2024-09-27 16:30:04 -05:00
|
|
|
subTasks: [
|
|
|
|
{ status: 'Complete the course', completed: false },
|
2024-12-06 18:47:05 -06:00
|
|
|
{ status: 'Select your completed project', completed: false },
|
2024-09-27 16:30:04 -05:00
|
|
|
]
|
|
|
|
},
|
2024-12-06 13:04:21 -06:00
|
|
|
{
|
|
|
|
status: 'Backend Course',
|
|
|
|
completed: false,
|
2024-12-10 16:44:34 -06:00
|
|
|
tier: 'Backend Dev',
|
2024-11-26 13:51:08 -06:00
|
|
|
courseId: 'f6825391-831c-44da-904a-9ac3d149b7be',
|
2024-09-27 16:30:04 -05:00
|
|
|
subTasks: [
|
2024-12-06 13:04:21 -06:00
|
|
|
{ status: 'Complete the course', completed: false },
|
2024-12-06 18:47:05 -06:00
|
|
|
{ status: 'Select your completed project', completed: false },
|
2024-09-27 16:30:04 -05:00
|
|
|
]
|
|
|
|
},
|
2024-09-27 13:33:27 -05:00
|
|
|
];
|
|
|
|
|
2024-09-20 12:22:42 -05:00
|
|
|
const UserProgress = () => {
|
|
|
|
const [progress, setProgress] = useState(0);
|
2024-12-06 18:47:05 -06:00
|
|
|
const [currentTier, setCurrentTier] = useState(null);
|
2024-09-30 12:59:19 -05:00
|
|
|
const [expandedItems, setExpandedItems] = useState({});
|
2024-09-23 22:44:32 -05:00
|
|
|
const [completedCourses, setCompletedCourses] = useState([]);
|
|
|
|
const [tasks, setTasks] = useState([]);
|
2024-12-11 18:04:22 -06:00
|
|
|
const [isLoading, setIsLoading] = useState(true);
|
2024-09-23 22:44:32 -05:00
|
|
|
|
2024-12-09 12:43:33 -06:00
|
|
|
const router = useRouter();
|
2024-12-06 18:47:05 -06:00
|
|
|
const { data: session, update } = useSession();
|
2024-09-23 22:44:32 -05:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (session?.user) {
|
2024-12-11 18:04:22 -06:00
|
|
|
setIsLoading(true);
|
2024-09-23 22:44:32 -05:00
|
|
|
const user = session.user;
|
2024-09-27 13:33:27 -05:00
|
|
|
const ids = user?.userCourses?.map(course => course?.completed ? course.courseId : null).filter(id => id !== null);
|
|
|
|
if (ids && ids.length > 0) {
|
2024-11-26 13:57:21 -06:00
|
|
|
setCompletedCourses(ids);
|
|
|
|
generateTasks(ids);
|
|
|
|
calculateProgress(ids);
|
|
|
|
calculateCurrentTier(ids);
|
2024-09-27 13:33:27 -05:00
|
|
|
} else {
|
|
|
|
generateTasks([]);
|
2024-11-26 13:57:21 -06:00
|
|
|
calculateProgress([]);
|
|
|
|
calculateCurrentTier([]);
|
2024-09-27 13:33:27 -05:00
|
|
|
}
|
2024-12-11 18:04:22 -06:00
|
|
|
setIsLoading(false);
|
2024-09-23 22:44:32 -05:00
|
|
|
}
|
|
|
|
}, [session]);
|
|
|
|
|
|
|
|
const generateTasks = (completedCourseIds) => {
|
2024-12-06 18:47:05 -06:00
|
|
|
const updatedTasks = allTasks.map(task => {
|
|
|
|
if (task.status === 'Connect GitHub') {
|
|
|
|
return {
|
|
|
|
...task,
|
2024-12-09 12:43:33 -06:00
|
|
|
completed: session?.account?.provider === 'github' ? true : false,
|
2024-12-06 18:47:05 -06:00
|
|
|
subTasks: task.subTasks ? task.subTasks.map(subTask => ({
|
|
|
|
...subTask,
|
2024-12-09 12:43:33 -06:00
|
|
|
completed: session?.account?.provider === 'github' ? true : false
|
2024-12-06 18:47:05 -06:00
|
|
|
})) : undefined
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
...task,
|
|
|
|
completed: task.courseId === null || completedCourseIds.includes(task.courseId),
|
|
|
|
subTasks: task.subTasks ? task.subTasks.map(subTask => ({
|
|
|
|
...subTask,
|
|
|
|
completed: completedCourseIds.includes(task.courseId)
|
|
|
|
})) : undefined
|
|
|
|
};
|
|
|
|
});
|
2024-09-23 22:44:32 -05:00
|
|
|
|
|
|
|
setTasks(updatedTasks);
|
|
|
|
};
|
2024-09-20 12:22:42 -05:00
|
|
|
|
2024-11-26 13:57:21 -06:00
|
|
|
const calculateProgress = (completedCourseIds) => {
|
2024-12-06 18:47:05 -06:00
|
|
|
let progressValue = 0;
|
|
|
|
|
2024-12-09 12:43:33 -06:00
|
|
|
if (session?.account?.provider === 'github') {
|
2024-12-06 18:47:05 -06:00
|
|
|
progressValue += 25;
|
|
|
|
}
|
2024-12-06 13:04:21 -06:00
|
|
|
|
2024-11-26 13:57:21 -06:00
|
|
|
const remainingTasks = allTasks.slice(1);
|
|
|
|
remainingTasks.forEach(task => {
|
|
|
|
if (completedCourseIds.includes(task.courseId)) {
|
|
|
|
progressValue += 25;
|
|
|
|
}
|
|
|
|
});
|
2024-09-20 12:22:42 -05:00
|
|
|
|
2024-11-26 13:57:21 -06:00
|
|
|
setProgress(progressValue);
|
2024-09-20 12:22:42 -05:00
|
|
|
};
|
|
|
|
|
2024-11-26 13:57:21 -06:00
|
|
|
const calculateCurrentTier = (completedCourseIds) => {
|
2024-12-06 18:47:05 -06:00
|
|
|
let tier = null;
|
2024-12-06 13:04:21 -06:00
|
|
|
|
2024-11-26 13:57:21 -06:00
|
|
|
if (completedCourseIds.includes("f6825391-831c-44da-904a-9ac3d149b7be")) {
|
2024-12-10 16:44:34 -06:00
|
|
|
tier = 'Backend Dev';
|
2024-12-06 18:47:05 -06:00
|
|
|
} else if (completedCourseIds.includes("f73c37f4-df2e-4f7d-a838-dce568c76136")) {
|
2024-12-10 16:44:34 -06:00
|
|
|
tier = 'Frontend Dev';
|
2024-12-06 18:47:05 -06:00
|
|
|
} else if (completedCourseIds.includes("f6daa88a-53d6-4901-8dbd-d2203a05b7ab")) {
|
2024-12-10 16:44:34 -06:00
|
|
|
tier = 'Plebdev';
|
2024-12-09 12:43:33 -06:00
|
|
|
} else if (session?.account?.provider === 'github') {
|
2024-12-06 18:47:05 -06:00
|
|
|
tier = 'Pleb';
|
2024-11-26 13:57:21 -06:00
|
|
|
}
|
2024-12-06 13:04:21 -06:00
|
|
|
|
2024-11-26 13:57:21 -06:00
|
|
|
setCurrentTier(tier);
|
|
|
|
};
|
2024-09-20 12:22:42 -05:00
|
|
|
|
2024-09-30 12:59:19 -05:00
|
|
|
const handleAccordionChange = (index, isExpanded) => {
|
|
|
|
setExpandedItems(prev => ({
|
|
|
|
...prev,
|
|
|
|
[index]: isExpanded
|
|
|
|
}));
|
|
|
|
};
|
|
|
|
|
2024-12-06 18:47:05 -06:00
|
|
|
const handleGitHubLink = async () => {
|
2024-12-09 12:43:33 -06:00
|
|
|
try {
|
|
|
|
// If user is already signed in, we'll link the accounts
|
|
|
|
if (session?.user) {
|
|
|
|
const result = await signIn("github", {
|
|
|
|
redirect: false,
|
|
|
|
// Pass existing user data for linking
|
2024-12-09 20:40:22 -06:00
|
|
|
userId: session?.user?.id,
|
|
|
|
pubkey: session?.user?.pubkey,
|
|
|
|
privkey: session?.user?.privkey || null
|
2024-12-09 12:43:33 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
if (result?.ok) {
|
|
|
|
// Wait for session update
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
const updatedSession = await getSession();
|
|
|
|
if (updatedSession?.account?.provider === 'github') {
|
|
|
|
router.push('/'); // Accounts linked successfully
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Normal GitHub sign in
|
|
|
|
await signIn("github");
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
console.error("GitHub sign in error:", error);
|
|
|
|
}
|
2024-12-06 18:47:05 -06:00
|
|
|
};
|
|
|
|
|
2024-09-20 12:22:42 -05:00
|
|
|
return (
|
2024-12-17 17:41:14 -06:00
|
|
|
<div className="bg-gray-800 rounded-lg p-4 pb-0 m-2 w-full border border-gray-700 shadow-md max-lap:mx-0">
|
2024-12-11 18:04:22 -06:00
|
|
|
<div className="flex flex-row justify-between items-center">
|
|
|
|
<h1 className="text-3xl font-bold text-white mb-2">Dev Journey</h1>
|
|
|
|
<i className="pi pi-question-circle text-2xl cursor-pointer text-gray-200"
|
|
|
|
data-pr-tooltip="Track your progress from Pleb to Plebdev" />
|
|
|
|
<Tooltip target=".pi-question-circle" position="left" />
|
|
|
|
</div>
|
2024-09-20 12:22:42 -05:00
|
|
|
<p className="text-gray-400 mb-4">Track your progress from Pleb to Plebdev</p>
|
2024-09-21 15:35:38 -05:00
|
|
|
|
2024-09-20 12:22:42 -05:00
|
|
|
<div className="flex justify-between items-center mb-2">
|
|
|
|
<span className="text-gray-300">Progress</span>
|
|
|
|
<span className="text-gray-300">{progress}%</span>
|
|
|
|
</div>
|
|
|
|
<ProgressBar value={progress} className="h-2 mb-6" pt={{
|
|
|
|
label: {
|
|
|
|
className: 'hidden'
|
|
|
|
}
|
|
|
|
}} />
|
2024-09-21 15:35:38 -05:00
|
|
|
|
2024-09-20 12:22:42 -05:00
|
|
|
<div className="mb-6">
|
|
|
|
<span className="text-white text-lg font-semibold">Current Tier: </span>
|
2024-12-06 18:47:05 -06:00
|
|
|
{currentTier ? (
|
|
|
|
<span className="bg-green-500 text-white px-3 py-1 rounded-full">
|
|
|
|
{currentTier}
|
|
|
|
</span>
|
|
|
|
) : (
|
|
|
|
<span className="bg-gray-700 text-gray-400 px-3 py-1 rounded-full text-sm">
|
|
|
|
Not Started
|
|
|
|
</span>
|
|
|
|
)}
|
2024-09-20 12:22:42 -05:00
|
|
|
</div>
|
2024-09-21 15:35:38 -05:00
|
|
|
|
2024-12-17 17:41:14 -06:00
|
|
|
<div className="flex max-sidebar:flex-col gap-6 mb-6">
|
|
|
|
<div className="w-1/2 max-sidebar:w-full">
|
2024-12-11 18:04:22 -06:00
|
|
|
<ul className="space-y-6 pt-2">
|
|
|
|
{tasks.map((task, index) => (
|
|
|
|
<li key={index}>
|
|
|
|
<Accordion
|
|
|
|
activeIndex={expandedItems[index] ? 0 : null}
|
|
|
|
onTabChange={(e) => handleAccordionChange(index, e.index === 0)}
|
|
|
|
>
|
|
|
|
<AccordionTab
|
|
|
|
header={
|
|
|
|
<div className="flex items-center justify-between w-full">
|
|
|
|
<div className="flex items-center">
|
|
|
|
{task.completed ? (
|
|
|
|
<div className="w-6 h-6 bg-green-500 rounded-full flex items-center justify-center mr-3">
|
|
|
|
<i className="pi pi-check text-white text-lg"></i>
|
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
<div className="w-6 h-6 bg-gray-700 rounded-full flex items-center justify-center mr-3">
|
|
|
|
<i className="pi pi-info-circle text-white text-lg"></i>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
<span className={`text-lg ${task.completed ? 'text-white' : 'text-gray-400'}`}>{task.status}</span>
|
2024-12-06 18:47:05 -06:00
|
|
|
</div>
|
2024-12-11 18:04:22 -06:00
|
|
|
<span className="bg-blue-500 text-white text-sm px-2 py-1 rounded-full w-24 text-center">
|
|
|
|
{task.tier}
|
2024-12-06 18:47:05 -06:00
|
|
|
</span>
|
2024-12-11 18:04:22 -06:00
|
|
|
</div>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
{task.status === 'Connect GitHub' && !task.completed && (
|
|
|
|
<div className="mb-4">
|
|
|
|
<GenericButton
|
|
|
|
label="Connect GitHub"
|
|
|
|
icon="pi pi-github"
|
|
|
|
onClick={handleGitHubLink}
|
|
|
|
className="w-fit bg-[#24292e] hover:bg-[#2f363d] border border-[#f8f8ff] text-[#f8f8ff] font-semibold"
|
|
|
|
rounded
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
{task.subTasks && (
|
|
|
|
<ul className="space-y-2">
|
|
|
|
{task.subTasks.map((subTask, subIndex) => (
|
|
|
|
<li key={subIndex} className="flex items-center pl-[28px]">
|
|
|
|
{subTask.completed ? (
|
|
|
|
<div className="w-4 h-4 bg-green-500 rounded-full flex items-center justify-center mr-3">
|
|
|
|
<i className="pi pi-check text-white text-sm"></i>
|
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
<div className="w-4 h-4 bg-gray-700 rounded-full flex items-center justify-center mr-3">
|
|
|
|
<i className="pi pi-info-circle text-white text-sm"></i>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
<span className={`${subTask.completed ? 'text-white' : 'text-gray-400'}`}>
|
|
|
|
{subTask.status}
|
|
|
|
</span>
|
|
|
|
</li>
|
|
|
|
))}
|
|
|
|
</ul>
|
|
|
|
)}
|
|
|
|
{task.courseId && (
|
|
|
|
<div className="mt-2 flex justify-end">
|
|
|
|
<GenericButton
|
|
|
|
icon="pi pi-external-link"
|
|
|
|
onClick={() => router.push(`/courses/${task.courseId}`)}
|
|
|
|
tooltip="View Course"
|
|
|
|
tooltipOptions={{
|
|
|
|
position: "top"
|
|
|
|
}}
|
|
|
|
outlined
|
|
|
|
size="small"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</AccordionTab>
|
|
|
|
</Accordion>
|
|
|
|
</li>
|
|
|
|
))}
|
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
|
2024-12-17 17:41:14 -06:00
|
|
|
<div className="w-1/2 max-sidebar:w-full">
|
2024-12-11 18:04:22 -06:00
|
|
|
{isLoading ? (
|
|
|
|
<div className="h-[400px] bg-gray-800 rounded-3xl flex items-center justify-center">
|
|
|
|
<i className="pi pi-spin pi-spinner text-4xl text-gray-600"></i>
|
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
<UserProgressFlow tasks={tasks} />
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</div>
|
2024-09-20 12:22:42 -05:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default UserProgress;
|