Skip to content

Commit

Permalink
refactor: improve component structure and extract data aggregation fu…
Browse files Browse the repository at this point in the history
…nctionality to custom hooks
  • Loading branch information
sjschlapbach committed Dec 23, 2024
1 parent 4adb5ca commit 6b23edb
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Course } from '@klicker-uzh/graphql/dist/ops'
import { H3 } from '@uzh-bf/design-system'
import { useTranslations } from 'next-intl'
import PreviewTag from '~/components/common/PreviewTag'
import PreviewTag from '../../common/PreviewTag'
import AnalyticsCourseLabel from './AnalyticsCourseLabel'
import DashboardButtons from './DashboardButtons'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import Loader from '@klicker-uzh/shared-components/src/Loader'
import TableSortingButton from '@klicker-uzh/shared-components/src/TableSortingButton'
import { Button, Checkbox, H2, UserNotification } from '@uzh-bf/design-system'
import { useTranslations } from 'next-intl'
import { useMemo, useState } from 'react'
import { useState } from 'react'
import useActivityMap from './useActivityMap'
import useStudentActivityPerformanceTableData from './useStudentActivityPerformanceTableData'

function StudentActivityPerformance({
courseId,
Expand All @@ -37,57 +39,16 @@ function StudentActivityPerformance({
})
}

// TODO: extract the following functions to custom hooks
const activityNameMap = useMemo(
() => ({
...(course?.practiceQuizzes?.reduce<Record<string, string>>((acc, pq) => {
acc[pq.id] = pq.name
return acc
}, {}) ?? {}),
...(course?.microLearnings?.reduce<Record<string, string>>((acc, ml) => {
acc[ml.id] = ml.name
return acc
}, {}) ?? {}),
}),
[course?.practiceQuizzes, course?.microLearnings]
)

const allActivityIds = useMemo(
() => [
...(course?.practiceQuizzes?.map((quiz) => quiz.id) ?? []),
...(course?.microLearnings?.map((ml) => ml.id) ?? []),
],
[course?.practiceQuizzes, course?.microLearnings]
)

const tableData = useMemo(() => {
if (loading || !course) {
return []
}

// map the performances to a data structure where every selected activity entry can be
// identified through a direct key - {activityId}-totalScore and {activityId}-completion
return performances.map((studentPerformance) =>
studentPerformance.performances.reduce<Record<string, string | number>>(
(acc, performance) => {
if (selectedActivities.includes(performance.activityId)) {
acc[`${performance.activityId}-totalScore`] = performance.totalScore
acc[`${performance.activityId}-completion`] = Math.round(
performance.completion * 100
)
}
const { activityNameMap, allActivityIds } = useActivityMap({
practiceQuizzes: course?.practiceQuizzes,
microLearnings: course?.microLearnings,
})

return acc
},
{
participantUsername: studentPerformance.participantUsername,
participantEmail:
studentPerformance.participantEmail ??
t('manage.analytics.emailMissing'),
}
)
)
}, [loading, course, performances, t, selectedActivities])
const tableData = useStudentActivityPerformanceTableData({
dataAvailable: !loading && !!course,
performances,
selectedActivities,
})

if (loading || !tableData) {
return <Loader />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { MicroLearning, PracticeQuiz } from '@klicker-uzh/graphql/dist/ops'
import { useMemo } from 'react'

function useActivityMap({
practiceQuizzes,
microLearnings,
}: {
practiceQuizzes?: Pick<PracticeQuiz, 'id' | 'name'>[] | null
microLearnings?: Pick<MicroLearning, 'id' | 'name'>[] | null
}) {
const activityNameMap = useMemo(
() => ({
...(practiceQuizzes?.reduce<Record<string, string>>((acc, pq) => {
acc[pq.id] = pq.name
return acc
}, {}) ?? {}),
...(microLearnings?.reduce<Record<string, string>>((acc, ml) => {
acc[ml.id] = ml.name
return acc
}, {}) ?? {}),
}),
[practiceQuizzes, microLearnings]
)

const allActivityIds = useMemo(
() => [
...(practiceQuizzes?.map((quiz) => quiz.id) ?? []),
...(microLearnings?.map((ml) => ml.id) ?? []),
],
[practiceQuizzes, microLearnings]
)

return { activityNameMap, allActivityIds }
}

export default useActivityMap
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { ParticipantActivityPerformances } from '@klicker-uzh/graphql/dist/ops'
import { useTranslations } from 'next-intl'
import { useMemo } from 'react'

function useStudentActivityPerformanceTableData({
dataAvailable,
performances,
selectedActivities,
}: {
dataAvailable: boolean
performances: ParticipantActivityPerformances[]
selectedActivities: string[]
}) {
const t = useTranslations()

return useMemo(() => {
if (!dataAvailable) {
return []
}

// map the performances to a data structure where every selected activity entry can be
// identified through a direct key - {activityId}-totalScore and {activityId}-completion
return performances.map((studentPerformance) =>
studentPerformance.performances.reduce<Record<string, string | number>>(
(acc, performance) => {
if (selectedActivities.includes(performance.activityId)) {
acc[`${performance.activityId}-totalScore`] = performance.totalScore
acc[`${performance.activityId}-completion`] = Math.round(
performance.completion * 100
)
}

return acc
},
{
participantUsername: studentPerformance.participantUsername,
participantEmail:
studentPerformance.participantEmail ??
t('manage.analytics.emailMissing'),
}
)
)
}, [dataAvailable, performances, t, selectedActivities])
}

export default useStudentActivityPerformanceTableData
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { H1 } from '@uzh-bf/design-system'
import { GetStaticPropsContext } from 'next'
import { useTranslations } from 'next-intl'
import { useRouter } from 'next/router'
import PreviewTag from '~/components/common/PreviewTag'
import ActivityAnalyticsNavigation from '../../../components/analytics/activity/ActivityAnalyticsNavigation'
import DailyActivityPlot from '../../../components/analytics/activity/DailyActivityPlot'
import DailyActivityTimeSeries from '../../../components/analytics/activity/DailyActivityTimeSeries'
import TotalStudentActivityPlot from '../../../components/analytics/activity/TotalStudentActivityPlot'
import WeeklyActivityTimeSeries from '../../../components/analytics/activity/WeeklyActivityTimeSeries'
import AnalyticsErrorView from '../../../components/analytics/AnalyticsErrorView'
import AnalyticsLoadingView from '../../../components/analytics/AnalyticsLoadingView'
import PreviewTag from '../../../components/common/PreviewTag'
import Layout from '../../../components/Layout'

function ActivityDashboard() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { useTranslations } from 'next-intl'
import { useRouter } from 'next/router'
import { useState } from 'react'
import { twMerge } from 'tailwind-merge'
import PreviewTag from '~/components/common/PreviewTag'
import AnalyticsErrorView from '../../../components/analytics/AnalyticsErrorView'
import AnalyticsLoadingView from '../../../components/analytics/AnalyticsLoadingView'
import ActivityInstanceFeedbacksPlot from '../../../components/analytics/performance/ActivityInstanceFeedbacksPlot'
Expand All @@ -15,6 +14,7 @@ import PerformanceAnalyticsNavigation from '../../../components/analytics/perfor
import PerformanceRates from '../../../components/analytics/performance/PerformanceRates'
import StudentActivityPerformance from '../../../components/analytics/performance/StudentActivityPerformance'
import TotalStudentPerformancePlot from '../../../components/analytics/performance/TotalStudentPerformancePlot'
import PreviewTag from '../../../components/common/PreviewTag'
import Layout from '../../../components/Layout'

function PerformanceDashboard() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import { Button, H1 } from '@uzh-bf/design-system'
import { GetStaticPropsContext } from 'next'
import { useTranslations } from 'next-intl'
import { useRouter } from 'next/router'
import ActivityAnalyticsCharts from '~/components/analytics/quiz/ActivityAnalyticsCharts'
import InstanceQuizAnalytics from '~/components/analytics/quiz/InstanceQuizAnalytics'
import QuizAnalyticsNavigation from '~/components/analytics/quiz/QuizAnalyticsNavigation'
import PreviewTag from '~/components/common/PreviewTag'
import Layout from '~/components/Layout'
import AnalyticsErrorView from '../../../../components/analytics/AnalyticsErrorView'
import AnalyticsLoadingView from '../../../../components/analytics/AnalyticsLoadingView'
import ActivityAnalyticsCharts from '../../../../components/analytics/quiz/ActivityAnalyticsCharts'
import InstanceQuizAnalytics from '../../../../components/analytics/quiz/InstanceQuizAnalytics'
import QuizAnalyticsNavigation from '../../../../components/analytics/quiz/QuizAnalyticsNavigation'
import PreviewTag from '../../../../components/common/PreviewTag'
import Layout from '../../../../components/Layout'

function QuizAnalytics() {
const router = useRouter()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ import { useTranslations } from 'next-intl'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useMemo, useState } from 'react'
import PreviewTag from '~/components/common/PreviewTag'
import AnalyticsErrorView from '../../../../components/analytics/AnalyticsErrorView'
import AnalyticsLoadingView from '../../../../components/analytics/AnalyticsLoadingView'
import QuizSelectionNavigation from '../../../../components/analytics/quiz/QuizSelectionNavigation'
import PreviewTag from '../../../../components/common/PreviewTag'
import Layout from '../../../../components/Layout'

const ActivityLink = ({
Expand Down

0 comments on commit 6b23edb

Please sign in to comment.