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.
142 lines
3.7 KiB
142 lines
3.7 KiB
import { useEffect, useState } from 'react'; |
|
import { EmptyProgress } from './EmptyProgress'; |
|
import { httpGet } from '../../lib/http'; |
|
import { HeroRoadmaps } from './HeroRoadmaps'; |
|
import { isLoggedIn } from '../../lib/jwt'; |
|
|
|
export type UserProgressResponse = { |
|
resourceId: string; |
|
resourceType: 'roadmap' | 'best-practice'; |
|
resourceTitle: string; |
|
isFavorite: boolean; |
|
done: number; |
|
learning: number; |
|
skipped: number; |
|
total: number; |
|
updatedAt: Date; |
|
isCustomResource: boolean; |
|
}[]; |
|
|
|
function renderProgress(progressList: UserProgressResponse) { |
|
progressList.forEach((progress) => { |
|
const href = |
|
progress.resourceType === 'best-practice' |
|
? `/best-practices/${progress.resourceId}` |
|
: `/${progress.resourceId}`; |
|
const element = document.querySelector(`a[href="${href}"]`); |
|
if (!element) { |
|
return; |
|
} |
|
|
|
window.dispatchEvent( |
|
new CustomEvent('mark-favorite', { |
|
detail: { |
|
resourceId: progress.resourceId, |
|
resourceType: progress.resourceType, |
|
isFavorite: progress.isFavorite, |
|
}, |
|
}) |
|
); |
|
|
|
const totalDone = progress.done + progress.skipped; |
|
const percentageDone = (totalDone / progress.total) * 100; |
|
|
|
const progressBar: HTMLElement | null = |
|
element.querySelector('[data-progress]'); |
|
if (progressBar) { |
|
progressBar.style.width = `${percentageDone}%`; |
|
} |
|
}); |
|
} |
|
|
|
type ProgressResponse = UserProgressResponse; |
|
|
|
export function FavoriteRoadmaps() { |
|
const isAuthenticated = isLoggedIn(); |
|
if (!isAuthenticated) { |
|
return null; |
|
} |
|
|
|
const [isPreparing, setIsPreparing] = useState(true); |
|
const [isLoading, setIsLoading] = useState(true); |
|
const [progress, setProgress] = useState<ProgressResponse>([]); |
|
const [containerOpacity, setContainerOpacity] = useState(0); |
|
|
|
function showProgressContainer() { |
|
const heroEl = document.getElementById('hero-text')!; |
|
if (!heroEl) { |
|
return; |
|
} |
|
|
|
heroEl.classList.add('opacity-0'); |
|
setTimeout(() => { |
|
heroEl.parentElement?.removeChild(heroEl); |
|
setIsPreparing(false); |
|
|
|
setTimeout(() => { |
|
setContainerOpacity(100); |
|
}, 50); |
|
}, 0); |
|
} |
|
|
|
async function loadProgress() { |
|
setIsLoading(true); |
|
|
|
const { response: progressList, error } = await httpGet<ProgressResponse>( |
|
`${import.meta.env.PUBLIC_API_URL}/v1-get-hero-roadmaps` |
|
); |
|
|
|
if (error || !progressList) { |
|
return; |
|
} |
|
|
|
setProgress(progressList); |
|
setIsLoading(false); |
|
showProgressContainer(); |
|
|
|
// render progress on featured items |
|
renderProgress(progressList); |
|
} |
|
|
|
useEffect(() => { |
|
loadProgress().finally(() => { |
|
setIsLoading(false); |
|
}); |
|
}, []); |
|
|
|
useEffect(() => { |
|
window.addEventListener('refresh-favorites', loadProgress); |
|
return () => window.removeEventListener('refresh-favorites', loadProgress); |
|
}, []); |
|
|
|
if (isPreparing) { |
|
return null; |
|
} |
|
|
|
const hasProgress = progress?.length > 0; |
|
const customRoadmaps = progress?.filter((p) => p.isCustomResource); |
|
const defaultRoadmaps = progress?.filter((p) => !p.isCustomResource); |
|
|
|
return ( |
|
<div |
|
className={`transition-opacity duration-500 opacity-${containerOpacity}`} |
|
> |
|
<div |
|
className={`flex min-h-[192px] bg-gradient-to-b sm:min-h-[280px] ${ |
|
hasProgress && `border-t border-t-[#1e293c]` |
|
}`} |
|
> |
|
<div className="container min-h-full"> |
|
{!isLoading && progress?.length == 0 && <EmptyProgress />} |
|
{hasProgress && ( |
|
<HeroRoadmaps |
|
customRoadmaps={customRoadmaps} |
|
progress={defaultRoadmaps} |
|
isLoading={isLoading} |
|
/> |
|
)} |
|
</div> |
|
</div> |
|
</div> |
|
); |
|
}
|
|
|