Compare commits

...

11 Commits

Author SHA1 Message Date
Arik Chakma
b3b43e3068 Fix progress modal 2023-11-10 03:31:23 +06:00
Kamran Ahmed
c95272e213 Update 2023-11-09 21:30:58 +00:00
Kamran Ahmed
689792665b Friends and notification pages 2023-11-09 21:30:58 +00:00
Arik Chakma
ae94ddfc04 Merge branch 'images-fix' of https://github.com/kamranahmedse/developer-roadmap into images-fix 2023-11-10 03:29:53 +06:00
Kamran Ahmed
b47f712dec Friends and notification pages 2023-11-09 21:29:21 +00:00
Arik Chakma
48b0059ade Fix user progress modal 2023-11-10 03:29:19 +06:00
Arik Chakma
2f07d5edf0 Fix invite friend 2023-11-10 03:27:48 +06:00
Kamran Ahmed
1dd9a53a32 Personal roadmap list and empty friends 2023-11-09 21:26:01 +00:00
Kamran Ahmed
540e13271e Team roadmap icon fix 2023-11-09 21:23:41 +00:00
Arik Chakma
12f617bd0e Merge branch 'images-fix' of https://github.com/kamranahmedse/developer-roadmap into images-fix 2023-11-10 03:23:08 +06:00
Arik Chakma
82a7c205eb Fix respond invite 2023-11-10 03:22:47 +06:00
15 changed files with 142 additions and 134 deletions

View File

@@ -1,14 +1,11 @@
import RoadmapIcon from '../../icons/roadmap.svg';
import { RoadmapIcon } from "../ReactIcons/RoadmapIcon";
export function EmptyActivity() {
return (
<div className="rounded-md">
<div className="flex flex-col items-center p-7 text-center">
<img
alt="no roadmaps"
src={RoadmapIcon.src}
className="mb-2 w-[60px] h-[60px] sm:h-[120px] sm:w-[120px] opacity-10"
/>
<RoadmapIcon className="mb-2 w-[60px] h-[60px] sm:h-[120px] sm:w-[120px] opacity-10" />
<h2 className="text-lg sm:text-xl font-bold">No Progress</h2>
<p className="my-1 sm:my-2 max-w-[400px] text-gray-500 text-sm sm:text-base">
Progress will appear here as you start tracking your{' '}

View File

@@ -1,4 +1,4 @@
import ChevronDownIcon from '../../icons/chevron-down.svg';
import { ChevronDownIcon } from '../ReactIcons/ChevronDownIcon';
type NotDropdownProps = {
onClick: () => void;
@@ -37,11 +37,7 @@ export function NotDropdown(props: NotDropdownProps) {
</div>
)}
<img
alt={singularName}
src={ChevronDownIcon.src}
className={'relative top-[1px] h-[17px] w-[17px] opacity-40'}
/>
<ChevronDownIcon className="relative top-[1px] h-[17px] w-[17px] opacity-40" />
</div>
);
}

View File

@@ -14,11 +14,11 @@ import {
type AllowedRoadmapVisibility,
type RoadmapDocument,
} from './CreateRoadmap/CreateRoadmapModal';
import RoadmapIcon from '../../icons/roadmap.svg';
import { PersonalRoadmapActionDropdown } from './PersonalRoadmapActionDropdown';
import type { GetRoadmapListResponse } from './RoadmapListPage';
import { useState, type Dispatch, type SetStateAction } from 'react';
import { ShareOptionsModal } from '../ShareOptions/ShareOptionsModal';
import {RoadmapIcon} from "../ReactIcons/RoadmapIcon.tsx";
type PersonalRoadmapListType = {
roadmaps: GetRoadmapListResponse['personalRoadmaps'];
@@ -91,11 +91,8 @@ export function PersonalRoadmapList(props: PersonalRoadmapListType) {
if (roadmapList.length === 0) {
return (
<div className="flex flex-col items-center p-4 py-20">
<img
alt="roadmap"
src={RoadmapIcon.src}
className="mb-4 h-24 w-24 opacity-10"
/>
<RoadmapIcon className="mb-4 h-24 w-24 opacity-10" />
<h3 className="mb-1 text-2xl font-bold text-gray-900">No roadmaps</h3>
<p className="text-base text-gray-500">
Create a roadmap to get started

View File

@@ -1,6 +1,5 @@
import UserPlusIcon from '../../icons/user-plus.svg';
import CopyIcon from '../../icons/copy.svg';
import { useCopyText } from '../../hooks/use-copy-text';
import { CopyIcon, UserPlus2 } from 'lucide-react';
type EmptyFriendsProps = {
befriendUrl: string;
@@ -13,14 +12,12 @@ export function EmptyFriends(props: EmptyFriendsProps) {
return (
<div className="rounded-md">
<div className="mx-auto flex flex-col items-center p-7 text-center">
<img
alt="no friends"
src={UserPlusIcon.src}
className="mb-2 h-[60px] w-[60px] opacity-10 sm:h-[120px] sm:w-[120px]"
/>
<UserPlus2 className="mb-2 h-[60px] w-[60px] opacity-10 sm:h-[120px] sm:w-[120px]" />
<h2 className="text-lg font-bold sm:text-xl">Invite your Friends</h2>
<p className="mb-4 mt-1 max-w-[400px] text-sm leading-relaxed text-gray-500">
Share the unique link below with your friends to track their skills and progress.
Share the unique link below with your friends to track their skills
and progress.
</p>
<div className="flex w-full max-w-[352px] items-center justify-center gap-2 rounded-lg border-2 p-1 text-sm">
@@ -44,7 +41,8 @@ export function EmptyFriends(props: EmptyFriendsProps) {
copyText(befriendUrl);
}}
>
<img src={CopyIcon.src} className="h-4 w-4" alt="Invite Friends" />
<CopyIcon className="mr-1 h-4 w-4" />
{isCopied ? 'Copied' : 'Copy'}
</button>
</div>

View File

@@ -7,10 +7,10 @@ import type { FriendshipStatus } from '../Befriend';
import { useToast } from '../../hooks/use-toast';
import { EmptyFriends } from './EmptyFriends';
import { FriendProgressItem } from './FriendProgressItem';
import UserIcon from '../../icons/user.svg';
import { UserProgressModal } from '../UserProgress/UserProgressModal';
import { InviteFriendPopup } from './InviteFriendPopup';
import { UserCustomProgressModal } from '../UserProgress/UserCustomProgressModal';
import { UserIcon } from '../ReactIcons/UserIcon.tsx';
type FriendResourceProgress = {
updatedAt: string;
@@ -64,7 +64,7 @@ export function FriendsPage() {
async function loadFriends() {
const { response, error } = await httpGet<ListFriendsResponse>(
`${import.meta.env.PUBLIC_API_URL}/v1-list-friends`
`${import.meta.env.PUBLIC_API_URL}/v1-list-friends`,
);
if (error || !response) {
@@ -89,15 +89,15 @@ export function FriendsPage() {
const befriendUrl = `${baseUrl}/befriend?u=${user?.id}`;
const selectedGroupingType = groupingTypes.find(
(grouping) => grouping.value === selectedGrouping
(grouping) => grouping.value === selectedGrouping,
);
const filteredFriends = friends.filter((friend) =>
selectedGroupingType?.statuses.includes(friend.status)
const filteredFriends = friends.filter(
(friend) => selectedGroupingType?.statuses.includes(friend.status),
);
const receivedRequests = friends.filter(
(friend) => friend.status === 'received'
(friend) => friend.status === 'received',
);
if (isLoading) {
@@ -203,11 +203,8 @@ export function FriendsPage() {
{filteredFriends.length === 0 && (
<div className="flex flex-col items-center justify-center py-12">
<img
src={UserIcon.src}
alt="Empty Friends"
className="mb-3 w-12 opacity-20"
/>
<UserIcon className="mb-3 w-12 opacity-20" />
<h2 className="text-lg font-semibold">
{selectedGrouping === 'active' && 'No friends yet'}
{selectedGrouping === 'sent' && 'No requests sent'}

View File

@@ -1,8 +1,8 @@
import type { MouseEvent } from 'react';
import { useRef } from 'react';
import { useOutsideClick } from '../../hooks/use-outside-click';
import CopyIcon from '../../icons/copy.svg';
import { useCopyText } from '../../hooks/use-copy-text';
import { CopyIcon } from 'lucide-react';
type InviteFriendPopupProps = {
befriendUrl: string;
@@ -54,11 +54,7 @@ export function InviteFriendPopup(props: InviteFriendPopupProps) {
copyText(befriendUrl);
}}
>
<img
src={CopyIcon.src}
className="h-4 w-4"
alt="Invite Friends"
/>
<CopyIcon className="mr-1 h-4 w-4" />
{isCopied ? 'Copied' : 'Copy URL'}
</button>
</div>

View File

@@ -1,10 +1,10 @@
import { useEffect, useState } from 'react';
import { httpGet, httpPatch, httpPost } from '../../lib/http';
import { httpGet, httpPatch } from '../../lib/http';
import { pageProgressMessage } from '../../stores/page';
import type { TeamMemberDocument } from '../TeamMembers/TeamMembersPage';
import XIcon from '../../icons/close-dark.svg';
import AcceptIcon from '../../icons/accept.svg';
import { useToast } from '../../hooks/use-toast';
import { AcceptIcon } from '../ReactIcons/AcceptIcon.tsx';
import { XIcon } from 'lucide-react';
interface NotificationList extends TeamMemberDocument {
name: string;
@@ -18,7 +18,7 @@ export function NotificationPage() {
const lostNotifications = async () => {
const { error, response } = await httpGet<NotificationList[]>(
`${import.meta.env.PUBLIC_API_URL}/v1-get-invitation-list`
`${import.meta.env.PUBLIC_API_URL}/v1-get-invitation-list`,
);
if (error || !response) {
toast.error(error?.message || 'Something went wrong');
@@ -28,28 +28,37 @@ export function NotificationPage() {
setNotifications(response);
};
async function respondInvitation(status: 'accept' | 'reject', inviteId: string) {
async function respondInvitation(
status: 'accept' | 'reject',
inviteId: string,
) {
setIsLoading(true);
setError('');
const { response, error } = await httpPatch<{ teamId: string }>(
`${import.meta.env.PUBLIC_API_URL}/v1-respond-invite/${inviteId}`, {
status
});
`${import.meta.env.PUBLIC_API_URL}/v1-respond-invite/${inviteId}`,
{
status,
},
);
if (error || !response) {
setError(error?.message || 'Something went wrong')
setIsLoading(false)
setError(error?.message || 'Something went wrong');
setIsLoading(false);
return;
}
if (status === 'accept') {
window.location.href = `/team/progress?t=${response.teamId}`;
} else {
window.dispatchEvent(new CustomEvent('refresh-notification', {
detail: {
count: notifications.length - 1
}
}));
setNotifications(notifications.filter((notification) => notification._id !== inviteId));
window.dispatchEvent(
new CustomEvent('refresh-notification', {
detail: {
count: notifications.length - 1,
},
}),
);
setNotifications(
notifications.filter((notification) => notification._id !== inviteId),
);
setIsLoading(false);
}
}
@@ -66,15 +75,20 @@ export function NotificationPage() {
<h2 className="text-3xl font-bold sm:text-4xl">Notification</h2>
<p className="mt-2 text-gray-400">Manage your notifications</p>
</div>
{
notifications.length === 0 && (
<div className="flex items-center justify-center mt-6">
<p className="text-gray-400">
No notifications, you can <a href="/team/new" className="text-blue-500 underline hover:no-underline">create a team</a> and invite your friends to join.
</p>
</div>
)
}
{notifications.length === 0 && (
<div className="mt-6 flex items-center justify-center">
<p className="text-gray-400">
No notifications, you can{' '}
<a
href="/team/new"
className="text-blue-500 underline hover:no-underline"
>
create a team
</a>{' '}
and invite your friends to join.
</p>
</div>
)}
<div className="space-y-4">
{notifications.map((notification) => (
<div className="flex items-center justify-between rounded-md border p-2">
@@ -86,19 +100,21 @@ export function NotificationPage() {
</div>
</div>
<div className="flex items-center space-x-2">
<button type="button"
<button
type="button"
disabled={isLoading}
className="inline-flex border p-1 rounded hover:bg-gray-50 disabled:opacity-75"
className="inline-flex rounded border p-1 hover:bg-gray-50 disabled:opacity-75"
onClick={() => respondInvitation('accept', notification?._id!)}
>
<img src={AcceptIcon.src} className="h-4 w-4" />
<AcceptIcon className="h-4 w-4" />
</button>
<button type="button"
<button
type="button"
disabled={isLoading}
className="inline-flex border p-1 rounded hover:bg-gray-50 disabled:opacity-75"
className="inline-flex rounded border p-1 hover:bg-gray-50 disabled:opacity-75"
onClick={() => respondInvitation('reject', notification?._id!)}
>
<img alt={'Close'} src={XIcon.src} className="h-4 w-4" />
<XIcon className="h-4 w-4" />
</button>
</div>
</div>

View File

@@ -0,0 +1,24 @@
type AcceptIconProps = {
className?: string;
};
export function AcceptIcon(props: AcceptIconProps) {
const { className } = props;
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="2"
stroke="#000"
className={className}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M4.5 12.75l6 6 9-13.5"
/>
</svg>
);
}

View File

@@ -1,7 +1,5 @@
import { useEffect, useState } from 'react';
import { httpGet, httpPatch } from '../lib/http';
import BuildingIcon from '../icons/building.svg';
import ErrorIcon from '../icons/error.svg';
import { pageProgressMessage } from '../stores/page';
import type { TeamDocument } from './CreateTeam/CreateTeamForm';
import type { AllowedRoles } from './CreateTeam/RoleDropdown';
@@ -9,6 +7,8 @@ import type { AllowedMemberStatus } from './TeamDropdown/TeamDropdown';
import { isLoggedIn } from '../lib/jwt';
import { showLoginPopup } from '../lib/popup';
import { getUrlParams } from '../lib/browser';
import { ErrorIcon2 } from './ReactIcons/ErrorIcon2';
import { BuildingIcon } from './ReactIcons/BuildingIcon';
type InvitationResponse = {
team: TeamDocument;
@@ -85,11 +85,7 @@ export function RespondInviteForm() {
if (!invite) {
return (
<div className="container text-center">
<img
alt={'error'}
src={ErrorIcon.src}
className="mx-auto mb-4 mt-24 w-20 opacity-20"
/>
<ErrorIcon2 className="mx-auto mb-4 mt-24 w-20 opacity-20" />
<h2 className={'mb-1 text-2xl font-bold'}>Error</h2>
<p className="mb-4 text-base leading-6 text-gray-600">
@@ -110,11 +106,7 @@ export function RespondInviteForm() {
return (
<div className="container text-center">
<img
alt={'join team'}
src={BuildingIcon.src}
className="mx-auto mb-4 mt-24 w-20 opacity-20"
/>
<BuildingIcon className="mx-auto mb-4 mt-24 w-20 opacity-20" />
<h2 className={'mb-1 text-2xl font-bold'}>Join Team</h2>
<p className="mb-3 text-base leading-6 text-gray-600">

View File

@@ -1,8 +1,8 @@
import { useState } from 'react';
import type { GroupByRoadmap, TeamMember } from './TeamProgressPage';
import { getUrlParams } from '../../lib/browser';
import ExternalLinkIcon from '../../icons/external-link.svg';
import { useAuth } from '../../hooks/use-auth';
import { LucideExternalLink } from 'lucide-react';
type GroupRoadmapItemProps = {
roadmap: GroupByRoadmap;
@@ -33,11 +33,7 @@ export function GroupRoadmapItem(props: GroupRoadmapItemProps) {
className="group mb-0.5 flex shrink-0 items-center justify-between text-base font-medium leading-none text-black"
target={'_blank'}
>
<img
alt={'link'}
src={ExternalLinkIcon.src}
className="ml-2 h-4 w-4 opacity-20 transition-opacity group-hover:opacity-100"
/>
<LucideExternalLink className="h-4 w-4 opacity-20 transition-opacity group-hover:opacity-100" />
</a>
</div>
</div>
@@ -58,7 +54,7 @@ export function GroupRoadmapItem(props: GroupRoadmapItemProps) {
onClick={() => {
onShowResourceProgress(
member.member,
member.progress?.resourceId!
member.progress?.resourceId!,
);
}}
>

View File

@@ -25,6 +25,7 @@ import type { Node } from 'reactflow';
import { useKeydown } from '../../hooks/use-keydown';
import { useOutsideClick } from '../../hooks/use-outside-click';
import { MemberProgressModalHeader } from './MemberProgressModalHeader';
import { X } from 'lucide-react';
export type ProgressMapProps = {
member: TeamMember;
@@ -284,7 +285,7 @@ export function MemberCustomProgressModal(props: ProgressMapProps) {
}`}
onClick={onClose}
>
<img alt={'close'} src={CloseIcon.src} className="h-4 w-4" />
<X className="h-4 w-4" />
<span className="sr-only">Close modal</span>
</button>
</div>

View File

@@ -12,12 +12,12 @@ import {
type ResourceType,
updateResourceProgress,
} from '../../lib/resource-progress';
import CloseIcon from '../../icons/close.svg';
import { useToast } from '../../hooks/use-toast';
import { useAuth } from '../../hooks/use-auth';
import { pageProgressMessage } from '../../stores/page';
import { MemberProgressModalHeader } from './MemberProgressModalHeader';
import {replaceChildren} from "../../lib/dom.ts";
import { replaceChildren } from '../../lib/dom.ts';
import { XIcon } from 'lucide-react';
export type ProgressMapProps = {
member: TeamMember;
@@ -68,12 +68,12 @@ export function MemberProgressModal(props: ProgressMapProps) {
teamId: string,
memberId: string,
resourceType: string,
resourceId: string
resourceId: string,
) {
const { error, response } = await httpGet<MemberProgressResponse>(
`${
import.meta.env.PUBLIC_API_URL
}/v1-get-member-resource-progress/${teamId}/${memberId}?resourceType=${resourceType}&resourceId=${resourceId}`
}/v1-get-member-resource-progress/${teamId}/${memberId}?resourceType=${resourceType}&resourceId=${resourceId}`,
);
if (error || !response) {
toast.error(error?.message || 'Failed to get member progress');
@@ -160,14 +160,14 @@ export function MemberProgressModal(props: ProgressMapProps) {
resourceType: resourceType as ResourceType,
topicId,
},
newStatus
newStatus,
)
.then(() => {
renderTopicProgress(topicId, newStatus);
getMemberProgress(teamId, member._id, resourceType, resourceId).then(
(data) => {
setMemberProgress(data);
}
},
);
})
.catch((err) => {
@@ -227,7 +227,7 @@ export function MemberProgressModal(props: ProgressMapProps) {
e.preventDefault();
updateTopicStatus(
topicId,
!isCurrentStatusLearning ? 'learning' : 'pending'
!isCurrentStatusLearning ? 'learning' : 'pending',
);
return;
}
@@ -236,7 +236,7 @@ export function MemberProgressModal(props: ProgressMapProps) {
e.preventDefault();
updateTopicStatus(
topicId,
!isCurrentStatusSkipped ? 'skipped' : 'pending'
!isCurrentStatusSkipped ? 'skipped' : 'pending',
);
return;
@@ -298,7 +298,8 @@ export function MemberProgressModal(props: ProgressMapProps) {
}`}
onClick={onClose}
>
<img alt={'close'} src={CloseIcon.src} className="h-4 w-4" />
<XIcon className="h-4 w-4" />
<span className="sr-only">Close modal</span>
</button>
</div>

View File

@@ -4,7 +4,6 @@ import type { TeamDocument } from '../CreateTeam/CreateTeamForm';
import type { TeamResourceConfig } from '../CreateTeam/RoadmapSelector';
import { httpGet, httpPut } from '../../lib/http';
import { pageProgressMessage } from '../../stores/page';
import RoadmapIcon from '../../icons/roadmap.svg';
import type { PageType } from '../CommandMenu/CommandMenu';
import { useStore } from '@nanostores/react';
import { $canManageCurrentTeam } from '../../stores/team';
@@ -28,6 +27,7 @@ import { RoadmapActionDropdown } from './RoadmapActionDropdown';
import { UpdateTeamResourceModal } from '../CreateTeam/UpdateTeamResourceModal';
import { ShareOptionsModal } from '../ShareOptions/ShareOptionsModal';
import { cn } from '../../lib/classname';
import { RoadmapIcon } from '../ReactIcons/RoadmapIcon.tsx';
export function TeamRoadmaps() {
const { t: teamId } = getUrlParams();
@@ -73,7 +73,7 @@ export function TeamRoadmaps() {
async function loadTeam(teamIdToFetch: string) {
const { response, error } = await httpGet<TeamDocument>(
`${import.meta.env.PUBLIC_API_URL}/v1-get-team/${teamIdToFetch}`
`${import.meta.env.PUBLIC_API_URL}/v1-get-team/${teamIdToFetch}`,
);
if (error || !response) {
@@ -87,7 +87,7 @@ export function TeamRoadmaps() {
async function loadTeamResourceConfig(teamId: string) {
const { error, response } = await httpGet<TeamResourceConfig>(
`${import.meta.env.PUBLIC_API_URL}/v1-get-team-resource-config/${teamId}`
`${import.meta.env.PUBLIC_API_URL}/v1-get-team-resource-config/${teamId}`,
);
if (error || !Array.isArray(response)) {
console.error(error);
@@ -127,7 +127,7 @@ export function TeamRoadmaps() {
{
resourceId: roadmapId,
resourceType: 'roadmap',
}
},
);
if (error || !response) {
@@ -156,7 +156,7 @@ export function TeamRoadmaps() {
resourceId: roadmapId,
resourceType: 'roadmap',
removed: [],
}
},
);
if (error || !response) {
@@ -190,13 +190,13 @@ export function TeamRoadmaps() {
}
window.addEventListener(
'custom-roadmap-created',
handleCustomRoadmapCreated
handleCustomRoadmapCreated,
);
return () => {
window.removeEventListener(
'custom-roadmap-created',
handleCustomRoadmapCreated
handleCustomRoadmapCreated,
);
};
}, []);
@@ -252,13 +252,13 @@ export function TeamRoadmaps() {
);
const placeholderRoadmaps = teamResources.filter(
(c: TeamResourceConfig[0]) => c.isCustomResource && !c.topics
(c: TeamResourceConfig[0]) => c.isCustomResource && !c.topics,
);
const customRoadmaps = teamResources.filter(
(c: TeamResourceConfig[0]) => c.isCustomResource && c.topics
(c: TeamResourceConfig[0]) => c.isCustomResource && c.topics,
);
const defaultRoadmaps = teamResources.filter(
(c: TeamResourceConfig[0]) => !c.isCustomResource
(c: TeamResourceConfig[0]) => !c.isCustomResource,
);
const hasRoadmaps =
@@ -272,11 +272,8 @@ export function TeamRoadmaps() {
{addRoadmapModal}
{createRoadmapModal}
<img
alt="roadmap"
src={RoadmapIcon.src}
className="mb-4 h-24 w-24 opacity-10"
/>
<RoadmapIcon className="mb-4 h-24 w-24 opacity-10" />
<h3 className="mb-1 text-2xl font-bold text-gray-900">No roadmaps</h3>
<p className="text-base text-gray-500">
{canManageCurrentTeam
@@ -380,11 +377,11 @@ export function TeamRoadmaps() {
onDelete={() => {
if (
confirm(
'Are you sure you want to remove this roadmap?'
'Are you sure you want to remove this roadmap?',
)
) {
onRemove(resourceConfig.resourceId).finally(
() => {}
() => {},
);
}
}}
@@ -405,7 +402,7 @@ export function TeamRoadmaps() {
)}
</div>
);
}
},
)}
</div>
</div>
@@ -433,7 +430,7 @@ export function TeamRoadmaps() {
'grid grid-cols-1 p-2.5',
canManageCurrentTeam
? 'sm:grid-cols-[auto_172px]'
: 'sm:grid-cols-[auto_110px]'
: 'sm:grid-cols-[auto_110px]',
)}
key={resourceConfig.resourceId}
>
@@ -464,11 +461,11 @@ export function TeamRoadmaps() {
onDelete={() => {
if (
confirm(
'Are you sure you want to remove this roadmap?'
'Are you sure you want to remove this roadmap?',
)
) {
onRemove(resourceConfig.resourceId).finally(
() => {}
() => {},
);
}
}}
@@ -557,11 +554,11 @@ export function TeamRoadmaps() {
onDelete={() => {
if (
confirm(
'Are you sure you want to remove this roadmap?'
'Are you sure you want to remove this roadmap?',
)
) {
onRemove(resourceConfig.resourceId).finally(
() => {}
() => {},
);
}
}}

View File

@@ -4,13 +4,13 @@ import { useKeydown } from '../../hooks/use-keydown';
import { httpGet } from '../../lib/http';
import type { ResourceType } from '../../lib/resource-progress';
import { topicSelectorAll } from '../../lib/resource-progress';
import CloseIcon from '../../icons/close.svg';
import { deleteUrlParam, getUrlParams } from '../../lib/browser';
import { useAuth } from '../../hooks/use-auth';
import type { GetRoadmapResponse } from '../CustomRoadmap/CustomRoadmap';
import { ReadonlyEditor } from '../../../editor/readonly-editor';
import { ProgressLoadingError } from './ProgressLoadingError';
import { UserProgressModalHeader } from './UserProgressModalHeader';
import { X } from 'lucide-react';
export type ProgressMapProps = {
userId?: string;
@@ -208,7 +208,7 @@ export function UserCustomProgressModal(props: ProgressMapProps) {
className={`absolute right-2.5 top-3 ml-auto inline-flex items-center rounded-lg bg-gray-100 bg-transparent p-1.5 text-sm text-gray-400 hover:text-gray-900 lg:hidden`}
onClick={onClose}
>
<img alt={'close'} src={CloseIcon.src} className="h-4 w-4" />
<X className="h-4 w-4" />
<span className="sr-only">Close modal</span>
</button>
</div>

View File

@@ -6,11 +6,11 @@ import { useKeydown } from '../../hooks/use-keydown';
import { httpGet } from '../../lib/http';
import type { ResourceType } from '../../lib/resource-progress';
import { topicSelectorAll } from '../../lib/resource-progress';
import CloseIcon from '../../icons/close.svg';
import { deleteUrlParam, getUrlParams } from '../../lib/browser';
import { useAuth } from '../../hooks/use-auth';
import { ProgressLoadingError } from './ProgressLoadingError';
import { UserProgressModalHeader } from './UserProgressModalHeader';
import { X } from 'lucide-react';
export type ProgressMapProps = {
userId?: string;
@@ -70,12 +70,12 @@ export function UserProgressModal(props: ProgressMapProps) {
async function getUserProgress(
userId: string,
resourceType: string,
resourceId: string
resourceId: string,
): Promise<UserProgressResponse | undefined> {
const { error, response } = await httpGet<UserProgressResponse>(
`${
import.meta.env.PUBLIC_API_URL
}/v1-get-user-progress/${userId}?resourceType=${resourceType}&resourceId=${resourceId}`
}/v1-get-user-progress/${userId}?resourceType=${resourceType}&resourceId=${resourceId}`,
);
if (error || !response) {
@@ -86,7 +86,7 @@ export function UserProgressModal(props: ProgressMapProps) {
}
async function getRoadmapSVG(
jsonUrl: string
jsonUrl: string,
): Promise<SVGElement | undefined> {
const { error, response: roadmapJson } = await httpGet(jsonUrl);
if (error || !roadmapJson) {
@@ -216,7 +216,7 @@ export function UserProgressModal(props: ProgressMapProps) {
className={`absolute right-2.5 top-3 ml-auto inline-flex items-center rounded-lg bg-gray-100 bg-transparent p-1.5 text-sm text-gray-400 hover:text-gray-900 lg:hidden`}
onClick={onClose}
>
<img alt={'close'} src={CloseIcon.src} className="h-4 w-4" />
<X className="h-4 w-4" />
<span className="sr-only">Close modal</span>
</button>
</div>