diff --git a/src/components/charts/ActivityContributionChart.js b/src/components/charts/ActivityContributionChart.js index e049232..6afd0d9 100644 --- a/src/components/charts/ActivityContributionChart.js +++ b/src/components/charts/ActivityContributionChart.js @@ -65,9 +65,6 @@ const ActivityContributionChart = ({ session }) => { } }); - console.log('All Learning Activities:', allActivities); - console.log('Activities by Date:', activityData); - setContributionData(activityData); setTotalActivities(Object.values(activityData).reduce((a, b) => a + b, 0)); @@ -112,15 +109,6 @@ const ActivityContributionChart = ({ session }) => { const dateString = currentDate.toLocaleDateString('en-CA'); // YYYY-MM-DD format const activityCount = contributionData[dateString] || 0; - // Debug log - if (activityCount > 0) { - console.log('Found activity:', { - date: currentDate.toDateString(), - dateString, - activityCount - }); - } - calendar[weekDay].push({ date: new Date(currentDate), count: activityCount diff --git a/src/components/profile/progress/UserProgress.js b/src/components/profile/progress/UserProgress.js index 0eff1c0..eaaa252 100644 --- a/src/components/profile/progress/UserProgress.js +++ b/src/components/profile/progress/UserProgress.js @@ -1,7 +1,8 @@ import React, { useState, useEffect } from 'react'; import { ProgressBar } from 'primereact/progressbar'; import { Accordion, AccordionTab } from 'primereact/accordion'; -import { useSession } from 'next-auth/react'; +import { useSession, signIn } from 'next-auth/react'; +import GenericButton from '@/components/buttons/GenericButton'; const allTasks = [ { @@ -18,11 +19,10 @@ const allTasks = [ status: 'PlebDevs Starter', completed: false, tier: 'New Dev', - courseId: "f538f5c5-1a72-4804-8eb1-3f05cea64874", + // courseId: "f538f5c5-1a72-4804-8eb1-3f05cea64874", + courseId: "f6daa88a-53d6-4901-8dbd-d2203a05b7ab", subTasks: [ - { status: 'Connect GitHub', completed: false }, - { status: 'Create First GitHub Repo', completed: false }, - { status: 'Push Commit', completed: false } + { status: 'Complete the course', completed: false }, ] }, { @@ -32,7 +32,7 @@ const allTasks = [ courseId: 'f73c37f4-df2e-4f7d-a838-dce568c76136', subTasks: [ { status: 'Complete the course', completed: false }, - { status: 'Submit Link to completed project', completed: false }, + { status: 'Select your completed project', completed: false }, ] }, { @@ -42,19 +42,19 @@ const allTasks = [ courseId: 'f6825391-831c-44da-904a-9ac3d149b7be', subTasks: [ { status: 'Complete the course', completed: false }, - { status: 'Submit Link to completed project', completed: false }, + { status: 'Select your completed project', completed: false }, ] }, ]; const UserProgress = () => { const [progress, setProgress] = useState(0); - const [currentTier, setCurrentTier] = useState('Pleb'); + const [currentTier, setCurrentTier] = useState(null); const [expandedItems, setExpandedItems] = useState({}); const [completedCourses, setCompletedCourses] = useState([]); const [tasks, setTasks] = useState([]); - const { data: session } = useSession(); + const { data: session, update } = useSession(); useEffect(() => { if (session?.user) { @@ -74,20 +74,37 @@ const UserProgress = () => { }, [session]); const generateTasks = (completedCourseIds) => { - const updatedTasks = allTasks.map(task => ({ - ...task, - completed: task.courseId === null || completedCourseIds.includes(task.courseId), - subTasks: task.subTasks ? task.subTasks.map(subTask => ({ - ...subTask, - completed: completedCourseIds.includes(task.courseId) - })) : undefined - })); + const updatedTasks = allTasks.map(task => { + if (task.status === 'Connect GitHub') { + return { + ...task, + completed: session?.githubProfile ? true : false, + subTasks: task.subTasks ? task.subTasks.map(subTask => ({ + ...subTask, + completed: session?.githubProfile ? true : false + })) : 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 + }; + }); setTasks(updatedTasks); }; const calculateProgress = (completedCourseIds) => { - let progressValue = 25; + let progressValue = 0; + + if (session?.githubProfile) { + progressValue += 25; + } const remainingTasks = allTasks.slice(1); remainingTasks.forEach(task => { @@ -100,16 +117,16 @@ const UserProgress = () => { }; const calculateCurrentTier = (completedCourseIds) => { - let tier = 'Pleb'; + let tier = null; - if (completedCourseIds.includes("f538f5c5-1a72-4804-8eb1-3f05cea64874")) { - tier = 'New Dev'; - } - if (completedCourseIds.includes("f73c37f4-df2e-4f7d-a838-dce568c76136")) { - tier = 'Junior Dev'; - } if (completedCourseIds.includes("f6825391-831c-44da-904a-9ac3d149b7be")) { tier = 'Plebdev'; + } else if (completedCourseIds.includes("f73c37f4-df2e-4f7d-a838-dce568c76136")) { + tier = 'Junior Dev'; + } else if (completedCourseIds.includes("f6daa88a-53d6-4901-8dbd-d2203a05b7ab")) { + tier = 'New Dev'; + } else if (session?.githubProfile) { + tier = 'Pleb'; } setCurrentTier(tier); @@ -122,6 +139,12 @@ const UserProgress = () => { })); }; + const handleGitHubLink = async () => { + if (!session?.user?.id) return; + + await signIn("github"); + }; + return (

Dev Journey

@@ -139,30 +162,92 @@ const UserProgress = () => {
Current Tier: - {currentTier} + {currentTier ? ( + + {currentTier} + + ) : ( + + Not Started + + )}
diff --git a/src/pages/api/auth/[...nextauth].js b/src/pages/api/auth/[...nextauth].js index e8c4d4f..ae05d3d 100644 --- a/src/pages/api/auth/[...nextauth].js +++ b/src/pages/api/auth/[...nextauth].js @@ -12,8 +12,6 @@ import { createRole } from "@/db/models/roleModels"; import appConfig from "@/config/appConfig"; import GithubProvider from "next-auth/providers/github"; import NDK from "@nostr-dev-kit/ndk"; -import { SimplePool } from "nostr-tools"; -import { finalizeEvent } from "nostr-tools"; // todo: currently email accounts ephemeral privkey gets saved to db but not anon user, is this required at all given the newer auth setup? @@ -40,7 +38,7 @@ const authorize = async (pubkey) => { dbUser = await getUserByPubkey(pubkey); } } else if (fields.username !== dbUser.username) { - const updatedUser = await updateUser(dbUser.id, { username: fields.username }); + const updatedUser = await updateUser(dbUser.id, { username: fields.username, name: fields.username }); if (updatedUser) { dbUser = await getUserByPubkey(pubkey); } @@ -53,7 +51,7 @@ const authorize = async (pubkey) => { // Create user if (profile) { const fields = await findKind0Fields(profile); - const payload = { pubkey, username: fields.username, avatar: fields.avatar }; + const payload = { pubkey, username: fields.username, avatar: fields.avatar, name: fields.username }; if (appConfig.authorPubkeys.includes(pubkey)) { // create a new author role for this user @@ -168,8 +166,32 @@ export const authOptions = { // Create new user if not exists dbUser = await createUser({ pubkey: pubkey, - username: pubkey.slice(0, 8), // Use first 8 characters of pubkey as username + username: pubkey.slice(0, 8), }); + } else { + // Check if this user has a linked GitHub account + const githubAccount = await prisma.account.findFirst({ + where: { + userId: dbUser.id, + provider: 'github' + }, + include: { + user: true + } + }); + + if (githubAccount) { + // Return the user with GitHub provider information + return { + ...dbUser, + pubkey, + privkey, + // Add these fields to switch to GitHub provider + provider: 'github', + type: 'oauth', + providerAccountId: githubAccount.providerAccountId + }; + } } // Return user object with pubkey and privkey @@ -179,11 +201,23 @@ export const authOptions = { ], callbacks: { async jwt({ token, user, account, trigger, profile }) { - // Add account and profile to token if they exist - if (account) { - token.account = account; + if (user?.provider === 'github') { + // User has a linked GitHub account, use that as the primary provider + token.account = { + provider: 'github', + type: 'oauth', + providerAccountId: user.providerAccountId + }; + // Add GitHub profile information + token.githubProfile = { + login: user.username, + avatar_url: user.avatar, + email: user.email + }; + } else if (account) { // Store GitHub-specific information if (account.provider === 'github') { + token.account = account; token.githubProfile = { login: profile?.login, avatar_url: profile?.avatar_url, @@ -246,6 +280,22 @@ export const authOptions = { user.email = token.githubProfile?.email; } + if (account && account.provider === "github" && user?.id && user?.pubkey) { + // we are linking a github account to an existing account + const updatedUser = await updateUser(user.id, { + name: profile?.login, + username: profile?.login, + avatar: profile?.avatar_url, + email: profile?.email, + privkey: user.privkey || token.privkey, // Preserve the existing privkey + image: profile?.avatar_url, // Also save to image field + }); + + if (updatedUser) { + user = await getUserById(user.id); + } + } + if (user) { token.user = user; if (user.pubkey && user.privkey) { @@ -269,9 +319,10 @@ export const authOptions = { // Override only the GitHub-specific fields session.user = { ...dbUser, // This includes role, purchases, userCourses, userLessons, etc. - username: token.githubProfile.login, - avatar: token.githubProfile.avatar_url, - email: token.githubProfile.email + username: token.githubProfile?.login, + name: token.githubProfile?.login, + avatar: token.githubProfile?.avatar_url, + email: token.githubProfile?.email }; } else { // For non-GitHub sessions, use the existing token.user