@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
207 lines (169 loc) • 5.76 kB
JavaScript
import React, {createContext, useContext} from 'react'
import update from 'immutability-helper'
import findIndex from 'lodash/findIndex'
import omit from 'lodash/omit'
import without from 'lodash/without'
const CategorizationPresenterContext = createContext(null)
function CategorizationPresenterProvider({
interactionData,
scoringData,
changeItemState,
newId,
children,
}) {
// =============
// HELPERS
// =============
function getCategoryOrder() {
// This is to protect against quizzes which were
// created before categoryOrder was introduced
return interactionData.categoryOrder || Object.keys(interactionData.categories)
}
function updateInteractionData(updates) {
changeItemState({
interactionData: Object.assign({}, interactionData || {}, updates),
})
}
// ===========
// ACTIONS - CATEGORIES
// ===========
function onCategoryInputChange(itemId, e) {
const categories = update(interactionData.categories, {
[itemId]: {itemBody: {$set: e.target.value}},
})
updateInteractionData({categories})
}
function onCreateCategory() {
const newItemId = newId()
const newItem = {id: newItemId, itemBody: ''}
const newCategories = update(interactionData.categories, {
[newItemId]: {$set: newItem},
})
const newCategoryOrder = update(getCategoryOrder(), {
$push: [newItemId],
})
const newCategoryScoringData = {
id: newItemId,
scoringAlgorithm: 'AllOrNothing',
scoringData: {
value: [],
},
}
const newInteractionData = update(interactionData, {
categories: {$set: newCategories},
categoryOrder: {$set: newCategoryOrder},
})
const newScoringData = update(scoringData, {
value: {
$push: [newCategoryScoringData],
},
})
changeItemState({interactionData: newInteractionData, scoringData: newScoringData})
}
function onRemoveCategory(categoryId) {
const newCategories = omit(interactionData.categories, categoryId)
const newCategoryOrder = getCategoryOrder().filter(c => c !== categoryId)
const newDistractors = omit(
interactionData.distractors,
scoringData.value.filter(item => item.id === categoryId)[0].scoringData.value,
)
const newScoringDataValue = scoringData.value.filter(item => item.id !== categoryId)
const newInteractionData = update(interactionData, {
categoryOrder: {$set: newCategoryOrder},
categories: {$set: newCategories},
distractors: {$set: newDistractors},
})
const newScoringData = update(scoringData, {
value: {
$set: newScoringDataValue,
},
})
changeItemState({interactionData: newInteractionData, scoringData: newScoringData})
}
// ===========
// ACTIONS - ANSWERS
// ===========
function onCreateAnswer(categoryId) {
const newItemId = newId()
const newItem = {id: newItemId, itemBody: ''}
const newDistractors = update(interactionData.distractors, {
[newItemId]: {$set: newItem},
})
const scoringDataCategoryIndex = findIndex(scoringData.value, item => item.id === categoryId)
const newInteractionData = update(interactionData, {
distractors: {$set: newDistractors},
})
const newScoringData = update(scoringData, {
value: {
[scoringDataCategoryIndex]: {
scoringData: {
value: {
// because kinesis does not save empty arrays well,
// we need to guard against this being null
$apply: answersList => (answersList || []).concat([newItemId]),
},
},
},
},
})
changeItemState({interactionData: newInteractionData, scoringData: newScoringData})
}
function onRemoveAnswer(itemId, categoryId) {
const newDistractors = omit(interactionData.distractors, itemId)
const scoringDataCategoryIndex = findIndex(scoringData.value, item => item.id === categoryId)
const scoringDataCategory = scoringData.value[scoringDataCategoryIndex]
const newCategScoringDataValues = without(scoringDataCategory.scoringData.value, itemId)
const newInteractionData = update(interactionData, {
distractors: {$set: newDistractors},
})
const newScoringData = update(scoringData, {
value: {
[scoringDataCategoryIndex]: {
scoringData: {
value: {$set: newCategScoringDataValues},
},
},
},
})
changeItemState({interactionData: newInteractionData, scoringData: newScoringData})
}
// ===========
// ACTIONS - DISTRACTORS
// ===========
function onDistractorInputChange(itemId, e) {
const distractors = update(interactionData.distractors, {
[itemId]: {itemBody: {$set: e.target.value}},
})
updateInteractionData({distractors})
}
function onRemoveDistractor(itemId) {
const newList = omit(interactionData.distractors, itemId)
const newInteractionData = update(interactionData, {
distractors: {$set: newList},
})
changeItemState({
interactionData: newInteractionData,
})
}
const value = {
getCategoryOrder,
updateInteractionData,
onCategoryInputChange,
onCreateCategory,
onRemoveCategory,
onCreateAnswer,
onRemoveAnswer,
onDistractorInputChange,
onRemoveDistractor,
}
return (
<CategorizationPresenterContext.Provider value={value}>
{children}
</CategorizationPresenterContext.Provider>
)
}
function useCategorizationPresenter() {
return useContext(CategorizationPresenterContext)
}
export {CategorizationPresenterContext, CategorizationPresenterProvider, useCategorizationPresenter}
export default CategorizationPresenterProvider