diff --git a/src/components/Dashboard/DashboardPage.tsx b/src/components/Dashboard/DashboardPage.tsx index 3483cef76..f55370d6e 100644 --- a/src/components/Dashboard/DashboardPage.tsx +++ b/src/components/Dashboard/DashboardPage.tsx @@ -46,9 +46,10 @@ export function DashboardPage(props: DashboardPageProps) { getAllTeams().finally(() => setIsLoading(false)); }, []); - const userAvatar = currentUser?.avatar - ? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${currentUser.avatar}` - : '/images/default-avatar.png'; + const userAvatar = + currentUser?.avatar && !isLoading + ? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${currentUser.avatar}` + : '/images/default-avatar.png'; return (
@@ -118,6 +119,6 @@ export function DashboardPage(props: DashboardPageProps) { function DashboardTabSkeleton() { return ( -
+
); } diff --git a/src/components/Dashboard/DashboardProgressCard.tsx b/src/components/Dashboard/DashboardProgressCard.tsx index b2041c523..376fc3871 100644 --- a/src/components/Dashboard/DashboardProgressCard.tsx +++ b/src/components/Dashboard/DashboardProgressCard.tsx @@ -1,4 +1,5 @@ import { getPercentage } from '../../helper/number'; +import { getRelativeTimeString } from '../../lib/date'; import type { UserProgress } from '../TeamProgress/TeamProgressPage'; type DashboardProgressCardProps = { @@ -17,6 +18,7 @@ export function DashboardProgressCard(props: DashboardProgressCardProps) { skipped: skippedCount, roadmapSlug, isCustomResource, + updatedAt, } = progress; let url = @@ -34,16 +36,29 @@ export function DashboardProgressCard(props: DashboardProgressCardProps) { return (

{resourceTitle}

-
-
+
+
+
+
+ + {Math.floor(+progressPercentage)}% +
+ +

+ {isCustomResource ? ( + <>Last updated {getRelativeTimeString(updatedAt)} + ) : ( + <>Last practiced {getRelativeTimeString(updatedAt)} + )} +

); } diff --git a/src/components/Dashboard/DashboardTab.tsx b/src/components/Dashboard/DashboardTab.tsx index 0895fe107..74c4fdec7 100644 --- a/src/components/Dashboard/DashboardTab.tsx +++ b/src/components/Dashboard/DashboardTab.tsx @@ -20,7 +20,7 @@ export function DashboardTab(props: DashboardTabProps) { + ) : ( ) : null; + const Slot = isAIGeneratedRoadmaps ? 'a' : 'button'; + return ( <> {customRoadmapModal} +

- Custom Roadmaps + {isAIGeneratedRoadmaps ? 'AI Generated Roadmaps' : 'Custom Roadmaps'}

- {isLoading ? ( -
- {Array.from({ length: 8 }).map((_, index) => ( - - ))} -
- ) : ( -
- {progresses.map((progress) => ( - - ))} +
+ {isLoading ? ( + <> + {Array.from({ length: 8 }).map((_, index) => ( + + ))} + + ) : ( + <> + {progresses.map((progress) => ( + + ))} - -
- )} + { + setIsCreateCustomRoadmapModalOpen(true); + }, + })} + > + {isAIGeneratedRoadmaps ? '+ Generate New' : '+ Create New'} + + + )} +
); } diff --git a/src/components/Dashboard/ListDashboardProgress.tsx b/src/components/Dashboard/ListDashboardProgress.tsx index 258d7c665..4fd9609f2 100644 --- a/src/components/Dashboard/ListDashboardProgress.tsx +++ b/src/components/Dashboard/ListDashboardProgress.tsx @@ -22,22 +22,24 @@ export function ListDashboardProgress(props: ListDashboardProgressProps) { Progress and Bookmarks - {isLoading ? ( -
- {Array.from({ length: 8 }).map((_, index) => ( - - ))} -
- ) : ( -
- {progresses.map((progress) => ( - - ))} -
- )} +
+ {isLoading ? ( + <> + {Array.from({ length: 8 }).map((_, index) => ( + + ))} + + ) : ( + <> + {progresses.map((progress) => ( + + ))} + + )} +
); } @@ -48,6 +50,6 @@ export function DashboardProgressCardSkeleton( props: DashboardProgressCardSkeletonProps, ) { return ( -
+
); } diff --git a/src/components/Dashboard/PersonalDashboard.tsx b/src/components/Dashboard/PersonalDashboard.tsx index 073e4510c..a3399906a 100644 --- a/src/components/Dashboard/PersonalDashboard.tsx +++ b/src/components/Dashboard/PersonalDashboard.tsx @@ -47,7 +47,6 @@ export function PersonalDashboard(props: PersonalDashboardProps) { builtInBestPractices = [], builtInSkillRoadmaps = [], } = props; - const toast = useToast(); const [isLoading, setIsLoading] = useState(true); const [personalDashboardDetails, setPersonalDashboardDetails] = @@ -111,22 +110,37 @@ export function PersonalDashboard(props: PersonalDashboardProps) { return updatedAtB.getTime() - updatedAtA.getTime(); }); - const { avatar, name, headline, email, username } = - personalDashboardDetails || {}; + const aiGeneratedRoadmaps = customRoadmaps.filter( + (progress) => progress?.aiRoadmapId, + ); + const customRoadmapsToShow = customRoadmaps.filter( + (progress) => !progress?.aiRoadmapId, + ); + + const { avatar, name } = personalDashboardDetails || {}; const avatarLink = avatar ? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${avatar}` : '/images/default-avatar.png'; const currentPeriod = getCurrentPeriod(); - const relatedRoadmapIds = [...builtInRoleRoadmaps, ...builtInSkillRoadmaps] + const allRoadmapsAndBestPractices = [ + ...builtInRoleRoadmaps, + ...builtInSkillRoadmaps, + ...builtInBestPractices, + ]; + + const relatedRoadmapIds = allRoadmapsAndBestPractices .filter((roadmap) => learningRoadmapsToShow?.some( (learningRoadmap) => learningRoadmap.resourceId === roadmap.id, ), ) .flatMap((roadmap) => roadmap.relatedRoadmapIds) - .filter(Boolean); + .filter( + (roadmapId) => + !learningRoadmapsToShow.some((lr) => lr.resourceId === roadmapId), + ); const recommendedRoadmapIds = new Set( relatedRoadmapIds.length === 0 @@ -134,10 +148,9 @@ export function PersonalDashboard(props: PersonalDashboardProps) { : relatedRoadmapIds, ); - const recommendedRoadmaps = [ - ...builtInRoleRoadmaps, - ...builtInSkillRoadmaps, - ].filter((roadmap) => recommendedRoadmapIds.has(roadmap.id)); + const recommendedRoadmaps = allRoadmapsAndBestPractices.filter((roadmap) => + recommendedRoadmapIds.has(roadmap.id), + ); return (
@@ -149,47 +162,54 @@ export function PersonalDashboard(props: PersonalDashboardProps) { )} -
+
{isLoading ? ( -
+ <> + + + + + ) : ( - -
- {name} -
- -
-

{name}

-

Setup your profile

-
-
- )} + <> + +
+ {name} +
+ +
+

{name}

+

Setup your profile

+
+
- - - + + + + + )}
-
); @@ -238,9 +258,15 @@ function DashboardCard(props: DashboardCardProps) {
-

{title}

+

{title}

{description}

); } + +function DashboardCardSkeleton() { + return ( +
+ ); +} diff --git a/src/components/Dashboard/RecommendedRoadmaps.tsx b/src/components/Dashboard/RecommendedRoadmaps.tsx index 9b587ea73..1c18338e5 100644 --- a/src/components/Dashboard/RecommendedRoadmaps.tsx +++ b/src/components/Dashboard/RecommendedRoadmaps.tsx @@ -1,6 +1,5 @@ -import { useEffect, useState } from 'react'; import type { BuiltInRoadmap } from './PersonalDashboard'; -import { MarkFavorite } from '../FeaturedItems/MarkFavorite'; +import { ArrowUpRight } from 'lucide-react'; type RecommendedRoadmapsProps = { roadmaps: BuiltInRoadmap[]; @@ -8,20 +7,7 @@ type RecommendedRoadmapsProps = { }; export function RecommendedRoadmaps(props: RecommendedRoadmapsProps) { - const { roadmaps, isLoading } = props; - - const [showAll, setShowAll] = useState(false); - const roadmapsToShow = showAll ? roadmaps : roadmaps.slice(0, 12); - - const [isMounted, setIsMounted] = useState(false); - - useEffect(() => { - setIsMounted(true); - }, []); - - useEffect(() => { - setShowAll(roadmaps.length < 12); - }, [roadmaps]); + const { roadmaps: roadmapsToShow, isLoading } = props; return ( <> @@ -36,57 +22,39 @@ export function RecommendedRoadmaps(props: RecommendedRoadmapsProps) { ))}
) : ( -
-
- {roadmapsToShow.map((roadmap) => ( -
- - {roadmap.title} - - - {isMounted && ( - - )} -
- ))} -
- - {!showAll && ( -
- -
- )} +
+ {roadmapsToShow.map((roadmap) => ( + + ))}
)} ); } +type RecommendedRoadmapCardProps = { + roadmap: BuiltInRoadmap; +}; + +export function RecommendedRoadmapCard(props: RecommendedRoadmapCardProps) { + const { roadmap } = props; + const { title, url, description } = roadmap; + + return ( + + {title} + {description} + + + + ); +} + function RecommendedCardSkeleton() { return ( -
+
); } diff --git a/src/components/TeamProgress/TeamProgressPage.tsx b/src/components/TeamProgress/TeamProgressPage.tsx index 6f386d55e..b0e39b660 100644 --- a/src/components/TeamProgress/TeamProgressPage.tsx +++ b/src/components/TeamProgress/TeamProgressPage.tsx @@ -23,6 +23,7 @@ export type UserProgress = { updatedAt: string; isCustomResource?: boolean; roadmapSlug?: string; + aiRoadmapId?: string; }; export type TeamMember = { @@ -191,7 +192,7 @@ export function TeamProgressPage() { key={grouping.value} className={`rounded-md border p-1 px-2 text-sm ${ selectedGrouping === grouping.value - ? ' border-gray-400 bg-gray-200 ' + ? 'border-gray-400 bg-gray-200' : '' }`} onClick={() => setSelectedGrouping(grouping.value)}