Refactor UI

feat/readonly-editor
Arik Chakma 1 year ago
parent 7065530e73
commit c255b277b0
  1. 132
      src/components/TeamProgress/MemberCustomProgressModal.tsx
  2. 130
      src/components/TeamProgress/MemberProgressModal.tsx
  3. 148
      src/components/TeamProgress/MemberProgressModalHeader.tsx
  4. 37
      src/components/UserProgress/ProgressLoadingError.tsx
  5. 100
      src/components/UserProgress/UserCustomProgressModal.tsx
  6. 102
      src/components/UserProgress/UserProgressModal.tsx
  7. 79
      src/components/UserProgress/UserProgressModalHeader.tsx

@ -28,6 +28,7 @@ import { calculateDimensions } from '../../../editor/utils/roadmap';
import { isMobile } from '../../../editor/utils/is-mobile'; import { isMobile } from '../../../editor/utils/is-mobile';
import { useKeydown } from '../../hooks/use-keydown'; import { useKeydown } from '../../hooks/use-keydown';
import { useOutsideClick } from '../../hooks/use-outside-click'; import { useOutsideClick } from '../../hooks/use-outside-click';
import { MemberProgressModalHeader } from './MemberProgressModalHeader';
export type ProgressMapProps = { export type ProgressMapProps = {
member: TeamMember; member: TeamMember;
@ -39,7 +40,7 @@ export type ProgressMapProps = {
isCustomResource?: boolean; isCustomResource?: boolean;
}; };
type MemberProgressResponse = { export type MemberProgressResponse = {
removed: string[]; removed: string[];
done: string[]; done: string[];
learning: string[]; learning: string[];
@ -227,22 +228,6 @@ export function MemberCustomProgressModal(props: ProgressMapProps) {
} }
}, []); }, []);
const removedTopics = memberProgress?.removed || [];
const memberDone =
memberProgress?.done.filter((id) => !removedTopics.includes(id)).length ||
0;
const memberLearning =
memberProgress?.learning.filter((id) => !removedTopics.includes(id))
.length || 0;
const memberSkipped =
memberProgress?.skipped.filter((id) => !removedTopics.includes(id))
.length || 0;
const currProgress = member.progress.find((p) => p.resourceId === resourceId);
const memberTotal = currProgress?.total || 0;
const progressPercentage = Math.round((memberDone / memberTotal) * 100);
return ( return (
<div className="fixed left-0 right-0 top-0 z-50 h-full items-center justify-center overflow-y-auto overflow-x-hidden overscroll-contain bg-black/50"> <div className="fixed left-0 right-0 top-0 z-50 h-full items-center justify-center overflow-y-auto overflow-x-hidden overscroll-contain bg-black/50">
<div <div
@ -253,111 +238,14 @@ export function MemberCustomProgressModal(props: ProgressMapProps) {
className="relative rounded-lg bg-white pt-[1px] shadow" className="relative rounded-lg bg-white pt-[1px] shadow"
ref={popupBodyEl} ref={popupBodyEl}
> >
{isCurrentUser && ( <MemberProgressModalHeader
<div className="sticky top-1 z-50 mx-1 mb-0 mt-1 rounded-xl bg-gray-900 p-4 text-gray-300"> resourceId={resourceId}
<h2 className={'mb-1.5 text-base'}> member={member}
Follow the Instructions below to update your progress progress={memberProgress}
</h2> isCurrentUser={isCurrentUser}
<ul className="flex flex-col gap-1"> onShowMyProgress={onShowMyProgress}
<li className="leading-loose"> isLoading={isLoading}
<kbd className="rounded-md bg-yellow-200 px-2 py-1.5 text-xs text-gray-900"> />
Right Mouse Click
</kbd>{' '}
on a topic to mark as{' '}
<span className={'font-medium text-white'}>Done</span>.
</li>
<li className="leading-loose">
<kbd className="rounded-md bg-yellow-200 px-2 py-1.5 text-xs text-gray-900">
Shift
</kbd>{' '}
+{' '}
<kbd className="rounded-md bg-yellow-200 px-2 py-1.5 text-xs text-gray-900">
Click
</kbd>{' '}
on a topic to mark as{' '}
<span className="font-medium text-white">In progress</span>.
</li>
</ul>
</div>
)}
<div className="p-4">
{!isCurrentUser && (
<div className="mb-5 mt-0 text-left md:mt-4 md:text-center">
<h2 className={'mb-1 text-lg font-bold md:text-2xl'}>
{member.name}'s Progress
</h2>
<p
className={
'hidden text-xs text-gray-500 sm:text-sm md:block md:text-base'
}
>
You are looking at {member.name}'s progress.{' '}
<button
className="text-blue-600 underline"
onClick={onShowMyProgress}
>
View your progress
</button>
.
</p>
<p className={'block text-gray-500 md:hidden'}>
<button
className="text-blue-600 underline"
onClick={onShowMyProgress}
>
View your progress.
</button>
</p>
</div>
)}
<p
className={`-mx-4 mb-3 flex items-center justify-start border-b border-t px-4 py-2 text-sm sm:hidden ${
isLoading ? 'striped-loader' : ''
}`}
>
<span className="mr-2.5 block rounded-sm bg-yellow-200 px-1 py-0.5 text-xs font-medium uppercase text-yellow-900">
<span>{progressPercentage}</span>% Done
</span>
<span>
<span>{memberDone}</span> of <span>{memberTotal}</span> done
</span>
</p>
<p
className={`-mx-4 mb-3 hidden items-center justify-center border-b border-t py-2 text-sm sm:flex ${
isLoading ? 'striped-loader' : ''
}`}
>
<span className="mr-2.5 block rounded-sm bg-yellow-200 px-1 py-0.5 text-xs font-medium uppercase text-yellow-900">
<span>{progressPercentage}</span>% Done
</span>
<span>
<span>{memberDone}</span> completed
</span>
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span data-progress-learning="">{memberLearning}</span> in
progress
</span>
{memberSkipped > 0 && (
<>
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span data-progress-skipped="">{memberSkipped}</span>{' '}
skipped
</span>
</>
)}
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span data-progress-total="">{memberTotal}</span> Total
</span>
</p>
</div>
{!isLoading && roadmap && ( {!isLoading && roadmap && (
<div className="px-4 pb-2"> <div className="px-4 pb-2">

@ -16,7 +16,7 @@ import CloseIcon from '../../icons/close.svg';
import { useToast } from '../../hooks/use-toast'; import { useToast } from '../../hooks/use-toast';
import { useAuth } from '../../hooks/use-auth'; import { useAuth } from '../../hooks/use-auth';
import { pageProgressMessage } from '../../stores/page'; import { pageProgressMessage } from '../../stores/page';
import { renderFlowJSON } from '../../../renderer/renderer'; import { MemberProgressModalHeader } from './MemberProgressModalHeader';
export type ProgressMapProps = { export type ProgressMapProps = {
member: TeamMember; member: TeamMember;
@ -255,22 +255,6 @@ export function MemberProgressModal(props: ProgressMapProps) {
}; };
}, [member]); }, [member]);
const removedTopics = memberProgress?.removed || [];
const memberDone =
memberProgress?.done.filter((id) => !removedTopics.includes(id)).length ||
0;
const memberLearning =
memberProgress?.learning.filter((id) => !removedTopics.includes(id))
.length || 0;
const memberSkipped =
memberProgress?.skipped.filter((id) => !removedTopics.includes(id))
.length || 0;
const currProgress = member.progress.find((p) => p.resourceId === resourceId);
const memberTotal = currProgress?.total || 0;
const progressPercentage = Math.round((memberDone / memberTotal) * 100);
return ( return (
<div className="fixed left-0 right-0 top-0 z-50 h-full items-center justify-center overflow-y-auto overflow-x-hidden overscroll-contain bg-black/50"> <div className="fixed left-0 right-0 top-0 z-50 h-full items-center justify-center overflow-y-auto overflow-x-hidden overscroll-contain bg-black/50">
<div <div
@ -281,110 +265,14 @@ export function MemberProgressModal(props: ProgressMapProps) {
ref={popupBodyEl} ref={popupBodyEl}
className="popup-body relative rounded-lg bg-white pt-[1px] shadow" className="popup-body relative rounded-lg bg-white pt-[1px] shadow"
> >
{isCurrentUser && ( <MemberProgressModalHeader
<div className="sticky top-1 mx-1 mb-0 mt-1 rounded-xl bg-gray-900 p-4 text-gray-300"> resourceId={resourceId}
<h2 className={'mb-1.5 text-base'}> member={member}
Follow the Instructions below to update your progress progress={memberProgress}
</h2> isCurrentUser={isCurrentUser}
<ul className="flex flex-col gap-1"> onShowMyProgress={onShowMyProgress}
<li className="leading-loose"> isLoading={isLoading}
<kbd className="rounded-md bg-yellow-200 px-2 py-1.5 text-xs text-gray-900"> />
Right Mouse Click
</kbd>{' '}
on a topic to mark as{' '}
<span className={'font-medium text-white'}>Done</span>.
</li>
<li className="leading-loose">
<kbd className="rounded-md bg-yellow-200 px-2 py-1.5 text-xs text-gray-900">
Shift
</kbd>{' '}
+{' '}
<kbd className="rounded-md bg-yellow-200 px-2 py-1.5 text-xs text-gray-900">
Click
</kbd>{' '}
on a topic to mark as{' '}
<span className="font-medium text-white">In progress</span>.
</li>
</ul>
</div>
)}
<div className="p-4">
{!isCurrentUser && (
<div className="mb-5 mt-0 text-left md:mt-4 md:text-center">
<h2 className={'mb-1 text-lg font-bold md:text-2xl'}>
{member.name}'s Progress
</h2>
<p
className={
'hidden text-xs text-gray-500 sm:text-sm md:block md:text-base'
}
>
You are looking at {member.name}'s progress.{' '}
<button
className="text-blue-600 underline"
onClick={onShowMyProgress}
>
View your progress
</button>
.
</p>
<p className={'block text-gray-500 md:hidden'}>
<button
className="text-blue-600 underline"
onClick={onShowMyProgress}
>
View your progress.
</button>
</p>
</div>
)}
<p
className={`-mx-4 mb-3 flex items-center justify-start border-b border-t px-4 py-2 text-sm sm:hidden ${
isLoading ? 'striped-loader' : ''
}`}
>
<span className="mr-2.5 block rounded-sm bg-yellow-200 px-1 py-0.5 text-xs font-medium uppercase text-yellow-900">
<span>{progressPercentage}</span>% Done
</span>
<span>
<span>{memberDone}</span> of <span>{memberTotal}</span> done
</span>
</p>
<p
className={`-mx-4 mb-3 hidden items-center justify-center border-b border-t py-2 text-sm sm:flex ${
isLoading ? 'striped-loader' : ''
}`}
>
<span className="mr-2.5 block rounded-sm bg-yellow-200 px-1 py-0.5 text-xs font-medium uppercase text-yellow-900">
<span>{progressPercentage}</span>% Done
</span>
<span>
<span>{memberDone}</span> completed
</span>
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span data-progress-learning="">{memberLearning}</span> in
progress
</span>
{memberSkipped > 0 && (
<>
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span data-progress-skipped="">{memberSkipped}</span>{' '}
skipped
</span>
</>
)}
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span data-progress-total="">{memberTotal}</span> Total
</span>
</p>
</div>
<div <div
id={'resource-svg-wrap'} id={'resource-svg-wrap'}

@ -0,0 +1,148 @@
import type { MemberProgressResponse } from './MemberCustomProgressModal';
import type { TeamMember } from './TeamProgressPage';
type MemberProgressModalHeaderProps = {
member: TeamMember;
progress?: MemberProgressResponse;
resourceId: string;
isLoading: boolean;
onShowMyProgress: () => void;
isCurrentUser: boolean;
};
export function MemberProgressModalHeader(
props: MemberProgressModalHeaderProps
) {
const {
progress: memberProgress,
member,
resourceId,
isLoading,
onShowMyProgress,
isCurrentUser,
} = props;
const removedTopics = memberProgress?.removed || [];
const memberDone =
memberProgress?.done.filter((id) => !removedTopics.includes(id)).length ||
0;
const memberLearning =
memberProgress?.learning.filter((id) => !removedTopics.includes(id))
.length || 0;
const memberSkipped =
memberProgress?.skipped.filter((id) => !removedTopics.includes(id))
.length || 0;
const currProgress = member.progress.find((p) => p.resourceId === resourceId);
const memberTotal = currProgress?.total || 0;
const progressPercentage = Math.round((memberDone / memberTotal) * 100);
return (
<>
{isCurrentUser && (
<div className="sticky top-1 z-50 mx-1 mb-0 mt-1 rounded-xl bg-gray-900 p-4 text-gray-300">
<h2 className={'mb-1.5 text-base'}>
Follow the Instructions below to update your progress
</h2>
<ul className="flex flex-col gap-1">
<li className="leading-loose">
<kbd className="rounded-md bg-yellow-200 px-2 py-1.5 text-xs text-gray-900">
Right Mouse Click
</kbd>{' '}
on a topic to mark as{' '}
<span className={'font-medium text-white'}>Done</span>.
</li>
<li className="leading-loose">
<kbd className="rounded-md bg-yellow-200 px-2 py-1.5 text-xs text-gray-900">
Shift
</kbd>{' '}
+{' '}
<kbd className="rounded-md bg-yellow-200 px-2 py-1.5 text-xs text-gray-900">
Click
</kbd>{' '}
on a topic to mark as{' '}
<span className="font-medium text-white">In progress</span>.
</li>
</ul>
</div>
)}
<div className="p-4">
{!isCurrentUser && (
<div className="mb-5 mt-0 text-left md:mt-4 md:text-center">
<h2 className={'mb-1 text-lg font-bold md:text-2xl'}>
{member.name}'s Progress
</h2>
<p
className={
'hidden text-xs text-gray-500 sm:text-sm md:block md:text-base'
}
>
You are looking at {member.name}'s progress.{' '}
<button
className="text-blue-600 underline"
onClick={onShowMyProgress}
>
View your progress
</button>
.
</p>
<p className={'block text-gray-500 md:hidden'}>
<button
className="text-blue-600 underline"
onClick={onShowMyProgress}
>
View your progress.
</button>
</p>
</div>
)}
<p
className={`-mx-4 mb-3 flex items-center justify-start border-b border-t px-4 py-2 text-sm sm:hidden ${
isLoading ? 'striped-loader' : ''
}`}
>
<span className="mr-2.5 block rounded-sm bg-yellow-200 px-1 py-0.5 text-xs font-medium uppercase text-yellow-900">
<span>{progressPercentage}</span>% Done
</span>
<span>
<span>{memberDone}</span> of <span>{memberTotal}</span> done
</span>
</p>
<p
className={`-mx-4 mb-3 hidden items-center justify-center border-b border-t py-2 text-sm sm:flex ${
isLoading ? 'striped-loader' : ''
}`}
>
<span className="mr-2.5 block rounded-sm bg-yellow-200 px-1 py-0.5 text-xs font-medium uppercase text-yellow-900">
<span>{progressPercentage}</span>% Done
</span>
<span>
<span>{memberDone}</span> completed
</span>
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span data-progress-learning="">{memberLearning}</span> in progress
</span>
{memberSkipped > 0 && (
<>
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span data-progress-skipped="">{memberSkipped}</span> skipped
</span>
</>
)}
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span data-progress-total="">{memberTotal}</span> Total
</span>
</p>
</div>
</>
);
}

@ -0,0 +1,37 @@
import { ErrorIcon } from "../ReactIcons/ErrorIcon";
import { Spinner } from "../ReactIcons/Spinner";
type ProgressLoadingErrorProps = {
isLoading: boolean;
error: string;
}
export function ProgressLoadingError(props: ProgressLoadingErrorProps) {
const { isLoading, error } = props;
return (
<div className="fixed left-0 right-0 top-0 z-50 h-full items-center justify-center overflow-y-auto overflow-x-hidden overscroll-contain bg-black/50">
<div className="relative mx-auto flex h-full w-full items-center justify-center">
<div className="popup-body relative rounded-lg bg-white p-5 shadow">
<div className="flex items-center">
{isLoading && (
<>
<Spinner className="h-6 w-6" isDualRing={false} />
<span className="ml-3 text-lg font-semibold">
Loading user progress...
</span>
</>
)}
{error && (
<>
<ErrorIcon additionalClasses="h-6 w-6 text-red-500" />
<span className="ml-3 text-lg font-semibold">{error}</span>
</>
)}
</div>
</div>
</div>
</div>
)
}

@ -7,12 +7,12 @@ import { topicSelectorAll } from '../../lib/resource-progress';
import CloseIcon from '../../icons/close.svg'; import CloseIcon from '../../icons/close.svg';
import { deleteUrlParam, getUrlParams } from '../../lib/browser'; import { deleteUrlParam, getUrlParams } from '../../lib/browser';
import { useAuth } from '../../hooks/use-auth'; import { useAuth } from '../../hooks/use-auth';
import { Spinner } from '../ReactIcons/Spinner';
import { ErrorIcon } from '../ReactIcons/ErrorIcon';
import type { GetRoadmapResponse } from '../CustomRoadmap/CustomRoadmap'; import type { GetRoadmapResponse } from '../CustomRoadmap/CustomRoadmap';
import { ReadonlyEditor } from '../../../editor/readonly-editor'; import { ReadonlyEditor } from '../../../editor/readonly-editor';
import { isMobile } from '../../../editor/utils/is-mobile'; import { isMobile } from '../../../editor/utils/is-mobile';
import { calculateDimensions } from '../../../editor/utils/roadmap'; import { calculateDimensions } from '../../../editor/utils/roadmap';
import { ProgressLoadingError } from './ProgressLoadingError';
import { UserProgressModalHeader } from './UserProgressModalHeader';
export type ProgressMapProps = { export type ProgressMapProps = {
userId?: string; userId?: string;
@ -147,16 +147,6 @@ export function UserCustomProgressModal(props: ProgressMapProps) {
}); });
}, [userId]); }, [userId]);
const user = progressResponse?.user;
const progress = progressResponse?.progress;
const userProgressTotal = progress?.total || 0;
const userDone = progress?.done?.length || 0;
const progressPercentage =
Math.round((userDone / userProgressTotal) * 100) || 0;
const userLearning = progress?.learning?.length || 0;
const userSkipped = progress?.skipped?.length || 0;
if (currentUser?.id === userId) { if (currentUser?.id === userId) {
deleteUrlParam('s'); deleteUrlParam('s');
return null; return null;
@ -167,31 +157,7 @@ export function UserCustomProgressModal(props: ProgressMapProps) {
} }
if (isLoading || error) { if (isLoading || error) {
return ( return <ProgressLoadingError isLoading={isLoading} error={error || ''} />;
<div className="fixed left-0 right-0 top-0 z-50 h-full items-center justify-center overflow-y-auto overflow-x-hidden overscroll-contain bg-black/50">
<div className="relative mx-auto flex h-full w-full items-center justify-center">
<div className="popup-body relative rounded-lg bg-white p-5 shadow">
<div className="flex items-center">
{isLoading && (
<>
<Spinner className="h-6 w-6" isDualRing={false} />
<span className="ml-3 text-lg font-semibold">
Loading user progress...
</span>
</>
)}
{error && (
<>
<ErrorIcon additionalClasses="h-6 w-6 text-red-500" />
<span className="ml-3 text-lg font-semibold">{error}</span>
</>
)}
</div>
</div>
</div>
</div>
);
} }
return ( return (
@ -204,62 +170,10 @@ export function UserCustomProgressModal(props: ProgressMapProps) {
ref={popupBodyEl} ref={popupBodyEl}
className={`popup-body relative rounded-lg bg-white pt-[1px] shadow`} className={`popup-body relative rounded-lg bg-white pt-[1px] shadow`}
> >
<div className="p-4"> <UserProgressModalHeader
<div className="mb-5 mt-0 min-h-[28px] text-left sm:text-center md:mt-4 md:h-[60px]"> isLoading={isLoading}
<h2 className={'mb-1 text-lg font-bold md:text-2xl'}> progressResponse={progressResponse}
{user?.name}'s Progress />
</h2>
<p
className={
'hidden text-xs text-gray-500 sm:text-sm md:block md:text-base'
}
>
You can close this popup and start tracking your progress.
</p>
</div>
<p
className={`-mx-4 mb-3 flex items-center justify-start border-b border-t px-4 py-2 text-sm sm:hidden`}
>
<span className="mr-2.5 block rounded-sm bg-yellow-200 px-1 py-0.5 text-xs font-medium uppercase text-yellow-900">
<span>{progressPercentage}</span>% Done
</span>
<span>
<span>{userDone}</span> of <span>{userProgressTotal}</span> done
</span>
</p>
<p
className={`-mx-4 mb-3 hidden items-center justify-center border-b border-t py-2 text-sm sm:flex ${
isLoading ? 'striped-loader' : ''
}`}
>
<span className="mr-2.5 block rounded-sm bg-yellow-200 px-1 py-0.5 text-xs font-medium uppercase text-yellow-900">
<span>{progressPercentage}</span>% Done
</span>
<span>
<span>{userDone}</span> completed
</span>
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span>{userLearning}</span> in progress
</span>
{userSkipped > 0 && (
<>
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span>{userSkipped}</span> skipped
</span>
</>
)}
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span>{userProgressTotal}</span> Total
</span>
</p>
</div>
<div ref={resourceSvgEl} className="px-4 pb-2"> <div ref={resourceSvgEl} className="px-4 pb-2">
<ReadonlyEditor <ReadonlyEditor

@ -9,8 +9,8 @@ import { topicSelectorAll } from '../../lib/resource-progress';
import CloseIcon from '../../icons/close.svg'; import CloseIcon from '../../icons/close.svg';
import { deleteUrlParam, getUrlParams } from '../../lib/browser'; import { deleteUrlParam, getUrlParams } from '../../lib/browser';
import { useAuth } from '../../hooks/use-auth'; import { useAuth } from '../../hooks/use-auth';
import { Spinner } from '../ReactIcons/Spinner'; import { ProgressLoadingError } from './ProgressLoadingError';
import { ErrorIcon } from '../ReactIcons/ErrorIcon'; import { UserProgressModalHeader } from './UserProgressModalHeader';
export type ProgressMapProps = { export type ProgressMapProps = {
userId?: string; userId?: string;
@ -20,7 +20,7 @@ export type ProgressMapProps = {
isCustomResource?: boolean; isCustomResource?: boolean;
}; };
type UserProgressResponse = { export type UserProgressResponse = {
user: { user: {
_id: string; _id: string;
name: string; name: string;
@ -177,16 +177,6 @@ export function UserProgressModal(props: ProgressMapProps) {
}); });
}, [userId]); }, [userId]);
const user = progressResponse?.user;
const progress = progressResponse?.progress;
const userProgressTotal = progress?.total || 0;
const userDone = progress?.done?.length || 0;
const progressPercentage =
Math.round((userDone / userProgressTotal) * 100) || 0;
const userLearning = progress?.learning?.length || 0;
const userSkipped = progress?.skipped?.length || 0;
if (currentUser?.id === userId) { if (currentUser?.id === userId) {
deleteUrlParam('s'); deleteUrlParam('s');
return null; return null;
@ -197,31 +187,7 @@ export function UserProgressModal(props: ProgressMapProps) {
} }
if (isLoading || error) { if (isLoading || error) {
return ( return <ProgressLoadingError isLoading={isLoading} error={error} />;
<div className="fixed left-0 right-0 top-0 z-50 h-full items-center justify-center overflow-y-auto overflow-x-hidden overscroll-contain bg-black/50">
<div className="relative mx-auto flex h-full w-full items-center justify-center">
<div className="popup-body relative rounded-lg bg-white p-5 shadow">
<div className="flex items-center">
{isLoading && (
<>
<Spinner className="h-6 w-6" isDualRing={false} />
<span className="ml-3 text-lg font-semibold">
Loading user progress...
</span>
</>
)}
{error && (
<>
<ErrorIcon additionalClasses="h-6 w-6 text-red-500" />
<span className="ml-3 text-lg font-semibold">{error}</span>
</>
)}
</div>
</div>
</div>
</div>
);
} }
return ( return (
@ -234,62 +200,10 @@ export function UserProgressModal(props: ProgressMapProps) {
ref={popupBodyEl} ref={popupBodyEl}
className={`popup-body relative rounded-lg bg-white pt-[1px] shadow`} className={`popup-body relative rounded-lg bg-white pt-[1px] shadow`}
> >
<div className="p-4"> <UserProgressModalHeader
<div className="mb-5 mt-0 min-h-[28px] text-left sm:text-center md:mt-4 md:h-[60px]"> isLoading={isLoading}
<h2 className={'mb-1 text-lg font-bold md:text-2xl'}> progressResponse={progressResponse}
{user?.name}'s Progress />
</h2>
<p
className={
'hidden text-xs text-gray-500 sm:text-sm md:block md:text-base'
}
>
You can close this popup and start tracking your progress.
</p>
</div>
<p
className={`-mx-4 mb-3 flex items-center justify-start border-b border-t px-4 py-2 text-sm sm:hidden`}
>
<span className="mr-2.5 block rounded-sm bg-yellow-200 px-1 py-0.5 text-xs font-medium uppercase text-yellow-900">
<span>{progressPercentage}</span>% Done
</span>
<span>
<span>{userDone}</span> of <span>{userProgressTotal}</span> done
</span>
</p>
<p
className={`-mx-4 mb-3 hidden items-center justify-center border-b border-t py-2 text-sm sm:flex ${
isLoading ? 'striped-loader' : ''
}`}
>
<span className="mr-2.5 block rounded-sm bg-yellow-200 px-1 py-0.5 text-xs font-medium uppercase text-yellow-900">
<span>{progressPercentage}</span>% Done
</span>
<span>
<span>{userDone}</span> completed
</span>
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span>{userLearning}</span> in progress
</span>
{userSkipped > 0 && (
<>
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span>{userSkipped}</span> skipped
</span>
</>
)}
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span>{userProgressTotal}</span> Total
</span>
</p>
</div>
<div <div
ref={resourceSvgEl} ref={resourceSvgEl}

@ -0,0 +1,79 @@
import type { UserProgressResponse } from './UserProgressModal';
type UserProgressModalHeaderProps = {
isLoading: boolean;
progressResponse: UserProgressResponse | undefined;
};
export function UserProgressModalHeader(props: UserProgressModalHeaderProps) {
const { isLoading, progressResponse } = props;
const user = progressResponse?.user;
const progress = progressResponse?.progress;
const userProgressTotal = progress?.total || 0;
const userDone = progress?.done?.length || 0;
const progressPercentage =
Math.round((userDone / userProgressTotal) * 100) || 0;
const userLearning = progress?.learning?.length || 0;
const userSkipped = progress?.skipped?.length || 0;
return (
<div className="p-4">
<div className="mb-5 mt-0 min-h-[28px] text-left sm:text-center md:mt-4 md:h-[60px]">
<h2 className={'mb-1 text-lg font-bold md:text-2xl'}>
{user?.name}'s Progress
</h2>
<p
className={
'hidden text-xs text-gray-500 sm:text-sm md:block md:text-base'
}
>
You can close this popup and start tracking your progress.
</p>
</div>
<p
className={`-mx-4 mb-3 flex items-center justify-start border-b border-t px-4 py-2 text-sm sm:hidden`}
>
<span className="mr-2.5 block rounded-sm bg-yellow-200 px-1 py-0.5 text-xs font-medium uppercase text-yellow-900">
<span>{progressPercentage}</span>% Done
</span>
<span>
<span>{userDone}</span> of <span>{userProgressTotal}</span> done
</span>
</p>
<p
className={`-mx-4 mb-3 hidden items-center justify-center border-b border-t py-2 text-sm sm:flex ${
isLoading ? 'striped-loader' : ''
}`}
>
<span className="mr-2.5 block rounded-sm bg-yellow-200 px-1 py-0.5 text-xs font-medium uppercase text-yellow-900">
<span>{progressPercentage}</span>% Done
</span>
<span>
<span>{userDone}</span> completed
</span>
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span>{userLearning}</span> in progress
</span>
{userSkipped > 0 && (
<>
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span>{userSkipped}</span> skipped
</span>
</>
)}
<span className="mx-1.5 text-gray-400">·</span>
<span>
<span>{userProgressTotal}</span> Total
</span>
</p>
</div>
);
}
Loading…
Cancel
Save