Collapse and expand

pull/8189/head
Kamran Ahmed 3 months ago
parent d9c25d8dff
commit a143b0ec20
  1. 59
      src/components/Dashboard/PersonalDashboard.tsx
  2. 43
      src/components/HeroSection/FavoriteRoadmaps.tsx

@ -2,6 +2,7 @@ import { useStore } from '@nanostores/react';
import { import {
CheckCircle, CheckCircle,
ChevronsDownUp, ChevronsDownUp,
ChevronsUpDown,
FolderGit2, FolderGit2,
Zap, Zap,
type LucideIcon, type LucideIcon,
@ -58,6 +59,8 @@ type DashboardStatsProps = {
topicsDoneToday?: number; topicsDoneToday?: number;
finishedProjectsCount?: number; finishedProjectsCount?: number;
isLoading: boolean; isLoading: boolean;
isAllCollapsed: boolean;
onToggleCollapseAll: () => void;
}; };
type DashboardStatItemProps = { type DashboardStatItemProps = {
@ -98,10 +101,12 @@ function DashboardStats(props: DashboardStatsProps) {
topicsDoneToday = 0, topicsDoneToday = 0,
finishedProjectsCount = 0, finishedProjectsCount = 0,
isLoading, isLoading,
onToggleCollapseAll,
isAllCollapsed,
} = props; } = props;
return ( return (
<div className="container flex items-center justify-between gap-2 pb-2 pt-6 text-sm text-slate-400"> <div className="container flex items-center justify-between gap-2 pb-2 pt-6 text-sm text-slate-400 mb-3">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<DashboardStatItem <DashboardStatItem
icon={Zap} icon={Zap}
@ -126,9 +131,21 @@ function DashboardStats(props: DashboardStatsProps) {
/> />
</div> </div>
<button className="flex items-center gap-1 rounded-lg border border-transparent py-1.5 pl-3 pr-3 text-xs uppercase tracking-wide text-slate-400 hover:border-slate-800 hover:bg-slate-800"> <button
className="flex items-center gap-1 rounded-lg border border-transparent py-1.5 pl-3 pr-3 text-xs uppercase tracking-wide text-slate-400 hover:border-slate-800 hover:bg-slate-800"
onClick={onToggleCollapseAll}
>
{isAllCollapsed ? (
<>
<ChevronsUpDown className="size-3" />
<span>Expand All</span>
</>
) : (
<>
<ChevronsDownUp className="size-3" /> <ChevronsDownUp className="size-3" />
<span>Collapse All</span> <span>Collapse All</span>
</>
)}
</button> </button>
</div> </div>
); );
@ -142,7 +159,9 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
} = props; } = props;
const toast = useToast(); const toast = useToast();
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [isAllCollapsed, setIsAllCollapsed] = useState(false);
const [personalDashboardDetails, setPersonalDashboardDetails] = const [personalDashboardDetails, setPersonalDashboardDetails] =
useState<UserDashboardResponse>(); useState<UserDashboardResponse>();
const [projectDetails, setProjectDetails] = useState<PageType[]>([]); const [projectDetails, setProjectDetails] = useState<PageType[]>([]);
@ -261,37 +280,6 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
...builtInBestPractices, ...builtInBestPractices,
]; ];
const relatedRoadmapIds = allRoadmapsAndBestPractices
// take the ones that user is learning
.filter((roadmap) =>
learningRoadmapsToShow?.some(
(learningRoadmap) => learningRoadmap.resourceId === roadmap.id,
),
)
.flatMap((roadmap) => roadmap.relatedRoadmapIds)
// remove the ones that user is already learning or has bookmarked
.filter(
(roadmapId) =>
!learningRoadmapsToShow.some((lr) => lr.resourceId === roadmapId),
);
const recommendedRoadmapIds = new Set(
relatedRoadmapIds.length === 0
? [
'frontend',
'backend',
'devops',
'ai-data-scientist',
'full-stack',
'api-design',
]
: relatedRoadmapIds,
);
const recommendedRoadmaps = allRoadmapsAndBestPractices.filter((roadmap) =>
recommendedRoadmapIds.has(roadmap.id),
);
const enrichedProjects = personalDashboardDetails?.projects const enrichedProjects = personalDashboardDetails?.projects
.map((project) => { .map((project) => {
const projectDetail = projectDetails.find( const projectDetail = projectDetails.find(
@ -323,6 +311,10 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
isLoading={isLoading} isLoading={isLoading}
accountStreak={accountStreak} accountStreak={accountStreak}
topicsDoneToday={personalDashboardDetails?.topicDoneToday} topicsDoneToday={personalDashboardDetails?.topicDoneToday}
onToggleCollapseAll={() => {
setIsAllCollapsed(!isAllCollapsed);
}}
isAllCollapsed={isAllCollapsed}
finishedProjectsCount={ finishedProjectsCount={
enrichedProjects?.filter((p) => p.submittedAt && p.repositoryUrl) enrichedProjects?.filter((p) => p.submittedAt && p.repositoryUrl)
.length .length
@ -335,6 +327,7 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
aiRoadmaps={aiGeneratedRoadmaps} aiRoadmaps={aiGeneratedRoadmaps}
projects={enrichedProjects || []} projects={enrichedProjects || []}
isLoading={isLoading} isLoading={isLoading}
isAllCollapsed={isAllCollapsed}
/> />
<div className="relative mt-6 border-t border-t-[#1e293c] pt-12"> <div className="relative mt-6 border-t border-t-[#1e293c] pt-12">

@ -112,7 +112,7 @@ function HeroTitle(props: HeroTitleProps) {
return ( return (
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<p className="mb-4 flex items-center text-sm text-gray-400"> <p className="flex items-center text-sm text-gray-400">
{!isLoading && icon} {!isLoading && icon}
{isLoading && ( {isLoading && (
<span className="mr-1.5"> <span className="mr-1.5">
@ -134,6 +134,7 @@ type FavoriteRoadmapsProps = {
customRoadmaps: UserProgress[]; customRoadmaps: UserProgress[];
aiRoadmaps: AIRoadmapType[]; aiRoadmaps: AIRoadmapType[];
isLoading: boolean; isLoading: boolean;
isAllCollapsed: boolean;
}; };
type HeroProjectProps = { type HeroProjectProps = {
@ -185,7 +186,7 @@ export function HeroProject({ project }: HeroProjectProps) {
} }
export function FavoriteRoadmaps(props: FavoriteRoadmapsProps) { export function FavoriteRoadmaps(props: FavoriteRoadmapsProps) {
const { progress, isLoading, customRoadmaps, aiRoadmaps, projects } = props; const { progress, isLoading, customRoadmaps, aiRoadmaps, projects, isAllCollapsed } = props;
const [showCompleted, setShowCompleted] = useState(false); const [showCompleted, setShowCompleted] = useState(false);
const completedProjects = projects.filter( const completedProjects = projects.filter(
@ -201,8 +202,11 @@ export function FavoriteRoadmaps(props: FavoriteRoadmapsProps) {
]; ];
return ( return (
<div className="flex flex-col gap-5 pt-5"> <div className="flex flex-col">
<div className="border-b border-b-slate-800/70"> <div className={cn("", {
"border-b border-b-slate-800/70 pt-5 pb-5": !isAllCollapsed,
"py-2": isAllCollapsed
})}>
<div className="container"> <div className="container">
<HeroTitle <HeroTitle
icon={ icon={
@ -213,8 +217,8 @@ export function FavoriteRoadmaps(props: FavoriteRoadmapsProps) {
isLoading={isLoading} isLoading={isLoading}
title="Your progress and bookmarks" title="Your progress and bookmarks"
/> />
{!isLoading && progress.length > 0 && ( {!isLoading && progress.length > 0 && !isAllCollapsed && (
<div className="grid grid-cols-1 gap-2 pb-5 sm:grid-cols-2 md:grid-cols-3"> <div className="grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-3 mt-3">
{progress.map((resource) => ( {progress.map((resource) => (
<HeroRoadmap <HeroRoadmap
key={`${resource.resourceType}-${resource.resourceId}`} key={`${resource.resourceType}-${resource.resourceId}`}
@ -238,15 +242,18 @@ export function FavoriteRoadmaps(props: FavoriteRoadmapsProps) {
</div> </div>
</div> </div>
<div className="border-b border-b-slate-800/70"> <div className={cn("", {
"border-b border-b-slate-800/70 pt-5 pb-5": !isAllCollapsed,
"py-2": isAllCollapsed
})}>
<div className="container"> <div className="container">
<HeroTitle <HeroTitle
icon={(<MapIcon className="mr-1.5 h-[14px] w-[14px]" />) as any} icon={(<MapIcon className="mr-1.5 h-[14px] w-[14px]" />) as any}
isLoading={isLoading} isLoading={isLoading}
title="Your custom roadmaps" title="Your custom roadmaps"
/> />
{!isLoading && customRoadmaps.length > 0 && ( {!isLoading && customRoadmaps.length > 0 && !isAllCollapsed && (
<div className="grid grid-cols-1 gap-2 pb-5 sm:grid-cols-2 md:grid-cols-3"> <div className="grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-3 mt-3">
{customRoadmaps.map((customRoadmap) => ( {customRoadmaps.map((customRoadmap) => (
<HeroRoadmap <HeroRoadmap
key={customRoadmap.resourceId} key={customRoadmap.resourceId}
@ -268,15 +275,18 @@ export function FavoriteRoadmaps(props: FavoriteRoadmapsProps) {
</div> </div>
</div> </div>
<div className="border-b border-b-slate-800/70"> <div className={cn("", {
"border-b border-b-slate-800/70 pt-5 pb-5": !isAllCollapsed,
"py-2": isAllCollapsed
})}>
<div className="container"> <div className="container">
<HeroTitle <HeroTitle
icon={(<Sparkle className="mr-1.5 h-[14px] w-[14px]" />) as any} icon={(<Sparkle className="mr-1.5 h-[14px] w-[14px]" />) as any}
isLoading={isLoading} isLoading={isLoading}
title="Your AI roadmaps" title="Your AI roadmaps"
/> />
{!isLoading && aiRoadmaps.length > 0 && ( {!isLoading && aiRoadmaps.length > 0 && !isAllCollapsed && (
<div className="grid grid-cols-1 gap-2 pb-5 sm:grid-cols-2 md:grid-cols-3"> <div className="grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-3 mt-3">
{aiRoadmaps.map((aiRoadmap) => ( {aiRoadmaps.map((aiRoadmap) => (
<HeroRoadmap <HeroRoadmap
key={aiRoadmap.id} key={aiRoadmap.id}
@ -304,7 +314,10 @@ export function FavoriteRoadmaps(props: FavoriteRoadmapsProps) {
</div> </div>
</div> </div>
<div className=""> <div className={cn("", {
"border-b border-b-slate-800/70 pt-5 pb-5": !isAllCollapsed,
"py-2": isAllCollapsed
})}>
<div className="container"> <div className="container">
<HeroTitle <HeroTitle
icon={ icon={
@ -328,8 +341,8 @@ export function FavoriteRoadmaps(props: FavoriteRoadmapsProps) {
) )
} }
/> />
{!isLoading && projectsToShow.length > 0 && ( {!isLoading && projectsToShow.length > 0 && !isAllCollapsed && (
<div className="grid grid-cols-1 gap-2 pb-5 sm:grid-cols-2 md:grid-cols-3"> <div className="grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-3 mt-3">
{projectsToShow.map((project) => ( {projectsToShow.map((project) => (
<HeroProject key={project._id} project={project} /> <HeroProject key={project._id} project={project} />
))} ))}

Loading…
Cancel
Save