Merge branch 'dev' of into dev
This commit is contained in:
commit
c47b78df76
|
|
@ -5,6 +5,7 @@ import ImageIcon from "./ImageIcon";
|
||||||
import ImageCancelIcon from "./ImageCancelIcon";
|
import ImageCancelIcon from "./ImageCancelIcon";
|
||||||
import { getNestedValue } from "../../../utils/getNestedValue";
|
import { getNestedValue } from "../../../utils/getNestedValue";
|
||||||
import { generateImagePreview } from "./generateImagePreview";
|
import { generateImagePreview } from "./generateImagePreview";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
// Helper function to generate image preview from a File
|
// Helper function to generate image preview from a File
|
||||||
|
|
||||||
|
|
@ -13,7 +14,7 @@ const ImageBoxField = ({ name }: any) => {
|
||||||
const value = getNestedValue(formik?.values, name);
|
const value = getNestedValue(formik?.values, name);
|
||||||
const [imagePreview, setImagePreview] = useState<string | null>(null);
|
const [imagePreview, setImagePreview] = useState<string | null>(null);
|
||||||
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
||||||
|
const [t] = useTranslation()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (value instanceof File) {
|
if (value instanceof File) {
|
||||||
generateImagePreview(value, setImagePreview);
|
generateImagePreview(value, setImagePreview);
|
||||||
|
|
@ -26,6 +27,19 @@ const ImageBoxField = ({ name }: any) => {
|
||||||
|
|
||||||
const handleFileChange = (event: any) => {
|
const handleFileChange = (event: any) => {
|
||||||
const file = event.target.files[0];
|
const file = event.target.files[0];
|
||||||
|
if (file) {
|
||||||
|
const maxSize = 2 * 1024 * 1024;
|
||||||
|
|
||||||
|
if (file.size > maxSize) {
|
||||||
|
alert(t('validation.File_size_exceeds_2_MB_limit.'));
|
||||||
|
event.target.value = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the file
|
||||||
|
console.log('File selected:', file);
|
||||||
|
}
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
generateImagePreview(file, setImagePreview);
|
generateImagePreview(file, setImagePreview);
|
||||||
formik.setFieldValue(name, file);
|
formik.setFieldValue(name, file);
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,62 @@
|
||||||
import React from "react";
|
import React, { useCallback, useState } from "react";
|
||||||
|
import '../styles/index.scss';
|
||||||
|
import CustomInput from "../design-system/CustomInput";
|
||||||
|
import { Button } from "antd";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
interface IFilterBody {
|
interface IFilterBody {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useFilter = () => {
|
const useFilter = () => {
|
||||||
const FilterButton = () => {
|
const [isBodyVisible, setIsBodyVisible] = useState(true);
|
||||||
return <div>FilterButton</div>;
|
|
||||||
|
const toggleBodyVisibility = () => {
|
||||||
|
setIsBodyVisible((prev) => !prev);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const FilterButton = () => {
|
||||||
|
return (
|
||||||
|
<button onClick={toggleBodyVisibility}>
|
||||||
|
{isBodyVisible ? "Hide Filter" : "Show Filter"}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const FilterBody = ({ children }: IFilterBody) => {
|
const FilterBody = ({ children }: IFilterBody) => {
|
||||||
return <div>FilterBody</div>;
|
const [values, setValues] = useState({ name1: '', name2: '' });
|
||||||
|
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const { name, value } = e.target;
|
||||||
|
setValues((prev) => ({ ...prev, [name]: value }));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleSubmit = (event:React.FormEvent<HTMLFormElement>) => {
|
||||||
|
event.preventDefault();
|
||||||
|
console.log(values,"values");
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const [t] = useTranslation()
|
||||||
|
return (
|
||||||
|
<div className={`filter_body ${isBodyVisible ? 'visible' : 'hidden'}`}>
|
||||||
|
<form onSubmit={handleSubmit} >
|
||||||
|
{children}
|
||||||
|
<CustomInput
|
||||||
|
name="name1"
|
||||||
|
value={values.name1}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<CustomInput
|
||||||
|
name="name2"
|
||||||
|
value={values.name2}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<Button block htmlType="submit" type="primary" > {t("practical.submit")} </Button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
22
src/Components/FilterField/design-system/CustomInput.tsx
Normal file
22
src/Components/FilterField/design-system/CustomInput.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Input } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface CustomInputProps {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CustomInput: React.FC<CustomInputProps> = React.memo(({ name, value, onChange }) => {
|
||||||
|
console.log(`Rendering ${name}`); // For debugging purposes
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
name={name}
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default CustomInput;
|
||||||
33
src/Components/FilterField/styles/index.scss
Normal file
33
src/Components/FilterField/styles/index.scss
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
.filter_body {
|
||||||
|
max-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: max-height 0.3s ease-out, opacity 0.3s ease-out, transform 0.3s ease-out;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-20px);
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 20px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter_body.visible {
|
||||||
|
max-height: 200px;
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter_body.hidden {
|
||||||
|
max-height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.DummyHomePage {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 40px;
|
||||||
|
width: 70%;
|
||||||
|
padding: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -37,19 +37,14 @@ interface FormikFormProps extends Omit<FormikConfig<any>, OmitFormikProps> {
|
||||||
setIsOpen: any;
|
setIsOpen: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SubmitButtonProps extends Omit<ButtonProps, "loading"> {}
|
|
||||||
|
|
||||||
const useFilter = () => {
|
const useFilter = () => {
|
||||||
const { setIsOpen, isOpen } = useModalState((state) => state);
|
const { setIsOpen, isOpen } = useModalState((state) => state);
|
||||||
const { filterState, setFilterState, clearFilterState } = useFilterState();
|
const { filterState, setFilterState, clearFilterState } = useFilterState();
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const [formValues, setFormValues] = useState({});
|
const [formValues, setFormValues] = useState({});
|
||||||
const formik = useFormikContext();
|
|
||||||
// Define the type for the callback
|
// Define the type for the callback
|
||||||
type SubmitCallback = () => void;
|
type SubmitCallback = () => void;
|
||||||
// console.log(formik?.values);
|
|
||||||
// console.log(InitialValue);
|
|
||||||
|
|
||||||
const FilterButton = () => {
|
const FilterButton = () => {
|
||||||
const handleState = () => {
|
const handleState = () => {
|
||||||
if (isOpen === ModalEnum?.FILTER) {
|
if (isOpen === ModalEnum?.FILTER) {
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,18 @@ const File = ({
|
||||||
const customRequest = async ({ onSuccess, no_label, label_icon }: any) => {
|
const customRequest = async ({ onSuccess, no_label, label_icon }: any) => {
|
||||||
onSuccess();
|
onSuccess();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const beforeUpload = (file: File) => {
|
||||||
|
const maxSize = 2 * 1024 * 1024; // 2 MB in bytes
|
||||||
|
|
||||||
|
if (file.size > maxSize) {
|
||||||
|
alert(t('validation.File_size_exceeds_2_MB_limit.'));
|
||||||
|
return Upload.LIST_IGNORE; // Prevent the file from being uploaded
|
||||||
|
}
|
||||||
|
return true; // Allow the file to be uploaded
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`ValidationField upload_image_button ${className ?? ""} `}>
|
<div className={`ValidationField upload_image_button ${className ?? ""} `}>
|
||||||
<label htmlFor={name} className="text">
|
<label htmlFor={name} className="text">
|
||||||
|
|
@ -55,6 +67,7 @@ const File = ({
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<Upload
|
<Upload
|
||||||
|
beforeUpload={beforeUpload} // Set the beforeUpload function
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
listType="picture"
|
listType="picture"
|
||||||
maxCount={1}
|
maxCount={1}
|
||||||
|
|
@ -63,6 +76,7 @@ const File = ({
|
||||||
customRequest={customRequest}
|
customRequest={customRequest}
|
||||||
className={` w-100`}
|
className={` w-100`}
|
||||||
id={name}
|
id={name}
|
||||||
|
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
className={isError ? "isError w-100 " : " w-100"}
|
className={isError ? "isError w-100 " : " w-100"}
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,6 @@ const DeleteModels: React.FC<ModalFormProps> = ({
|
||||||
|
|
||||||
const { mutate, isLoading, isSuccess } = deleteMutation;
|
const { mutate, isLoading, isSuccess } = deleteMutation;
|
||||||
const { objectToEdit, setObjectToEdit } = useObjectToEdit();
|
const { objectToEdit, setObjectToEdit } = useObjectToEdit();
|
||||||
console.log(objectToEdit?.key);
|
|
||||||
console.log(inputValue);
|
|
||||||
|
|
||||||
const iaDisabled = idVerify
|
const iaDisabled = idVerify
|
||||||
? Number(objectToEdit?.id) !== Number(inputValue) || isLoading
|
? Number(objectToEdit?.id) !== Number(inputValue) || isLoading
|
||||||
|
|
|
||||||
|
|
@ -15,16 +15,20 @@ import {
|
||||||
import ActionButtons from "../../../Components/Table/ActionButtons";
|
import ActionButtons from "../../../Components/Table/ActionButtons";
|
||||||
import ColumnsImage from "../../../Components/Columns/ColumnsImage";
|
import ColumnsImage from "../../../Components/Columns/ColumnsImage";
|
||||||
import { Grade } from "../../../types/Grade";
|
import { Grade } from "../../../types/Grade";
|
||||||
import { CiImageOff } from "react-icons/ci";
|
import { useFilterState } from "../../../Components/Utils/Filter/FilterState";
|
||||||
import { isValidImage } from "../../../utils/isValidImage";
|
import { useFilterStateState } from "../../../zustand/Filter";
|
||||||
|
|
||||||
export const useColumns = () => {
|
export const useColumns = () => {
|
||||||
const { handel_open_model } = useModalHandler();
|
const { handel_open_model } = useModalHandler();
|
||||||
|
|
||||||
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { setFilter } = useFilterStateState();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handelShow = (record: Grade) => {
|
const handelShow = (record: Grade) => {
|
||||||
|
setFilter({})
|
||||||
navigate(`${record?.id}`);
|
navigate(`${record?.id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,13 @@ import {
|
||||||
canEditQuestion,
|
canEditQuestion,
|
||||||
} from "../../../utils/hasAbilityFn";
|
} from "../../../utils/hasAbilityFn";
|
||||||
import ActionButtons from "../../../Components/Table/ActionButtons";
|
import ActionButtons from "../../../Components/Table/ActionButtons";
|
||||||
|
import { useFilterStateState } from "../../../zustand/Filter";
|
||||||
|
|
||||||
export const useColumns = () => {
|
export const useColumns = () => {
|
||||||
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { setIsOpen } = useModalState((state) => state);
|
const { setIsOpen } = useModalState((state) => state);
|
||||||
|
const { setFilter } = useFilterStateState();
|
||||||
|
|
||||||
const handelDelete = (data: any) => {
|
const handelDelete = (data: any) => {
|
||||||
setObjectToEdit(data);
|
setObjectToEdit(data);
|
||||||
|
|
@ -28,6 +30,8 @@ export const useColumns = () => {
|
||||||
const unit = lesson?.unit;
|
const unit = lesson?.unit;
|
||||||
const subject = unit?.subject;
|
const subject = unit?.subject;
|
||||||
const grade = subject?.grade;
|
const grade = subject?.grade;
|
||||||
|
|
||||||
|
setFilter({})
|
||||||
navigate(`/${ABILITIES_ENUM?.GRADE}/${grade?.id}/${ABILITIES_ENUM?.SUBJECT}/${subject?.id}/${ABILITIES_ENUM?.UNIT}/${unit?.id}/${ABILITIES_ENUM?.LESSON}/${lesson?.id}/${ABILITIES_ENUM?.QUESTION}/${record?.id}`);
|
navigate(`/${ABILITIES_ENUM?.GRADE}/${grade?.id}/${ABILITIES_ENUM?.SUBJECT}/${subject?.id}/${ABILITIES_ENUM?.UNIT}/${unit?.id}/${ABILITIES_ENUM?.LESSON}/${lesson?.id}/${ABILITIES_ENUM?.QUESTION}/${record?.id}`);
|
||||||
};
|
};
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,18 @@ import ActionButtons from "../../../Components/Table/ActionButtons";
|
||||||
import { Unit } from "../../../types/Unit";
|
import { Unit } from "../../../types/Unit";
|
||||||
import { ConvertEnumToTranslate } from "../../../utils/ConvertEnumToTranslate";
|
import { ConvertEnumToTranslate } from "../../../utils/ConvertEnumToTranslate";
|
||||||
import { DragHandleUnit } from "./DrapableTable";
|
import { DragHandleUnit } from "./DrapableTable";
|
||||||
|
import { useFilterState } from "../../../Components/Utils/Filter/FilterState";
|
||||||
|
import { useFilterStateState } from "../../../zustand/Filter";
|
||||||
|
|
||||||
export const useColumns = () => {
|
export const useColumns = () => {
|
||||||
const { handel_open_model } = useModalHandler();
|
const { handel_open_model } = useModalHandler();
|
||||||
|
const { setFilter } = useFilterStateState();
|
||||||
|
|
||||||
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const handelShow = (record: Unit) => {
|
const handelShow = (record: Unit) => {
|
||||||
|
setFilter({})
|
||||||
navigate(`${ABILITIES_ENUM?.UNIT}/${record?.id}`);
|
navigate(`${ABILITIES_ENUM?.UNIT}/${record?.id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,18 @@ import {
|
||||||
} from "../../../utils/hasAbilityFn";
|
} from "../../../utils/hasAbilityFn";
|
||||||
import ActionButtons from "../../../Components/Table/ActionButtons";
|
import ActionButtons from "../../../Components/Table/ActionButtons";
|
||||||
import { DragHandleLesson } from "./DrapableTable";
|
import { DragHandleLesson } from "./DrapableTable";
|
||||||
|
import { useFilterState } from "../../../Components/Utils/Filter/FilterState";
|
||||||
|
import { useFilterStateState } from "../../../zustand/Filter";
|
||||||
|
|
||||||
export const useColumns = () => {
|
export const useColumns = () => {
|
||||||
const { handel_open_model } = useModalHandler();
|
const { handel_open_model } = useModalHandler();
|
||||||
|
|
||||||
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { setFilter } = useFilterStateState();
|
||||||
|
|
||||||
const handelShow = (record: any) => {
|
const handelShow = (record: any) => {
|
||||||
|
setFilter({})
|
||||||
navigate(`${ABILITIES_ENUM.LESSON}/${record?.id}`);
|
navigate(`${ABILITIES_ENUM.LESSON}/${record?.id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ const AddPage: React.FC = () => {
|
||||||
|
|
||||||
const { mutateAsync,isLoading:LoadingAsync } = useAddQuestionAsync();
|
const { mutateAsync,isLoading:LoadingAsync } = useAddQuestionAsync();
|
||||||
const { mutate, isLoading, isSuccess } = useAddQuestion();
|
const { mutate, isLoading, isSuccess } = useAddQuestion();
|
||||||
const { isBseQuestion, setTagsSearch, objectToEdit, setSuccess } =
|
const { isBseQuestion, setTagsSearch, setSuccess } =
|
||||||
useObjectToEdit();
|
useObjectToEdit();
|
||||||
|
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
|
|
@ -35,7 +35,6 @@ const AddPage: React.FC = () => {
|
||||||
const handleSubmit = ( values: any) => {
|
const handleSubmit = ( values: any) => {
|
||||||
const DataToSend = structuredClone(values);
|
const DataToSend = structuredClone(values);
|
||||||
setTagsSearch(null);
|
setTagsSearch(null);
|
||||||
console.log(1);
|
|
||||||
|
|
||||||
const canAnswersBeShuffled = DataToSend?.canAnswersBeShuffled ? 1 : 0;
|
const canAnswersBeShuffled = DataToSend?.canAnswersBeShuffled ? 1 : 0;
|
||||||
|
|
||||||
|
|
@ -64,12 +63,7 @@ const AddPage: React.FC = () => {
|
||||||
...item,
|
...item,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
console.log(answers);
|
|
||||||
if (answers?.length > 0) {
|
|
||||||
const isValidAnswers = answers?.some(
|
|
||||||
(answer: any) => answer?.isCorrect === 1,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
mutate({
|
mutate({
|
||||||
...item,
|
...item,
|
||||||
parent_id: newBseQuestionId,
|
parent_id: newBseQuestionId,
|
||||||
|
|
@ -82,8 +76,6 @@ const AddPage: React.FC = () => {
|
||||||
console.log(newBseQuestionId, "newBseQuestionId");
|
console.log(newBseQuestionId, "newBseQuestionId");
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log(1);
|
|
||||||
|
|
||||||
const tags = processTags(DataToSend);
|
const tags = processTags(DataToSend);
|
||||||
const answers = values?.answers?.map((item: any, index: number) => {
|
const answers = values?.answers?.map((item: any, index: number) => {
|
||||||
return {
|
return {
|
||||||
|
|
@ -112,6 +104,8 @@ const AddPage: React.FC = () => {
|
||||||
const handleValidateSingleQuestion = (values:any)=>{
|
const handleValidateSingleQuestion = (values:any)=>{
|
||||||
const haveMoreThanOneAnswer = values?.answers?.length > 1;
|
const haveMoreThanOneAnswer = values?.answers?.length > 1;
|
||||||
const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true )
|
const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true )
|
||||||
|
const haveImageOrContent = haveOneAnswerRight && values?.answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
||||||
|
|
||||||
if(!haveMoreThanOneAnswer){
|
if(!haveMoreThanOneAnswer){
|
||||||
toast.error(t("validation.it_should_have_more_than_one_answers")) ;
|
toast.error(t("validation.it_should_have_more_than_one_answers")) ;
|
||||||
return false ;
|
return false ;
|
||||||
|
|
@ -120,6 +114,10 @@ const AddPage: React.FC = () => {
|
||||||
toast.error(t("validation.it_should_have_more_than_one_correct_answers")) ;
|
toast.error(t("validation.it_should_have_more_than_one_correct_answers")) ;
|
||||||
return false ;
|
return false ;
|
||||||
}
|
}
|
||||||
|
if(haveImageOrContent){
|
||||||
|
toast.error("validation.one_of_image_and_content_should_be_enter")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,9 +126,9 @@ const AddPage: React.FC = () => {
|
||||||
const answers = Question?.answers;
|
const answers = Question?.answers;
|
||||||
const haveAnswers = answers?.length > 0;
|
const haveAnswers = answers?.length > 0;
|
||||||
const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1;
|
const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1;
|
||||||
const haveOneAnswerRight =
|
const haveOneAnswerRight = haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true);
|
||||||
haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true);
|
const haveImageOrContent = haveOneAnswerRight && values?.answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
||||||
|
|
||||||
if (!haveAnswers) {
|
if (!haveAnswers) {
|
||||||
toast.error(t("validation.it_should_have_more_than_one_answers"));
|
toast.error(t("validation.it_should_have_more_than_one_answers"));
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -145,6 +143,11 @@ const AddPage: React.FC = () => {
|
||||||
toast.error(t("validation.it_should_have_more_than_one_correct_answers"));
|
toast.error(t("validation.it_should_have_more_than_one_correct_answers"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(haveImageOrContent){
|
||||||
|
toast.error("validation.one_of_image_and_content_should_be_enter")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import CheckboxField from "./CheckboxField";
|
||||||
import TextField from "./TextField";
|
import TextField from "./TextField";
|
||||||
import ImageBoxField from "../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
import ImageBoxField from "../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
||||||
import { GoTrash } from "react-icons/go";
|
import { GoTrash } from "react-icons/go";
|
||||||
|
import { Popconfirm } from "antd";
|
||||||
|
|
||||||
const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
|
const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
|
||||||
const formik = useFormikContext<any>();
|
const formik = useFormikContext<any>();
|
||||||
|
|
@ -51,7 +52,16 @@ const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
|
||||||
name={index}
|
name={index}
|
||||||
type="Checkbox"
|
type="Checkbox"
|
||||||
/>
|
/>
|
||||||
<p className="delete_question_options" onClick={handleDeleteChoice}>
|
|
||||||
|
<Popconfirm
|
||||||
|
title={t("header.this_will_un_do_all_your_changes")}
|
||||||
|
okText={t("practical.yes")}
|
||||||
|
cancelText={t("practical.no")}
|
||||||
|
onConfirm={()=>{handleDeleteChoice()}}
|
||||||
|
defaultOpen={false}
|
||||||
|
|
||||||
|
>
|
||||||
|
<p className="delete_question_options">
|
||||||
{t("header.delete_choice")}
|
{t("header.delete_choice")}
|
||||||
<GoTrash
|
<GoTrash
|
||||||
className="trash_icon"
|
className="trash_icon"
|
||||||
|
|
@ -59,6 +69,10 @@ const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
|
||||||
size={17}
|
size={17}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
</Popconfirm>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="exercise_form_width">
|
<div className="exercise_form_width">
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import TextField from "./TextField";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
||||||
import { GoTrash } from "react-icons/go";
|
import { GoTrash } from "react-icons/go";
|
||||||
|
import { Popconfirm } from "antd";
|
||||||
|
|
||||||
const ChoiceFields = ({
|
const ChoiceFields = ({
|
||||||
index,
|
index,
|
||||||
|
|
@ -69,7 +70,16 @@ const ChoiceFields = ({
|
||||||
type="Checkbox"
|
type="Checkbox"
|
||||||
parent_index={parent_index}
|
parent_index={parent_index}
|
||||||
/>
|
/>
|
||||||
<p className="delete_question_options" onClick={handleDeleteChoice}>
|
|
||||||
|
<Popconfirm
|
||||||
|
title={t("header.this_will_un_do_all_your_changes")}
|
||||||
|
okText={t("practical.yes")}
|
||||||
|
cancelText={t("practical.no")}
|
||||||
|
onConfirm={()=>{handleDeleteChoice()}}
|
||||||
|
defaultOpen={false}
|
||||||
|
|
||||||
|
>
|
||||||
|
<p className="delete_question_options" >
|
||||||
{t("header.delete_choice")}
|
{t("header.delete_choice")}
|
||||||
<GoTrash
|
<GoTrash
|
||||||
className="trash_icon"
|
className="trash_icon"
|
||||||
|
|
@ -77,6 +87,8 @@ const ChoiceFields = ({
|
||||||
size={17}
|
size={17}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
</Popconfirm>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import TextField from "./TextField";
|
||||||
import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState";
|
||||||
import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
||||||
import { GoTrash } from "react-icons/go";
|
import { GoTrash } from "react-icons/go";
|
||||||
|
import { Popconfirm } from "antd";
|
||||||
|
|
||||||
const QuestionFIeld = ({ index, data }: { index: number; data: Choice }) => {
|
const QuestionFIeld = ({ index, data }: { index: number; data: Choice }) => {
|
||||||
const formik = useFormikContext<any>();
|
const formik = useFormikContext<any>();
|
||||||
|
|
@ -47,7 +48,15 @@ const QuestionFIeld = ({ index, data }: { index: number; data: Choice }) => {
|
||||||
|
|
||||||
<ImageBoxField name={`Questions.${index}.content_image`} />
|
<ImageBoxField name={`Questions.${index}.content_image`} />
|
||||||
|
|
||||||
<div className="answer_status" onClick={handleDeleteQuestion}>
|
<div className="answer_status" >
|
||||||
|
<Popconfirm
|
||||||
|
title={t("header.this_will_un_do_all_your_changes")}
|
||||||
|
okText={t("practical.yes")}
|
||||||
|
cancelText={t("practical.no")}
|
||||||
|
onConfirm={()=>{handleDeleteQuestion()}}
|
||||||
|
defaultOpen={false}
|
||||||
|
|
||||||
|
>
|
||||||
<p className="delete_question_options">
|
<p className="delete_question_options">
|
||||||
{t("header.delete_question")}
|
{t("header.delete_question")}
|
||||||
<GoTrash
|
<GoTrash
|
||||||
|
|
@ -56,7 +65,10 @@ const QuestionFIeld = ({ index, data }: { index: number; data: Choice }) => {
|
||||||
size={17}
|
size={17}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
</Popconfirm>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,10 @@ export const getValidationSchema = () => {
|
||||||
// validate input
|
// validate input
|
||||||
return Yup.object().shape({
|
return Yup.object().shape({
|
||||||
content_image: Yup.string().nullable(),
|
content_image: Yup.string().nullable(),
|
||||||
content: Yup.string().required("validation.required"),
|
content: Yup.string().required("validation.required").nullable(),
|
||||||
answers: Yup.array().of(
|
answers: Yup.array().of(
|
||||||
Yup.object().shape({
|
Yup.object().shape({
|
||||||
content: Yup.string().required("validation.required"),
|
content: Yup.string().nullable(),
|
||||||
content_image: Yup.string().nullable(),
|
content_image: Yup.string().nullable(),
|
||||||
isCorrect: Yup.boolean(),
|
isCorrect: Yup.boolean(),
|
||||||
}),
|
}),
|
||||||
|
|
@ -36,10 +36,12 @@ export const getValidationSchema = () => {
|
||||||
"at-least-one-correct",
|
"at-least-one-correct",
|
||||||
"At least one answer must be correct",
|
"At least one answer must be correct",
|
||||||
(answers: any) => {
|
(answers: any) => {
|
||||||
return answers?.some(
|
|
||||||
(answer: any) =>
|
const hasCorrectAnswer = answers?.some((answer:any) => answer?.isCorrect === true || answer?.isCorrect === 1);
|
||||||
answer?.isCorrect === true || answer?.isCorrect === 1,
|
|
||||||
);
|
const haveImageOrContent = answers?.some((item:any)=> !(item?.content) && !(item.content_image));
|
||||||
|
|
||||||
|
return hasCorrectAnswer && !haveImageOrContent ;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
@ -106,11 +108,12 @@ export const getValidationSchemaBase = () => {
|
||||||
"at-least-one-correct",
|
"at-least-one-correct",
|
||||||
"At least one answer must be correct",
|
"At least one answer must be correct",
|
||||||
(answers: any) => {
|
(answers: any) => {
|
||||||
|
|
||||||
return answers.some(
|
const hasCorrectAnswer = answers?.some((answer:any) => answer?.isCorrect === true || answer?.isCorrect === 1);
|
||||||
(answer: any) =>
|
|
||||||
answer.isCorrect === true || answer.isCorrect === 1,
|
const haveImageOrContent = answers?.some((item:any)=> !(item?.content) && !(item.content_image));
|
||||||
);
|
|
||||||
|
return hasCorrectAnswer && !haveImageOrContent ;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,13 @@ import {
|
||||||
} from "../../../../utils/hasAbilityFn";
|
} from "../../../../utils/hasAbilityFn";
|
||||||
import { ABILITIES_ENUM } from "../../../../enums/abilities";
|
import { ABILITIES_ENUM } from "../../../../enums/abilities";
|
||||||
import { Subject } from "../../../../types/Subject";
|
import { Subject } from "../../../../types/Subject";
|
||||||
import { CiImageOff } from "react-icons/ci";
|
import { useFilterStateState } from "../../../../zustand/Filter";
|
||||||
|
|
||||||
export const useColumns = () => {
|
export const useColumns = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||||
const { setIsOpen } = useModalState((state) => state);
|
const { setIsOpen } = useModalState((state) => state);
|
||||||
|
const { setFilter } = useFilterStateState();
|
||||||
|
|
||||||
const handelDelete = (record: Subject) => {
|
const handelDelete = (record: Subject) => {
|
||||||
setObjectToEdit(record);
|
setObjectToEdit(record);
|
||||||
|
|
@ -31,6 +32,7 @@ export const useColumns = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handelShow = (record: Subject) => {
|
const handelShow = (record: Subject) => {
|
||||||
|
setFilter({})
|
||||||
navigate(`${ABILITIES_ENUM?.SUBJECT}/${record?.id}`);
|
navigate(`${ABILITIES_ENUM?.SUBJECT}/${record?.id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ABILITIES_ENUM } from "../../enums/abilities";
|
|
||||||
import useSetPageTitle from "../../Hooks/useSetPageTitle";
|
|
||||||
import useFilter from "../../Components/FilterField/components/useFilter";
|
import useFilter from "../../Components/FilterField/components/useFilter";
|
||||||
import { Button, Popconfirm } from "antd";
|
|
||||||
import PageTitle from "../../Layout/Dashboard/PageTitle";
|
|
||||||
|
|
||||||
const Dummy = () => {
|
const Dummy = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
useSetPageTitle(`${t(ABILITIES_ENUM?.MAIN_PAGE)} / ${t("dashboard")}`);
|
|
||||||
const { FilterButton, FilterBody } = useFilter();
|
const { FilterButton, FilterBody } = useFilter();
|
||||||
return (
|
return (
|
||||||
<div className="DummyHomePage">
|
<div className="DummyHomePage">
|
||||||
<PageTitle/>
|
|
||||||
|
<FilterButton/>
|
||||||
|
<FilterBody>
|
||||||
|
karim
|
||||||
|
</FilterBody>
|
||||||
|
|
||||||
|
karim2
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|
||||||
background: var(--bgSideBar);
|
background: var(--bgSideBar);
|
||||||
color: var(--textSideBar);
|
color: var(--textSideBar);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -19,6 +20,12 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.side_bar_header {
|
.side_bar_header {
|
||||||
height: var(--navBarHeight);
|
height: var(--navBarHeight);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@
|
||||||
"Sorry, the question must have at least one option": "عذرًا، يجب أن يحتوي السؤال على خيار واحد على الأقل",
|
"Sorry, the question must have at least one option": "عذرًا، يجب أن يحتوي السؤال على خيار واحد على الأقل",
|
||||||
"at_least_one_answer_should_be_correct": "يجب أن تكون إجابة واحدة صحيحة",
|
"at_least_one_answer_should_be_correct": "يجب أن تكون إجابة واحدة صحيحة",
|
||||||
"it_should_have_more_than_one_answers": "يجب أن يحتوي على أكثر من إجابة",
|
"it_should_have_more_than_one_answers": "يجب أن يحتوي على أكثر من إجابة",
|
||||||
"it_should_have_more_than_one_correct_answers": "يجب أن يحتوي على إجابة صحيحة"
|
"it_should_have_more_than_one_correct_answers": "يجب أن يحتوي على إجابة صحيحة",
|
||||||
|
"File_size_exceeds_2_MB_limit.":"حجم الملف يتجاوز الحد الأقصى البالغ 2 ميجابايت"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"register_students": "تسجيل الطلاب",
|
"register_students": "تسجيل الطلاب",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user