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 {
CheckCircle,
ChevronsDownUp,
ChevronsUpDown,
FolderGit2,
Zap,
type LucideIcon,
@ -58,6 +59,8 @@ type DashboardStatsProps = {
topicsDoneToday?: number;
finishedProjectsCount?: number;
isLoading: boolean;
isAllCollapsed: boolean;
onToggleCollapseAll: () => void;
};
type DashboardStatItemProps = {
@ -98,10 +101,12 @@ function DashboardStats(props: DashboardStatsProps) {
topicsDoneToday = 0,
finishedProjectsCount = 0,
isLoading,
onToggleCollapseAll,
isAllCollapsed,
} = props;
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">
<DashboardStatItem
icon={Zap}
@ -126,9 +131,21 @@ function DashboardStats(props: DashboardStatsProps) {
/>
</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" />
<span>Collapse All</span>
</>
)}
</button>
</div>
);
@ -142,7 +159,9 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
} = props;
const toast = useToast();
const [isLoading, setIsLoading] = useState(true);
const [isAllCollapsed, setIsAllCollapsed] = useState(false);
const [personalDashboardDetails, setPersonalDashboardDetails] =
useState<UserDashboardResponse>();
const [projectDetails, setProjectDetails] = useState<PageType[]>([]);
@ -261,37 +280,6 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
...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
.map((project) => {
const projectDetail = projectDetails.find(
@ -323,6 +311,10 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
isLoading={isLoading}
accountStreak={accountStreak}
topicsDoneToday={personalDashboardDetails?.topicDoneToday}
onToggleCollapseAll={() => {
setIsAllCollapsed(!isAllCollapsed);
}}
isAllCollapsed={isAllCollapsed}
finishedProjectsCount={
enrichedProjects?.filter((p) => p.submittedAt && p.repositoryUrl)
.length
@ -335,6 +327,7 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
aiRoadmaps={aiGeneratedRoadmaps}
projects={enrichedProjects || []}
isLoading={isLoading}
isAllCollapsed={isAllCollapsed}
/>
<div className="relative mt-6 border-t border-t-[#1e293c] pt-12">

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

Loading…
Cancel
Save