-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
enhance(apps/analytics): add illustrations for asynchronous activity …
…progress on performance dashboard (#4396)
- Loading branch information
1 parent
69cc23b
commit 1310b0c
Showing
20 changed files
with
736 additions
and
43 deletions.
There are no files selected for viewing
28 changes: 28 additions & 0 deletions
28
apps/frontend-manage/src/components/analytics/AnalyticsErrorView.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { H1, UserNotification } from '@uzh-bf/design-system' | ||
import { useTranslations } from 'next-intl' | ||
import React from 'react' | ||
import Layout from '~/components/Layout' | ||
|
||
function AnalyticsErrorView({ | ||
title, | ||
navigation, | ||
}: { | ||
title: string | ||
navigation: React.ReactNode | ||
}) { | ||
const t = useTranslations() | ||
|
||
return ( | ||
<Layout displayName={title}> | ||
{navigation} | ||
<H1>{title}</H1> | ||
<UserNotification | ||
message={t('manage.analytics.analyticsLoadingFailed')} | ||
type="error" | ||
className={{ root: 'mx-auto my-auto w-max max-w-full text-base' }} | ||
/> | ||
</Layout> | ||
) | ||
} | ||
|
||
export default AnalyticsErrorView |
25 changes: 25 additions & 0 deletions
25
apps/frontend-manage/src/components/analytics/AnalyticsLoadingView.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import Loader from '@klicker-uzh/shared-components/src/Loader' | ||
import { useTranslations } from 'next-intl' | ||
import Layout from '~/components/Layout' | ||
|
||
function AnalyticsLoadingView({ | ||
title, | ||
navigation, | ||
}: { | ||
title: string | ||
navigation: React.ReactNode | ||
}) { | ||
const t = useTranslations() | ||
|
||
return ( | ||
<Layout displayName={title}> | ||
{navigation} | ||
<div className="flex h-full w-full flex-row items-center justify-center gap-4 text-lg"> | ||
{t('manage.analytics.analyticsLoadingWait')} | ||
<Loader basic /> | ||
</div> | ||
</Layout> | ||
) | ||
} | ||
|
||
export default AnalyticsLoadingView |
89 changes: 89 additions & 0 deletions
89
apps/frontend-manage/src/components/analytics/performance/ActivityProgressPlot.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { ActivityProgress, ActivityType } from '@klicker-uzh/graphql/dist/ops' | ||
import { H2, H4 } from '@uzh-bf/design-system' | ||
import { useTranslations } from 'next-intl' | ||
import { Legend } from 'recharts' | ||
import StackedProgress from './StackedProgress' | ||
|
||
function ActivityProgressPlot({ | ||
activityProgresses, | ||
participants, | ||
}: { | ||
activityProgresses: ActivityProgress[] | ||
participants: number | ||
}) { | ||
const t = useTranslations() | ||
const pqProgresses = activityProgresses.filter( | ||
(progress) => progress.activityType === ActivityType.PracticeQuiz | ||
) | ||
const mlProgresses = activityProgresses.filter( | ||
(progress) => progress.activityType === ActivityType.MicroLearning | ||
) | ||
|
||
const chartColors = { | ||
started: '#4ade80', | ||
completed: '#15803d', | ||
repeated: '#064e3b', | ||
} | ||
|
||
return ( | ||
<div className="border-uzh-grey-80 rounded-xl border border-solid p-3"> | ||
<div className="relative"> | ||
<H2>{t('manage.analytics.asynchronousActivityProgress')}</H2> | ||
<Legend | ||
payload={[ | ||
{ | ||
value: t('manage.analytics.started'), | ||
color: chartColors.started, | ||
type: 'rect', | ||
}, | ||
{ | ||
value: t('manage.analytics.completed'), | ||
color: chartColors.completed, | ||
type: 'rect', | ||
}, | ||
{ | ||
value: t('manage.analytics.repeated'), | ||
color: chartColors.repeated, | ||
type: 'rect', | ||
}, | ||
]} | ||
wrapperStyle={{ bottom: 0, right: 0 }} | ||
/> | ||
</div> | ||
<div className="flex flex-col gap-6"> | ||
{pqProgresses.length > 0 && ( | ||
<div> | ||
<H4>{t('shared.generic.practiceQuizzes')}</H4> | ||
<div className="max-h-[13rem] overflow-y-scroll"> | ||
{pqProgresses.map((progress, idx) => ( | ||
<StackedProgress | ||
key={`activity-progress-pq-${idx}`} | ||
progress={progress} | ||
participants={participants} | ||
colors={chartColors} | ||
/> | ||
))} | ||
</div> | ||
</div> | ||
)} | ||
{mlProgresses.length > 0 && ( | ||
<div> | ||
<H4>{t('shared.generic.microlearnings')}</H4> | ||
<div className="max-h-[13rem] overflow-y-scroll"> | ||
{mlProgresses.map((progress, idx) => ( | ||
<StackedProgress | ||
key={`activity-progress-ml-${idx}`} | ||
progress={progress} | ||
participants={participants} | ||
colors={chartColors} | ||
/> | ||
))} | ||
</div> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
export default ActivityProgressPlot |
16 changes: 16 additions & 0 deletions
16
apps/frontend-manage/src/components/analytics/performance/PerformanceAnalyticsNavigation.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import ActivityDashboardLabel from '../overview/ActivityDashboardLabel' | ||
import AnalyticsNavigation from '../overview/AnalyticsNavigation' | ||
import QuizDashboardLabel from '../overview/QuizDashboardLabel' | ||
|
||
function PerformanceAnalyticsNavigation({ courseId }: { courseId: string }) { | ||
return ( | ||
<AnalyticsNavigation | ||
hrefLeft={`/analytics/${courseId}/activity`} | ||
labelLeft={<ActivityDashboardLabel />} | ||
hrefRight={`/analytics/${courseId}/quizzes`} | ||
labelRight={<QuizDashboardLabel />} | ||
/> | ||
) | ||
} | ||
|
||
export default PerformanceAnalyticsNavigation |
87 changes: 87 additions & 0 deletions
87
apps/frontend-manage/src/components/analytics/performance/StackedProgress.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { ActivityProgress } from '@klicker-uzh/graphql/dist/ops' | ||
import { useTranslations } from 'next-intl' | ||
import { | ||
Bar, | ||
BarChart, | ||
ResponsiveContainer, | ||
Tooltip, | ||
XAxis, | ||
YAxis, | ||
} from 'recharts' | ||
|
||
function StackedProgress({ | ||
progress, | ||
participants, | ||
colors, | ||
}: { | ||
progress: ActivityProgress | ||
participants: number | ||
colors: { | ||
started: string | ||
completed: string | ||
repeated: string | ||
} | ||
}) { | ||
const t = useTranslations() | ||
const repeatedSet = | ||
progress.repeatedCount !== null && | ||
typeof progress.repeatedCount !== 'undefined' | ||
const repeatedPercent = repeatedSet | ||
? (progress.repeatedCount! / participants) * 100 | ||
: 0 | ||
const completedPercent = (progress.completedCount / participants) * 100 | ||
const startedPercent = (progress.startedCount / participants) * 100 | ||
|
||
const data = [ | ||
{ | ||
repeated: repeatedPercent, | ||
completed: completedPercent - repeatedPercent, | ||
started: startedPercent - completedPercent, | ||
full: 100 - startedPercent, | ||
}, | ||
] | ||
|
||
return ( | ||
<div className="flex h-8 items-center gap-4"> | ||
<div className="w-48 overflow-hidden overflow-ellipsis whitespace-nowrap"> | ||
{progress.activityName} | ||
</div> | ||
<div className="flex-1"> | ||
<ResponsiveContainer width="100%" height={35}> | ||
<BarChart data={data} layout="vertical"> | ||
<XAxis type="number" domain={[0, 100]} hide /> | ||
<YAxis type="category" hide /> | ||
<Bar dataKey="repeated" stackId="a" fill={colors.repeated} /> | ||
<Bar dataKey="completed" stackId="a" fill={colors.completed} /> | ||
<Bar dataKey="started" stackId="a" fill={colors.started} /> | ||
<Bar dataKey="full" stackId="a" fill="#f0f0f0" /> | ||
<Tooltip | ||
wrapperStyle={{ zIndex: 20 }} | ||
content={({ payload }) => { | ||
if (!payload?.length) return null | ||
|
||
return ( | ||
<div className="flex flex-col rounded border bg-white p-2 shadow-md"> | ||
<div | ||
style={{ color: colors.started }} | ||
>{`${t('manage.analytics.started')}: ${startedPercent.toFixed(1)} %`}</div> | ||
<div | ||
style={{ color: colors.completed }} | ||
>{`${t('manage.analytics.completed')}: ${completedPercent.toFixed(1)} %`}</div> | ||
{repeatedSet ? ( | ||
<div | ||
style={{ color: colors.repeated }} | ||
>{`${t('manage.analytics.repeated')}: ${repeatedPercent.toFixed(1)} %`}</div> | ||
) : null} | ||
</div> | ||
) | ||
}} | ||
/> | ||
</BarChart> | ||
</ResponsiveContainer> | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
export default StackedProgress |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.