diff options
| author | Max Nanis | 2025-06-06 16:32:17 +0700 |
|---|---|---|
| committer | Max Nanis | 2025-06-06 16:32:17 +0700 |
| commit | 696dee6a6a9506fcf771d0ec4911dcc82a279fda (patch) | |
| tree | 3e8d0bde7cded0f3e1fba82e3af1f2253c06bcbf /src/models/questionSlice.ts | |
| parent | 2f675eecec576b1ab17260e2513e1eec187a81d2 (diff) | |
| download | panel-ui-696dee6a6a9506fcf771d0ec4911dcc82a279fda.tar.gz panel-ui-696dee6a6a9506fcf771d0ec4911dcc82a279fda.zip | |
Lots of reducer work to organize active Question in redux state (rather than useState). Various UX/CSS checks for Pagination state.
Diffstat (limited to 'src/models/questionSlice.ts')
| -rw-r--r-- | src/models/questionSlice.ts | 72 |
1 files changed, 67 insertions, 5 deletions
diff --git a/src/models/questionSlice.ts b/src/models/questionSlice.ts index 814caf9..ec9f84a 100644 --- a/src/models/questionSlice.ts +++ b/src/models/questionSlice.ts @@ -1,26 +1,88 @@ import {createSelector, createSlice, PayloadAction} from '@reduxjs/toolkit' import type {RootState} from '@/store' import {UpkQuestion} from "@/api"; +import {Answer} from "@/models/answerSlice.ts"; -const initialState: UpkQuestion[] = [] +export interface ProfileQuestion extends UpkQuestion { + active: false +} + +const initialState: ProfileQuestion[] = [] const questionSlice = createSlice({ name: 'questions', initialState, reducers: { - setQuestions(state, action: PayloadAction<UpkQuestion[]>) { + setQuestions(state, action: PayloadAction<ProfileQuestion[]>) { return action.payload; }, - questionAdded(state, action: PayloadAction<UpkQuestion>) { + questionAdded(state, action: PayloadAction<ProfileQuestion>) { state.push(action.payload); }, + setNextQuestion(state) { + const item = state.find((i) => i.active) + + const index = state.findIndex(q => q.question_id === item.question_id) + const nextQuestion = index !== -1 ? state[index + 1] ?? null : null + + state.forEach((q) => { + q.active = q.question_id === nextQuestion.question_id + }) + + }, + setQuestionActive(state, action: PayloadAction<ProfileQuestion>) { + state.forEach((q) => { + q.active = q.question_id === action.payload.question_id + }) + }, + updateQuestion(state, action: PayloadAction<{ question_id: string, updates: Partial<ProfileQuestion> }>) { + const item = state.find((i) => i.question_id === action.payload.question_id) + if (item) { + Object.assign(item, action.payload.updates) + } + } } }) -export const {setAnswer, setQuestions, questionAdded, questionUpdated} = questionSlice.actions; +export const { + setQuestions, + setQuestionActive, + setNextQuestion, + questionAdded, + updateQuestion +} = questionSlice.actions; export default questionSlice.reducer -// export const selectAllQuestions = (state: RootState) => state.questions +// We need to fetch the next available Question that either doesn't have an Answer, or the Answer +// isn't Answer.completed +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( + [selectQuestions, selectAnswers], + (questions, answers) => { + + // -- Check if there are any questions marked as active + const active = questions.find(q => q.active) + if (active) { + return active + } + + let res = questions.filter(q => { + const a: Answer | undefined = answers[q.question_id] + return !a || a.complete === false + }) + + // return res.reduce((min, q) => + // !min || q.order < min.order ? q : min, + // null as typeof res[0] | null + // ) + + return res[0] || null + } +) + export const selectQuestionById = (questionId: string) => createSelector( |
