From 093924033b713497332893fc91787d88a5111554 Mon Sep 17 00:00:00 2001 From: Alireza khaji Date: Tue, 5 Jul 2022 16:55:26 +0430 Subject: [PATCH] create exam api | 400 --- src/redux/actions/exam.js | 22 +- src/redux/actions/examQuestion.js | 22 + src/redux/actions/index.js | 2 + src/redux/reducers/exam.js | 735 +++++++++--------- src/redux/reducers/exam2.js | 8 +- src/redux/reducers/examQuestion.js | 30 + src/redux/reducers/index.js | 2 + src/view/addExam/components/addQuestion.js | 226 ++++-- src/view/addExam/components/question.js | 89 ++- .../addExam/views/AddQuestionsFromBank.js | 225 ++++-- src/view/addExam/views/ViewExam.js | 12 +- .../addExam/views/addQuestionnaireExam.js | 40 +- 12 files changed, 876 insertions(+), 537 deletions(-) create mode 100644 src/redux/actions/examQuestion.js create mode 100644 src/redux/reducers/examQuestion.js diff --git a/src/redux/actions/exam.js b/src/redux/actions/exam.js index edd96fb..7ddc268 100644 --- a/src/redux/actions/exam.js +++ b/src/redux/actions/exam.js @@ -17,6 +17,10 @@ const exam = { (data = {}) => async (dispatch) => await proxy.post("exam/subexamAdd", data, { dispatch }), + confirm: + (data = {}) => + async (dispatch) => + await proxy.put("exam/confirm", data, { dispatch }), emptySubexamList: (data = {}) => { return (dispatch) => { dispatch({ @@ -36,7 +40,7 @@ const exam = { addExamGradeAndGroup: (data = {}) => { return (dispatch) => { dispatch({ - type: "ADD_EXAM_GRADE_AND_GROUP", + type: "ADD_EXAM_GRADE_AND_GROUP", payload: data, }); }; @@ -65,6 +69,14 @@ const exam = { }); }; }, + addExamQuestion2: (data = {}) => { + return (dispatch) => { + dispatch({ + type: "ADD_EXAM_QUESTIONS2", + payload: data, + }); + }; + }, removeQuestionFromBank: (data = {}) => { return (dispatch) => { dispatch({ @@ -97,6 +109,14 @@ const exam = { }); }; }, + addCustomQuestion: (data = {}) => { + return (dispatch) => { + dispatch({ + type: "ADD_CUSTOM_QUESTION", + payload: data, + }); + }; + }, }; export default exam; diff --git a/src/redux/actions/examQuestion.js b/src/redux/actions/examQuestion.js new file mode 100644 index 0000000..f010d63 --- /dev/null +++ b/src/redux/actions/examQuestion.js @@ -0,0 +1,22 @@ + +import proxy from "../proxy"; +const examQuestion = { + info: + (data = {}) => + async (dispatch) => + await proxy.get("examQuestion/info", data, { dispatch }), + list: + (data = {}) => + async (dispatch) => + await proxy.get("examQuestion/list", data, { dispatch }), + add: + (data = {}) => + async (dispatch) => + await proxy.post("examQuestion/add", data, { dispatch }), + delete: + (data = {}) => + async (dispatch) => + await proxy.delete("examQuestion/delete", data, { dispatch }), +}; + +export default examQuestion; \ No newline at end of file diff --git a/src/redux/actions/index.js b/src/redux/actions/index.js index 51f87a1..61923fb 100644 --- a/src/redux/actions/index.js +++ b/src/redux/actions/index.js @@ -18,6 +18,8 @@ export { default as examGroup } from "./examGroup"; export { default as lesson } from "./lesson"; export { default as question } from "./question"; export { default as category } from "./category"; +export { default as examQuestion } from "./examQuestion"; + diff --git a/src/redux/reducers/exam.js b/src/redux/reducers/exam.js index 125e62c..86207a9 100644 --- a/src/redux/reducers/exam.js +++ b/src/redux/reducers/exam.js @@ -1,363 +1,402 @@ -import { IoReturnUpBack } from "react-icons/io5" -import fizikpdf from '../../assets/fizik.pdf' -import samplePdf from '../../assets/sample.pdf' +import { IoReturnUpBack } from "react-icons/io5"; +import fizikpdf from "../../assets/fizik.pdf"; +import samplePdf from "../../assets/sample.pdf"; const initialState = { - grade: 8, - groupId: 0, - name: '', - startDate: new Date(), - endDate: new Date(), - startTime: '19:0', - endTime: '', - description: '', - type: 'bank', - duration:null, - budgetFileId:null, - - questionnaires: [ + grade: 8, + groupId: 0, + name: "", + startDate: new Date(), + endDate: new Date(), + startTime: "19:0", + endTime: "", + description: "", + type: "bank", + duration: null, + budgetFileId: null, + + questionnaires: [ + // { + // id: 1, + // name: "عمومی", + // fileUrl: fizikpdf, + // courses: [ + // { + // id: 0, + // questionnaireId: 1, + // name: "دینی", + // coefficient: 4, + // questionStart: 1, + // questionEnd: 21, + // }, + // ], + // answers: [], + // }, + // { + // id: 2, + // name: "اختصاصی", + // fileUrl: samplePdf, + // courses: [], + // answers: [], + // }, + ], + + answers: [], + + courseBank: [ + // { + // id: 1, + // title: 'ریاضی', + // coefficient: 4, + // numberOfOptions: 4, + // selectedQuestions: [] + // }, + // { + // id: 2, + // title: 'شیمی', + // coefficient: 3, + // numberOfOptions: 3, + // selectedQuestions: [] + // }, + ], + questionBank: [ + { + questionId: 1, + courseId: 2, + title: "تترا فلورید اسید چنتا اسید داره؟", + answeredPercentage: "83%", + score: 1, + options: [ { - id: 1, - name: 'عمومی', - fileUrl: fizikpdf, - courses: [ - - { - id: 0, - questionnaireId: 1, - name: 'دینی', - coefficient: 4, - questionStart: 1, - questionEnd: 21 - }, - - ], - answers:[ - - ] + id: 1, + title: "تترا", + isAnswer: false, }, { - id: 2, - name: 'اختصاصی', - fileUrl: samplePdf, - courses: [], - answers:[ - - ] - } - ], - - - answers: [ - - ], - - courseBank: [ - // { - // id: 1, - // title: 'ریاضی', - // coefficient: 4, - // numberOfOptions: 4, - // selectedQuestions: [] - // }, - // { - // id: 2, - // title: 'شیمی', - // coefficient: 3, - // numberOfOptions: 3, - // selectedQuestions: [] - // }, - ], - questionBank: [ + id: 2, + title: "سه ترا", + isAnswer: false, + }, { - questionId: 1, - courseId: 2, - title: 'تترا فلورید اسید چنتا اسید داره؟', - answeredPercentage: '83%', - score: 1, - options: [ - { - id: 1, - title: 'تترا', - isAnswer: false - }, - { - id: 2, - title: 'سه ترا', - isAnswer: false - }, - { - id: 3, - title: 'هویج و گوجه فرنگی؟', - isAnswer: true - }, - { - id: 4, - title: 'فلور تا', - isAnswer: false - }, - ] + id: 3, + title: "هویج و گوجه فرنگی؟", + isAnswer: true, }, { - questionId: 2, - courseId: 2, - title: 'asdaw dsfsdfiermc', - answeredPercentage: '83%', - score: 1, - options: [ - { - id: 1, - title: 'asdasd', - isAnswer: false - }, - { - id: 2, - title: 'asdasd2', - isAnswer: false - }, - { - id: 3, - title: '', - isAnswer: true - }, - { - id: 4, - title: 'asdasd4', - isAnswer: false - }, - ] + id: 4, + title: "فلور تا", + isAnswer: false, }, + ], + }, + { + questionId: 2, + courseId: 2, + title: "asdaw dsfsdfiermc", + answeredPercentage: "83%", + score: 1, + options: [ { - questionId: 3, - courseId: 1, - title: 'برای حل مساءل مربوط به مساحت زیر نمودار باید از کدام مبحث ریاضی استفاده کرد؟', - answeredPercentage: '43%', - score: 1, - options: [ - { - id: 1, - title: 'لگاریتم طبیعی', - isAnswer: false - }, - { - id: 2, - title: 'حد و مشتق', - isAnswer: false - }, - { - id: 3, - title: 'قدر مطلق', - isAnswer: false - }, - { - id: 4, - title: 'نخوندم 🗿', - isAnswer: true - }, - ] + id: 1, + title: "asdasd", + isAnswer: false, }, { - questionId: 4, - courseId: 2, - title: 'asdaw dsfsdfisdfsdfsfsdfsfsdfsdfermc', - answeredPercentage: '83%', - score: 1, - options: [ - { - id: 1, - title: 'asdasd', - isAnswer: false - }, - { - id: 2, - title: 'asdasd2', - isAnswer: false - }, - { - id: 3, - title: 'sdfsdfsdfsfd', - isAnswer: true - }, - { - id: 4, - title: 'asdasd4', - isAnswer: false - }, - ] + id: 2, + title: "asdasd2", + isAnswer: false, }, - - ], - courses: [ - - ], - questions: [ - - ], - - -} + { + id: 3, + title: "", + isAnswer: true, + }, + { + id: 4, + title: "asdasd4", + isAnswer: false, + }, + ], + }, + { + questionId: 3, + courseId: 1, + title: + "برای حل مساءل مربوط به مساحت زیر نمودار باید از کدام مبحث ریاضی استفاده کرد؟", + answeredPercentage: "43%", + score: 1, + options: [ + { + id: 1, + title: "لگاریتم طبیعی", + isAnswer: false, + }, + { + id: 2, + title: "حد و مشتق", + isAnswer: false, + }, + { + id: 3, + title: "قدر مطلق", + isAnswer: false, + }, + { + id: 4, + title: "نخوندم 🗿", + isAnswer: true, + }, + ], + }, + { + questionId: 4, + courseId: 2, + title: "asdaw dsfsdfisdfsdfsfsdfsfsdfsdfermc", + answeredPercentage: "83%", + score: 1, + options: [ + { + id: 1, + title: "asdasd", + isAnswer: false, + }, + { + id: 2, + title: "asdasd2", + isAnswer: false, + }, + { + id: 3, + title: "sdfsdfsdfsfd", + isAnswer: true, + }, + { + id: 4, + title: "asdasd4", + isAnswer: false, + }, + ], + }, + ], + courses: [], + questions: [], +}; export const numOfinitQs = initialState.questionBank.length; -export default function addExamReduser(state = initialState, { type, payload }) { - switch (type) { - - case 'ADD_EXAM_GRADE_AND_GROUP': - return { - ...state, - grade: payload.grade, - groupId: payload.groupId - } - - case 'ADD_EXAM_DESCRIPTION': - return { - ...state, - name: payload.name, - startDate: new Date(), - endDate: new Date(), - startTime: "19:0", - endTime: "", - description: payload.description, - type: payload.type, - duration: payload.duration, - startDate: payload.startDate, - endDate: payload.endDate, - budgetFileId: payload.budgetFileId, - }; - - case 'ADD_EXAM_QUESTIONAIRES': - return { - ...state, - questionnaires: [...state.questionnaires, payload] - } - case 'ADD_QUESTIONNAIRE_COURSES': - console.log(payload) - let thisQ = state.questionnaires.find(itm => itm.id == payload.questionnaireId) - let otherQ = state.questionnaires.filter(itm => itm.id !== payload.questionnaireId) - thisQ = { - ...thisQ, - courses: [ ...thisQ.courses,payload] - } - console.log(thisQ) - return { - ...state, - questionnaires: [...otherQ, thisQ] - } - case 'ADD_ANSWERS': - console.log(payload) - let thisQC = state.questionnaires.find(itm => itm.id == payload[0].questionnaierId) - let otherQC = state.questionnaires.filter(itm => itm.id !== payload[0].questionnaierId) - thisQC = { - ...thisQC, - answers: [ ...thisQC?.answers,...payload] - } - - return { - ...state, - questionnaires: [...otherQC, thisQC] - } - - case 'ADD_EXAM_COURSE': - return { - ...state, - courses: [...state.courses, { ...payload, selectedQuestions:[]}], - }; - case 'REMOVE_EXAM_COURSE': - return { - ...state, - courses: state.courses.filter(itm => itm.id !== payload.id) - } - - case 'ADD_EXAM_QUESTIONS': - console.log("??????????????"); - console.log(payload) - console.log(state.courses); - const othercourses = state.courses.filter( - (itm) => itm.id !== payload.lessonId - ); - const selectedC = state.courses.filter( - (itm) => itm.id == payload.lessonId - ); - selectedC[0] = { ...selectedC[0], selectedQuestions: [payload, ...selectedC[0].selectedQuestions] } - const newCourses = [...othercourses, ...selectedC] - - return { - ...state, - courses: newCourses - - } - - - case 'REMOVE_EXAM_QUESTIONS': - const dontDeleteThese = state.courses.filter(itm => itm.id !== payload.courseId) - const courseForDelete = state.courses.filter(itm => itm.id == payload.courseId) - courseForDelete[0] = { ...courseForDelete[0], selectedQuestions: courseForDelete[0].selectedQuestions.filter(itm => itm.questionId !== payload.questionId) } - const newCoursesWithDeleted = [...dontDeleteThese, ...courseForDelete] - console.log(newCoursesWithDeleted) - console.log(courseForDelete) - console.log(dontDeleteThese) - console.log(payload) - return { - ...state, - courses: newCoursesWithDeleted - +export default function addExamReduser( + state = initialState, + { type, payload } +) { + switch (type) { + case "ADD_EXAM_GRADE_AND_GROUP": + return { + ...state, + grade: payload.grade, + groupId: payload.groupId, + }; + + case "ADD_EXAM_DESCRIPTION": + return { + ...state, + name: payload.name, + startDate: new Date(), + endDate: new Date(), + startTime: "19:0", + endTime: "", + description: payload.description, + type: payload.type, + duration: payload.duration, + startDate: payload.startDate, + endDate: payload.endDate, + budgetFileId: payload.budgetFileId, + }; + + case "ADD_EXAM_QUESTIONAIRES": + return { + ...state, + questionnaires: [...state.questionnaires, payload], + }; + case "ADD_QUESTIONNAIRE_COURSES": + console.log(payload); + let thisQ = state.questionnaires.find( + (itm) => itm.id == payload.questionnaireId + ); + let otherQ = state.questionnaires.filter( + (itm) => itm.id !== payload.questionnaireId + ); + thisQ = { + ...thisQ, + courses: [...thisQ.courses, payload], + }; + console.log(thisQ); + return { + ...state, + questionnaires: [...otherQ, thisQ], + }; + case "ADD_ANSWERS": + console.log(payload); + let thisQC = state.questionnaires.find( + (itm) => itm.id == payload[0].questionnaierId + ); + let otherQC = state.questionnaires.filter( + (itm) => itm.id !== payload[0].questionnaierId + ); + thisQC = { + ...thisQC, + answers: [...thisQC?.answers, ...payload], + }; + + return { + ...state, + questionnaires: [...otherQC, thisQC], + }; + + case "ADD_EXAM_COURSE": + return { + ...state, + courses: [...state.courses, { ...payload, selectedQuestions: [] }], + }; + case "REMOVE_EXAM_COURSE": + return { + ...state, + courses: state.courses.filter((itm) => itm.id !== payload.id), + }; + + case "ADD_EXAM_QUESTIONS": + console.log("??????????????"); + console.log(payload); + console.log(state.courses); + const othercourses = state.courses.filter( + (itm) => itm.id !== payload.lessonId + ); + const selectedC = state.courses.filter( + (itm) => itm.id == payload.lessonId + ); + selectedC[0] = { + ...selectedC[0], + selectedQuestions: [payload, ...selectedC[0].selectedQuestions], + }; + const newCourses = [...othercourses, ...selectedC]; + + return { + ...state, + courses: newCourses, + }; + case "ADD_EXAM_QUESTIONS2": + let newList = state.questions; + let isNew = true; + for(let i=0;i itm.questionId !== payload.questionId) - } - case 'GET_QUESTION_BACK_TO_BANK': - return { - ...state, - questionBank: [payload, ...state.questionBank,] - } - - case 'CHANGE_QUESTION_ORDER': - const dontChangeThese = state.courses.filter(itm => itm.id !== payload[0].courseId) - const courseForChange = state.courses.filter(itm => itm.id == payload[0].courseId) - courseForChange[0] = { ...courseForChange[0], selectedQuestions: payload } - const newChangedCourseSort = [...dontChangeThese, ...courseForChange] - console.log(payload) - return { - ...state, - courses: newChangedCourseSort - } - case 'CHANGE_COURSE_ORDER': - console.log(payload) - return { - ...state, - courses: payload - } - case 'ADD_CUSTOM_QUESTION': - const otherCourses = state.courses.filter(itm => itm.id !== payload.courseId) - const selectedc = state.courses.filter(itm => itm.id == payload.courseId) - selectedc[0] = { ...selectedc[0], selectedQuestions: [payload, ...selectedc[0].selectedQuestions] } - const newcourses = [...selectedc, ...otherCourses] - return { - ...state, - courses: newcourses - - } - case 'CHANGE_COURSE_NUM_OF_OPTIONS': - const otherCourseS = state.courses.filter(itm => itm.id !== payload.courseId) - const seLectedC = state.courses.filter(itm => itm.id == payload.courseId) - seLectedC[0] = { ...seLectedC[0], numberOfOptions: payload.value } - const neWCourses = [...seLectedC, ...otherCourseS] - return { - ...state, - courses: neWCourses - - } - - case 'CHANGE_QUESTIONNAIRES_ORDER': - return { - ...state, - questionnaires: payload - - } - - default: - return state; - - } - -} \ No newline at end of file + } + if(isNew){ + newList.push({ + examId: payload.examId, + list: [payload.item], + }); + } + return { + ...state, + questions: newList, + }; + + case "REMOVE_EXAM_QUESTIONS": + const dontDeleteThese = state.courses.filter( + (itm) => itm.id !== payload.courseId + ); + const courseForDelete = state.courses.filter( + (itm) => itm.id == payload.courseId + ); + courseForDelete[0] = { + ...courseForDelete[0], + selectedQuestions: courseForDelete[0].selectedQuestions.filter( + (itm) => itm.questionId !== payload.questionId + ), + }; + const newCoursesWithDeleted = [...dontDeleteThese, ...courseForDelete]; + console.log(newCoursesWithDeleted); + console.log(courseForDelete); + console.log(dontDeleteThese); + console.log(payload); + return { + ...state, + courses: newCoursesWithDeleted, + }; + case "REMOVE_QUESTION_FROM_BANK": + return { + ...state, + questionBank: state.questionBank.filter( + (itm) => itm.questionId !== payload.questionId + ), + }; + case "GET_QUESTION_BACK_TO_BANK": + return { + ...state, + questionBank: [payload, ...state.questionBank], + }; + + case "CHANGE_QUESTION_ORDER": + const dontChangeThese = state.courses.filter( + (itm) => itm.id !== payload[0].courseId + ); + const courseForChange = state.courses.filter( + (itm) => itm.id == payload[0].courseId + ); + courseForChange[0] = { + ...courseForChange[0], + selectedQuestions: payload, + }; + const newChangedCourseSort = [...dontChangeThese, ...courseForChange]; + console.log(payload); + return { + ...state, + courses: newChangedCourseSort, + }; + case "CHANGE_COURSE_ORDER": + console.log(payload); + return { + ...state, + courses: payload, + }; + case "ADD_CUSTOM_QUESTION": + const otherCourses = state.courses.filter( + (itm) => itm.id !== payload.courseId + ); + const selectedc = state.courses.filter( + (itm) => itm.id == payload.courseId + ); + selectedc[0] = { + ...selectedc[0], + selectedQuestions: [payload, ...selectedc[0].selectedQuestions], + }; + const newcourses = [...selectedc, ...otherCourses]; + return { + ...state, + courses: newcourses, + }; + + case "CHANGE_COURSE_NUM_OF_OPTIONS": + const otherCourseS = state.courses.filter( + (itm) => itm.id !== payload.courseId + ); + const seLectedC = state.courses.filter( + (itm) => itm.id == payload.courseId + ); + seLectedC[0] = { ...seLectedC[0], numberOfOptions: payload.value }; + const neWCourses = [...seLectedC, ...otherCourseS]; + return { + ...state, + courses: neWCourses, + }; + + case "CHANGE_QUESTIONNAIRES_ORDER": + return { + ...state, + questionnaires: payload, + }; + + default: + return state; + } +} diff --git a/src/redux/reducers/exam2.js b/src/redux/reducers/exam2.js index aa32958..428ca11 100644 --- a/src/redux/reducers/exam2.js +++ b/src/redux/reducers/exam2.js @@ -7,8 +7,9 @@ const initialState = { error: null, info: null, lastExamAdd: null, - preview : null, - subExamList:[], + preview: null, + subExamList: [], + confirm:null }; export default function exam2(state = initialState, action) { let { type, data } = action; @@ -17,6 +18,9 @@ export default function exam2(state = initialState, action) { return { ...state, loading: false, info: data, error: null }; case "exam/preview": return { ...state, loading: false, preview: data, error: null }; + case "exam/confirm": + toast.success("درخواست با موفقیت انجام شد"); + return { ...state, loading: false, confirm: data, error: null }; case "exam/parentAdd": toast.success("آزمون شما با موفقیت ثبت شد"); return { ...state, loading: false, error: null, lastExamAdd: data.id }; diff --git a/src/redux/reducers/examQuestion.js b/src/redux/reducers/examQuestion.js new file mode 100644 index 0000000..cb5307a --- /dev/null +++ b/src/redux/reducers/examQuestion.js @@ -0,0 +1,30 @@ + + +import { toast } from "react-toastify"; + +const initialState = { + loading: false, + error: null, + info: null, + list: null, + lastAdd: null, +}; +export default function examQuestion(state = initialState, action) { + let { type, data } = action; + switch (type) { + case "examQuestion/info": + return { ...state, loading: false, info: data, error: null }; + case "examQuestion/add": + // toast.success("درخواست با موفقیت انجام شد"); + return { ...state, loading: false, error: null, lastAdd: data }; + case "examQuestion/list": + return { ...state, loading: false, error: null, list: data }; + case "examQuestion/loading": + return { ...state, loading: true }; + case "examQuestion/error": + toast.error(data.message); + return { ...state, loading: false, error: data.message }; + default: + return state; + } +} \ No newline at end of file diff --git a/src/redux/reducers/index.js b/src/redux/reducers/index.js index 6f0e56f..9222d3c 100644 --- a/src/redux/reducers/index.js +++ b/src/redux/reducers/index.js @@ -18,4 +18,6 @@ export { default as examGroup } from "./examGroup"; export { default as lesson } from "./lesson"; export { default as question } from "./question"; export { default as category } from "./category"; +export { default as examQuestion } from "./examQuestion"; + diff --git a/src/view/addExam/components/addQuestion.js b/src/view/addExam/components/addQuestion.js index b6294b8..2220a72 100644 --- a/src/view/addExam/components/addQuestion.js +++ b/src/view/addExam/components/addQuestion.js @@ -1,89 +1,153 @@ import React, { useEffect, useState } from "react"; -import attachIcon from '../../../assets/img/attach-circle.svg'; -const AddQuestionPopUp = ({ titlePass, scorePass, submitOnClick, cancelOnClick, passOptionTitle, setAsAnswer, options }) => { - - - const gozine = [ - 'الف', - 'ب', - 'ج', - 'د', - 'ه', - 'ز', - ] +import { connect } from "react-redux"; +import attachIcon from "../../../assets/img/attach-circle.svg"; +import { question } from "../../../redux/actions"; +const AddQuestionPopUp = ({ + titlePass, + scorePass, + submitOnClick, + cancelOnClick, + passOptionTitle, + setAsAnswer, + options, + submitQuestion, +}) => { + const gozine = ["الف", "ب", "ج", "د", "ه", "ز"]; - return ( -
-
-
-
- - - - - - - - -
-
-
-
-