Roadmap to becoming a developer in 2022
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.
 
 
 
 
 

656 lines
15 KiB

import { useEffect, useState } from 'react';
import { cn } from '../../lib/classname.ts';
import { Filter, X } from 'lucide-react';
import { CategoryFilterButton } from './CategoryFilterButton.tsx';
import {
deleteUrlParam,
getUrlParams,
setUrlParams,
} from '../../lib/browser.ts';
import { RoadmapCard } from './RoadmapCard.tsx';
import { httpGet } from '../../lib/http.ts';
import { isLoggedIn } from '../../lib/jwt.ts';
import type { AllowedMemberRoles } from '../ShareOptions/ShareTeamMemberList.tsx';
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;
roadmapSlug?: string;
team?: {
name: string;
id: string;
role: AllowedMemberRoles;
};
}[];
const groupNames = [
'Absolute Beginners',
'Web Development',
'Languages / Platforms',
'Frameworks',
'Mobile Development',
'Databases',
'Computer Science',
'Machine Learning',
'Management',
'Game Development',
'Design',
'DevOps',
'Blockchain',
'Cyber Security',
];
type AllowGroupNames = (typeof groupNames)[number];
export type GroupType = {
group: AllowGroupNames;
roadmaps: {
title: string;
link: string;
type: 'role' | 'skill';
otherGroups?: AllowGroupNames[];
}[];
};
const groups: GroupType[] = [
{
group: 'Absolute Beginners',
roadmaps: [
{
title: 'Frontend Beginner',
link: '/frontend?r=frontend-beginner',
type: 'role',
otherGroups: ['Web Development'],
},
{
title: 'Backend Beginner',
link: '/backend?r=backend-beginner',
type: 'role',
otherGroups: ['Web Development'],
},
{
title: 'DevOps Beginner',
link: '/devops?r=devops-beginner',
type: 'role',
otherGroups: ['Web Development'],
},
],
},
{
group: 'Web Development',
roadmaps: [
{
title: 'Frontend',
link: '/frontend',
type: 'role',
otherGroups: ['Web Development'],
},
{
title: 'Backend',
link: '/backend',
type: 'role',
otherGroups: ['Web Development'],
},
{
title: 'Full Stack',
link: '/full-stack',
type: 'role',
otherGroups: ['Web Development', 'Absolute Beginners'],
},
{
title: 'API Design',
link: '/api-design',
type: 'role',
otherGroups: ['Web Development'],
},
{
title: 'QA',
link: '/qa',
type: 'role',
},
{
title: 'GraphQL',
link: '/graphql',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Git and GitHub',
link: '/git-github',
type: 'skill',
otherGroups: ['Web Development', 'DevOps'],
},
],
},
{
group: 'Frameworks',
roadmaps: [
{
title: 'React',
link: '/react',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Vue',
link: '/vue',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Angular',
link: '/angular',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Spring Boot',
link: '/spring-boot',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'ASP.NET Core',
link: '/aspnet-core',
type: 'skill',
otherGroups: ['Web Development'],
},
],
},
{
group: 'Languages / Platforms',
roadmaps: [
{
title: 'JavaScript',
link: '/javascript',
type: 'skill',
otherGroups: ['Web Development', 'DevOps', 'Mobile Development'],
},
{
title: 'TypeScript',
link: '/typescript',
type: 'skill',
otherGroups: ['Web Development', 'Mobile Development'],
},
{
title: 'Node.js',
link: '/nodejs',
type: 'skill',
otherGroups: ['Web Development', 'DevOps'],
},
{
title: 'PHP',
link: '/php',
type: 'skill',
otherGroups: ['Web Development', 'DevOps'],
},
{
title: 'C++',
link: '/cpp',
type: 'skill',
},
{
title: 'Go',
link: '/golang',
type: 'skill',
otherGroups: ['Web Development', 'DevOps'],
},
{
title: 'Rust',
link: '/rust',
type: 'skill',
otherGroups: ['Web Development', 'DevOps'],
},
{
title: 'Python',
link: '/python',
type: 'skill',
otherGroups: ['Web Development', 'DevOps'],
},
{
title: 'Java',
link: '/java',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'SQL',
link: '/sql',
type: 'skill',
otherGroups: ['Web Development', 'Databases', 'DevOps'],
},
],
},
{
group: 'DevOps',
roadmaps: [
{
title: 'DevOps',
link: '/devops',
type: 'role',
otherGroups: ['Web Development'],
},
{
title: 'Docker',
link: '/docker',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Kubernetes',
link: '/kubernetes',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'AWS',
link: '/aws',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Cloudflare',
link: '/cloudflare',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Linux',
link: '/linux',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Terraform',
link: '/terraform',
type: 'skill',
otherGroups: ['Web Development'],
},
],
},
{
group: 'Mobile Development',
roadmaps: [
{
title: 'Android',
link: '/android',
type: 'role',
},
{
title: 'iOS',
link: '/ios',
type: 'role',
},
{
title: 'React Native',
link: '/react-native',
type: 'skill',
},
{
title: 'Flutter',
link: '/flutter',
type: 'skill',
},
],
},
{
group: 'Databases',
roadmaps: [
{
title: 'PostgreSQL',
link: '/postgresql-dba',
type: 'role',
otherGroups: ['Web Development'],
},
{
title: 'MongoDB',
link: '/mongodb',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Redis',
link: '/redis',
type: 'skill',
otherGroups: ['Web Development'],
},
],
},
{
group: 'Computer Science',
roadmaps: [
{
title: 'Computer Science',
link: '/computer-science',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Data Structures',
link: '/datastructures-and-algorithms',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'System Design',
link: '/system-design',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Design and Architecture',
link: '/software-design-architecture',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Software Architect',
link: '/software-architect',
type: 'role',
otherGroups: ['Web Development'],
},
{
title: 'Code Review',
link: '/code-review',
type: 'skill',
otherGroups: ['Web Development'],
},
{
title: 'Technical Writer',
link: '/technical-writer',
type: 'role',
},
{
title: 'DevRel Engineer',
link: '/devrel',
type: 'role',
},
],
},
{
group: 'Machine Learning',
roadmaps: [
{
title: 'AI and Data Scientist',
link: '/ai-data-scientist',
type: 'role',
},
{
title: 'AI Engineer',
link: '/ai-engineer',
type: 'role',
},
{
title: 'AI Agents',
link: '/ai-agents',
type: 'role',
},
{
title: 'AI Red Teaming',
link: '/ai-red-teaming',
type: 'skill',
},
{
title: 'Data Analyst',
link: '/data-analyst',
type: 'role',
},
{
title: 'MLOps',
link: '/mlops',
type: 'role',
},
{
title: 'Prompt Engineering',
link: '/prompt-engineering',
type: 'skill',
},
],
},
{
group: 'Management',
roadmaps: [
{
title: 'Product Manager',
link: '/product-manager',
type: 'role',
},
{
title: 'Engineering Manager',
link: '/engineering-manager',
type: 'role',
},
],
},
{
group: 'Game Development',
roadmaps: [
{
title: 'Client Side Game Dev.',
link: '/game-developer',
type: 'role',
},
{
title: 'Server Side Game Dev.',
link: '/server-side-game-developer',
type: 'role',
},
],
},
{
group: 'Design',
roadmaps: [
{
title: 'UX Design',
link: '/ux-design',
type: 'role',
},
{
title: 'Design System',
link: '/design-system',
type: 'skill',
otherGroups: ['Web Development'],
},
],
},
{
group: 'Blockchain',
roadmaps: [
{
title: 'Blockchain',
link: '/blockchain',
type: 'role',
},
],
},
{
group: 'Cyber Security',
roadmaps: [
{
title: 'Cyber Security',
link: '/cyber-security',
type: 'role',
},
],
},
];
const roleRoadmaps = groups.flatMap((group) =>
group.roadmaps.filter((roadmap) => roadmap.type === 'role'),
);
const skillRoadmaps = groups.flatMap((group) =>
group.roadmaps.filter((roadmap) => roadmap.type === 'skill'),
);
const allGroups = [
{
group: 'Role Based Roadmaps',
roadmaps: roleRoadmaps,
},
{
group: 'Skill Based Roadmaps',
roadmaps: skillRoadmaps,
},
];
export function RoadmapsPage() {
const [activeGroup, setActiveGroup] = useState<AllowGroupNames>('');
const [visibleGroups, setVisibleGroups] = useState<GroupType[]>(allGroups);
const [isFilterOpen, setIsFilterOpen] = useState(false);
useEffect(() => {
if (!activeGroup) {
setVisibleGroups(allGroups);
return;
}
const group = groups.find((group) => group.group === activeGroup);
if (!group) {
return;
}
// other groups that have a roadmap that is in the same group
const otherGroups = groups.filter((g) => {
return (
g.group !== group.group &&
g.roadmaps.some((roadmap) => {
return roadmap.otherGroups?.includes(group.group);
})
);
});
setVisibleGroups([
group,
...otherGroups.map((g) => ({
...g,
roadmaps: g.roadmaps.filter((roadmap) =>
roadmap.otherGroups?.includes(group.group),
),
})),
]);
}, [activeGroup]);
async function loadProgress() {
const { response: progressList, error } =
await httpGet<UserProgressResponse>(
`${import.meta.env.PUBLIC_API_URL}/v1-get-hero-roadmaps`,
);
if (error || !progressList) {
return;
}
progressList?.forEach((progress) => {
window.dispatchEvent(
new CustomEvent('mark-favorite', {
detail: {
resourceId: progress.resourceId,
resourceType: progress.resourceType,
isFavorite: progress.isFavorite,
},
}),
);
});
}
useEffect(() => {
if (!isLoggedIn()) {
return;
}
loadProgress().finally(() => {});
}, []);
useEffect(() => {
const { g } = getUrlParams() as { g: AllowGroupNames };
if (!g) {
return;
}
setActiveGroup(g);
}, []);
return (
<div className="border-t bg-gray-100">
<button
onClick={() => {
setIsFilterOpen(!isFilterOpen);
}}
id="filter-button"
className={cn(
'-mt-1 flex w-full items-center justify-center bg-gray-300 py-2 text-sm text-black focus:shadow-none focus:outline-0 sm:hidden',
{
'mb-3': !isFilterOpen,
},
)}
>
{!isFilterOpen && <Filter size={13} className="mr-1" />}
{isFilterOpen && <X size={13} className="mr-1" />}
Categories
</button>
<div className="container relative flex flex-col gap-4 sm:flex-row">
<div
className={cn(
'hidden w-full flex-col from-gray-100 sm:w-[180px] sm:border-r sm:bg-linear-to-l sm:pt-6',
{
'hidden sm:flex': !isFilterOpen,
'z-50 flex': isFilterOpen,
},
)}
>
<div className="absolute top-0 -mx-4 w-full bg-white pb-0 shadow-xl sm:sticky sm:top-10 sm:mx-0 sm:bg-transparent sm:pb-20 sm:shadow-none">
<div className="grid grid-cols-1">
<CategoryFilterButton
onClick={() => {
setActiveGroup('');
setIsFilterOpen(false);
deleteUrlParam('g');
}}
category={'All Roadmaps'}
selected={activeGroup === ''}
/>
{groups.map((group) => (
<CategoryFilterButton
key={group.group}
onClick={() => {
setActiveGroup(group.group);
setIsFilterOpen(false);
document?.getElementById('filter-button')?.scrollIntoView();
setUrlParams({ g: group.group });
}}
category={group.group}
selected={activeGroup === group.group}
/>
))}
</div>
</div>
</div>
<div className="flex grow flex-col gap-6 pb-20 pt-2 sm:pt-8">
{visibleGroups.map((group) => (
<div key={`${group.group}-${group.roadmaps.length}`}>
<h2 className="mb-2 text-xs uppercase tracking-wide text-gray-400">
{group.group}
</h2>
<div className="grid grid-cols-1 gap-1.5 sm:grid-cols-2 md:grid-cols-3">
{group.roadmaps.map((roadmap) => (
<RoadmapCard roadmap={roadmap} key={roadmap.link} />
))}
</div>
</div>
))}
</div>
</div>
</div>
);
}