#68 reorder questions

This commit is contained in:
Majd_dk 2025-09-28 10:51:22 +03:00
parent 0cf4026a08
commit 5638be0664
9 changed files with 242 additions and 119 deletions

View File

@ -68,7 +68,7 @@ const ImageBoxFieldMemo = memo(
console.log(name);
return (
<div className="ImageBoxField">
<div className="ImageBoxField" key={name}>
<div className="ImageHeader">
{imagePreview ? (
<>
@ -99,10 +99,11 @@ const ImageBoxFieldMemo = memo(
/>
</div>
);
},
(prevProps, nextProps) => {
return areFieldPropsEqual(prevProps, nextProps);
},
}
// ,
// (prevProps, nextProps) => {
// return areFieldPropsEqual(prevProps, nextProps);
// },
);
export default ImageBoxFieldMemo;

View 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 }
}

View File

@ -35,7 +35,7 @@ const CheckboxField = ({
);
};
return (
<div className={Group ? "d-inline mt-5 Checkbox" : ``}>
<div className={Group ? "d-inline mt-5 Checkbox" : ``} key={name}>
<Checkbox
onChange={onChange || CheckboxhandleChange}
disabled={isDisabled}

View File

@ -1,4 +1,4 @@
import React from "react";
import React, { useEffect } from "react";
import ValidationField from "../../../../../../Components/ValidationField/ValidationField";
import { Field } from "formik";
import { useTranslation } from "react-i18next";
@ -9,17 +9,21 @@ import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState";
import LaTeXInputMemo from "../../../../../../Components/LatextInput/LaTeXInputMemo";
import ImageBoxFieldMemo from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxFieldMemo";
const ChoiceFields = React.memo(
({
index,
parent_index,
setFieldValue,
values,
choiceId,
}: {
index: number;
parent_index: number;
setFieldValue: any;
values: any;
choiceId:number | string
}) => {
const [t] = useTranslation();
const { ShowHint } = useObjectToEdit();
@ -49,6 +53,11 @@ const ChoiceFields = React.memo(
}
return false;
};
const nameTxt = `Questions[${parent_index}].answers[${index}].content`;
const nameImg = `Questions[${parent_index}].answers[${index}].content_image`;
// useEffect(()=>{
// })a
return (
<>
@ -58,13 +67,15 @@ const ChoiceFields = React.memo(
>
<Field
component={LaTeXInputMemo}
name={`Questions[${parent_index}].answers[${index}].content`}
name={nameTxt}
key={nameTxt}
label={t(`input.choice`) + ` ` + `( ${index + 1} )`}
/>
<Field
component={ImageBoxFieldMemo}
name={`Questions.${parent_index}.answers.${index}.content_image`}
name={nameImg}
key={nameImg}
/>
<div className="answer_status">
@ -106,26 +117,27 @@ const ChoiceFields = React.memo(
</div>
</>
);
},
(prevProps, nextProps) => {
console.log(
prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[
prevProps?.index
] ===
nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[
prevProps?.index
],
);
}
// areEqual
// (prevProps, nextProps) => {
// console.log(
// prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[
// prevProps?.index
// ] ===
// nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[
// prevProps?.index
// ],
// );
return (
prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[
prevProps?.index
] ===
nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[
prevProps?.index
]
);
},
// return (
// prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[
// prevProps?.index
// ] ===
// nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[
// prevProps?.index
// ]
// );
// },
);
export default ChoiceFields;

View File

@ -45,9 +45,10 @@ const Choices = React.memo(
{(values?.Questions?.[parent_index]?.answers || []).map(
(item: Choice, index: number) => {
return (
<div className="Choices ChoicesMalty" key={index}>
<div className="Choices ChoicesMalty" key={item?.id} onClick={() => console.log(item)}>
<ChoiceFields
key={index}
key={item?.id}
choiceId={item.id} // جديد
parent_index={parent_index}
index={index}
setFieldValue={setFieldValue}
@ -104,13 +105,14 @@ const Choices = React.memo(
</DragDropContext> */}
</>
);
},
(prevProps, nextProps) => {
return (
prevProps.values?.Questions?.[prevProps?.parent_index]?.answers ===
nextProps.values?.Questions?.[nextProps?.parent_index]?.answers
);
},
}
// ,
// (prevProps, nextProps) => {
// return (
// prevProps.values?.Questions?.[prevProps?.parent_index]?.answers ===
// nextProps.values?.Questions?.[nextProps?.parent_index]?.answers
// );
// },
);
export default Choices;

View File

@ -19,6 +19,7 @@ const QuestionFIeld = ({
const formik = useFormikContext<any>();
const { setDeletedQuestions, DeletedQuestions } = useObjectToEdit();
// const path = git
const [t] = useTranslation();
useEffect(() => {
setDeletedQuestions([]);
@ -46,9 +47,14 @@ const QuestionFIeld = ({
return false;
};
const nameImg = `Questions[${index}].content_image`;
return (
<>
<div className="exercise_forms">
<div className="exercise_forms" onClick={() => {
console.log(values.Questions[index])
console.log(index)
}}>
<div className="ChoiceFields">
<Field
component={LaTeXInputMemo}
@ -57,8 +63,10 @@ const QuestionFIeld = ({
label={t(`input.question`) + ` ` + `( ${index + 1} )`}
/>
<Field
onClick={ () => console.log(index)}
component={ImageBoxFieldMemo}
name={`Questions.${index}.content_image`}
name={nameImg}
/>
{handelCanDeleteAnswers() ? (
<div className="answer_status">

View File

@ -9,6 +9,7 @@ import { toast } from "react-toastify";
import SelectTagV2 from "../../../../../../Components/CustomFields/SelectTagV2";
import LaTeXInputMemo from "../../../../../../Components/LatextInput/LaTeXInputMemo";
import { Field } from "formik";
import { uid } from "../../../../../../utils/reOrder";
export const Question: React.FC<any> = React.memo(({ index, 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`, [
...(values?.Questions?.[parent_index]?.answers as Choice[]),
{
id: uid(),
answer: null,
content_image: null,
content: null,
@ -38,7 +40,6 @@ export const Question: React.FC<any> = React.memo(({ index, data }) => {
<QuestionFIeld
setFieldValue={setFieldValue}
values={values}
key={index}
index={index}
/>
</div>
@ -65,9 +66,9 @@ export const Question: React.FC<any> = React.memo(({ index, data }) => {
name={`Questions[${index}].hint`}
label={t("input.hint_question")}
type="TextArea"
style={{ width: "100%", height: 60, resize: "none" }}
// style={{ width: "100%", height: 60, resize: "none" }}
showCount={false}
autoSize={{ minRows: 2, maxRows: 10 }}
// autoSize={{ minRows: 2, maxRows: 10 }}
/>
)}
<MaltySelectTag parent_index={index} />

View File

@ -3,6 +3,9 @@ import { VariableSizeList as List } from "react-window";
import { useTranslation } from "react-i18next";
import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState";
import { Question } from "./Question";
import { moveToBottom, moveToTop } from "../../../../../../utils/reOrder";
import { FaArrowRightLong } from "react-icons/fa6";
import { useReOrderQuestions } from "../../../../../../Hooks/useReOrderQuestions";
interface QuestionsProps {
setFieldValue: (field: string, value: any) => void;
@ -16,7 +19,9 @@ const Questions: React.FC<QuestionsProps> = React.memo(
const questions = values?.Questions || [];
const { ShowHint } = useObjectToEdit();
const [t] = useTranslation();
const listRef = useRef<List>(null);
// const listRef = useRef<List>(null);
const rowRefs = useRef<Record<string, HTMLDivElement | null>>({});
const getItemSize = useCallback(
(index: number) => {
@ -33,22 +38,24 @@ const Questions: React.FC<QuestionsProps> = React.memo(
},
[questions, ShowHint],
);
// == we don use it ==
// const itemData = useMemo(
// () => ({
// values,
// setFieldValue,
// ShowHint,
// t,
// }),
// [values, setFieldValue, ShowHint, t],
// );
const itemData = useMemo(
() => ({
values,
setFieldValue,
ShowHint,
t,
}),
[values, setFieldValue, ShowHint, t],
);
// useEffect(() => {
// if (listRef.current) {
// listRef.current.resetAfterIndex(0);
// }
// }, [questions, ShowHint]);
useEffect(() => {
if (listRef.current) {
listRef.current.resetAfterIndex(0);
}
}, [questions, ShowHint]);
const { moveItemDown , moveItemUp} = useReOrderQuestions()
return (
<>
@ -66,12 +73,25 @@ const Questions: React.FC<QuestionsProps> = React.memo(
{Question}
</List> */}
{questions?.map((item: any, index: number) => {
console.log(item)
console.log(questions)
return (
<Question
key={index}
<div
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}
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
View 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);