computer-scienceangular-roadmapbackend-roadmapblockchain-roadmapdba-roadmapdeveloper-roadmapdevops-roadmapfrontend-roadmapgo-roadmaphactoberfestjava-roadmapjavascript-roadmapnodejs-roadmappython-roadmapqa-roadmapreact-roadmaproadmapstudy-planvue-roadmapweb3-roadmap
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
6.6 KiB
209 lines
6.6 KiB
import { useEffect, useState } from 'react'; |
|
import { httpGet } from '../../lib/http'; |
|
import { ActivityCounters } from './ActivityCounters'; |
|
import { ResourceProgress } from './ResourceProgress'; |
|
import { pageProgressMessage } from '../../stores/page'; |
|
import { EmptyActivity } from './EmptyActivity'; |
|
import { ActivityStream, type UserStreamActivity } from './ActivityStream'; |
|
|
|
type ProgressResponse = { |
|
updatedAt: string; |
|
title: string; |
|
id: string; |
|
learning: number; |
|
skipped: number; |
|
done: number; |
|
total: number; |
|
isCustomResource: boolean; |
|
roadmapSlug?: string; |
|
}; |
|
|
|
export type ActivityResponse = { |
|
done: { |
|
today: number; |
|
total: number; |
|
}; |
|
learning: { |
|
today: number; |
|
total: number; |
|
roadmaps: ProgressResponse[]; |
|
bestPractices: ProgressResponse[]; |
|
customs: ProgressResponse[]; |
|
}; |
|
streak: { |
|
count: number; |
|
firstVisitAt: Date | null; |
|
lastVisitAt: Date | null; |
|
}; |
|
activity: { |
|
type: 'done' | 'learning' | 'pending' | 'skipped'; |
|
createdAt: Date; |
|
metadata: { |
|
resourceId?: string; |
|
resourceType?: 'roadmap' | 'best-practice'; |
|
topicId?: string; |
|
topicLabel?: string; |
|
resourceTitle?: string; |
|
}; |
|
}[]; |
|
activities: UserStreamActivity[]; |
|
}; |
|
|
|
export function ActivityPage() { |
|
const [activity, setActivity] = useState<ActivityResponse>(); |
|
const [isLoading, setIsLoading] = useState(true); |
|
|
|
async function loadActivity() { |
|
const { error, response } = await httpGet<ActivityResponse>( |
|
`${import.meta.env.PUBLIC_API_URL}/v1-get-user-stats`, |
|
); |
|
|
|
if (!response || error) { |
|
console.error('Error loading activity'); |
|
console.error(error); |
|
|
|
return; |
|
} |
|
|
|
setActivity(response); |
|
} |
|
|
|
useEffect(() => { |
|
loadActivity().finally(() => { |
|
pageProgressMessage.set(''); |
|
setIsLoading(false); |
|
}); |
|
}, []); |
|
|
|
const learningRoadmaps = activity?.learning.roadmaps || []; |
|
const learningBestPractices = activity?.learning.bestPractices || []; |
|
|
|
if (isLoading) { |
|
return null; |
|
} |
|
|
|
const learningRoadmapsToShow = learningRoadmaps |
|
.sort((a, b) => { |
|
const updatedAtA = new Date(a.updatedAt); |
|
const updatedAtB = new Date(b.updatedAt); |
|
|
|
return updatedAtB.getTime() - updatedAtA.getTime(); |
|
}) |
|
.filter((roadmap) => roadmap.learning > 0 || roadmap.done > 0); |
|
|
|
const learningBestPracticesToShow = learningBestPractices |
|
.sort((a, b) => { |
|
const updatedAtA = new Date(a.updatedAt); |
|
const updatedAtB = new Date(b.updatedAt); |
|
|
|
return updatedAtB.getTime() - updatedAtA.getTime(); |
|
}) |
|
.filter( |
|
(bestPractice) => bestPractice.learning > 0 || bestPractice.done > 0, |
|
); |
|
|
|
const hasProgress = |
|
learningRoadmapsToShow.length !== 0 || |
|
learningBestPracticesToShow.length !== 0; |
|
|
|
return ( |
|
<> |
|
<ActivityCounters |
|
done={activity?.done || { today: 0, total: 0 }} |
|
learning={activity?.learning || { today: 0, total: 0 }} |
|
streak={activity?.streak || { count: 0 }} |
|
/> |
|
|
|
<div className="mx-0 px-0 py-5 pb-0 md:-mx-10 md:px-8 md:py-8 md:pb-0"> |
|
{learningRoadmapsToShow.length === 0 && |
|
learningBestPracticesToShow.length === 0 && <EmptyActivity />} |
|
|
|
{(learningRoadmapsToShow.length > 0 || |
|
learningBestPracticesToShow.length > 0) && ( |
|
<> |
|
<h2 className="mb-3 text-xs uppercase text-gray-400"> |
|
Continue Following |
|
</h2> |
|
<div className="grid grid-cols-1 gap-1.5 sm:grid-cols-2"> |
|
{learningRoadmaps |
|
.sort((a, b) => { |
|
const updatedAtA = new Date(a.updatedAt); |
|
const updatedAtB = new Date(b.updatedAt); |
|
|
|
return updatedAtB.getTime() - updatedAtA.getTime(); |
|
}) |
|
.filter((roadmap) => roadmap.learning > 0 || roadmap.done > 0) |
|
.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.id} |
|
isCustomResource={roadmap.isCustomResource} |
|
doneCount={ |
|
doneCount > totalCount ? totalCount : doneCount |
|
} |
|
learningCount={ |
|
learningCount > totalCount ? totalCount : learningCount |
|
} |
|
totalCount={totalCount} |
|
skippedCount={skippedCount} |
|
resourceId={roadmap.id} |
|
resourceType={'roadmap'} |
|
updatedAt={roadmap.updatedAt} |
|
title={roadmap.title} |
|
onCleared={() => { |
|
pageProgressMessage.set('Updating activity'); |
|
loadActivity().finally(() => { |
|
pageProgressMessage.set(''); |
|
}); |
|
}} |
|
/> |
|
); |
|
})} |
|
|
|
{learningBestPractices |
|
.sort((a, b) => { |
|
const updatedAtA = new Date(a.updatedAt); |
|
const updatedAtB = new Date(b.updatedAt); |
|
|
|
return updatedAtB.getTime() - updatedAtA.getTime(); |
|
}) |
|
.filter( |
|
(bestPractice) => |
|
bestPractice.learning > 0 || bestPractice.done > 0, |
|
) |
|
.map((bestPractice) => ( |
|
<ResourceProgress |
|
isCustomResource={bestPractice.isCustomResource} |
|
key={bestPractice.id} |
|
doneCount={bestPractice.done || 0} |
|
totalCount={bestPractice.total || 0} |
|
learningCount={bestPractice.learning || 0} |
|
resourceId={bestPractice.id} |
|
skippedCount={bestPractice.skipped || 0} |
|
resourceType={'best-practice'} |
|
title={bestPractice.title} |
|
updatedAt={bestPractice.updatedAt} |
|
onCleared={() => { |
|
pageProgressMessage.set('Updating activity'); |
|
loadActivity().finally(() => { |
|
pageProgressMessage.set(''); |
|
}); |
|
}} |
|
/> |
|
))} |
|
</div> |
|
</> |
|
)} |
|
</div> |
|
|
|
{hasProgress && ( |
|
<ActivityStream activities={activity?.activities || []} /> |
|
)} |
|
</> |
|
); |
|
}
|
|
|