Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quantum-kittens
GitHub Repository: quantum-kittens/platypus
Path: blob/main/frontend/ts/storage.ts
3855 views
1
import { mergeJson } from './utilities'
2
3
const STORAGE_KEY = 'qiskit/textbook/course'
4
5
interface ProgressData {
6
progressData: {[x: string]: any}
7
}
8
9
declare global {
10
interface Window extends ProgressData {}
11
}
12
13
const getUserData = function (): {[x: string]: any} {
14
let userData = {}
15
try {
16
const userDataString = window.localStorage.getItem(STORAGE_KEY)
17
userData = userDataString ? JSON.parse(userDataString) : {}
18
} catch (e) {
19
console.error(e)
20
}
21
22
const userDataFromMathigon = JSON.parse(document.getElementById('userdata')?.textContent || '{}')
23
24
return {
25
...userData,
26
...userDataFromMathigon
27
}
28
}
29
30
const storeUserData = function (data: {[x: string]: any}): boolean {
31
try {
32
const userData = getUserData()
33
let updatedUserData = mergeJson(userData, data)
34
const userDataString = JSON.stringify(updatedUserData)
35
window.localStorage.setItem(STORAGE_KEY, userDataString)
36
return true
37
} catch (e) {
38
console.error(e)
39
return false
40
}
41
}
42
43
const saveProgressData = function (course: XCourse, progressData: SectionProgress) {
44
const savedProgressData = getUserData()?.[course.id]?.[course.section] || {}
45
const updatedProgressData = mergeJson(savedProgressData, progressData)
46
47
let scores = 0
48
const steps = updatedProgressData?.steps || {}
49
for (let s in steps) {
50
scores += steps[s].scores.length
51
}
52
const progress = (scores * 100) / (course.goals || 0)
53
if (!isNaN(progress)) {
54
updatedProgressData.progress = parseFloat(progress.toFixed(2))
55
updatedProgressData.completed = progress > 99
56
57
storeUserData({
58
[course.id]: {
59
[course.section]: updatedProgressData
60
}
61
})
62
}
63
}
64
65
const getProgressData = function () {
66
let pathname = window.location.pathname
67
pathname = pathname.startsWith('/') ? pathname.substring(1) : pathname
68
const paths = pathname.split('/')
69
let savedProgressData = {}
70
71
if (paths.length === 3 && paths[0] === 'course') {
72
const courseId = paths[1]
73
const sectionId = paths[2]
74
savedProgressData = getUserData()?.[courseId]?.[sectionId] || savedProgressData
75
}
76
77
return savedProgressData
78
}
79
80
const renderProgessData = function (courseId: string) {
81
const courseSectionsData = getUserData()?.[courseId] || {}
82
for (let sectionId in courseSectionsData) {
83
const sectionProgressIndicator = document.querySelector(`[data-section-id="${sectionId}"] x-progress`)
84
if (sectionProgressIndicator) {
85
sectionProgressIndicator.setAttribute('p', `${(courseSectionsData[sectionId]?.progress || 0) / 100}`)
86
}
87
}
88
}
89
90
const storeProgressLocally = function (course: XCourse) {
91
console.debug(`storing progress in localStorage for ${course.id}/${course.section}`)
92
93
renderProgessData(course.id)
94
95
const _origfetch = window.fetch
96
window.fetch = async (url: RequestInfo, options) => {
97
if (typeof(url) === 'string' && url.startsWith(`/course/${course.id}/${course.section}`)) {
98
if (options?.method === 'POST' && typeof(options.body) === 'string') {
99
try {
100
let formData = decodeURIComponent(options.body)
101
if (formData.startsWith('data=')) {
102
// strip the 'data=' prefix to get to the formData (i.e., progress info) being submitted
103
formData = formData.substring(5)
104
}
105
106
const progress = JSON.parse(formData) as SectionProgress
107
saveProgressData(course, progress)
108
} catch (e) {
109
console.error('Failed to process fetch options:', e)
110
}
111
}
112
}
113
114
return await _origfetch(url, options)
115
}
116
}
117
118
export {
119
getProgressData,
120
storeProgressLocally,
121
getUserData,
122
storeUserData
123
}
124
125