diff options
| author | Max Nanis | 2025-06-04 05:35:57 +0700 |
|---|---|---|
| committer | Max Nanis | 2025-06-04 05:35:57 +0700 |
| commit | 4bf1b3f5bc9564070dba1481e380179431ddf62b (patch) | |
| tree | ac5d996ed31b27f5195f4a8268055d183f316405 /src/models | |
| parent | 6aa972cff98dc1fea53ee0710f77ca460479eb94 (diff) | |
| download | panel-ui-4bf1b3f5bc9564070dba1481e380179431ddf62b.tar.gz panel-ui-4bf1b3f5bc9564070dba1481e380179431ddf62b.zip | |
Saving answers to server. Updating views based on reducer states (pagination disable after question is answered).
Diffstat (limited to 'src/models')
| -rw-r--r-- | src/models/answerSlice.ts | 118 |
1 files changed, 40 insertions, 78 deletions
diff --git a/src/models/answerSlice.ts b/src/models/answerSlice.ts index f271288..e0f9931 100644 --- a/src/models/answerSlice.ts +++ b/src/models/answerSlice.ts @@ -4,7 +4,7 @@ import {createSelector, createSlice, PayloadAction} from '@reduxjs/toolkit' import {RootState} from '@/store'; // your root state type import {PatternValidation, UpkQuestion} from "@/api"; -interface Answer { +export interface Answer { values: string[]; error_msg: string; @@ -23,8 +23,17 @@ const answerSlice = createSlice({ name: 'answers', initialState, reducers: { - addAnswer(state, action: PayloadAction<{ question: UpkQuestion, val: string }>) { + /* If the question is MC, validate: + - validate selector SA vs MA (1 selected vs >1 selected) + - the answers match actual codes in the choices + - validate configuration.max_select + - validate choices.exclusive + + If the question is TE, validate that: + - configuration.max_length + - validation.patterns + */ let question: UpkQuestion = action.payload.question; let val: string = action.payload.val.trim(); let answer: Answer = state[question.question_id] ?? { @@ -34,17 +43,7 @@ const answerSlice = createSlice({ processing: false } as Answer; - /* - If the question is MC, validate: - - validate selector SA vs MA (1 selected vs >1 selected) - - the answers match actual codes in the choices - - validate configuration.max_select - - validate choices.exclusive - - If the question is TE, validate that: - - configuration.max_length - - validation.patterns - */ + answer.error_msg = "" // Reset any error messages switch (question.question_type) { case "TE": @@ -78,26 +77,22 @@ const answerSlice = createSlice({ } }) - answer.error_msg = "" break; case "MC": - switch (question.selector) { - case "SA": // Single Answer + if (answer.values.includes(val)) { + // The item has already been selected + answer.values = answer.values.filter(value => value !== val); + + } else { + // It's a new selection + if (question.selector == "SA") { answer.values = [val] - break - case "MA": /// Multi Answer - if (answer.values.includes(val)) { - // The item has already been selected - answer.values = answer.values.filter(value => value !== val); - } else { - // It's a new selection - answer.values.push(val); - } - break + } else if (question.selector == "MA") { + answer.values.push(val); + } } - if (answer.values.length == 0) { answer.error_msg = "MC question with no selected answers" } @@ -145,62 +140,29 @@ const answerSlice = createSlice({ state[question.question_id] = answer }, - // removeAnswer(val: string): null { - // switch (this.getType()) { - // // You can only remove a value from a MultiChoice - // case "MC": - // // TODO: implement this - // // let current_values: string[] = this._answer?.values - // // current_values.push(val) - // // this._answer = new ProfilingAnswer(this.questionId, current_values); - // break - // default: - // throw new Error("Incorrect Question Type provided"); - // } - // this.validate() - // } - - // save() { - // let question: ProfilingQuestion = this; - // // @ts-ignore - // let answer: ProfilingAnswer = question._answer; - // - // if (this._complete || this._processing) { - // return - // } - // this._processing = true - // - // let res = JSON.stringify({ - // "answers": [{ - // "question_id": answer.get('question_id'), - // "answer": map(answer.get("values"), "value") - // }] - // }); - // - // $.ajax({ - // url: ["https://fsb.generalresearch.com", questions.BPID, "profiling-questions", ""].join("/") + "?" + stringify({"bpuid": questions.BPUID}), - // xhrFields: {withCredentials: false}, - // processData: false, - // type: "POST", - // contentType: "application/json; charset=utf-8", - // data: res, - // success: function (data) { - // channel.trigger("ProfilingQuestions:start"); - // }, - // error: function (data) { - // channel.trigger("ProfilingQuestions:start"); - // Sentry.captureMessage("Profiling Question submission failed."); - // } - // }); - // } - - + saveAnswer(state, action: PayloadAction<{ question: UpkQuestion }>) { + let question: UpkQuestion = action.payload.question; + let answer: Answer = state[question.question_id] + + state[question.question_id] = { + 'values': answer.values, + 'error_msg': "", + 'processing': false, + 'complete': false + } as Answer + } } }) -export const {addAnswer, setAnswer, setQuestions, questionAdded, questionUpdated} = answerSlice.actions; +export const {addAnswer, saveAnswer} = answerSlice.actions; export default answerSlice.reducer +export const answerForQuestion = (state: RootState, question: UpkQuestion) => state.answers[question.question_id] ?? { + values: [], + error_msg: "", + complete: false, + processing: false +} as Answer; export const makeSelectChoicesByQuestion = (question: UpkQuestion) => createSelector( |
