Skip to content

Commit

Permalink
Merge pull request #762 from rage/progress-update-fix
Browse files Browse the repository at this point in the history
Progress update fix
  • Loading branch information
nygrenh authored May 3, 2021
2 parents 9576e75 + 9f86f33 commit 9c4a290
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 220 deletions.
61 changes: 18 additions & 43 deletions packages/moocfi-quizzes/src/CourseStatusProvider/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as React from "react"
import { useEffect, useRef, useState } from "react"
import React, { useContext, useEffect, useRef, useState } from "react"
import {
CourseProgressProviderInterface,
ProgressData,
Expand All @@ -9,9 +8,8 @@ import {
ProgressResponse,
ExerciseCompletionsBySection,
CourseResponse,
CourseProgressProvider,
useCourseProgressState,
} from "../contexes/courseProgressProviderContext"
import { CourseProgressProviderContext } from "../contexes/courseProgressProviderContext"
import { PointsByGroup } from "../modelTypes"
import { languageOptions } from "../utils/languages"
import { ToastContainer, toast, TypeOptions } from "react-toastify"
Expand Down Expand Up @@ -69,7 +67,6 @@ export const CourseStatusProvider: React.FunctionComponent<CourseStatusProviderP
const fetchProgressData = async () => {
try {
const progressData = await getUserCourseData(courseId, accessToken)

const data = transformData(progressData.currentUser, progressData.course)
setData(data)
setLoading(false)
Expand All @@ -85,6 +82,12 @@ export const CourseStatusProvider: React.FunctionComponent<CourseStatusProviderP
}
}

const progress: CourseProgressProviderInterface = {
error,
loading,
courseProgressData: data,
}

const logout = () => {
setLoading(true)
setError(false)
Expand All @@ -107,21 +110,15 @@ export const CourseStatusProvider: React.FunctionComponent<CourseStatusProviderP
setUpdateQuiz({ ...updateQuiz, [id]: false })
}

const progress: CourseProgressProviderInterface = {
error,
loading,
courseProgressData: data,
courseId,
accessToken,
}

const status: CourseStatusProviderInterface = {
updateQuiz,
quizUpdated,
}

return (
<CourseProgressProvider courseProgress={progress}>
<CourseProgressProviderContext.Provider
value={{ progress, fetchProgressData }}
>
<CourseStatusProviderContext.Provider value={status}>
<ToastContainer
enableMultiContainer
Expand All @@ -140,7 +137,7 @@ export const CourseStatusProvider: React.FunctionComponent<CourseStatusProviderP
/>
{children}
</CourseStatusProviderContext.Provider>
</CourseProgressProvider>
</CourseProgressProviderContext.Provider>
)
}

Expand All @@ -150,34 +147,18 @@ export const injectCourseProgress = <P extends CourseProgressProviderInterface>(
props: P,
) => {
// initial course progress
const { state } = useCourseProgressState()
// course progress with updates
const { courseId, accessToken, ...rest } = state
const [injectProps, setInjectProps] = useState(rest)
const { progress: injectProps, fetchProgressData } = useContext(
CourseProgressProviderContext,
)

// Ref for the wrapped element
const ref: any = useRef<HTMLElement>()
const rootMargin = "0px"
const outOfViewThreshold = 10

const refetchData = async () => {
if (courseId && accessToken) {
// fetch data
setInjectProps({ ...injectProps, loading: true })
const progressData = await getUserCourseData(courseId, accessToken)
const data = transformData(progressData.currentUser, progressData.course)
setInjectProps({
...injectProps,
courseProgressData: data,
loading: false,
})
}
}
const outOfViewThreshold = 4

/**
* Triggers a refetch of progress after given time interval
* */

useEffect(() => {
const observer = new IntersectionObserver(
async ([entry]) => {
Expand All @@ -193,7 +174,7 @@ export const injectCourseProgress = <P extends CourseProgressProviderInterface>(
1000

if (secondsOutOfView >= outOfViewThreshold) {
await refetchData()
await fetchProgressData()
}

// reset off view counter
Expand All @@ -220,13 +201,7 @@ export const injectCourseProgress = <P extends CourseProgressProviderInterface>(
}
}, [])

const isLoggedInAndLoading = accessToken && state.loading

return (
<div ref={ref}>
{!isLoggedInAndLoading && <Component {...props} {...injectProps} />}
</div>
)
return <div ref={ref}>{<Component {...props} {...injectProps} />}</div>
}

const transformData = (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, { createContext, useContext, useReducer } from "react"

import { ProviderBaseInterface } from "./courseStatusProviderContext"
import { PointsByGroup } from "../modelTypes"

export interface ProgressResponse {
user_course_progressess: UserCourseProgress
completions: Completion[]
}

export interface CourseResponse {
exercises: Omit<Exercise, "exercise_completions">[]
}

export interface UserCourseProgress {
max_points: number
n_points: number
progress: PointsByGroup[]
course: Course
}

export interface Completion {
id: string
}

export interface Course {
points_needed: number
exercises: Exercise[]
}

export type Exercise = {
id: string
quizzes_id: string
name: string
part: number
section: number
max_points: number
exercise_completions: ExerciseCompletion[]
}

export type ExerciseCompletion = {
exercise_id: string
exercise_quizzes_id: string
part: number
section: number
n_points: number
completed: boolean
exercise_completion_required_actions: RequiredActionObject[]
}

export interface ExerciseCompletionsBySection {
part: number
section: number
exercises_total: number
exercises_completed: number
required_actions: RequiredAction[]
}

export interface RequiredActionObject {
value: RequiredAction
}

export enum RequiredAction {
REJECTED = "REJECTED",
GIVE_PEER_REVIEW = "GIVE_PEER_REVIEW",
PENDING_PEER_REVIEW = "PENDING_PEER_REVIEW",
}

export interface ProgressData {
completed: boolean
points_to_pass: number
n_points: number
max_points: number
exercise_completions: number
total_exercises: number
required_actions: RequiredAction[]
progress: PointsByGroup[]
exercises: Exercise[]
answers: ExerciseCompletion[]
exercise_completions_by_section: ExerciseCompletionsBySection[]
}

export interface CourseProgressProviderInterface extends ProviderBaseInterface {
error?: boolean
loading?: boolean
courseProgressData?: ProgressData
courseId?: string
accessToken?: string
}

interface CourseProgressProviderContextInterface {
progress: CourseProgressProviderInterface
fetchProgressData: () => Promise<void>
}

export const CourseProgressProviderContext = createContext<
CourseProgressProviderContextInterface
>({ progress: {}, fetchProgressData: () => Promise.resolve() })
Loading

0 comments on commit 9c4a290

Please sign in to comment.