#68 reorder questions
This commit is contained in:
parent
0cf4026a08
commit
5638be0664
|
|
@ -68,7 +68,7 @@ const ImageBoxFieldMemo = memo(
|
||||||
console.log(name);
|
console.log(name);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ImageBoxField">
|
<div className="ImageBoxField" key={name}>
|
||||||
<div className="ImageHeader">
|
<div className="ImageHeader">
|
||||||
{imagePreview ? (
|
{imagePreview ? (
|
||||||
<>
|
<>
|
||||||
|
|
@ -99,10 +99,11 @@ const ImageBoxFieldMemo = memo(
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
(prevProps, nextProps) => {
|
// ,
|
||||||
return areFieldPropsEqual(prevProps, nextProps);
|
// (prevProps, nextProps) => {
|
||||||
},
|
// return areFieldPropsEqual(prevProps, nextProps);
|
||||||
|
// },
|
||||||
);
|
);
|
||||||
|
|
||||||
export default ImageBoxFieldMemo;
|
export default ImageBoxFieldMemo;
|
||||||
|
|
|
||||||
43
src/Hooks/useReOrderQuestions.ts
Normal file
43
src/Hooks/useReOrderQuestions.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { useFormikContext } from 'formik';
|
||||||
|
import React from 'react'
|
||||||
|
import { moveToBottom, moveToTop } from '../utils/reOrder';
|
||||||
|
type FormValues = {
|
||||||
|
Questions: Array<{ id: string; sub_order?: number } & Record<string, any>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useReOrderQuestions() {
|
||||||
|
const {setFieldValue,values} = useFormikContext<FormValues>()
|
||||||
|
|
||||||
|
const withSubOrder = (arr: any[]) => arr.map((it, i) => ({ ...it, sub_order: i }));
|
||||||
|
|
||||||
|
const scrollToIdWithOffset = (id: string) => {
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
if (!el) return;
|
||||||
|
const top = el.getBoundingClientRect().top ;
|
||||||
|
console.log(el.getBoundingClientRect())
|
||||||
|
window.scrollBy({ top, behavior: "smooth" });
|
||||||
|
};
|
||||||
|
|
||||||
|
const afterLayout = (fn: () => void) => {
|
||||||
|
requestAnimationFrame(() => requestAnimationFrame(fn));
|
||||||
|
};
|
||||||
|
|
||||||
|
const moveItemUp = (item:any,index: number) => {
|
||||||
|
if (index <= 0) return;
|
||||||
|
const next = moveToTop(index, values.Questions);
|
||||||
|
setFieldValue("Questions", withSubOrder(next));
|
||||||
|
afterLayout(() => scrollToIdWithOffset(`q-${item.id}`));
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const moveItemDown = (item:any,index: number) => {
|
||||||
|
if (index >= values.Questions.length - 1) return;
|
||||||
|
const next = moveToBottom(index, values.Questions);
|
||||||
|
setFieldValue("Questions", withSubOrder(next));
|
||||||
|
afterLayout(() => scrollToIdWithOffset(`q-${item.id}`));
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return { moveItemDown , moveItemUp }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ const CheckboxField = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className={Group ? "d-inline mt-5 Checkbox" : ``}>
|
<div className={Group ? "d-inline mt-5 Checkbox" : ``} key={name}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
onChange={onChange || CheckboxhandleChange}
|
onChange={onChange || CheckboxhandleChange}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import ValidationField from "../../../../../../Components/ValidationField/ValidationField";
|
import ValidationField from "../../../../../../Components/ValidationField/ValidationField";
|
||||||
import { Field } from "formik";
|
import { Field } from "formik";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
@ -9,17 +9,21 @@ import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState";
|
||||||
import LaTeXInputMemo from "../../../../../../Components/LatextInput/LaTeXInputMemo";
|
import LaTeXInputMemo from "../../../../../../Components/LatextInput/LaTeXInputMemo";
|
||||||
import ImageBoxFieldMemo from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxFieldMemo";
|
import ImageBoxFieldMemo from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxFieldMemo";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const ChoiceFields = React.memo(
|
const ChoiceFields = React.memo(
|
||||||
({
|
({
|
||||||
index,
|
index,
|
||||||
parent_index,
|
parent_index,
|
||||||
setFieldValue,
|
setFieldValue,
|
||||||
values,
|
values,
|
||||||
|
choiceId,
|
||||||
}: {
|
}: {
|
||||||
index: number;
|
index: number;
|
||||||
parent_index: number;
|
parent_index: number;
|
||||||
setFieldValue: any;
|
setFieldValue: any;
|
||||||
values: any;
|
values: any;
|
||||||
|
choiceId:number | string
|
||||||
}) => {
|
}) => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const { ShowHint } = useObjectToEdit();
|
const { ShowHint } = useObjectToEdit();
|
||||||
|
|
@ -49,6 +53,11 @@ const ChoiceFields = React.memo(
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
const nameTxt = `Questions[${parent_index}].answers[${index}].content`;
|
||||||
|
const nameImg = `Questions[${parent_index}].answers[${index}].content_image`;
|
||||||
|
// useEffect(()=>{
|
||||||
|
|
||||||
|
// })a
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -58,13 +67,15 @@ const ChoiceFields = React.memo(
|
||||||
>
|
>
|
||||||
<Field
|
<Field
|
||||||
component={LaTeXInputMemo}
|
component={LaTeXInputMemo}
|
||||||
name={`Questions[${parent_index}].answers[${index}].content`}
|
name={nameTxt}
|
||||||
|
key={nameTxt}
|
||||||
label={t(`input.choice`) + ` ` + `( ${index + 1} )`}
|
label={t(`input.choice`) + ` ` + `( ${index + 1} )`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Field
|
<Field
|
||||||
component={ImageBoxFieldMemo}
|
component={ImageBoxFieldMemo}
|
||||||
name={`Questions.${parent_index}.answers.${index}.content_image`}
|
name={nameImg}
|
||||||
|
key={nameImg}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="answer_status">
|
<div className="answer_status">
|
||||||
|
|
@ -106,26 +117,27 @@ const ChoiceFields = React.memo(
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
(prevProps, nextProps) => {
|
// areEqual
|
||||||
console.log(
|
// (prevProps, nextProps) => {
|
||||||
prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[
|
// console.log(
|
||||||
prevProps?.index
|
// prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[
|
||||||
] ===
|
// prevProps?.index
|
||||||
nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[
|
// ] ===
|
||||||
prevProps?.index
|
// nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[
|
||||||
],
|
// prevProps?.index
|
||||||
);
|
// ],
|
||||||
|
// );
|
||||||
|
|
||||||
return (
|
// return (
|
||||||
prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[
|
// prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[
|
||||||
prevProps?.index
|
// prevProps?.index
|
||||||
] ===
|
// ] ===
|
||||||
nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[
|
// nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[
|
||||||
prevProps?.index
|
// prevProps?.index
|
||||||
]
|
// ]
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
);
|
);
|
||||||
|
|
||||||
export default ChoiceFields;
|
export default ChoiceFields;
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,10 @@ const Choices = React.memo(
|
||||||
{(values?.Questions?.[parent_index]?.answers || []).map(
|
{(values?.Questions?.[parent_index]?.answers || []).map(
|
||||||
(item: Choice, index: number) => {
|
(item: Choice, index: number) => {
|
||||||
return (
|
return (
|
||||||
<div className="Choices ChoicesMalty" key={index}>
|
<div className="Choices ChoicesMalty" key={item?.id} onClick={() => console.log(item)}>
|
||||||
<ChoiceFields
|
<ChoiceFields
|
||||||
key={index}
|
key={item?.id}
|
||||||
|
choiceId={item.id} // جديد
|
||||||
parent_index={parent_index}
|
parent_index={parent_index}
|
||||||
index={index}
|
index={index}
|
||||||
setFieldValue={setFieldValue}
|
setFieldValue={setFieldValue}
|
||||||
|
|
@ -104,13 +105,14 @@ const Choices = React.memo(
|
||||||
</DragDropContext> */}
|
</DragDropContext> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
(prevProps, nextProps) => {
|
// ,
|
||||||
return (
|
// (prevProps, nextProps) => {
|
||||||
prevProps.values?.Questions?.[prevProps?.parent_index]?.answers ===
|
// return (
|
||||||
nextProps.values?.Questions?.[nextProps?.parent_index]?.answers
|
// prevProps.values?.Questions?.[prevProps?.parent_index]?.answers ===
|
||||||
);
|
// nextProps.values?.Questions?.[nextProps?.parent_index]?.answers
|
||||||
},
|
// );
|
||||||
|
// },
|
||||||
);
|
);
|
||||||
|
|
||||||
export default Choices;
|
export default Choices;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ const QuestionFIeld = ({
|
||||||
const formik = useFormikContext<any>();
|
const formik = useFormikContext<any>();
|
||||||
const { setDeletedQuestions, DeletedQuestions } = useObjectToEdit();
|
const { setDeletedQuestions, DeletedQuestions } = useObjectToEdit();
|
||||||
|
|
||||||
|
// const path = git
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDeletedQuestions([]);
|
setDeletedQuestions([]);
|
||||||
|
|
@ -46,9 +47,14 @@ const QuestionFIeld = ({
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const nameImg = `Questions[${index}].content_image`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="exercise_forms">
|
<div className="exercise_forms" onClick={() => {
|
||||||
|
console.log(values.Questions[index])
|
||||||
|
console.log(index)
|
||||||
|
}}>
|
||||||
<div className="ChoiceFields">
|
<div className="ChoiceFields">
|
||||||
<Field
|
<Field
|
||||||
component={LaTeXInputMemo}
|
component={LaTeXInputMemo}
|
||||||
|
|
@ -57,8 +63,10 @@ const QuestionFIeld = ({
|
||||||
label={t(`input.question`) + ` ` + `( ${index + 1} )`}
|
label={t(`input.question`) + ` ` + `( ${index + 1} )`}
|
||||||
/>
|
/>
|
||||||
<Field
|
<Field
|
||||||
|
onClick={ () => console.log(index)}
|
||||||
component={ImageBoxFieldMemo}
|
component={ImageBoxFieldMemo}
|
||||||
name={`Questions.${index}.content_image`}
|
name={nameImg}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
{handelCanDeleteAnswers() ? (
|
{handelCanDeleteAnswers() ? (
|
||||||
<div className="answer_status">
|
<div className="answer_status">
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import { toast } from "react-toastify";
|
||||||
import SelectTagV2 from "../../../../../../Components/CustomFields/SelectTagV2";
|
import SelectTagV2 from "../../../../../../Components/CustomFields/SelectTagV2";
|
||||||
import LaTeXInputMemo from "../../../../../../Components/LatextInput/LaTeXInputMemo";
|
import LaTeXInputMemo from "../../../../../../Components/LatextInput/LaTeXInputMemo";
|
||||||
import { Field } from "formik";
|
import { Field } from "formik";
|
||||||
|
import { uid } from "../../../../../../utils/reOrder";
|
||||||
|
|
||||||
export const Question: React.FC<any> = React.memo(({ index, data }) => {
|
export const Question: React.FC<any> = React.memo(({ index, data }) => {
|
||||||
const { values, setFieldValue, ShowHint, t } = data;
|
const { values, setFieldValue, ShowHint, t } = data;
|
||||||
|
|
@ -18,6 +19,7 @@ export const Question: React.FC<any> = React.memo(({ index, data }) => {
|
||||||
setFieldValue(`Questions.[${parent_index}].answers`, [
|
setFieldValue(`Questions.[${parent_index}].answers`, [
|
||||||
...(values?.Questions?.[parent_index]?.answers as Choice[]),
|
...(values?.Questions?.[parent_index]?.answers as Choice[]),
|
||||||
{
|
{
|
||||||
|
id: uid(),
|
||||||
answer: null,
|
answer: null,
|
||||||
content_image: null,
|
content_image: null,
|
||||||
content: null,
|
content: null,
|
||||||
|
|
@ -38,7 +40,6 @@ export const Question: React.FC<any> = React.memo(({ index, data }) => {
|
||||||
<QuestionFIeld
|
<QuestionFIeld
|
||||||
setFieldValue={setFieldValue}
|
setFieldValue={setFieldValue}
|
||||||
values={values}
|
values={values}
|
||||||
key={index}
|
|
||||||
index={index}
|
index={index}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -65,9 +66,9 @@ export const Question: React.FC<any> = React.memo(({ index, data }) => {
|
||||||
name={`Questions[${index}].hint`}
|
name={`Questions[${index}].hint`}
|
||||||
label={t("input.hint_question")}
|
label={t("input.hint_question")}
|
||||||
type="TextArea"
|
type="TextArea"
|
||||||
style={{ width: "100%", height: 60, resize: "none" }}
|
// style={{ width: "100%", height: 60, resize: "none" }}
|
||||||
showCount={false}
|
showCount={false}
|
||||||
autoSize={{ minRows: 2, maxRows: 10 }}
|
// autoSize={{ minRows: 2, maxRows: 10 }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<MaltySelectTag parent_index={index} />
|
<MaltySelectTag parent_index={index} />
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ import { VariableSizeList as List } from "react-window";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState";
|
||||||
import { Question } from "./Question";
|
import { Question } from "./Question";
|
||||||
|
import { moveToBottom, moveToTop } from "../../../../../../utils/reOrder";
|
||||||
|
import { FaArrowRightLong } from "react-icons/fa6";
|
||||||
|
import { useReOrderQuestions } from "../../../../../../Hooks/useReOrderQuestions";
|
||||||
|
|
||||||
interface QuestionsProps {
|
interface QuestionsProps {
|
||||||
setFieldValue: (field: string, value: any) => void;
|
setFieldValue: (field: string, value: any) => void;
|
||||||
|
|
@ -16,7 +19,9 @@ const Questions: React.FC<QuestionsProps> = React.memo(
|
||||||
const questions = values?.Questions || [];
|
const questions = values?.Questions || [];
|
||||||
const { ShowHint } = useObjectToEdit();
|
const { ShowHint } = useObjectToEdit();
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const listRef = useRef<List>(null);
|
// const listRef = useRef<List>(null);
|
||||||
|
const rowRefs = useRef<Record<string, HTMLDivElement | null>>({});
|
||||||
|
|
||||||
|
|
||||||
const getItemSize = useCallback(
|
const getItemSize = useCallback(
|
||||||
(index: number) => {
|
(index: number) => {
|
||||||
|
|
@ -33,22 +38,24 @@ const Questions: React.FC<QuestionsProps> = React.memo(
|
||||||
},
|
},
|
||||||
[questions, ShowHint],
|
[questions, ShowHint],
|
||||||
);
|
);
|
||||||
|
// == we don use it ==
|
||||||
|
// const itemData = useMemo(
|
||||||
|
// () => ({
|
||||||
|
// values,
|
||||||
|
// setFieldValue,
|
||||||
|
// ShowHint,
|
||||||
|
// t,
|
||||||
|
// }),
|
||||||
|
// [values, setFieldValue, ShowHint, t],
|
||||||
|
// );
|
||||||
|
|
||||||
const itemData = useMemo(
|
// useEffect(() => {
|
||||||
() => ({
|
// if (listRef.current) {
|
||||||
values,
|
// listRef.current.resetAfterIndex(0);
|
||||||
setFieldValue,
|
// }
|
||||||
ShowHint,
|
// }, [questions, ShowHint]);
|
||||||
t,
|
|
||||||
}),
|
|
||||||
[values, setFieldValue, ShowHint, t],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
const { moveItemDown , moveItemUp} = useReOrderQuestions()
|
||||||
if (listRef.current) {
|
|
||||||
listRef.current.resetAfterIndex(0);
|
|
||||||
}
|
|
||||||
}, [questions, ShowHint]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -66,12 +73,25 @@ const Questions: React.FC<QuestionsProps> = React.memo(
|
||||||
{Question}
|
{Question}
|
||||||
</List> */}
|
</List> */}
|
||||||
{questions?.map((item: any, index: number) => {
|
{questions?.map((item: any, index: number) => {
|
||||||
|
console.log(item)
|
||||||
|
console.log(questions)
|
||||||
return (
|
return (
|
||||||
<Question
|
<div
|
||||||
key={index}
|
key={item.id}
|
||||||
|
id={`q-${item.id}`}
|
||||||
|
onClick={() => console.log(questions)}
|
||||||
|
ref={(el) => (rowRefs.current[item.id] = el)}
|
||||||
|
> <Question
|
||||||
|
// key={questions[index]?.content}
|
||||||
index={index}
|
index={index}
|
||||||
data={{ values, setFieldValue, ShowHint, t }}
|
data={{ values, setFieldValue, ShowHint, t }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div className="positionButtons">
|
||||||
|
<FaArrowRightLong className="toTop" onClick={() => moveItemUp(item,index)}/>
|
||||||
|
<FaArrowRightLong className="toBotton" onClick={() => moveItemDown(item,index)}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
36
src/utils/reOrder.ts
Normal file
36
src/utils/reOrder.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
// export function moveToTop(index:number,array:any[]){
|
||||||
|
// const indexItemBefore = index - 1
|
||||||
|
// if(indexItemBefore == -1)return array;
|
||||||
|
// const currentItem = array[index]
|
||||||
|
// array[index] = array[indexItemBefore]
|
||||||
|
// array[indexItemBefore] = currentItem
|
||||||
|
// return array
|
||||||
|
|
||||||
|
// }
|
||||||
|
// export function moveToBottom(index:number,array:any[]){
|
||||||
|
// const indexItemAfter = index + 1
|
||||||
|
// if(indexItemAfter == array.length)return array;
|
||||||
|
// const currentItem = array[index]
|
||||||
|
// array[index] = array[indexItemAfter]
|
||||||
|
// array[indexItemAfter] = currentItem
|
||||||
|
// return array
|
||||||
|
// }
|
||||||
|
|
||||||
|
function swapImmutable<T>(arr: T[], i: number, j: number): T[] {
|
||||||
|
if (i === j) return arr.slice();
|
||||||
|
const copy = arr.slice();
|
||||||
|
[copy[i], copy[j]] = [copy[j], copy[i]];
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function moveToTop(index: number, array: any[]) {
|
||||||
|
if (index <= 0) return array.slice();
|
||||||
|
return swapImmutable(array, index, index - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function moveToBottom(index: number, array: any[]) {
|
||||||
|
if (index >= array.length - 1) return array.slice();
|
||||||
|
return swapImmutable(array, index, index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const uid = () => Date.now().toString() + Math.random().toString(36).slice(2,9);
|
||||||
Loading…
Reference in New Issue
Block a user