mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-19 05:55:05 +00:00
Starting to restructure user profile around new dev journey
This commit is contained in:
parent
6c0e09292b
commit
c04a42eeb7
@ -157,20 +157,24 @@ const ActivityContributionChart = ({ session }) => {
|
|||||||
const weekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
const weekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto py-2 px-8 max-w-[1000px] bg-gray-800 rounded-lg">
|
<div className="w-full mx-2 bg-gray-800 rounded-lg border border-gray-700 shadow-md">
|
||||||
|
<div className="flex flex-row justify-between items-center p-4">
|
||||||
|
<h1 className="text-2xl font-bold text-gray-200">Activity</h1>
|
||||||
|
<i className="pi pi-question-circle text-2xl cursor-pointer text-gray-200"
|
||||||
|
data-pr-tooltip="Total number of learning activities on the platform" />
|
||||||
|
<Tooltip target=".pi-question-circle" position="left" />
|
||||||
|
</div>
|
||||||
|
<div className="max-w-[910px] p-4">
|
||||||
<div className="flex justify-between items-center mb-3">
|
<div className="flex justify-between items-center mb-3">
|
||||||
<h4 className="text-base font-semibold text-gray-200">
|
<h4 className="text-base font-semibold text-gray-200">
|
||||||
{totalActivities} learning activities in the last year
|
{totalActivities} learning activities in the last year
|
||||||
</h4>
|
</h4>
|
||||||
<i className="pi pi-question-circle text-lg cursor-pointer text-gray-400 hover:text-gray-200"
|
|
||||||
data-pr-tooltip="Total number of learning activities on the platform" />
|
|
||||||
<Tooltip target=".pi-question-circle" position="top" />
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
{/* Days of week labels */}
|
{/* Days of week labels */}
|
||||||
<div className="flex flex-col gap-[3px] text-[11px] text-gray-400 pr-3">
|
<div className="flex flex-col gap-[3px] text-[11px] text-gray-400 pr-3">
|
||||||
{weekDays.map((day, index) => (
|
{weekDays.map((day, index) => (
|
||||||
<div key={day} className="h-[13px] leading-[13px]">
|
<div key={day} className="h-[14px] leading-[14px]">
|
||||||
{index % 2 === 0 && day}
|
{index % 2 === 0 && day}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@ -184,7 +188,7 @@ const ActivityContributionChart = ({ session }) => {
|
|||||||
row[weekIndex] && (
|
row[weekIndex] && (
|
||||||
<div
|
<div
|
||||||
key={`${weekIndex}-${dayIndex}`}
|
key={`${weekIndex}-${dayIndex}`}
|
||||||
className={`w-[13px] h-[13px] ${getColor(row[weekIndex].count)} rounded-[2px] cursor-pointer transition-colors duration-100`}
|
className={`w-[14px] h-[14px] ${getColor(row[weekIndex].count)} rounded-[2px] cursor-pointer transition-colors duration-100`}
|
||||||
title={`${row[weekIndex].date.toDateString()}: ${
|
title={`${row[weekIndex].date.toDateString()}: ${
|
||||||
row[weekIndex].count > 0
|
row[weekIndex].count > 0
|
||||||
? `${row[weekIndex].count} activit${row[weekIndex].count !== 1 ? 'ies' : 'y'}`
|
? `${row[weekIndex].count} activit${row[weekIndex].count !== 1 ? 'ies' : 'y'}`
|
||||||
@ -214,15 +218,16 @@ const ActivityContributionChart = ({ session }) => {
|
|||||||
<div className="text-[11px] text-gray-400 flex items-center justify-end">
|
<div className="text-[11px] text-gray-400 flex items-center justify-end">
|
||||||
<span className="mr-2">Less</span>
|
<span className="mr-2">Less</span>
|
||||||
<div className="flex gap-[3px]">
|
<div className="flex gap-[3px]">
|
||||||
<div className="w-[13px] h-[13px] bg-gray-100 rounded-[2px]"></div>
|
<div className="w-[14px] h-[14px] bg-gray-100 rounded-[2px]"></div>
|
||||||
<div className="w-[13px] h-[13px] bg-green-300 rounded-[2px]"></div>
|
<div className="w-[14px] h-[14px] bg-green-300 rounded-[2px]"></div>
|
||||||
<div className="w-[13px] h-[13px] bg-green-400 rounded-[2px]"></div>
|
<div className="w-[14px] h-[14px] bg-green-400 rounded-[2px]"></div>
|
||||||
<div className="w-[13px] h-[13px] bg-green-600 rounded-[2px]"></div>
|
<div className="w-[14px] h-[14px] bg-green-600 rounded-[2px]"></div>
|
||||||
<div className="w-[13px] h-[13px] bg-green-700 rounded-[2px]"></div>
|
<div className="w-[14px] h-[14px] bg-green-700 rounded-[2px]"></div>
|
||||||
</div>
|
</div>
|
||||||
<span className="ml-2">More</span>
|
<span className="ml-2">More</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -181,16 +181,20 @@ const CombinedContributionChart = ({ session }) => {
|
|||||||
}, [calendar]);
|
}, [calendar]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto py-2 px-8 max-w-[1000px] bg-gray-800 rounded-lg">
|
<div className="w-full mx-2 bg-gray-800 rounded-lg border border-gray-700 shadow-md">
|
||||||
{(isLoading || isFetching) && <p>Loading contribution data... ({totalContributions} total contributions / activities fetched)</p>}
|
<div className="flex flex-row justify-between items-center p-4">
|
||||||
|
<h1 className="text-2xl font-bold text-gray-200">Activity</h1>
|
||||||
|
<i className="pi pi-question-circle text-2xl cursor-pointer text-gray-200"
|
||||||
|
data-pr-tooltip="Combined total of GitHub commits and learning activities (starting/completing courses and lessons)" />
|
||||||
|
<Tooltip target=".pi-question-circle" position="left" />
|
||||||
|
</div>
|
||||||
|
<div className="max-w-[910px] p-4">
|
||||||
|
{(isLoading || isFetching) && <h4 className="text-base font-semibold text-gray-200 mb-3">Loading contribution data... ({totalContributions} total contributions / activities fetched)</h4>}
|
||||||
{!isLoading && !isFetching &&
|
{!isLoading && !isFetching &&
|
||||||
<div className="flex justify-between items-center mb-3">
|
<div className="flex justify-between items-center mb-3">
|
||||||
<h4 className="text-base font-semibold text-gray-200">
|
<h4 className="text-base font-semibold text-gray-200">
|
||||||
{totalContributions} total contributions / activities in the last year
|
{totalContributions} total contributions / activities in the last year
|
||||||
</h4>
|
</h4>
|
||||||
<i className="pi pi-question-circle text-lg cursor-pointer text-gray-400 hover:text-gray-200"
|
|
||||||
data-pr-tooltip="Combined total of GitHub commits and learning activities (starting/completing courses and lessons)" />
|
|
||||||
<Tooltip target=".pi-question-circle" position="top" />
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
@ -211,9 +215,8 @@ const CombinedContributionChart = ({ session }) => {
|
|||||||
row[weekIndex] && (
|
row[weekIndex] && (
|
||||||
<div
|
<div
|
||||||
key={`${weekIndex}-${dayIndex}`}
|
key={`${weekIndex}-${dayIndex}`}
|
||||||
className={`w-[13px] h-[13px] ${getColor(row[weekIndex].count)} rounded-[2px] cursor-pointer transition-colors duration-100`}
|
className={`w-[14px] h-[14px] ${getColor(row[weekIndex].count)} rounded-[2px] cursor-pointer transition-colors duration-100`}
|
||||||
title={`${row[weekIndex].date.toDateString()}: ${
|
title={`${row[weekIndex].date.toDateString()}: ${[
|
||||||
[
|
|
||||||
row[weekIndex].githubCount > 0 ? `${row[weekIndex].githubCount} contribution${row[weekIndex].githubCount !== 1 ? 's' : ''}` : '',
|
row[weekIndex].githubCount > 0 ? `${row[weekIndex].githubCount} contribution${row[weekIndex].githubCount !== 1 ? 's' : ''}` : '',
|
||||||
row[weekIndex].activityCount > 0 ? `${row[weekIndex].activityCount} activit${row[weekIndex].activityCount !== 1 ? 'ies' : 'y'}` : ''
|
row[weekIndex].activityCount > 0 ? `${row[weekIndex].activityCount} activit${row[weekIndex].activityCount !== 1 ? 'ies' : 'y'}` : ''
|
||||||
].filter(Boolean).join(' & ') || 'No contributions or activities'
|
].filter(Boolean).join(' & ') || 'No contributions or activities'
|
||||||
@ -241,15 +244,16 @@ const CombinedContributionChart = ({ session }) => {
|
|||||||
<div className="text-[11px] text-gray-400 flex items-center justify-end">
|
<div className="text-[11px] text-gray-400 flex items-center justify-end">
|
||||||
<span className="mr-2">Less</span>
|
<span className="mr-2">Less</span>
|
||||||
<div className="flex gap-[3px]">
|
<div className="flex gap-[3px]">
|
||||||
<div className="w-[13px] h-[13px] bg-gray-100 rounded-[2px]"></div>
|
<div className="w-[14px] h-[14px] bg-gray-100 rounded-[2px]"></div>
|
||||||
<div className="w-[13px] h-[13px] bg-green-300 rounded-[2px]"></div>
|
<div className="w-[14px] h-[14px] bg-green-300 rounded-[2px]"></div>
|
||||||
<div className="w-[13px] h-[13px] bg-green-400 rounded-[2px]"></div>
|
<div className="w-[14px] h-[14px] bg-green-400 rounded-[2px]"></div>
|
||||||
<div className="w-[13px] h-[13px] bg-green-600 rounded-[2px]"></div>
|
<div className="w-[14px] h-[14px] bg-green-600 rounded-[2px]"></div>
|
||||||
<div className="w-[13px] h-[13px] bg-green-700 rounded-[2px]"></div>
|
<div className="w-[14px] h-[14px] bg-green-700 rounded-[2px]"></div>
|
||||||
</div>
|
</div>
|
||||||
<span className="ml-2">More</span>
|
<span className="ml-2">More</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ const UserProgressTable = ({ session, ndk, windowWidth }) => {
|
|||||||
emptyMessage="No Courses or Milestones completed"
|
emptyMessage="No Courses or Milestones completed"
|
||||||
value={prepareProgressData()}
|
value={prepareProgressData()}
|
||||||
header={header}
|
header={header}
|
||||||
style={{ maxWidth: windowWidth < 768 ? "100%" : "90%", margin: "0 auto" }}
|
style={{ margin: 8, width: "100%", borderRadius: "8px", border: "1px solid #333", boxShadow: "0 0 10px 0 rgba(0, 0, 0, 0.1)" }}
|
||||||
pt={{
|
pt={{
|
||||||
wrapper: {
|
wrapper: {
|
||||||
className: "rounded-b-lg shadow-md"
|
className: "rounded-b-lg shadow-md"
|
||||||
|
@ -53,7 +53,7 @@ const UserPurchaseTable = ({ session, windowWidth }) => {
|
|||||||
emptyMessage="No purchases"
|
emptyMessage="No purchases"
|
||||||
value={session.user?.purchased}
|
value={session.user?.purchased}
|
||||||
header={purchasesHeader}
|
header={purchasesHeader}
|
||||||
style={{ maxWidth: windowWidth < 768 ? "100%" : "90%", margin: "0 auto", marginTop: "2rem" }}
|
style={{ margin: 8, width: "100%", borderRadius: "8px", border: "1px solid #333", boxShadow: "0 0 10px 0 rgba(0, 0, 0, 0.1)" }}
|
||||||
pt={{
|
pt={{
|
||||||
wrapper: {
|
wrapper: {
|
||||||
className: "rounded-b-lg shadow-md"
|
className: "rounded-b-lg shadow-md"
|
||||||
|
@ -37,15 +37,16 @@ const UserProfile = () => {
|
|||||||
<h1 className="text-3xl font-bold mb-6">Profile</h1>
|
<h1 className="text-3xl font-bold mb-6">Profile</h1>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<div className="w-full flex flex-col justify-center mx-auto">
|
<div className="w-full flex flex-row">
|
||||||
<UserProfileCard user={user} />
|
<UserProfileCard user={user} />
|
||||||
|
<div className="w-full flex flex-col justify-center mx-auto">
|
||||||
|
|
||||||
{account && account?.provider === "github" ? (
|
{account && account?.provider === "github" ? (
|
||||||
<CombinedContributionChart session={session} />
|
<CombinedContributionChart session={session} />
|
||||||
) : (
|
) : (
|
||||||
<ActivityContributionChart session={session} />
|
<ActivityContributionChart session={session} />
|
||||||
)}
|
)}
|
||||||
<UserProgress />
|
<UserProgress />
|
||||||
</div>
|
|
||||||
<UserProgressTable
|
<UserProgressTable
|
||||||
session={session}
|
session={session}
|
||||||
ndk={ndk}
|
ndk={ndk}
|
||||||
@ -56,6 +57,8 @@ const UserProfile = () => {
|
|||||||
windowWidth={windowWidth}
|
windowWidth={windowWidth}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -41,8 +41,8 @@ const UserProfileCard = ({ user }) => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="lg:w-1/4 bg-gray-800 rounded-lg p-4 border border-gray-700 shadow-md">
|
||||||
<div className="relative flex w-full items-center justify-center">
|
<div className="flex flex-row gap-4">
|
||||||
<Image
|
<Image
|
||||||
alt="user's avatar"
|
alt="user's avatar"
|
||||||
src={returnImageProxy(user.avatar, user?.pubkey || "")}
|
src={returnImageProxy(user.avatar, user?.pubkey || "")}
|
||||||
@ -50,7 +50,9 @@ const UserProfileCard = ({ user }) => {
|
|||||||
height={100}
|
height={100}
|
||||||
className="rounded-full my-4"
|
className="rounded-full my-4"
|
||||||
/>
|
/>
|
||||||
<div className="absolute top-8 right-80 max-tab:right-20 max-mob:left-0">
|
|
||||||
|
<div className="flex flex-col gap-2 pt-4 w-full relative">
|
||||||
|
<div className="absolute top-0 right-0">
|
||||||
<i
|
<i
|
||||||
className="pi pi-ellipsis-h text-2xl cursor-pointer"
|
className="pi pi-ellipsis-h text-2xl cursor-pointer"
|
||||||
onClick={(e) => menu.current.toggle(e)}
|
onClick={(e) => menu.current.toggle(e)}
|
||||||
@ -62,29 +64,58 @@ const UserProfileCard = ({ user }) => {
|
|||||||
id="profile-options-menu"
|
id="profile-options-menu"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<h3 className="self-start">
|
||||||
|
|
||||||
|
|
||||||
<h1 className="text-center text-2xl my-2">
|
|
||||||
{user.username || user?.name || user?.email || "Anon"}
|
{user.username || user?.name || user?.email || "Anon"}
|
||||||
</h1>
|
</h3>
|
||||||
{user.pubkey && (
|
{
|
||||||
<h2 className="text-center text-xl my-2 truncate max-tab:px-4 max-mob:px-4">
|
user?.pubkey && (
|
||||||
<Tooltip target=".pubkey-tooltip" content={"this is your nostr npub"} />
|
<div className="flex flex-row gap-2">
|
||||||
{nip19.npubEncode(user.pubkey)} <i className="pi pi-question-circle text-xl pubkey-tooltip" />
|
<p className="truncate">
|
||||||
</h2>
|
{nip19.npubEncode(user.pubkey).slice(0, 12)}...
|
||||||
|
</p>
|
||||||
|
<Tooltip target=".pubkey-tooltip" content={"this is your account pubkey"} />
|
||||||
|
<i className="pi pi-question-circle pubkey-tooltip text-xs cursor-pointer" />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{user?.createdAt && (
|
||||||
|
<p className="truncate">
|
||||||
|
Joined: {new Date(user.createdAt).toLocaleDateString()}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
{user?.lightningAddress && (
|
</div>
|
||||||
<h3 className="w-fit mx-auto text-center text-xl my-2 bg-gray-800 rounded-lg p-4">
|
</div>
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
{user?.lightningAddress ? (
|
||||||
|
<h4 className="my-2 bg-gray-900 rounded-lg p-4">
|
||||||
<span className="font-bold">Lightning Address:</span> {user.lightningAddress.name}@plebdevs.com <i className="pi pi-copy cursor-pointer hover:text-gray-400" onClick={() => copyToClipboard(user.lightningAddress.name + "@plebdevs.com")} />
|
<span className="font-bold">Lightning Address:</span> {user.lightningAddress.name}@plebdevs.com <i className="pi pi-copy cursor-pointer hover:text-gray-400" onClick={() => copyToClipboard(user.lightningAddress.name + "@plebdevs.com")} />
|
||||||
</h3>
|
</h4>
|
||||||
|
) : (
|
||||||
|
<div className="flex flex-row justify-between my-2 bg-gray-900 rounded-lg p-4">
|
||||||
|
<h4 >
|
||||||
|
<span className="font-bold">Lightning Address:</span> None
|
||||||
|
</h4>
|
||||||
|
{/* todo: add tooltip */}
|
||||||
|
<Tooltip target=".lightning-address-tooltip" content={"this is your account lightning address"} />
|
||||||
|
<i className="pi pi-question-circle lightning-address-tooltip text-xs cursor-pointer" />
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{user?.nip05 && (
|
{user?.nip05 ? (
|
||||||
<h3 className="w-fit mx-auto text-center text-xl my-2 bg-gray-800 rounded-lg p-4">
|
<h4 className="my-2 bg-gray-900 rounded-lg p-4">
|
||||||
<span className="font-bold">NIP-05:</span> {user.nip05.name}@plebdevs.com <i className="pi pi-copy cursor-pointer hover:text-gray-400" onClick={() => copyToClipboard(user.nip05.name + "@plebdevs.com")} />
|
<span className="font-bold">NIP-05:</span> {user.nip05.name}@plebdevs.com <i className="pi pi-copy cursor-pointer hover:text-gray-400" onClick={() => copyToClipboard(user.nip05.name + "@plebdevs.com")} />
|
||||||
</h3>
|
</h4>
|
||||||
|
) : (
|
||||||
|
<div className="flex flex-row justify-between my-2 bg-gray-900 rounded-lg p-4">
|
||||||
|
<h4>
|
||||||
|
<span className="font-bold">NIP-05:</span> None
|
||||||
|
</h4>
|
||||||
|
{/* todo: add tooltip */}
|
||||||
|
<Tooltip target=".nip05-tooltip" content={"this is your account nip05"} />
|
||||||
|
<i className="pi pi-question-circle nip05-tooltip text-xs cursor-pointer" />
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import { useRouter } from 'next/router';
|
|||||||
import GenericButton from '@/components/buttons/GenericButton';
|
import GenericButton from '@/components/buttons/GenericButton';
|
||||||
import UserBadges from '@/components/profile/UserBadges';
|
import UserBadges from '@/components/profile/UserBadges';
|
||||||
import UserProgressFlow from './UserProgressFlow';
|
import UserProgressFlow from './UserProgressFlow';
|
||||||
|
import { Tooltip } from 'primereact/tooltip';
|
||||||
|
|
||||||
const allTasks = [
|
const allTasks = [
|
||||||
{
|
{
|
||||||
@ -56,12 +57,14 @@ const UserProgress = () => {
|
|||||||
const [completedCourses, setCompletedCourses] = useState([]);
|
const [completedCourses, setCompletedCourses] = useState([]);
|
||||||
const [tasks, setTasks] = useState([]);
|
const [tasks, setTasks] = useState([]);
|
||||||
const [showBadges, setShowBadges] = useState(false);
|
const [showBadges, setShowBadges] = useState(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { data: session, update } = useSession();
|
const { data: session, update } = useSession();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (session?.user) {
|
if (session?.user) {
|
||||||
|
setIsLoading(true);
|
||||||
const user = session.user;
|
const user = session.user;
|
||||||
const ids = user?.userCourses?.map(course => course?.completed ? course.courseId : null).filter(id => id !== null);
|
const ids = user?.userCourses?.map(course => course?.completed ? course.courseId : null).filter(id => id !== null);
|
||||||
if (ids && ids.length > 0) {
|
if (ids && ids.length > 0) {
|
||||||
@ -74,6 +77,7 @@ const UserProgress = () => {
|
|||||||
calculateProgress([]);
|
calculateProgress([]);
|
||||||
calculateCurrentTier([]);
|
calculateCurrentTier([]);
|
||||||
}
|
}
|
||||||
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
}, [session]);
|
}, [session]);
|
||||||
|
|
||||||
@ -173,8 +177,13 @@ const UserProgress = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-800 rounded-3xl p-6 w-[940px] max-mob:w-full max-tab:w-full mx-auto my-8">
|
<div className="bg-gray-800 rounded-lg p-4 m-2 w-full border border-gray-700 shadow-md">
|
||||||
|
<div className="flex flex-row justify-between items-center">
|
||||||
<h1 className="text-3xl font-bold text-white mb-2">Dev Journey</h1>
|
<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>
|
||||||
<p className="text-gray-400 mb-4">Track your progress from Pleb to Plebdev</p>
|
<p className="text-gray-400 mb-4">Track your progress from Pleb to Plebdev</p>
|
||||||
|
|
||||||
<div className="flex justify-between items-center mb-2">
|
<div className="flex justify-between items-center mb-2">
|
||||||
@ -200,11 +209,9 @@ const UserProgress = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-6">
|
<div className="flex gap-6 mb-6">
|
||||||
<UserProgressFlow tasks={tasks} />
|
<div className="w-1/2">
|
||||||
</div>
|
<ul className="space-y-6 pt-2">
|
||||||
|
|
||||||
<ul className="space-y-4 mb-6">
|
|
||||||
{tasks.map((task, index) => (
|
{tasks.map((task, index) => (
|
||||||
<li key={index}>
|
<li key={index}>
|
||||||
<Accordion
|
<Accordion
|
||||||
@ -246,7 +253,7 @@ const UserProgress = () => {
|
|||||||
{task.subTasks && (
|
{task.subTasks && (
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
{task.subTasks.map((subTask, subIndex) => (
|
{task.subTasks.map((subTask, subIndex) => (
|
||||||
<li key={subIndex} className="flex items-center">
|
<li key={subIndex} className="flex items-center pl-[28px]">
|
||||||
{subTask.completed ? (
|
{subTask.completed ? (
|
||||||
<div className="w-4 h-4 bg-green-500 rounded-full flex items-center justify-center mr-3">
|
<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>
|
<i className="pi pi-check text-white text-sm"></i>
|
||||||
@ -282,6 +289,18 @@ const UserProgress = () => {
|
|||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-1/2">
|
||||||
|
{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>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
className="w-full py-3 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-full font-semibold"
|
className="w-full py-3 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-full font-semibold"
|
||||||
|
@ -3,19 +3,20 @@ import ReactFlow, {
|
|||||||
Background,
|
Background,
|
||||||
Handle,
|
Handle,
|
||||||
Position,
|
Position,
|
||||||
|
Controls
|
||||||
} from 'reactflow';
|
} from 'reactflow';
|
||||||
import 'reactflow/dist/style.css';
|
import 'reactflow/dist/style.css';
|
||||||
|
|
||||||
const CustomNode = ({ data }) => (
|
const CustomNode = ({ data }) => (
|
||||||
<div className={`px-4 py-2 rounded-lg shadow-md w-48 text-center transition-all duration-300 ${
|
<div className={`px-4 py-2 rounded-lg shadow-md w-48 text-center transition-all duration-300 ${
|
||||||
data.completed
|
data.completed
|
||||||
? 'bg-green-500 text-white border-2 border-green-400'
|
? 'bg-green-500 text-white border-2 border-green-400 bg-opacity-50'
|
||||||
: 'bg-gray-700 text-gray-300 border-2 border-gray-600'
|
: 'bg-gray-700 text-gray-300 border-2 border-gray-600 bg-opacity-50'
|
||||||
}`}>
|
}`}>
|
||||||
<Handle type="target" position={Position.Top} />
|
<Handle type="target" position={Position.Top} />
|
||||||
<div className="flex items-center justify-center gap-2">
|
<div className="flex items-center justify-center gap-2">
|
||||||
{data.completed ? (
|
{data.completed ? (
|
||||||
<div className="w-5 h-5 bg-green-400 rounded-full flex items-center justify-center">
|
<div className="w-5 h-5 bg-green-500 rounded-full flex items-center justify-center">
|
||||||
<i className="pi pi-check text-white text-sm"></i>
|
<i className="pi pi-check text-white text-sm"></i>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@ -37,6 +38,13 @@ const nodeTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const UserProgressFlow = ({ tasks }) => {
|
const UserProgressFlow = ({ tasks }) => {
|
||||||
|
const [mounted, setMounted] = React.useState(false);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
setMounted(true);
|
||||||
|
return () => setMounted(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const nodes = [
|
const nodes = [
|
||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
@ -113,6 +121,8 @@ const UserProgressFlow = ({ tasks }) => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (!mounted) return <div style={{ height: 400 }} className="bg-gray-800 rounded-3xl" />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: 400 }} className="bg-gray-800 rounded-3xl">
|
<div style={{ height: 400 }} className="bg-gray-800 rounded-3xl">
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
@ -120,16 +130,20 @@ const UserProgressFlow = ({ tasks }) => {
|
|||||||
edges={edges}
|
edges={edges}
|
||||||
nodeTypes={nodeTypes}
|
nodeTypes={nodeTypes}
|
||||||
fitView
|
fitView
|
||||||
preventScrolling
|
|
||||||
zoomOnScroll={false}
|
|
||||||
panOnScroll={false}
|
|
||||||
nodesDraggable={false}
|
nodesDraggable={false}
|
||||||
nodesConnectable={false}
|
nodesConnectable={false}
|
||||||
elementsSelectable={false}
|
elementsSelectable={false}
|
||||||
minZoom={0.5}
|
panOnDrag={false}
|
||||||
maxZoom={2}
|
zoomOnScroll={false}
|
||||||
|
panOnScroll={false}
|
||||||
|
selectNodesOnDrag={false}
|
||||||
|
preventScrolling
|
||||||
|
minZoom={1}
|
||||||
|
maxZoom={1}
|
||||||
|
defaultViewport={{ x: 0, y: 0, zoom: 1 }}
|
||||||
>
|
>
|
||||||
<Background color="#4a5568" gap={16} />
|
<Background color="#4a5568" gap={16} />
|
||||||
|
{/* <Controls position="top-right" /> */}
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -231,7 +231,8 @@ export const authOptions = {
|
|||||||
purchased: fullUser.purchased,
|
purchased: fullUser.purchased,
|
||||||
nip05: fullUser.nip05,
|
nip05: fullUser.nip05,
|
||||||
lightningAddress: fullUser.lightningAddress,
|
lightningAddress: fullUser.lightningAddress,
|
||||||
githubUsername: token.githubUsername
|
githubUsername: token.githubUsername,
|
||||||
|
createdAt: fullUser.createdAt
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add GitHub account info to session if it exists
|
// Add GitHub account info to session if it exists
|
||||||
@ -249,7 +250,6 @@ export const authOptions = {
|
|||||||
return session;
|
return session;
|
||||||
},
|
},
|
||||||
async jwt({ token, user, account, profile, session }) {
|
async jwt({ token, user, account, profile, session }) {
|
||||||
console.log("JWT", token, user, account, profile, session);
|
|
||||||
// If we are linking a github account to an existing email or anon account (we have privkey)
|
// If we are linking a github account to an existing email or anon account (we have privkey)
|
||||||
if (account?.provider === "github" && user?.id && user?.pubkey && user?.privkey) {
|
if (account?.provider === "github" && user?.id && user?.pubkey && user?.privkey) {
|
||||||
try {
|
try {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user