aboutsummaryrefslogtreecommitdiff
path: root/src/models/questionSlice.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/models/questionSlice.ts')
-rw-r--r--src/models/questionSlice.ts58
1 files changed, 44 insertions, 14 deletions
diff --git a/src/models/questionSlice.ts b/src/models/questionSlice.ts
index ec9f84a..9543088 100644
--- a/src/models/questionSlice.ts
+++ b/src/models/questionSlice.ts
@@ -2,6 +2,8 @@ import {createSelector, createSlice, PayloadAction} from '@reduxjs/toolkit'
import type {RootState} from '@/store'
import {UpkQuestion} from "@/api";
import {Answer} from "@/models/answerSlice.ts";
+import {assert} from "@/lib/utils.ts"
+import {Selector} from "react-redux";
export interface ProfileQuestion extends UpkQuestion {
active: false
@@ -59,11 +61,18 @@ export const selectQuestions = (state: RootState) => state.questions
export const selectActiveQuestion = (state: RootState) => state.questions.find(i => i.active)
export const selectAnswers = (state: RootState) => state.answers
-export const selectNextAvailableQuestion = createSelector(
+export const selectFirstAvailableQuestion = createSelector(
[selectQuestions, selectAnswers],
- (questions, answers) => {
+ (questions, answers): Selector<RootState, ProfileQuestion | null> => {
+ /* This is used when the app loads up the Questions page and we
+ need to find the first Question that we'll present to
+ the Respondent.
+
+ If there are any questions marked as active, show that
+ first. However, if there are not.. go ahead and search for
+ the next Question without an Answer or an Answer that isn't complete
+ */
- // -- Check if there are any questions marked as active
const active = questions.find(q => q.active)
if (active) {
return active
@@ -71,23 +80,44 @@ export const selectNextAvailableQuestion = createSelector(
let res = questions.filter(q => {
const a: Answer | undefined = answers[q.question_id]
- return !a || a.complete === false
+ return !a || !a.complete
})
- // return res.reduce((min, q) =>
- // !min || q.order < min.order ? q : min,
- // null as typeof res[0] | null
- // )
return res[0] || null
}
)
+export const selectNextAvailableQuestion = createSelector(
+ [selectQuestions, selectAnswers],
+ (questions, answers): Selector<RootState, ProfileQuestion | null> => {
+ /* This takes the current active position and finds the next available
+ question to answer.
-export const selectQuestionById = (questionId: string) =>
- createSelector(
- (state: RootState) => state.questions,
- (questions) => {
- return questions.find(q => q.question_id === questionId);
+ Check if there are any questions marked as active. If there are not,
+ the Questions page didn't load yet and/or we don't know what the Respondent
+ is currently looking at... so we can't determine what is next. Immediately fail.
+ */
+ const active = questions.find(q => q.active)
+ assert(active, "Must have an active Question")
+ const active_index = questions.findIndex(q => q.question_id === active.question_id)
+
+ // Find any Questions without Answers, or Answers that are not complete
+ // that are positioned after the currently active Question
+ let found = questions.find((q, q_idx) => {
+ const a: Answer | undefined = answers[q.question_id]
+ return q_idx > active_index && (!a || !a.complete)
+ })
+
+ if (!found) {
+ // No eligible questions were found after the current active position, so
+ // go back and look for any before the current active position.
+ found = questions.find((q, q_idx) => {
+ const a: Answer | undefined = answers[q.question_id]
+ return q_idx < active_index && (!a || !a.complete)
+ })
}
- ); \ No newline at end of file
+
+ return found || null
+ }
+)