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

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

@ -8,6 +8,7 @@ import type { PageType } from '../CommandMenu/CommandMenu';
import { useToast } from '../../hooks/use-toast'; import { useToast } from '../../hooks/use-toast';
import { LoadingProgress } from './LoadingProgress'; import { LoadingProgress } from './LoadingProgress';
import { ArrowUpRight, Pencil } from 'lucide-react'; import { ArrowUpRight, Pencil } from 'lucide-react';
import { MarkFavorite } from '../FeaturedItems/MarkFavorite';
type UserDashboardResponse = { type UserDashboardResponse = {
name: string; name: string;
@ -21,17 +22,24 @@ type UserDashboardResponse = {
export type BuiltInRoadmap = { export type BuiltInRoadmap = {
id: string; id: string;
url: string;
title: string; title: string;
description: string; description: string;
isFavorite?: boolean;
}; };
type PersonalDashboardProps = { type PersonalDashboardProps = {
builtInRoadmaps?: BuiltInRoadmap[]; builtInRoleRoadmaps?: BuiltInRoadmap[];
builtInSkillRoadmaps?: BuiltInRoadmap[];
builtInBestPractices?: BuiltInRoadmap[]; builtInBestPractices?: BuiltInRoadmap[];
}; };
export function PersonalDashboard(props: PersonalDashboardProps) { export function PersonalDashboard(props: PersonalDashboardProps) {
const { builtInRoadmaps = [], builtInBestPractices = [] } = props; const {
builtInRoleRoadmaps = [],
builtInBestPractices = [],
builtInSkillRoadmaps = [],
} = props;
const toast = useToast(); const toast = useToast();
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
@ -49,6 +57,17 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
return; return;
} }
progressList?.progresses?.forEach((progress) => {
window.dispatchEvent(
new CustomEvent('mark-favorite', {
detail: {
resourceId: progress.resourceId,
resourceType: progress.resourceType,
isFavorite: progress.isFavorite,
},
}),
);
});
setPersonalDashboardDetails(progressList); setPersonalDashboardDetails(progressList);
} }
@ -74,12 +93,14 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
); );
}, []); }, []);
const learningRoadmaps = useEffect(() => {
personalDashboardDetails?.progresses?.filter( window.addEventListener('refresh-favorites', loadProgress);
(progress) => progress.resourceType === 'roadmap', 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 updatedAtA = new Date(a.updatedAt);
const updatedAtB = new Date(b.updatedAt); const updatedAtB = new Date(b.updatedAt);
@ -193,10 +214,10 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
totalCount={totalCount} totalCount={totalCount}
skippedCount={skippedCount} skippedCount={skippedCount}
resourceId={roadmap.resourceId} resourceId={roadmap.resourceId}
resourceType="roadmap" resourceType={roadmap.resourceType}
updatedAt={roadmap.updatedAt} updatedAt={roadmap.updatedAt}
title={roadmap.resourceTitle} title={roadmap.resourceTitle}
showActions={false} showActions={true}
roadmapSlug={roadmap.roadmapSlug} roadmapSlug={roadmap.roadmapSlug}
/> />
); );
@ -213,7 +234,7 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
<ProjectProgress <ProjectProgress
key={project.projectId} key={project.projectId}
projectStatus={project} 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"> <h2 className="mb-3 mt-6 text-xs uppercase text-gray-400">
All Roadmaps Role Based Roadmaps
</h2> </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"> <h2 className="mb-3 mt-6 text-xs uppercase text-gray-400">
Best Practices Best Practices
@ -242,23 +268,41 @@ export function ListRoadmaps(props: ListRoadmapsProps) {
const [showAll, setShowAll] = useState(roadmaps.length <= 12); const [showAll, setShowAll] = useState(roadmaps.length <= 12);
const roadmapsToShow = showAll ? roadmaps : roadmaps.slice(0, 12); const roadmapsToShow = showAll ? roadmaps : roadmaps.slice(0, 12);
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
return ( return (
<div className="relative"> <div className="relative">
<div className="grid grid-cols-1 gap-1.5 sm:grid-cols-2 md:grid-cols-3"> <div className="grid grid-cols-1 gap-1.5 sm:grid-cols-2 md:grid-cols-3">
{roadmapsToShow.map((roadmap) => ( {roadmapsToShow.map((roadmap) => (
<a <div className="relative w-full" key={roadmap.id}>
key={roadmap.id} <a
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" key={roadmap.id}
href={`/${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> {roadmap.title}
</a>
{isMounted && (
<MarkFavorite
resourceId={roadmap.id}
resourceType={
roadmap.url.includes('best-practices')
? 'best-practice'
: 'roadmap'
}
/>
)}
</div>
))} ))}
</div> </div>
{!showAll && ( {!showAll && (
<div <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={{ style={{
background: background:
'linear-gradient(180deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.8) 50%, rgba(255,255,255,1) 100%)', '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 { getAllBestPractices } from '../lib/best-practice';
import { getRoadmapsByTag } from '../lib/roadmap'; 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 bestPractices = await getAllBestPractices();
const enrichedRoadmaps = roadmaps.map((roadmap) => { const enrichedRoleRoadmaps = roleRoadmaps
const { frontmatter } = roadmap; .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 enrichedBestPractices = bestPractices.map((bestPractice) => {
const { frontmatter } = bestPractice; const { frontmatter } = bestPractice;
return { return {
id: bestPractice.id, id: bestPractice.id,
url: `/best-practices/${bestPractice.id}`,
title: frontmatter.briefTitle, title: frontmatter.briefTitle,
description: frontmatter.briefDescription, description: frontmatter.briefDescription,
}; };
@ -29,7 +48,8 @@ const enrichedBestPractices = bestPractices.map((bestPractice) => {
<BaseLayout title='Dashboard' noIndex={true}> <BaseLayout title='Dashboard' noIndex={true}>
<DashboardPage <DashboardPage
builtInRoadmaps={enrichedRoadmaps} builtInRoleRoadmaps={enrichedRoleRoadmaps}
builtInSkillRoadmaps={enrichedSkillRoadmaps}
builtInBestPractices={enrichedBestPractices} builtInBestPractices={enrichedBestPractices}
client:load client:load
/> />

Loading…
Cancel
Save