Add AI roadmap listing

feat/dashboard
Kamran Ahmed 6 months ago
parent 4348283ef5
commit c5eaed4149
  1. 78
      src/components/Dashboard/DashboardAiRoadmaps.tsx
  2. 2
      src/components/Dashboard/DashboardCustomProgressCard.tsx
  3. 30
      src/components/Dashboard/PersonalDashboard.tsx
  4. 2
      src/components/Dashboard/RecommendedRoadmaps.tsx

@ -0,0 +1,78 @@
import type { UserProgress } from '../TeamProgress/TeamProgressPage';
import { DashboardCustomProgressCard } from './DashboardCustomProgressCard';
import { DashboardCardLink } from './DashboardCardLink';
import { useState } from 'react';
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
import { Simulate } from 'react-dom/test-utils';
import { Bot, BrainCircuit, Map, PencilRuler } from 'lucide-react';
type DashboardAiRoadmapsProps = {
roadmaps: {
id: string;
title: string;
slug: string;
}[];
isLoading?: boolean;
};
export function DashboardAiRoadmaps(props: DashboardAiRoadmapsProps) {
const { roadmaps, isLoading = false } = props;
return (
<>
<h2 className="mb-2 mt-6 text-xs uppercase text-gray-400">
AI Generated Roadmaps
</h2>
{!isLoading && roadmaps.length === 0 && (
<DashboardCardLink
className="mt-0"
icon={BrainCircuit}
href="/ai"
title="Generate Roadmaps with AI"
description="You can generate your own roadmap with AI"
/>
)}
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-3">
{isLoading && (
<>
{Array.from({ length: 9 }).map((_, index) => (
<RoadmapCardSkeleton key={index} />
))}
</>
)}
{!isLoading && roadmaps.length > 0 && (
<>
{roadmaps.map((roadmap) => (
<a
href={`/r/${roadmap.slug}`}
className="relative rounded-md border bg-white p-2.5 text-left text-sm shadow-sm truncate hover:border-gray-400 hover:bg-gray-50"
>
{roadmap.title}
</a>
))}
<a
className="flex items-center justify-center rounded-lg border border-dashed border-gray-300 bg-white p-2.5 text-sm font-medium text-gray-500 hover:bg-gray-50 hover:text-gray-600"
href={'/ai'}
>
+ Generate New
</a>
</>
)}
</div>
</>
);
}
type CustomProgressCardSkeletonProps = {};
function RoadmapCardSkeleton(
props: CustomProgressCardSkeletonProps,
) {
return (
<div className="h-[42px] w-full animate-pulse rounded-md bg-gray-200" />
);
}

@ -36,7 +36,7 @@ export function DashboardCustomProgressCard(props: DashboardCustomProgressCardPr
return (
<a
href={url}
className="group relative flex min-h-[80px] w-full flex-col justify-between overflow-hidden rounded-md border bg-white p-3 text-left text-sm shadow-sm transition-all hover:border-gray-300"
className="group relative flex min-h-[80px] w-full flex-col justify-between overflow-hidden rounded-md border bg-white p-3 text-left text-sm shadow-sm transition-all hover:border-gray-400 hover:bg-gray-50"
>
<h4 className="truncate font-medium text-gray-900">{resourceTitle}</h4>

@ -13,6 +13,7 @@ import { $accountStreak, type StreakResponse } from '../../stores/streak';
import { CheckEmoji } from '../ReactIcons/CheckEmoji.tsx';
import { ConstructionEmoji } from '../ReactIcons/ConstructionEmoji.tsx';
import { BookEmoji } from '../ReactIcons/BookEmoji.tsx';
import { DashboardAiRoadmaps } from './DashboardAiRoadmaps.tsx';
type UserDashboardResponse = {
name: string;
@ -22,6 +23,11 @@ type UserDashboardResponse = {
username: string;
progresses: UserProgress[];
projects: ProjectStatusDocument[];
aiRoadmaps: {
id: string;
title: string;
slug: string;
}[];
topicDoneToday: number;
};
@ -142,6 +148,7 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
return updatedAtB.getTime() - updatedAtA.getTime();
});
const aiGeneratedRoadmaps = personalDashboardDetails?.aiRoadmaps || [];
const customRoadmaps = (personalDashboardDetails?.progresses || [])
.filter((progress) => progress.isCustomResource)
.sort((a, b) => {
@ -150,13 +157,6 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
return updatedAtB.getTime() - updatedAtA.getTime();
});
const aiGeneratedRoadmaps = customRoadmaps.filter(
(progress) => progress?.aiRoadmapId,
);
const customRoadmapsToShow = customRoadmaps.filter(
(progress) => !progress?.aiRoadmapId,
);
const { avatar, name } = personalDashboardDetails || {};
const avatarLink = avatar
? `${import.meta.env.PUBLIC_AVATAR_BASE_URL}/${avatar}`
@ -182,7 +182,14 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
const recommendedRoadmapIds = new Set(
relatedRoadmapIds.length === 0
? ['frontend', 'backend', 'devops', 'ai-data-scientist', 'full-stack', 'api-design']
? [
'frontend',
'backend',
'devops',
'ai-data-scientist',
'full-stack',
'api-design',
]
: relatedRoadmapIds,
);
@ -272,14 +279,13 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
/>
<ListDashboardCustomProgress
progresses={customRoadmapsToShow}
progresses={customRoadmaps}
isLoading={isLoading}
/>
<ListDashboardCustomProgress
progresses={aiGeneratedRoadmaps}
<DashboardAiRoadmaps
roadmaps={aiGeneratedRoadmaps}
isLoading={isLoading}
isAIGeneratedRoadmaps={true}
/>
<RecommendedRoadmaps

@ -58,7 +58,7 @@ export function RecommendedRoadmapCard(props: RecommendedRoadmapCardProps) {
return (
<a
href={url}
className="font-regular text-sm sm:text-base group relative block rounded-lg border border-gray-200 bg-white px-2.5 py-2 text-black no-underline hover:border-gray-400 hover:bg-gray-50"
className="font-regular text-sm sm:text-sm group relative block rounded-lg border border-gray-200 bg-white px-2.5 py-2 text-black no-underline hover:border-gray-400 hover:bg-gray-50"
>
<MarkFavorite className={'opacity-30'} resourceType={'roadmap'} resourceId={roadmap.id} />
{title}

Loading…
Cancel
Save