mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-01-17 14:18:17 +01:00
Hero roadmap section updates
This commit is contained in:
parent
e5e0a7c8c5
commit
7ec5e30b51
@ -12,10 +12,12 @@ import { useState } from 'react';
|
|||||||
type CreateRoadmapButtonProps = {
|
type CreateRoadmapButtonProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
type?: AllowedCustomRoadmapType;
|
type?: AllowedCustomRoadmapType;
|
||||||
|
text?: string;
|
||||||
|
teamId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function CreateRoadmapButton(props: CreateRoadmapButtonProps) {
|
export function CreateRoadmapButton(props: CreateRoadmapButtonProps) {
|
||||||
const { className, type } = props;
|
const { teamId, className, type, text = 'Create your own Roadmap' } = props;
|
||||||
|
|
||||||
const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false);
|
const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false);
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ export function CreateRoadmapButton(props: CreateRoadmapButtonProps) {
|
|||||||
<>
|
<>
|
||||||
{isCreatingRoadmap && (
|
{isCreatingRoadmap && (
|
||||||
<CreateRoadmapModal
|
<CreateRoadmapModal
|
||||||
|
teamId={teamId}
|
||||||
type={type}
|
type={type}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setIsCreatingRoadmap(false);
|
setIsCreatingRoadmap(false);
|
||||||
@ -46,7 +49,7 @@ export function CreateRoadmapButton(props: CreateRoadmapButtonProps) {
|
|||||||
onClick={toggleCreateRoadmapHandler}
|
onClick={toggleCreateRoadmapHandler}
|
||||||
>
|
>
|
||||||
<Plus size={16} />
|
<Plus size={16} />
|
||||||
Create your own Roadmap
|
{text}
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { EmptyProgress } from './EmptyProgress';
|
import { EmptyProgress } from './EmptyProgress';
|
||||||
import { httpGet } from '../../lib/http';
|
import { httpGet } from '../../lib/http';
|
||||||
import { HeroRoadmaps } from './HeroRoadmaps';
|
import { HeroRoadmaps, type HeroTeamRoadmaps } from './HeroRoadmaps';
|
||||||
import { isLoggedIn } from '../../lib/jwt';
|
import { isLoggedIn } from '../../lib/jwt';
|
||||||
|
import type { AllowedMemberRoles } from '../ShareOptions/ShareTeamMemberList.tsx';
|
||||||
|
|
||||||
export type UserProgressResponse = {
|
export type UserProgressResponse = {
|
||||||
resourceId: string;
|
resourceId: string;
|
||||||
@ -15,6 +16,11 @@ export type UserProgressResponse = {
|
|||||||
total: number;
|
total: number;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
isCustomResource: boolean;
|
isCustomResource: boolean;
|
||||||
|
team?: {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
role: AllowedMemberRoles;
|
||||||
|
};
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
function renderProgress(progressList: UserProgressResponse) {
|
function renderProgress(progressList: UserProgressResponse) {
|
||||||
@ -114,8 +120,22 @@ export function FavoriteRoadmaps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const hasProgress = progress?.length > 0;
|
const hasProgress = progress?.length > 0;
|
||||||
const customRoadmaps = progress?.filter((p) => p.isCustomResource);
|
const customRoadmaps = progress?.filter(
|
||||||
|
(p) => p.isCustomResource && !p.team?.name
|
||||||
|
);
|
||||||
const defaultRoadmaps = progress?.filter((p) => !p.isCustomResource);
|
const defaultRoadmaps = progress?.filter((p) => !p.isCustomResource);
|
||||||
|
const teamRoadmaps: HeroTeamRoadmaps = progress
|
||||||
|
?.filter((p) => p.isCustomResource && p.team?.name)
|
||||||
|
.reduce((acc: HeroTeamRoadmaps, curr) => {
|
||||||
|
const currTeam = curr.team!;
|
||||||
|
if (!acc[currTeam.name]) {
|
||||||
|
acc[currTeam.name] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
acc[currTeam.name].push(curr);
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -130,6 +150,7 @@ export function FavoriteRoadmaps() {
|
|||||||
{!isLoading && progress?.length == 0 && <EmptyProgress />}
|
{!isLoading && progress?.length == 0 && <EmptyProgress />}
|
||||||
{hasProgress && (
|
{hasProgress && (
|
||||||
<HeroRoadmaps
|
<HeroRoadmaps
|
||||||
|
teamRoadmaps={teamRoadmaps}
|
||||||
customRoadmaps={customRoadmaps}
|
customRoadmaps={customRoadmaps}
|
||||||
progress={defaultRoadmaps}
|
progress={defaultRoadmaps}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
|
@ -3,10 +3,10 @@ import { CheckIcon } from '../ReactIcons/CheckIcon';
|
|||||||
import { MarkFavorite } from '../FeaturedItems/MarkFavorite';
|
import { MarkFavorite } from '../FeaturedItems/MarkFavorite';
|
||||||
import { Spinner } from '../ReactIcons/Spinner';
|
import { Spinner } from '../ReactIcons/Spinner';
|
||||||
import type { ResourceType } from '../../lib/resource-progress';
|
import type { ResourceType } from '../../lib/resource-progress';
|
||||||
import { MapIcon } from 'lucide-react';
|
import { MapIcon, Users2 } from 'lucide-react';
|
||||||
import { CreateRoadmapButton } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapButton';
|
import { CreateRoadmapButton } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapButton';
|
||||||
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
|
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
|
||||||
import { useState } from 'react';
|
import { type ReactNode, useState } from 'react';
|
||||||
import { TeamAnnouncement } from '../TeamAnnouncement';
|
import { TeamAnnouncement } from '../TeamAnnouncement';
|
||||||
|
|
||||||
type ProgressRoadmapProps = {
|
type ProgressRoadmapProps = {
|
||||||
@ -56,7 +56,7 @@ function HeroRoadmap(props: ProgressRoadmapProps) {
|
|||||||
type ProgressTitleProps = {
|
type ProgressTitleProps = {
|
||||||
icon: any;
|
icon: any;
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
title: string;
|
title: string | ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function HeroTitle(props: ProgressTitleProps) {
|
export function HeroTitle(props: ProgressTitleProps) {
|
||||||
@ -74,25 +74,39 @@ export function HeroTitle(props: ProgressTitleProps) {
|
|||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
export type HeroTeamRoadmaps = Record<string, UserProgressResponse>;
|
||||||
|
|
||||||
type ProgressListProps = {
|
type ProgressListProps = {
|
||||||
progress: UserProgressResponse;
|
progress: UserProgressResponse;
|
||||||
customRoadmaps: UserProgressResponse;
|
customRoadmaps: UserProgressResponse;
|
||||||
|
teamRoadmaps?: HeroTeamRoadmaps;
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function HeroRoadmaps(props: ProgressListProps) {
|
export function HeroRoadmaps(props: ProgressListProps) {
|
||||||
const { progress, isLoading = false, customRoadmaps } = props;
|
const {
|
||||||
|
teamRoadmaps = {},
|
||||||
|
progress,
|
||||||
|
isLoading = false,
|
||||||
|
customRoadmaps,
|
||||||
|
} = props;
|
||||||
|
|
||||||
const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false);
|
const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false);
|
||||||
|
const [creatingRoadmapTeamId, setCreatingRoadmapTeamId] = useState<string>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative pb-12 pt-4 sm:pt-7">
|
<div className="relative pb-12 pt-4 sm:pt-7">
|
||||||
<p className="mb-7 text-sm mt-2">
|
<p className="mb-7 mt-2 text-sm">
|
||||||
<TeamAnnouncement />
|
<TeamAnnouncement />
|
||||||
</p>
|
</p>
|
||||||
{isCreatingRoadmap && (
|
{isCreatingRoadmap && (
|
||||||
<CreateRoadmapModal onClose={() => setIsCreatingRoadmap(false)} />
|
<CreateRoadmapModal
|
||||||
|
teamId={creatingRoadmapTeamId}
|
||||||
|
onClose={() => {
|
||||||
|
setIsCreatingRoadmap(false);
|
||||||
|
setCreatingRoadmapTeamId(undefined);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{
|
{
|
||||||
<HeroTitle
|
<HeroTitle
|
||||||
@ -168,6 +182,83 @@ export function HeroRoadmaps(props: ProgressListProps) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{Object.keys(teamRoadmaps).map((teamName) => {
|
||||||
|
const currentTeam: UserProgressResponse[0]['team'] =
|
||||||
|
teamRoadmaps?.[teamName]?.[0]?.team;
|
||||||
|
const roadmapsList = teamRoadmaps[teamName].filter(
|
||||||
|
(roadmap) => !!roadmap.resourceTitle
|
||||||
|
);
|
||||||
|
const canManageTeam = ['admin', 'manager'].includes(currentTeam?.role!);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mt-5">
|
||||||
|
{
|
||||||
|
<HeroTitle
|
||||||
|
icon={<Users2 className="mr-1.5 h-[14px] w-[14px]" />}
|
||||||
|
title={
|
||||||
|
<>
|
||||||
|
Team{' '}
|
||||||
|
<a
|
||||||
|
className="mx-1 font-medium underline underline-offset-2 transition-colors hover:text-gray-300"
|
||||||
|
href={`/team/progress?t=${currentTeam?.id}`}
|
||||||
|
>
|
||||||
|
{teamName}
|
||||||
|
</a>
|
||||||
|
Roadmaps
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
|
{roadmapsList.length === 0 && (
|
||||||
|
<p className="rounded-md border border-dashed border-gray-800 p-2 text-sm text-gray-600">
|
||||||
|
Team does not have any roadmaps yet.{' '}
|
||||||
|
{canManageTeam && (
|
||||||
|
<button
|
||||||
|
className="text-gray-500 underline underline-offset-2 hover:text-gray-400"
|
||||||
|
onClick={() => {
|
||||||
|
setCreatingRoadmapTeamId(currentTeam?.id);
|
||||||
|
setIsCreatingRoadmap(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Create one!
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{roadmapsList.length > 0 && (
|
||||||
|
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-3">
|
||||||
|
{roadmapsList.map((customRoadmap) => {
|
||||||
|
return (
|
||||||
|
<HeroRoadmap
|
||||||
|
key={customRoadmap.resourceId}
|
||||||
|
resourceId={customRoadmap.resourceId}
|
||||||
|
resourceType={'roadmap'}
|
||||||
|
resourceTitle={customRoadmap.resourceTitle}
|
||||||
|
percentageDone={
|
||||||
|
((customRoadmap.skipped + customRoadmap.done) /
|
||||||
|
customRoadmap.total) *
|
||||||
|
100
|
||||||
|
}
|
||||||
|
url={`/r?id=${customRoadmap.resourceId}`}
|
||||||
|
allowFavorite={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
{canManageTeam && (
|
||||||
|
<CreateRoadmapButton
|
||||||
|
teamId={currentTeam?.id}
|
||||||
|
text="Create Team Roadmap"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user