feat: dashboard favourite

feat/dashboard
Arik Chakma 3 months ago
parent 7d5cbd87db
commit 09fb526896
  1. 10
      src/components/Activity/ProjectProgress.tsx
  2. 9
      src/components/Dashboard/DashboardPage.tsx
  3. 84
      src/components/Dashboard/PersonalDashboard.tsx
  4. 40
      src/pages/dashboard.astro

@ -11,11 +11,15 @@ type ProjectProgressType = {
title: string;
};
showActions?: boolean;
userId?: string;
};
export function ProjectProgress(props: ProjectProgressType) {
const { projectStatus, showActions = true } = props;
const userId = getUser()?.id;
const {
projectStatus,
showActions = true,
userId: defaultUserId = getUser()?.id,
} = props;
const shouldShowActions =
projectStatus.submittedAt &&
@ -43,7 +47,7 @@ export function ProjectProgress(props: ProjectProgressType) {
{shouldShowActions && (
<div className="absolute right-2 top-0 flex h-full items-center">
<ProjectProgressActions
userId={userId!}
userId={defaultUserId!}
projectId={projectStatus.projectId}
/>
</div>

@ -10,12 +10,14 @@ import { TeamDashboard } from './TeamDashboard';
import { getUser } from '../../lib/jwt';
type DashboardPageProps = {
builtInRoadmaps?: BuiltInRoadmap[];
builtInRoleRoadmaps?: BuiltInRoadmap[];
builtInSkillRoadmaps?: BuiltInRoadmap[];
builtInBestPractices?: BuiltInRoadmap[];
};
export function DashboardPage(props: DashboardPageProps) {
const { builtInRoadmaps, builtInBestPractices } = props;
const { builtInRoleRoadmaps, builtInBestPractices, builtInSkillRoadmaps } =
props;
const currentUser = getUser();
const toast = useToast();
@ -95,7 +97,8 @@ export function DashboardPage(props: DashboardPageProps) {
{!selectedTeamId && (
<PersonalDashboard
builtInRoadmaps={builtInRoadmaps}
builtInRoleRoadmaps={builtInRoleRoadmaps}
builtInSkillRoadmaps={builtInSkillRoadmaps}
builtInBestPractices={builtInBestPractices}
/>
)}

@ -8,6 +8,7 @@ import type { PageType } from '../CommandMenu/CommandMenu';
import { useToast } from '../../hooks/use-toast';
import { LoadingProgress } from './LoadingProgress';
import { ArrowUpRight, Pencil } from 'lucide-react';
import { MarkFavorite } from '../FeaturedItems/MarkFavorite';
type UserDashboardResponse = {
name: string;
@ -21,17 +22,24 @@ type UserDashboardResponse = {
export type BuiltInRoadmap = {
id: string;
url: string;
title: string;
description: string;
isFavorite?: boolean;
};
type PersonalDashboardProps = {
builtInRoadmaps?: BuiltInRoadmap[];
builtInRoleRoadmaps?: BuiltInRoadmap[];
builtInSkillRoadmaps?: BuiltInRoadmap[];
builtInBestPractices?: BuiltInRoadmap[];
};
export function PersonalDashboard(props: PersonalDashboardProps) {
const { builtInRoadmaps = [], builtInBestPractices = [] } = props;
const {
builtInRoleRoadmaps = [],
builtInBestPractices = [],
builtInSkillRoadmaps = [],
} = props;
const toast = useToast();
const [isLoading, setIsLoading] = useState(true);
@ -49,6 +57,17 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
return;
}
progressList?.progresses?.forEach((progress) => {
window.dispatchEvent(
new CustomEvent('mark-favorite', {
detail: {
resourceId: progress.resourceId,
resourceType: progress.resourceType,
isFavorite: progress.isFavorite,
},
}),
);
});
setPersonalDashboardDetails(progressList);
}
@ -74,12 +93,14 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
);
}, []);
const learningRoadmaps =
personalDashboardDetails?.progresses?.filter(
(progress) => progress.resourceType === 'roadmap',
) || [];
useEffect(() => {
window.addEventListener('refresh-favorites', loadProgress);
return () => window.removeEventListener('refresh-favorites', loadProgress);
}, []);
const learningRoadmapsToShow = learningRoadmaps.sort((a, b) => {
const learningRoadmapsToShow = (
personalDashboardDetails?.progresses || []
).sort((a, b) => {
const updatedAtA = new Date(a.updatedAt);
const updatedAtB = new Date(b.updatedAt);
@ -193,10 +214,10 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
totalCount={totalCount}
skippedCount={skippedCount}
resourceId={roadmap.resourceId}
resourceType="roadmap"
resourceType={roadmap.resourceType}
updatedAt={roadmap.updatedAt}
title={roadmap.resourceTitle}
showActions={false}
showActions={true}
roadmapSlug={roadmap.roadmapSlug}
/>
);
@ -213,7 +234,7 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
<ProjectProgress
key={project.projectId}
projectStatus={project}
showActions={false}
showActions={true}
/>
);
})}
@ -221,9 +242,14 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
)}
<h2 className="mb-3 mt-6 text-xs uppercase text-gray-400">
All Roadmaps
Role Based Roadmaps
</h2>
<ListRoadmaps roadmaps={builtInRoadmaps} />
<ListRoadmaps roadmaps={builtInRoleRoadmaps} />
<h2 className="mb-3 mt-6 text-xs uppercase text-gray-400">
Skill Based Roadmaps
</h2>
<ListRoadmaps roadmaps={builtInSkillRoadmaps} />
<h2 className="mb-3 mt-6 text-xs uppercase text-gray-400">
Best Practices
@ -242,23 +268,41 @@ export function ListRoadmaps(props: ListRoadmapsProps) {
const [showAll, setShowAll] = useState(roadmaps.length <= 12);
const roadmapsToShow = showAll ? roadmaps : roadmaps.slice(0, 12);
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
return (
<div className="relative">
<div className="grid grid-cols-1 gap-1.5 sm:grid-cols-2 md:grid-cols-3">
{roadmapsToShow.map((roadmap) => (
<a
key={roadmap.id}
className="rounded-md border bg-white px-3 py-2 text-left text-sm shadow-sm transition-all hover:border-gray-300 hover:bg-gray-50"
href={`/${roadmap.id}`}
>
{roadmap.title}
</a>
<div className="relative w-full" key={roadmap.id}>
<a
key={roadmap.id}
className="block rounded-md border bg-white px-3 py-2 text-left text-sm shadow-sm transition-all hover:border-gray-300 hover:bg-gray-50"
href={roadmap.url}
>
{roadmap.title}
</a>
{isMounted && (
<MarkFavorite
resourceId={roadmap.id}
resourceType={
roadmap.url.includes('best-practices')
? 'best-practice'
: 'roadmap'
}
/>
)}
</div>
))}
</div>
{!showAll && (
<div
className="absolute bottom-0 left-0 right-0 -m-1 flex h-full items-end justify-center bg-gradient-to-t from-white to-transparent p-2"
className="absolute inset-0 z-50 -m-1 flex items-end justify-center bg-gradient-to-t from-white to-transparent"
style={{
background:
'linear-gradient(180deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.8) 50%, rgba(255,255,255,1) 100%)',

@ -4,23 +4,42 @@ import BaseLayout from '../layouts/BaseLayout.astro';
import { getAllBestPractices } from '../lib/best-practice';
import { getRoadmapsByTag } from '../lib/roadmap';
const roadmaps = await getRoadmapsByTag('roadmap');
const roleRoadmaps = await getRoadmapsByTag('role-roadmap');
const skillRoadmaps = await getRoadmapsByTag('skill-roadmap');
const bestPractices = await getAllBestPractices();
const enrichedRoadmaps = roadmaps.map((roadmap) => {
const { frontmatter } = roadmap;
const enrichedRoleRoadmaps = roleRoadmaps
.filter((roadmapItem) => !roadmapItem.frontmatter.isHidden)
.map((roadmap) => {
const { frontmatter } = roadmap;
return {
id: roadmap.id,
url: `/${roadmap.id}`,
title: frontmatter.briefTitle,
description: frontmatter.briefDescription,
};
});
const enrichedSkillRoadmaps = skillRoadmaps
.filter((roadmapItem) => !roadmapItem.frontmatter.isHidden)
.map((roadmap) => {
const { frontmatter } = roadmap;
return {
id: roadmap.id,
url: `/${roadmap.id}`,
title:
frontmatter.briefTitle === 'Go' ? 'Go Roadmap' : frontmatter.briefTitle,
description: frontmatter.briefDescription,
};
});
return {
id: roadmap.id,
title: frontmatter.briefTitle,
description: frontmatter.briefDescription,
};
});
const enrichedBestPractices = bestPractices.map((bestPractice) => {
const { frontmatter } = bestPractice;
return {
id: bestPractice.id,
url: `/best-practices/${bestPractice.id}`,
title: frontmatter.briefTitle,
description: frontmatter.briefDescription,
};
@ -29,7 +48,8 @@ const enrichedBestPractices = bestPractices.map((bestPractice) => {
<BaseLayout title='Dashboard' noIndex={true}>
<DashboardPage
builtInRoadmaps={enrichedRoadmaps}
builtInRoleRoadmaps={enrichedRoleRoadmaps}
builtInSkillRoadmaps={enrichedSkillRoadmaps}
builtInBestPractices={enrichedBestPractices}
client:load
/>

Loading…
Cancel
Save