Refactor progress stack

feat/dashboard
Kamran Ahmed 3 months ago
parent 10e493de99
commit f51a85ac21
  1. 37
      src/components/Dashboard/PersonalDashboard.tsx
  2. 147
      src/components/Dashboard/ProgressStack.tsx

@ -162,8 +162,6 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${avatar}`
: '/images/default-avatar.png';
const currentPeriod = getCurrentPeriod();
const allRoadmapsAndBestPractices = [
...builtInRoleRoadmaps,
...builtInSkillRoadmaps,
@ -221,7 +219,7 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
<div className="h-7 w-1/4 animate-pulse rounded-lg bg-gray-200"></div>
) : (
<h2 className="text-lg font-medium">
Hi {name}, good {currentPeriod}!
Hi {name}, good {getCurrentPeriod()}!
</h2>
)}
@ -235,23 +233,12 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
</>
) : (
<>
<a
className="overflow-hidden rounded-lg border border-gray-300 bg-white hover:border-gray-400 hover:bg-gray-50"
<DashboardCard
imgUrl={avatarLink}
title={name!}
description="Setup your profile"
href="/account/update-profile"
>
<div className="px-4 pb-1.5 pt-3.5">
<img
src={avatarLink}
alt={name}
className="size-8 rounded-full"
/>
</div>
<div className="flex flex-col gap-0.5 p-4">
<h3 className="truncate font-medium">{name}</h3>
<p className="text-xs">Setup your profile</p>
</div>
</a>
<DashboardCard
icon={BookEmoji}
@ -259,6 +246,7 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
description="Visit our Roadmaps"
href="/roadmaps"
/>
<DashboardCard
icon={ConstructionEmoji}
title="Practice your skills"
@ -302,14 +290,15 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
}
type DashboardCardProps = {
icon: JSXElementConstructor<any>;
icon?: JSXElementConstructor<any>;
imgUrl?: string;
title: string;
description: string;
href: string;
};
function DashboardCard(props: DashboardCardProps) {
const { icon: Icon, title, description, href } = props;
const { icon: Icon, imgUrl, title, description, href } = props;
return (
<a
@ -317,9 +306,17 @@ function DashboardCard(props: DashboardCardProps) {
target="_blank"
className="flex flex-col overflow-hidden rounded-lg border border-gray-300 bg-white hover:border-gray-400 hover:bg-gray-50"
>
{Icon && (
<div className="px-4 pb-3 pt-4">
<Icon className="size-6" />
</div>
)}
{imgUrl && (
<div className="px-4 pb-1.5 pt-3.5">
<img src={imgUrl} alt={title} className="size-8 rounded-full" />
</div>
)}
<div className="flex grow flex-col justify-center gap-0.5 p-4">
<h3 className="truncate font-medium text-black">{title}</h3>

@ -23,6 +23,57 @@ const MAX_PROGRESS_TO_SHOW = 5;
const MAX_PROJECTS_TO_SHOW = 8;
const MAX_BOOKMARKS_TO_SHOW = 8;
type ProgressLaneProps = {
title: string;
linkText?: string;
linkHref?: string;
isLoading?: boolean;
loadingSkeletonCount?: number;
loadingSkeletonClassName?: string;
children: React.ReactNode;
};
function ProgressLane(props: ProgressLaneProps) {
const {
title,
linkText,
linkHref,
isLoading = false,
loadingSkeletonCount = 4,
loadingSkeletonClassName = '',
children,
} = props;
return (
<div className="h-full rounded-md border bg-white p-4 shadow-sm">
<div className="flex items-center justify-between gap-2">
<h3 className="text-xs uppercase text-gray-500">{title}</h3>
{linkText && linkHref && (
<a
href={linkHref}
className="flex items-center gap-1 text-xs text-gray-500"
>
<ArrowUpRight size={12} />
{linkText}
</a>
)}
</div>
<div className="mt-4 flex flex-col gap-2.5">
{isLoading && (
<>
{Array.from({ length: loadingSkeletonCount }).map((_, index) => (
<CardSkeleton key={index} className={loadingSkeletonClassName} />
))}
</>
)}
{!isLoading && children}
</div>
</div>
);
}
export function ProgressStack(props: ProgressStackProps) {
const { progresses, projects, isLoading, accountStreak, topicDoneToday } =
props;
@ -77,19 +128,12 @@ export function ProgressStack(props: ProgressStackProps) {
</div>
<div className="mt-2 grid min-h-[330px] grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-3">
<div className="h-full rounded-md border bg-white p-4 shadow-sm">
<h3 className="text-xs uppercase text-gray-500">Your Progress</h3>
<div className="mt-4 flex flex-col gap-2">
{isLoading ? (
<>
<CardSkeleton />
<CardSkeleton />
<CardSkeleton />
<CardSkeleton />
<CardSkeleton />
</>
) : (
<ProgressLane
title={'Your Expertise'}
isLoading={isLoading}
loadingSkeletonCount={5}
>
{userProgressesToShow.length > 0 && (
<>
{userProgressesToShow.map((progress) => {
return (
@ -101,7 +145,6 @@ export function ProgressStack(props: ProgressStackProps) {
})}
</>
)}
</div>
{userProgresses.length > MAX_PROGRESS_TO_SHOW && (
<ShowAllButton
@ -112,36 +155,19 @@ export function ProgressStack(props: ProgressStackProps) {
className="mt-3"
/>
)}
</div>
</ProgressLane>
<div className="h-full rounded-md border bg-white p-4 shadow-sm">
<h3 className="text-xs uppercase text-gray-500">Projects</h3>
<div className="mt-4 flex flex-col gap-2.5">
{isLoading ? (
<>
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
</>
) : (
<>
<ProgressLane
title={'Projects'}
isLoading={isLoading}
loadingSkeletonClassName={'h-5'}
loadingSkeletonCount={8}
>
{projectsToShow.map((project) => {
return (
<DashboardProjectCard
key={project.projectId}
project={project}
/>
<DashboardProjectCard key={project.projectId} project={project} />
);
})}
</>
)}
</div>
{projects.length > MAX_PROJECTS_TO_SHOW && (
<ShowAllButton
@ -152,35 +178,16 @@ export function ProgressStack(props: ProgressStackProps) {
className="mt-3"
/>
)}
</div>
</ProgressLane>
<div className="h-full rounded-md border bg-white p-4 shadow-sm">
<div className="flex items-center justify-between gap-2">
<h3 className="text-xs uppercase text-gray-500">Bookmarks</h3>
<a
href="/roadmaps"
className="flex items-center gap-1 text-xs text-gray-500"
<ProgressLane
title={'Bookmarks'}
isLoading={isLoading}
loadingSkeletonClassName={'h-5'}
loadingSkeletonCount={8}
linkHref={'/roadmaps'}
linkText={'Explore'}
>
<ArrowUpRight size={12} />
Explore
</a>
</div>
<div className="mt-4 flex flex-col gap-2.5">
{isLoading ? (
<>
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
<CardSkeleton className="h-5" />
</>
) : (
<>
{bookmarksToShow.map((progress) => {
return (
<DashboardBookmarkCard
@ -189,10 +196,6 @@ export function ProgressStack(props: ProgressStackProps) {
/>
);
})}
</>
)}
</div>
{bookmarkedProgresses.length > MAX_BOOKMARKS_TO_SHOW && (
<ShowAllButton
showAll={showAllBookmarks}
@ -202,7 +205,7 @@ export function ProgressStack(props: ProgressStackProps) {
className="mt-3"
/>
)}
</div>
</ProgressLane>
</div>
</>
);
@ -260,7 +263,7 @@ function StatsCard(props: StatsCardProps) {
return (
<div className="flex flex-col gap-1 rounded-md border bg-white p-4 shadow-sm">
<h3 className="text-xs uppercase text-gray-500">{title}</h3>
<h3 className="mb-1 text-xs uppercase text-gray-500">{title}</h3>
{isLoading ? (
<CardSkeleton className="h-8" />
) : (

Loading…
Cancel
Save