feat/dashboard
Arik Chakma 3 months ago
parent 3ceab552f6
commit 9f1b6d107f
  1. 2
      .astro/settings.json
  2. 68
      src/components/Dashboard/DashboardPage.tsx
  3. 30
      src/components/Dashboard/DashboardTab.tsx
  4. 91
      src/components/Dashboard/PersonalDashboard.tsx
  5. 8
      src/pages/dashboard.astro

@ -3,6 +3,6 @@
"enabled": false
},
"_variables": {
"lastUpdateCheck": 1723855511353
"lastUpdateCheck": 1724902244772
}
}

@ -0,0 +1,68 @@
import { useEffect, useState, type ReactNode } from 'react';
import { httpGet } from '../../lib/http';
import type { UserProgress } from '../TeamProgress/TeamProgressPage';
import { useToast } from '../../hooks/use-toast';
import { useStore } from '@nanostores/react';
import { $teamList } from '../../stores/team';
import type { TeamListResponse } from '../TeamDropdown/TeamDropdown';
import { cn } from '../../lib/classname';
import { DashboardTab } from './DashboardTab';
import { PersonalDashboard } from './PersonalDashboard';
type DashboardPageProps = {};
export function DashboardPage(props: DashboardPageProps) {
const toast = useToast();
const teamList = useStore($teamList);
const [isLoading, setIsLoading] = useState(true);
const [selectedTeamId, setSelectedTeamId] = useState<string>();
async function getAllTeams() {
if (teamList.length > 0) {
return;
}
const { response, error } = await httpGet<TeamListResponse>(
`${import.meta.env.PUBLIC_API_URL}/v1-get-user-teams`,
);
if (error || !response) {
toast.error(error?.message || 'Something went wrong');
return;
}
$teamList.set(response);
}
useEffect(() => {
getAllTeams().finally(() => setIsLoading(false));
}, []);
return (
<div className="container py-6 pb-14">
<div className="flex flex-wrap items-center gap-1">
<DashboardTab
label="Personal"
isActive={!selectedTeamId}
onClick={() => setSelectedTeamId(undefined)}
/>
{teamList.map((team) => (
<DashboardTab
key={team._id}
label={team.name}
isActive={team._id === selectedTeamId}
onClick={() => setSelectedTeamId(team._id)}
/>
))}
<DashboardTab
label="+ Create Team"
isActive={false}
href="/team/new"
className="border-black bg-black text-white"
/>
</div>
{!selectedTeamId && <PersonalDashboard />}
</div>
);
}

@ -0,0 +1,30 @@
import type { ReactNode } from 'react';
import { cn } from '../../lib/classname';
type DashboardTabProps = {
label: string | ReactNode;
isActive: boolean;
onClick?: () => void;
className?: string;
href?: string;
};
export function DashboardTab(props: DashboardTabProps) {
const { isActive, onClick, label, className, href } = props;
const Slot = href ? 'a' : 'button';
return (
<Slot
onClick={onClick}
className={cn(
'shrink-0 rounded-md border p-1.5 px-2 text-sm leading-none text-gray-600',
isActive ? 'border-gray-500 bg-gray-200 text-gray-900' : '',
className,
)}
{...(href ? { href } : {})}
>
{label}
</Slot>
);
}

@ -0,0 +1,91 @@
import { useEffect, useState } from 'react';
import { httpGet } from '../../lib/http';
import type { UserProgress } from '../TeamProgress/TeamProgressPage';
import type { ProjectStatusDocument } from '../Projects/ListProjectSolutions';
import { ResourceProgress } from '../Activity/ResourceProgress';
type UserDashboardResponse = {
progresses: UserProgress[];
projects: ProjectStatusDocument[];
};
type PersonalDashboardProps = {};
export function PersonalDashboard(props: PersonalDashboardProps) {
const [isLoading, setIsLoading] = useState(true);
const [personalDashboardDetails, setPersonalDashboardDetails] =
useState<UserDashboardResponse>();
async function loadProgress() {
setIsLoading(true);
const { response: progressList, error } =
await httpGet<UserDashboardResponse>(
`${import.meta.env.PUBLIC_API_URL}/v1-user-dashboard`,
);
if (error || !progressList) {
return;
}
setPersonalDashboardDetails(progressList);
}
useEffect(() => {
loadProgress().finally(() => setIsLoading(false));
}, []);
const learningRoadmaps =
personalDashboardDetails?.progresses?.filter(
(progress) => progress.resourceType === 'roadmap',
) || [];
const learningRoadmapsToShow = learningRoadmaps.sort((a, b) => {
const updatedAtA = new Date(a.updatedAt);
const updatedAtB = new Date(b.updatedAt);
if (a.isFavorite && !b.isFavorite) {
return -1;
}
if (!a.isFavorite && b.isFavorite) {
return 1;
}
return updatedAtB.getTime() - updatedAtA.getTime();
});
return (
<section className="mt-8">
<h2 className="text-xs uppercase text-gray-400">
Progress and Bookmarks
</h2>
<div className="mt-3 grid grid-cols-1 gap-1.5 sm:grid-cols-3">
{learningRoadmapsToShow.map((roadmap) => {
const learningCount = roadmap.learning || 0;
const doneCount = roadmap.done || 0;
const totalCount = roadmap.total || 0;
const skippedCount = roadmap.skipped || 0;
return (
<ResourceProgress
key={roadmap.resourceId}
isCustomResource={roadmap?.isCustomResource || false}
doneCount={doneCount > totalCount ? totalCount : doneCount}
learningCount={
learningCount > totalCount ? totalCount : learningCount
}
totalCount={totalCount}
skippedCount={skippedCount}
resourceId={roadmap.resourceId}
resourceType="roadmap"
updatedAt={roadmap.updatedAt}
title={roadmap.resourceTitle}
showActions={false}
/>
);
})}
</div>
</section>
);
}

@ -0,0 +1,8 @@
---
import { DashboardPage } from '../components/Dashboard/DashboardPage';
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout title='Dashboard' noIndex={true}>
<DashboardPage client:load />
</BaseLayout>
Loading…
Cancel
Save