From d9c25d8dff9fad96c281542c9f2d15a78e56d745 Mon Sep 17 00:00:00 2001 From: Kamran Ahmed Date: Mon, 10 Feb 2025 22:53:39 +0000 Subject: [PATCH] Add builtin roadmaps and best practices --- src/components/Dashboard/DashboardPage.tsx | 98 +++-- .../Dashboard/PersonalDashboard.tsx | 382 ++++++++++-------- .../HeroSection/FavoriteRoadmaps.tsx | 38 +- src/pages/dashboard.astro | 2 + src/styles/global.css | 4 + 5 files changed, 285 insertions(+), 239 deletions(-) diff --git a/src/components/Dashboard/DashboardPage.tsx b/src/components/Dashboard/DashboardPage.tsx index aa7914a75..658d0352c 100644 --- a/src/components/Dashboard/DashboardPage.tsx +++ b/src/components/Dashboard/DashboardPage.tsx @@ -1,15 +1,15 @@ +import { useStore } from '@nanostores/react'; import { useEffect, useState } from 'react'; -import { httpGet } from '../../lib/http'; +import { cn } from '../../../editor/utils/classname'; +import { useParams } from '../../hooks/use-params'; import { useToast } from '../../hooks/use-toast'; -import { useStore } from '@nanostores/react'; +import { httpGet } from '../../lib/http'; +import { getUser } from '../../lib/jwt'; import { $teamList } from '../../stores/team'; import type { TeamListResponse } from '../TeamDropdown/TeamDropdown'; import { DashboardTabButton } from './DashboardTabButton'; import { PersonalDashboard, type BuiltInRoadmap } from './PersonalDashboard'; import { TeamDashboard } from './TeamDashboard'; -import { getUser } from '../../lib/jwt'; -import { useParams } from '../../hooks/use-params'; -import { cn } from '../../../editor/utils/classname'; type DashboardPageProps = { builtInRoleRoadmaps?: BuiltInRoadmap[]; @@ -69,55 +69,57 @@ export function DashboardPage(props: DashboardPageProps) { return ( <>
-
- +
+
+ - {!isLoading && ( - <> - {teamList.map((team) => { - const { avatar } = team; - const avatarUrl = avatar - ? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${avatar}` - : '/images/default-avatar.png'; - return ( - - ); - })} - - - )} + {!isLoading && ( + <> + {teamList.map((team) => { + const { avatar } = team; + const avatarUrl = avatar + ? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${avatar}` + : '/images/default-avatar.png'; + return ( + + ); + })} + + + )} +
{!selectedTeamId && !isTeamPage && ( -
+
); } - -function DashboardTabSkeleton() { - return ( -
- ); -} diff --git a/src/components/Dashboard/PersonalDashboard.tsx b/src/components/Dashboard/PersonalDashboard.tsx index f61f5115c..2e99a343f 100644 --- a/src/components/Dashboard/PersonalDashboard.tsx +++ b/src/components/Dashboard/PersonalDashboard.tsx @@ -1,27 +1,26 @@ -import { type JSXElementConstructor, useEffect, useState } from 'react'; -import { httpGet } from '../../lib/http'; -import type { UserProgress } from '../TeamProgress/TeamProgressPage'; -import type { ProjectStatusDocument } from '../Projects/ListProjectSolutions'; -import type { PageType } from '../CommandMenu/CommandMenu'; -import { useToast } from '../../hooks/use-toast'; -import { getCurrentPeriod } from '../../lib/date'; -import { ListDashboardCustomProgress } from './ListDashboardCustomProgress'; -import { RecommendedRoadmaps } from './RecommendedRoadmaps'; -import { ProgressStack } from './ProgressStack'; import { useStore } from '@nanostores/react'; -import { $accountStreak, type StreakResponse } from '../../stores/streak'; -import { CheckEmoji } from '../ReactIcons/CheckEmoji.tsx'; -import { ConstructionEmoji } from '../ReactIcons/ConstructionEmoji.tsx'; -import { BookEmoji } from '../ReactIcons/BookEmoji.tsx'; -import { DashboardAiRoadmaps } from './DashboardAiRoadmaps.tsx'; +import { + CheckCircle, + ChevronsDownUp, + FolderGit2, + Zap, + type LucideIcon, +} from 'lucide-react'; +import { useEffect, useState } from 'react'; import type { AllowedProfileVisibility } from '../../api/user.ts'; -import { PencilIcon, type LucideIcon } from 'lucide-react'; +import { useToast } from '../../hooks/use-toast'; import { cn } from '../../lib/classname.ts'; +import { httpGet } from '../../lib/http'; import type { AllowedRoadmapRenderer } from '../../lib/roadmap.ts'; +import { $accountStreak, type StreakResponse } from '../../stores/streak'; +import type { PageType } from '../CommandMenu/CommandMenu'; import { FavoriteRoadmaps, + HeroRoadmap, type AIRoadmapType, } from '../HeroSection/FavoriteRoadmaps.tsx'; +import type { ProjectStatusDocument } from '../Projects/ListProjectSolutions'; +import type { UserProgress } from '../TeamProgress/TeamProgressPage'; type UserDashboardResponse = { name: string; @@ -42,6 +41,7 @@ export type BuiltInRoadmap = { title: string; description: string; isFavorite?: boolean; + isNew?: boolean; relatedRoadmapIds?: string[]; renderer?: AllowedRoadmapRenderer; metadata?: Record; @@ -53,6 +53,87 @@ type PersonalDashboardProps = { builtInBestPractices?: BuiltInRoadmap[]; }; +type DashboardStatsProps = { + accountStreak?: StreakResponse; + topicsDoneToday?: number; + finishedProjectsCount?: number; + isLoading: boolean; +}; + +type DashboardStatItemProps = { + icon: LucideIcon; + iconClassName: string; + value: number; + label: string; + isLoading: boolean; +}; + +function DashboardStatItem(props: DashboardStatItemProps) { + const { icon: Icon, iconClassName, value, label, isLoading } = props; + + return ( +
+ + + {value} {label} + +
+ ); +} + +function DashboardStats(props: DashboardStatsProps) { + const { + accountStreak, + topicsDoneToday = 0, + finishedProjectsCount = 0, + isLoading, + } = props; + + return ( +
+
+ + + +
+ + +
+ ); +} + export function PersonalDashboard(props: PersonalDashboardProps) { const { builtInRoleRoadmaps = [], @@ -236,181 +317,130 @@ export function PersonalDashboard(props: PersonalDashboardProps) { const { username } = personalDashboardDetails || {}; - // later on it will be switching of version based on localstorage - if (true) { - return ( -
- -
- ); - } - return ( -
- {isLoading ? ( -
- ) : ( -
-

- Hi {name}, good {getCurrentPeriod()}! -

- - Visit Homepage - -
- )} - -
- {isLoading ? ( - <> - - - - - - ) : ( - <> - - - - - - - - )} -
- - + p.submittedAt && p.repositoryUrl) + .length + } /> - - - - -
- ); -} +
+
+

+ Role Based Roadmaps +

-type DashboardCardProps = { - icon?: JSXElementConstructor; - imgUrl?: string; - title: string; - description: string; - href: string; - externalLinkIcon?: LucideIcon; - externalLinkText?: string; - externalLinkHref?: string; - className?: string; -}; +
+ {builtInRoleRoadmaps.map((roadmap) => { + const roadmapProgress = learningRoadmapsToShow.find( + (lr) => lr.resourceId === roadmap.id, + ); + + const percentageDone = + (((roadmapProgress?.skipped || 0) + + (roadmapProgress?.done || 0)) / + (roadmapProgress?.total || 1)) * + 100; + + return ( + + ); + })} +
+
+
-function DashboardCard(props: DashboardCardProps) { - const { - icon: Icon, - imgUrl, - title, - description, - href, - externalLinkHref, - externalLinkIcon: ExternalLinkIcon, - externalLinkText, - className, - } = props; +
+
+

+ Skill Based Roadmaps +

- return ( - - {imgUrl && ( -
- {title} -
- )} +
); } - -function DashboardCardSkeleton() { - return ( -
- ); -} diff --git a/src/components/HeroSection/FavoriteRoadmaps.tsx b/src/components/HeroSection/FavoriteRoadmaps.tsx index cfccf38fd..a1898ed03 100644 --- a/src/components/HeroSection/FavoriteRoadmaps.tsx +++ b/src/components/HeroSection/FavoriteRoadmaps.tsx @@ -8,6 +8,8 @@ import { ChevronUp, Eye, EyeOff, + CircleDashed, + Circle, } from 'lucide-react'; import type { ReactNode } from 'react'; import type { ResourceType } from '../../lib/resource-progress.ts'; @@ -38,6 +40,7 @@ type ProgressRoadmapProps = { isFavorite?: boolean; isTrackable?: boolean; + isNew?: boolean; }; export function HeroRoadmap(props: ProgressRoadmapProps) { @@ -50,6 +53,7 @@ export function HeroRoadmap(props: ProgressRoadmapProps) { isFavorite, allowFavorite = true, isTrackable = true, + isNew = false, } = props; return ( @@ -82,6 +86,16 @@ export function HeroRoadmap(props: ProgressRoadmapProps) { favorite={isFavorite} /> )} + + {isNew && ( + + + + + + New + + )} ); } @@ -132,22 +146,22 @@ export function HeroProject({ project }: HeroProjectProps) { return (
-

+

{project.title}

- {project.submittedAt && project.repositoryUrl - ? 'Submitted' - : 'Started'} + {project.submittedAt && project.repositoryUrl ? 'Done' : ''}
@@ -290,14 +304,14 @@ export function FavoriteRoadmaps(props: FavoriteRoadmapsProps) {
-
+
) as any } isLoading={isLoading} - title="Your projects" + title="Your active projects" rightContent={ completedProjects.length > 0 && (