This commit is contained in:
karimalden 2024-08-07 14:52:29 +03:00
parent a4c3459efa
commit b873ac0bba
123 changed files with 7400 additions and 4579 deletions

View File

@ -5,18 +5,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" sizes="180x180" href="/App/Logo.png" />
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/App/Logo.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/App/Logo.png"
/>
<link rel="icon" type="image/png" sizes="32x32" href="/App/Logo.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/App/Logo.png" />
<link rel="manifest" href="/site.webmanifest" />
<meta
name="description"

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -17,7 +17,7 @@ const App = () => {
const { changeLanguage } = useChangeLanguage();
const navigate = useNavigate();
const { isAuthenticated } = useAuthState();
const [t] = useTranslation()
const [t] = useTranslation();
useEffect(() => {
if (!isAuthenticated) {
@ -26,7 +26,14 @@ const App = () => {
}, [isAuthenticated, navigate]);
const renderRouteElement = (route: any) => (
<Suspense fallback={<Layout> <SpinContainer/> </Layout>}>
<Suspense
fallback={
<Layout>
{" "}
<SpinContainer />{" "}
</Layout>
}
>
{route.header ? (
<Layout>{route.element}</Layout>
) : (

View File

@ -1,11 +1,11 @@
import { Spin } from 'antd'
import { Spin } from "antd";
const SpinContainer = () => {
return (
<div className='SpinContainer'>
<div className="SpinContainer">
<Spin />
</div>
)
}
);
};
export default SpinContainer
export default SpinContainer;

View File

@ -1,11 +1,11 @@
import { DatePicker } from 'antd'
import React from 'react'
import { useTranslation } from 'react-i18next';
import { useObjectToEdit } from '../../../zustand/ObjectToEditState';
import { useLocation, useNavigate } from 'react-router-dom';
import { DatePicker } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
import { useLocation, useNavigate } from "react-router-dom";
import type { DatePickerProps } from "antd";
import dayjs from "dayjs";
import { DateEnum } from '../../../enums/Date';
import { DateEnum } from "../../../enums/Date";
const CustomDatePicker = () => {
const [t] = useTranslation();
@ -24,7 +24,6 @@ const CustomDatePicker = () => {
};
const Today = new Date() as any;
return (
<div className="CustomDatePicker">
<DatePicker
@ -34,7 +33,7 @@ const CustomDatePicker = () => {
format={DateEnum?.FORMATE}
/>
</div>
)
}
);
};
export default CustomDatePicker
export default CustomDatePicker;

View File

@ -31,7 +31,7 @@ const components: { [key: string]: React.FC<any> } = {
MaltyFile: MaltyFile,
Checkbox: CheckboxField,
NumberFormate: NumberFormate,
Number:NumberField
Number: NumberField,
};
const ValidationField: React.FC<ValidationFieldProps> = React.memo(

View File

@ -1,7 +1,7 @@
import React from "react";
import useFormField from "../../../Hooks/useFormField";
import { Checkbox, Form } from "antd";
import {getNestedValue} from '../utils/getNestedValue'
import { getNestedValue } from "../utils/getNestedValue";
const CheckboxField = ({
name,
label,

View File

@ -25,9 +25,7 @@ const Default = ({
<label htmlFor={name} className="text">
{label2}
</label>
)
:no_label ? (
) : no_label ? (
<label htmlFor={name} className="text">
<span>empty</span>
</label>
@ -58,7 +56,6 @@ const Default = ({
name={name}
disabled={isDisabled}
size="large"
{...(type === "number" && { min: 0 })}
{...props}
/>

View File

@ -15,24 +15,24 @@ const File = ({
const { formik, t, isError, errorMsg } = useFormField(name, props);
let imageUrl = formik?.values?.[name] ?? null;
console.log(imageUrl);
console.log(typeof imageUrl === 'string');
console.log(typeof imageUrl === "string");
const fileList: UploadFile[] = useMemo(() => {
if (!imageUrl) return [];
return [
typeof imageUrl === 'string'
typeof imageUrl === "string"
? {
uid: '-1',
name: 'uploaded-image',
status: 'done',
uid: "-1",
name: "uploaded-image",
status: "done",
url: imageUrl,
thumbUrl: imageUrl,
}
: {
uid: imageUrl.uid || '-1',
name: imageUrl.name || 'uploaded-image',
status: 'done',
uid: imageUrl.uid || "-1",
name: imageUrl.name || "uploaded-image",
status: "done",
originFileObj: imageUrl,
},
];
@ -70,7 +70,6 @@ const File = ({
icon={<UploadOutlined />}
>
{placholder ?? t("input.Click_to_upload_the_image")}
</Button>
<div className="Error_color"> {isError ? "required" : ""}</div>
{errorMsg}

View File

@ -21,7 +21,7 @@ const NumberField = ({
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
console.log('Change:', e);
console.log("Change:", e);
formik.setFieldValue(name, e);
};

View File

@ -64,7 +64,6 @@ const NumberFormate = ({
disabled={isDisabled}
size="large"
// onChange={onChange ? onChange : handleChange}
/>
</Form.Item>

View File

@ -17,7 +17,7 @@ const SearchField = ({
props,
no_label,
label_icon,
isLoading
isLoading,
}: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
const [searchQuery, setSearchQuery] = useState<string>("");
@ -79,7 +79,6 @@ const SearchField = ({
showSearch
optionFilterProp="label"
notFoundContent={isLoading ? <Spin /> : "لا يوجد"}
onSearch={SearchHandleChange}
/>
</Form.Item>

View File

@ -15,7 +15,7 @@ const TextField = ({
props,
no_label,
label_icon,
className
className,
}: any) => {
const { formik, isError, errorMsg, t } = useFormField(name, props);
const TextFilehandleChange = (
@ -58,8 +58,6 @@ const TextField = ({
maxLength={1000}
onChange={onChange || TextFilehandleChange}
style={{ height: 120 }}
/>
</Form.Item>
</div>

View File

@ -62,7 +62,6 @@
}
.Checkboxs {
padding: 4%;
}
.ant-checkbox-wrapper {
min-width: 100px;
@ -203,7 +202,6 @@ input:-webkit-autofill:hover {
margin-bottom: 20px;
}
.ant-checkbox-wrapper {
margin-top: 25px !important;
}

View File

@ -1,9 +1,7 @@
export function getNestedValue(obj: any, path: any) {
return path
.replace(/\?.\[|\]\[|\]\.?/g, '.') // Replace question mark and square brackets
.split('.') // Split by dots
.replace(/\?.\[|\]\[|\]\.?/g, ".") // Replace question mark and square brackets
.split(".") // Split by dots
.filter(Boolean) // Remove empty strings
.reduce((acc: any, key: any) => acc && acc[key], obj); // Access nested properties
}

View File

@ -73,7 +73,7 @@ export interface ValidationFieldPropsSearch {
option: any[];
isMulti?: boolean;
searchBy: string;
isLoading?:any
isLoading?: any;
}
export interface ValidationFieldPropsDataRange {
name: string;
@ -161,31 +161,26 @@ export interface ValidationFieldPropstext {
[key: string]: any; // Index signature to allow any additional props
}
///// new
export interface BaseField {
name: string;
label?: string;
placeholder?: string;
}
export type OmitBaseType = 'placeholder' | 'name' | 'label' | 'type';
export type OmitBaseType = "placeholder" | "name" | "label" | "type";
export type OmitPicker = OmitBaseType | 'format';
export type OmitPicker = OmitBaseType | "format";
export interface ValidationFieldPropsInput
extends Omit<InputProps, OmitBaseType>,
BaseField {
type: 'text' | 'number' | 'password' | 'email' | "Number";
isDisabled?:boolean
no_label?:string
label_icon?:string
label2?:string
type: "text" | "number" | "password" | "email" | "Number";
isDisabled?: boolean;
no_label?: string;
label_icon?: string;
label2?: string;
}
export type ValidationFieldProps =
| ValidationFieldPropsInput
| ValidationFieldPropsSelect

View File

@ -1,28 +1,26 @@
import { useFormikContext } from 'formik';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { GoArrowSwitch } from 'react-icons/go';
import { useObjectToEdit } from '../../zustand/ObjectToEditState';
import { QUESTION_OBJECT_KEY } from '../../config/AppKey';
import { useFormikContext } from "formik";
import React from "react";
import { useTranslation } from "react-i18next";
import { GoArrowSwitch } from "react-icons/go";
import { useObjectToEdit } from "../../zustand/ObjectToEditState";
import { QUESTION_OBJECT_KEY } from "../../config/AppKey";
const Header = () => {
const [t] = useTranslation();
const { values, setFieldValue, setValues } = useFormikContext<any>();
const {isBseQuestion,setIsBseQuestion} = useObjectToEdit()
const {setSavedQuestionData} = useObjectToEdit()
const { isBseQuestion, setIsBseQuestion } = useObjectToEdit();
const { setSavedQuestionData } = useObjectToEdit();
const handleChange = () => {
setSavedQuestionData(null)
localStorage.removeItem(QUESTION_OBJECT_KEY)
setSavedQuestionData(null);
localStorage.removeItem(QUESTION_OBJECT_KEY);
if (isBseQuestion) {
setIsBseQuestion(false)
setValues(null)
setFieldValue("isBase",0)
setIsBseQuestion(false);
setValues(null);
setFieldValue("isBase", 0);
} else {
setIsBseQuestion(true)
setValues(null)
setFieldValue("isBase",1)
setIsBseQuestion(true);
setValues(null);
setFieldValue("isBase", 1);
}
};
@ -33,7 +31,9 @@ const Header = () => {
</div>
<div>
<GoArrowSwitch onClick={handleChange} className="m-2" />
{isBseQuestion || values?.isBase === 1 ? t("header.malty_exercise") :t("header.exercise") }
{isBseQuestion || values?.isBase === 1
? t("header.malty_exercise")
: t("header.exercise")}
</div>
</header>
);

View File

@ -1,4 +1,3 @@
export const useAddKeyToData = (dataSource: any, identifier = "id") => {
if (!dataSource || !Array.isArray(dataSource)) {
return [];

View File

@ -1,8 +1,12 @@
import { useEffect } from 'react';
import { useEffect } from "react";
type ModifierKey = 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey';
type ModifierKey = "ctrlKey" | "shiftKey" | "altKey" | "metaKey";
const useKeyPress = (targetKey: string, modifierKey: ModifierKey, callback:any) => {
const useKeyPress = (
targetKey: string,
modifierKey: ModifierKey,
callback: any,
) => {
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event[modifierKey] && event.key === targetKey) {
@ -11,10 +15,10 @@ const useKeyPress = (targetKey: string, modifierKey: ModifierKey, callback:any)
}
};
document.addEventListener('keydown', handleKeyDown);
document.addEventListener("keydown", handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
document.removeEventListener("keydown", handleKeyDown);
};
}, [targetKey, modifierKey, callback]);
};

View File

@ -1,16 +1,18 @@
import { useEffect } from 'react';
import { setLocalStorageQuestions } from '../utils/setLocalStorageQuestions';
import { useEffect } from "react";
import { setLocalStorageQuestions } from "../utils/setLocalStorageQuestions";
const useSaveOnDisconnect = (noChange: boolean, QUESTION_OBJECT_KEY: string, SavedQuestionData: any) => {
const useSaveOnDisconnect = (
noChange: boolean,
QUESTION_OBJECT_KEY: string,
SavedQuestionData: any,
) => {
useEffect(() => {
const handleBeforeUnload = (event: BeforeUnloadEvent) => {
console.log("disconnect");
if (noChange) {
if (SavedQuestionData?.isBase === 1) {
setLocalStorageQuestions(QUESTION_OBJECT_KEY, SavedQuestionData);
} else {
setLocalStorageQuestions(QUESTION_OBJECT_KEY, SavedQuestionData);
}
}
@ -21,22 +23,20 @@ const useSaveOnDisconnect = (noChange: boolean, QUESTION_OBJECT_KEY: string, Sav
if (noChange) {
if (SavedQuestionData?.isBase === 1) {
setLocalStorageQuestions(QUESTION_OBJECT_KEY, SavedQuestionData);
} else {
setLocalStorageQuestions(QUESTION_OBJECT_KEY, SavedQuestionData);
}
}
};
// Add event listeners
window.addEventListener('beforeunload', handleBeforeUnload);
window.addEventListener('offline', handleOffline);
window.addEventListener("beforeunload", handleBeforeUnload);
window.addEventListener("offline", handleOffline);
// Cleanup function
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
window.removeEventListener('offline', handleOffline);
window.removeEventListener("beforeunload", handleBeforeUnload);
window.removeEventListener("offline", handleOffline);
};
}, [noChange, QUESTION_OBJECT_KEY, SavedQuestionData]); // Add dependencies to the hook
};

View File

@ -30,7 +30,6 @@ const FormikFormModel: React.FC<FormikFormProps> = ({
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{(formik) => {
useEffect(() => {
@ -43,7 +42,6 @@ const FormikFormModel: React.FC<FormikFormProps> = ({
}
}, [isOpen]);
return <Form className="w-100">{children}</Form>;
}}
</Formik>

View File

@ -6,7 +6,6 @@ import { useTranslation } from "react-i18next";
import { ABILITIES_ENUM, ABILITIES_VALUES_ENUM } from "../../enums/abilities";
import { hasAbility } from "../../utils/hasAbility";
export {
SearchField,
useModalHandler,
@ -14,5 +13,5 @@ ModalEnum,
useTranslation,
ABILITIES_ENUM,
ABILITIES_VALUES_ENUM,
hasAbility
hasAbility,
};

View File

@ -80,7 +80,8 @@ const SideBar = () => {
<div className="side_bar">
<h1>
{/* {t("sidebar.dashboard")} */}
{branch_name} </h1>
{branch_name}{" "}
</h1>
<Divider />
<div className="side_bar_links">
{menuItems.map((item, index) => {

View File

@ -20,13 +20,11 @@ type FormFieldType = {
};
const FormField = ({ isLoading }: FormFieldType) => {
const [t] = useTranslation();
return (
<Form className="AuthForm">
<Image src="../App/Logo.png" />
<div className="AuthInput">
<label className="form-label" htmlFor="username">
{t("input.Username")}

View File

@ -13,7 +13,6 @@ const LoginForm = () => {
const { mutate, isLoading, isSuccess, data } = useLoginAdmin();
const [t] = useTranslation();
const handelSubmit = (values: FormValues) => {
mutate(values);
};

View File

@ -25,8 +25,6 @@ const Form = () => {
</Col>
<div>
<DynamicTags />
</div>
</Row>
);

View File

@ -23,9 +23,8 @@ const ModalForm: React.FC = () => {
}, [setIsOpen, isSuccess]);
const handleSubmit = (values: any) => {
mutate({
...values
...values,
});
};

View File

@ -6,7 +6,6 @@ import { useEffect } from "react";
import DynamicTags from "../synonyms/DynamicTags";
const Form = () => {
return (
<Row className="w-100">
<Col>
@ -14,8 +13,6 @@ const Form = () => {
</Col>
<div>
<DynamicTags />
</div>
</Row>
);

View File

@ -12,9 +12,7 @@ import ModelButtons from "../../../Components/models/ModelButtons";
const ModalForm: React.FC = () => {
const { isOpen, setIsOpen } = useModalState((state) => state);
const { objectToEdit, setObjectToEdit } = useObjectToEdit(
(state) => state,
);
const { objectToEdit, setObjectToEdit } = useObjectToEdit((state) => state);
const { mutate, isSuccess, isLoading } = useUpdateTag();
// console.log(objectToEdit,"objectToEdit");
const handleSubmit = (values: any) => {
@ -22,7 +20,7 @@ const ModalForm: React.FC = () => {
// phone_number: values?.number
// });
mutate({
...values
...values,
});
};
const handleCancel = () => {
@ -58,7 +56,6 @@ const ModalForm: React.FC = () => {
<main className="main_modal w-100">
<ModelBody />
<ModelButtons isLoading={isLoading} />
</main>
</FormikForm>
)}

View File

@ -5,30 +5,31 @@ import { ModalEnum } from "../../enums/Model";
// import useSetPageTitle from "../../Hooks/useSetPageTitle";
import { useTranslation } from "react-i18next";
import { lazy, Suspense } from 'react';
import { lazy, Suspense } from "react";
import { Spin } from "antd";
import { canAddTags } from "../../utils/hasAbilityFn";
import useSetPageTitle from "../../Hooks/useSetPageTitle";
const Table = lazy(() => import('./Table'));
const AddModalForm = lazy(() => import('./Model/AddModel'));
const EditModalForm = lazy(() => import('./Model/EditModel'));
const DeleteModalForm = lazy(() => import('./Model/Delete'));
const SearchField = lazy(() => import('../../Components/DataTable/SearchField'));
const Table = lazy(() => import("./Table"));
const AddModalForm = lazy(() => import("./Model/AddModel"));
const EditModalForm = lazy(() => import("./Model/EditModel"));
const DeleteModalForm = lazy(() => import("./Model/Delete"));
const SearchField = lazy(
() => import("../../Components/DataTable/SearchField"),
);
const TableHeader = () => {
const { handel_open_model } = useModalHandler();
const [t] = useTranslation();
useSetPageTitle(
t(`page_header.tags`),
);
useSetPageTitle(t(`page_header.tags`));
return (
<div className="TableWithHeader">
<Suspense fallback={<Spin />}>
<header className="d-flex justify-content-between">
<SearchField searchBy="name" placeholder={t("practical.search_here")} />
<SearchField
searchBy="name"
placeholder={t("practical.search_here")}
/>
{canAddTags && (
<div className="Selects">
@ -42,7 +43,6 @@ const TableHeader = () => {
)}
</header>
<Table />
<DeleteModalForm />
<AddModalForm />

View File

@ -13,5 +13,5 @@ export {
AddModalForm,
EditModalForm,
DeleteModalForm,
FaPlus
FaPlus,
};

View File

@ -1,14 +1,12 @@
import { useFormikContext } from 'formik'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { FaCirclePlus } from 'react-icons/fa6'
import Tag from './Tag'
import { useFormikContext } from "formik";
import React from "react";
import { useTranslation } from "react-i18next";
import { FaCirclePlus } from "react-icons/fa6";
import Tag from "./Tag";
const DynamicTags = () => {
const formik = useFormikContext<any>()
const [t] = useTranslation()
const formik = useFormikContext<any>();
const [t] = useTranslation();
console.log(formik?.values?.synonyms);
@ -17,54 +15,42 @@ const DynamicTags = () => {
const lastElement = formik?.values?.synonyms[length - 1];
if (lastElement !== "") {
formik.setFieldValue('synonyms', [...(formik?.values as any)?.synonyms as any[],""])
formik.setFieldValue("synonyms", [
...((formik?.values as any)?.synonyms as any[]),
"",
]);
} else {
}
}
};
// console.log(formik?.values);
// console.log(currentTag);
return (
<div className='DynamicTags'>
{formik?.values?.synonyms?.length < 1 &&
<div className="DynamicTags">
{formik?.values?.synonyms?.length < 1 && (
<p className="add_new_button">
<FaCirclePlus size={23} onClick={handleAddChoice} /> {t("header.add_synonyms")}
<FaCirclePlus size={23} onClick={handleAddChoice} />{" "}
{t("header.add_synonyms")}
</p>
}
)}
<div className="tag_container">
<div className="tags">
{
(((formik?.values as any)?.synonyms as any[])||[]) .map((item:any,index:number)=>{
return (
<Tag key={index} index={index} data={item}/>
)
}
)
}
{(((formik?.values as any)?.synonyms as any[]) || []).map(
(item: any, index: number) => {
return <Tag key={index} index={index} data={item} />;
},
)}
</div>
{formik?.values?.synonyms?.length > 0 &&
{formik?.values?.synonyms?.length > 0 && (
<p className="add_new_button">
<FaCirclePlus onClick={handleAddChoice} size={20} />
</p>
}
)}
</div>
</div>
)
}
);
};
export default DynamicTags
export default DynamicTags;

View File

@ -1,9 +1,9 @@
import { useFormikContext } from 'formik';
import React, { useRef, useEffect } from 'react';
import { useObjectToEdit } from '../../../zustand/ObjectToEditState';
import { FaTrash } from 'react-icons/fa';
import { useFormikContext } from "formik";
import React, { useRef, useEffect } from "react";
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
import { FaTrash } from "react-icons/fa";
const Tag = ({ data, index }: { data: any, index: number }) => {
const Tag = ({ data, index }: { data: any; index: number }) => {
const inputRef = useRef<HTMLInputElement>(null);
const formik = useFormikContext<any>();
const { setTagsSearch, setCurrentTag } = useObjectToEdit();
@ -16,13 +16,11 @@ const Tag = ({ data, index }: { data: any, index: number }) => {
console.log(formik?.values?.synonyms);
console.log(index);
const handleEditInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// console.log(e.target.value);
formik.setFieldValue(`synonyms[${index}]`, e.target.value);
setTagsSearch(e.target.value)
setCurrentTag(index)
setTagsSearch(e.target.value);
setCurrentTag(index);
};
const handleInputBlur = () => {
@ -38,14 +36,14 @@ const Tag = ({ data, index }: { data: any, index: number }) => {
console.log(currentTags); // Log the updated tags array
// Update formik field value with the updated tags array
formik.setFieldValue('synonyms', currentTags);
formik.setFieldValue("synonyms", currentTags);
// Reset search state if needed
setTagsSearch(null);
};
return (
<div className='tag'>
<div className="tag">
<input
ref={inputRef}
className="tagInput"
@ -53,7 +51,6 @@ const Tag = ({ data, index }: { data: any, index: number }) => {
value={formik?.values?.synonyms[index]}
onChange={handleEditInputChange}
onBlur={handleInputBlur}
/>
<FaTrash onClick={handleDeleteChoice} />
</div>
@ -61,6 +58,3 @@ const Tag = ({ data, index }: { data: any, index: number }) => {
};
export default Tag;

View File

@ -19,8 +19,6 @@ export const useColumns = () => {
};
const [t] = useTranslation();
const columns: TableColumnsType<tags> = [
{
title: t("columns.id"),
@ -57,16 +55,10 @@ export const useColumns = () => {
placement="top"
title={t("practical.edit")}
color="#E0E0E0"
>
<span onClick={() => handleEdit(record)}>
<MdOutlineEdit
size={22}
style={{ color: "#A098AE" }}
/>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</span>
</Tooltip>
)}

View File

@ -1,15 +1,15 @@
import { useTranslation } from "react-i18next";
import { lazy, Suspense } from 'react';
import { lazy, Suspense } from "react";
import { Spin } from "antd";
import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../enums/params";
import { useGetAllSubject } from "../../api/subject";
import useSetPageTitle from "../../Hooks/useSetPageTitle";
const Table = lazy(() => import('./Table'));
const AddModalForm = lazy(() => import('./Model/AddModel'));
const EditModalForm = lazy(() => import('./Model/EditModel'));
const DeleteModels = lazy(() => import('./Model/Delete'));
const Table = lazy(() => import("./Table"));
const AddModalForm = lazy(() => import("./Model/AddModel"));
const EditModalForm = lazy(() => import("./Model/EditModel"));
const DeleteModels = lazy(() => import("./Model/Delete"));
const TableHeader = () => {
const [t] = useTranslation();
@ -17,17 +17,12 @@ const TableHeader = () => {
const { subject_id } = useParams<ParamsEnum>();
const { data: Subject } = useGetAllSubject({
show:subject_id
show: subject_id,
});
const SubjectName = Subject?.data?.name ?? "";
useSetPageTitle(
t(`page_header.subject`) +
"/" +
t(`${SubjectName}`),
);
useSetPageTitle(t(`page_header.subject`) + "/" + t(`${SubjectName}`));
return (
<div className="TableWithHeader">
@ -36,14 +31,12 @@ const TableHeader = () => {
<h6>
{t("models.units")} {SubjectName}
</h6>
</header>
<Table />
<AddModalForm />
<EditModalForm />
<DeleteModels />
</Suspense>
</div>
);
};

View File

@ -7,7 +7,7 @@ import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../enums/params";
const App: React.FC = () => {
const {subject_id} = useParams<ParamsEnum>()
const { subject_id } = useParams<ParamsEnum>();
const response = useGetAllUnit({ subject_id: subject_id, pagination: true });
console.log(response?.data?.data, "response?.data");

View File

@ -10,20 +10,23 @@ import { useTranslation } from "react-i18next";
import { ABILITIES_ENUM } from "../../enums/abilities";
import { BsEyeFill } from "react-icons/bs";
import { useNavigate } from "react-router-dom";
import { canAddUnit, canDeleteUnit, canEditUnit, canShowUnit } from "../../utils/hasAbilityFn";
import {
canAddUnit,
canDeleteUnit,
canEditUnit,
canShowUnit,
} from "../../utils/hasAbilityFn";
export const useColumns = () => {
const { handel_open_model } = useModalHandler();
const { setObjectToEdit } = useObjectToEdit((state) => state);
const navigate = useNavigate()
const navigate = useNavigate();
const handelShow = (record: any) => {
navigate(`${ABILITIES_ENUM?.UNIT}/${record?.id}`);
};
const handelDelete = (data: any) => {
setObjectToEdit(data);
handel_open_model(ModalEnum?.UNIT_DELETE);
@ -86,11 +89,7 @@ export const useColumns = () => {
color="#E0E0E0"
>
<span onClick={() => handleEdit(record)}>
<MdOutlineEdit
size={22}
style={{ color: "#A098AE" }}
/>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</span>
</Tooltip>
)}
@ -102,15 +101,12 @@ export const useColumns = () => {
/>
)}
{canShowUnit && (
<BsEyeFill
onClick={() => handelShow(record)}
size={22}
style={{ color: "green" }}
/>
)}
</Space>
);
},

View File

@ -20,7 +20,6 @@ const Form = () => {
<Col>
<ValidationField name="name" label="name" />
</Col>
</Row>
);
};

View File

@ -20,7 +20,7 @@ const ModalForm: React.FC = () => {
const { mutate, isSuccess, isLoading } = useAddLesson();
const {unit_id} = useParams<ParamsEnum>()
const { unit_id } = useParams<ParamsEnum>();
useEffect(() => {
if (isSuccess) {
setIsOpen("");

View File

@ -8,7 +8,6 @@ const Form = () => {
<Col>
<ValidationField name="name" label="name" />
</Col>
</Row>
);
};

View File

@ -1,15 +1,15 @@
import { useTranslation } from "react-i18next";
import { lazy, Suspense } from 'react';
import { lazy, Suspense } from "react";
import { Spin } from "antd";
import useSetPageTitle from "../../Hooks/useSetPageTitle";
import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../enums/params";
import { useGetAllUnit } from "../../api/unit";
const Table = lazy(() => import('./Table'));
const AddModalForm = lazy(() => import('./Model/AddModel'));
const EditModalForm = lazy(() => import('./Model/EditModel'));
const DeleteModels = lazy(() => import('./Model/Delete'));
const Table = lazy(() => import("./Table"));
const AddModalForm = lazy(() => import("./Model/AddModel"));
const EditModalForm = lazy(() => import("./Model/EditModel"));
const DeleteModels = lazy(() => import("./Model/Delete"));
const TableHeader = () => {
const [t] = useTranslation();
@ -28,11 +28,9 @@ const TableHeader = () => {
"/" +
t(`page_title.unit`) +
"/" +
`${unitName}`
`${unitName}`,
);
return (
<div className="TableWithHeader">
<Suspense fallback={<Spin />}>
@ -40,14 +38,12 @@ const TableHeader = () => {
<h6>
{t("models.lessons")} {SubjectName} {unitName}
</h6>
</header>
<Table />
<AddModalForm />
<EditModalForm />
<DeleteModels />
</Suspense>
</div>
);
};

View File

@ -6,7 +6,7 @@ import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../enums/params";
const App: React.FC = () => {
const {unit_id} = useParams<ParamsEnum>()
const { unit_id } = useParams<ParamsEnum>();
const response = useGetAllLesson({ unit_id: unit_id, pagination: true });
return <DataTable response={response} useColumns={useColumns} />;

View File

@ -14,20 +14,23 @@ import { ABILITIES_ENUM, ABILITIES_VALUES_ENUM } from "../../enums/abilities";
import { formatNumber } from "../../utils/formatNumber";
import { BsEyeFill } from "react-icons/bs";
import { useNavigate } from "react-router-dom";
import { canAddLesson, canDeleteLesson, canEditLesson, canShowLesson } from "../../utils/hasAbilityFn";
import {
canAddLesson,
canDeleteLesson,
canEditLesson,
canShowLesson,
} from "../../utils/hasAbilityFn";
export const useColumns = () => {
const { handel_open_model } = useModalHandler();
const { setObjectToEdit } = useObjectToEdit((state) => state);
const navigate = useNavigate()
const navigate = useNavigate();
const handelShow = (record: any) => {
navigate(`${ABILITIES_ENUM.LESSON}/${record?.id}`);
};
const handelDelete = (data: any) => {
setObjectToEdit(data);
handel_open_model(ModalEnum?.LESSON_DELETE);
@ -81,11 +84,7 @@ export const useColumns = () => {
color="#E0E0E0"
>
<span onClick={() => handleEdit(record)}>
<MdOutlineEdit
size={22}
style={{ color: "#A098AE" }}
/>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</span>
</Tooltip>
)}
@ -97,15 +96,12 @@ export const useColumns = () => {
/>
)}
{canShowLesson && (
<BsEyeFill
onClick={() => handelShow(record)}
size={22}
style={{ color: "green" }}
/>
)}
</Space>
);
},

View File

@ -1,7 +1,13 @@
import React, { Suspense, lazy, useEffect } from "react";
import { Modal, Spin } from "antd";
import FormikForm from "../../Layout/Dashboard/FormikFormModel";
import { getInitialValues, getValidationSchema ,getInitialValuesBase, getValidationSchemaBase, processTags} from "./Model/formUtil";
import {
getInitialValues,
getValidationSchema,
getInitialValuesBase,
getValidationSchemaBase,
processTags,
} from "./Model/formUtil";
import { useAddQuestion, useAddQuestionAsync } from "../../api/Question";
import { useTranslation } from "react-i18next";
import { useNavigate, useParams } from "react-router-dom";
@ -10,9 +16,9 @@ import { useObjectToEdit } from "../../zustand/ObjectToEditState";
import Header from "../../Components/exercise/Header";
import { Question } from "../../types/Item";
import BaseForm from './Model/Malty/Add'
import Form from './Model/Add'
const AcceptModal = lazy(() => import('./Model/AcceptModal'));
import BaseForm from "./Model/Malty/Add";
import Form from "./Model/Add";
const AcceptModal = lazy(() => import("./Model/AcceptModal"));
import { useModalState } from "../../zustand/Modal";
import { ModalEnum } from "../../enums/Model";
@ -27,19 +33,23 @@ import { useGetAllUnit } from "../../api/unit";
import { useGetAllLesson } from "../../api/lesson";
const AddPage: React.FC = () => {
const {isSuccess:isSuccessAsync,mutateAsync} = useAddQuestionAsync()
const { isSuccess: isSuccessAsync, mutateAsync } = useAddQuestionAsync();
const { mutate, isSuccess, isLoading } = useAddQuestion();
const {isBseQuestion,setTagsSearch,setObjectToEdit,setSuccess,SavedQuestionData} = useObjectToEdit()
const {
isBseQuestion,
setTagsSearch,
setObjectToEdit,
setSuccess,
SavedQuestionData,
} = useObjectToEdit();
const {subject_id,lesson_id,unit_id} = useParams<ParamsEnum>()
const { subject_id, lesson_id, unit_id } = useParams<ParamsEnum>();
const { setIsOpen } = useModalState((state) => state);
const { data: unit } = useGetAllUnit({ show: unit_id });
const { data: lesson } = useGetAllLesson({ show: lesson_id });
const [t] = useTranslation()
const [t] = useTranslation();
const unitName = unit?.data?.name ?? "";
const SubjectName = unit?.data?.subject?.name ?? "";
const lessonName = lesson?.data?.name ?? "";
@ -51,31 +61,32 @@ const AddPage: React.FC = () => {
"/" +
t(`page_title.unit`) +
"/" +
`${unitName}`+"/"
+
`${unitName}` +
"/" +
t(`page_title.lesson`) +
"/" +
`${lessonName}`+ "/" +
t(`page_title.questions`)
`${lessonName}` +
"/" +
t(`page_title.questions`),
);
const handleSubmit = (values: any, { resetForm }: { resetForm: () => void }) => {
const handleSubmit = (
values: any,
{ resetForm }: { resetForm: () => void },
) => {
const DataToSend = structuredClone(values);
setTagsSearch(null);
console.log(isBseQuestion);
if (isBseQuestion || DataToSend?.isBase === 1) {
const newBseQuestion = {
"subject_id": subject_id,
"content": DataToSend?.content,
"image": DataToSend?.image ?? "",
"isBase": 1,
"lessons_ids":[lesson_id]
subject_id: subject_id,
content: DataToSend?.content,
image: DataToSend?.image ?? "",
isBase: 1,
lessons_ids: [lesson_id],
};
mutateAsync(newBseQuestion).then((data: any) => {
const newBseQuestionId = (data as any)?.data?.id;
const Questions = DataToSend?.Questions;
@ -88,75 +99,67 @@ const AddPage: React.FC = () => {
mutate({
...item,
parent_id: newBseQuestionId,
"subject_id": subject_id,
subject_id: subject_id,
tags,
"lessons_ids":[lesson_id]
lessons_ids: [lesson_id],
});
});
console.log(newBseQuestionId, "newBseQuestionId");
});
} else {
const tags = processTags(DataToSend);
mutate({ ...values, subject_id: subject_id, tags , "lessons_ids":[lesson_id] })
mutate({
...values,
subject_id: subject_id,
tags,
lessons_ids: [lesson_id],
});
}
};
const navigate = useNavigate()
const navigate = useNavigate();
useEffect(() => {
if (isSuccessAsync && ( SavedQuestionData?.Questions?.length > 0 ? isSuccess: true )) {
setObjectToEdit(null)
setSuccess(true)
localStorage.removeItem(QUESTION_OBJECT_KEY)
if (
isSuccessAsync &&
(SavedQuestionData?.Questions?.length > 0 ? isSuccess : true)
) {
setObjectToEdit(null);
setSuccess(true);
localStorage.removeItem(QUESTION_OBJECT_KEY);
}
if(isSuccess && !(SavedQuestionData?.Questions?.length)){
toast.success(t("validation.the_possess_done_successful"))
setObjectToEdit(null)
setSuccess(true)
localStorage.removeItem(QUESTION_OBJECT_KEY)
if (isSuccess && !SavedQuestionData?.Questions?.length) {
toast.success(t("validation.the_possess_done_successful"));
setObjectToEdit(null);
setSuccess(true);
localStorage.removeItem(QUESTION_OBJECT_KEY);
}
}, [isSuccess,isSuccessAsync])
}, [isSuccess, isSuccessAsync]);
let cleanedQuestionOptions = cleanObject(SavedQuestionData);
let noChange =hasItems(cleanedQuestionOptions)
let noChange = hasItems(cleanedQuestionOptions);
useSaveOnDisconnect(noChange, QUESTION_OBJECT_KEY, SavedQuestionData);
const SavedData = getLocalStorageQuestions(QUESTION_OBJECT_KEY)
const SavedData = getLocalStorageQuestions(QUESTION_OBJECT_KEY);
const handleCancel = () => {
if (!noChange) {
navigate(-1)
localStorage.removeItem(QUESTION_OBJECT_KEY)
navigate(-1);
localStorage.removeItem(QUESTION_OBJECT_KEY);
} else {
setIsOpen(ModalEnum?.QUESTION_ACCEPT);
}
};
if (isBseQuestion || SavedData?.isBase === 1) {
return (
<div className="exercise_add">
<FormikForm
handleSubmit={handleSubmit}
initialValues={getInitialValuesBase(SavedData)}
validationSchema={getValidationSchemaBase}
>
<main className="w-100 exercise_add_main">
<Header />
<BaseForm />
@ -177,20 +180,16 @@ const AddPage: React.FC = () => {
<Suspense fallback={<Spin />}>
<AcceptModal />
</Suspense>
</div>
);
}
return (
<div className="exercise_add">
<FormikForm
handleSubmit={handleSubmit}
initialValues={getInitialValues(SavedData)}
validationSchema={getValidationSchema}
>
<main className="w-100 exercise_add_main">
<Header />
<Form />
@ -217,5 +216,3 @@ const AddPage: React.FC = () => {
};
export default AddPage;

View File

@ -1,8 +1,19 @@
import React, { useEffect } from "react";
import { Modal, Spin } from "antd";
import FormikForm from "../../Layout/Dashboard/FormikFormModel";
import { getInitialValues, getValidationSchema ,getInitialValuesBase, getValidationSchemaBase, processTags} from "./Model/formUtil";
import { useAddQuestion, useDeleteQuestion, useGetAllQuestion, useUpdateQuestion } from "../../api/Question";
import {
getInitialValues,
getValidationSchema,
getInitialValuesBase,
getValidationSchemaBase,
processTags,
} from "./Model/formUtil";
import {
useAddQuestion,
useDeleteQuestion,
useGetAllQuestion,
useUpdateQuestion,
} from "../../api/Question";
import { useQueryClient } from "react-query";
import { useTranslation } from "react-i18next";
import { useNavigate, useParams } from "react-router-dom";
@ -10,8 +21,8 @@ import { ParamsEnum } from "../../enums/params";
import { useObjectToEdit } from "../../zustand/ObjectToEditState";
import { removeStringKeys } from "../../utils/removeStringKeys";
import SpinContainer from "../../Components/Layout/SpinContainer";
import Form from './Model/Edit'
import BaseForm from './Model/Malty/Edit'
import Form from "./Model/Edit";
import BaseForm from "./Model/Malty/Edit";
import { Question } from "../../types/Item";
import { toast } from "react-toastify";
import useSetPageTitle from "../../Hooks/useSetPageTitle";
@ -19,34 +30,37 @@ import { useGetAllUnit } from "../../api/unit";
import { useGetAllLesson } from "../../api/lesson";
const EditPage: React.FC = () => {
const {question_id,subject_id,unit_id} = useParams<ParamsEnum>()
const {isBseQuestion,setIsBseQuestion,setTagsSearch,DeletedQuestions} = useObjectToEdit()
const { question_id, subject_id, unit_id } = useParams<ParamsEnum>();
const { isBseQuestion, setIsBseQuestion, setTagsSearch, DeletedQuestions } =
useObjectToEdit();
const { mutate, isSuccess, isLoading } = useUpdateQuestion();
const { mutate: DeleteQuestion } = useDeleteQuestion();
const { mutate: mutateAdd } = useAddQuestion();
const {data,isLoading:dataLoading}= useGetAllQuestion({show:question_id})
const { data, isLoading: dataLoading } = useGetAllQuestion({
show: question_id,
});
const {data:Questions,isLoading:QuestionsDataLoading}= useGetAllQuestion({questionParentId:question_id ,onlyWithNoParents:false})
const { data: Questions, isLoading: QuestionsDataLoading } =
useGetAllQuestion({
questionParentId: question_id,
onlyWithNoParents: false,
});
const objectToEdit = { ...data?.data, Questions: Questions?.data };
const {lesson_id} = useParams()
const { lesson_id } = useParams();
useEffect(() => {
if (objectToEdit?.isBase && isBseQuestion !== true) {
setIsBseQuestion(true)
setIsBseQuestion(true);
}
}, [objectToEdit?.isBase])
}, [objectToEdit?.isBase]);
const { data: unit } = useGetAllUnit({ show: unit_id });
const { data: lesson } = useGetAllLesson({ show: lesson_id });
const [t] = useTranslation()
const [t] = useTranslation();
const unitName = unit?.data?.name ?? "";
const SubjectName = unit?.data?.subject?.name ?? "";
const lessonName = lesson?.data?.name ?? "";
@ -58,41 +72,40 @@ const EditPage: React.FC = () => {
"/" +
t(`page_title.unit`) +
"/" +
`${unitName}`+"/"
+
`${unitName}` +
"/" +
t(`page_title.lesson`) +
"/" +
`${lessonName}`+ "/" +
t(`page_title.questions`)
`${lessonName}` +
"/" +
t(`page_title.questions`),
);
const handleSubmit = (values: any) => {
const DataToSend = structuredClone(values);
setTagsSearch(null)
setTagsSearch(null);
console.log(DataToSend);
if (isBseQuestion) {
const UpdateBseQuestion = {
"id":DataToSend?.id,
"content" : DataToSend?.content,
"image": DataToSend?.image ?? "",
}
if( typeof UpdateBseQuestion?.image === "string" && UpdateBseQuestion?.image !== ""){
delete UpdateBseQuestion["image"]
id: DataToSend?.id,
content: DataToSend?.content,
image: DataToSend?.image ?? "",
};
if (
typeof UpdateBseQuestion?.image === "string" &&
UpdateBseQuestion?.image !== ""
) {
delete UpdateBseQuestion["image"];
}
console.log(DeletedQuestions, "DeletedQuestions");
console.log(UpdateBseQuestion);
mutate(UpdateBseQuestion)
mutate(UpdateBseQuestion);
DeletedQuestions?.map((item: any) => {
DeleteQuestion({id:item?.id})
})
DeleteQuestion({ id: item?.id });
});
const Questions = DataToSend?.Questions;
console.log(Questions, "Questions");
@ -100,13 +113,12 @@ const EditPage: React.FC = () => {
Questions?.map((item: Question) => {
console.log(item);
if (item?.id) {
const itemToSend = structuredClone(item);
const keysToRemove = ['image', 'answer_image'];
const keysToRemove = ["image", "answer_image"];
const updatedObject = removeStringKeys(itemToSend, keysToRemove);
console.log(updatedObject, "updatedObject");
const tags = processTags(updatedObject)
const tags = processTags(updatedObject);
const oldQuestionOptions = [] as any;
const newQuestionOptions = [] as any;
@ -119,34 +131,35 @@ const EditPage: React.FC = () => {
});
const QuestionOptions = {
old: oldQuestionOptions,
new: newQuestionOptions
new: newQuestionOptions,
};
console.log(QuestionOptions);
mutate({
...updatedObject,
QuestionOptions,
tags
})
tags,
});
} else {
console.log(values?.id);
const tags = processTags(DataToSend);
mutateAdd({ ...item, subject_id: subject_id, tags , "lessons_ids":[lesson_id], parent_id:values?.id })
mutateAdd({
...item,
subject_id: subject_id,
tags,
lessons_ids: [lesson_id],
parent_id: values?.id,
});
}
})
});
} else {
const keysToRemove = ['image', 'answer_image'];
const keysToRemove = ["image", "answer_image"];
const updatedObject = removeStringKeys(DataToSend, keysToRemove);
delete updatedObject["parent_id"];
const tags = processTags(updatedObject)
const tags = processTags(updatedObject);
console.log(updatedObject, "updatedObject");
if(!(updatedObject?.image)){
if (!updatedObject?.image) {
updatedObject["image"] = "";
}
console.log(updatedObject);
@ -169,55 +182,44 @@ const EditPage: React.FC = () => {
const QuestionOptions = {
old: oldQuestionOptions,
new: newQuestionOptions
new: newQuestionOptions,
};
console.log(QuestionOptions, "QuestionOptions");
mutate({ ...updatedObject, QuestionOptions, tags });
}
};
const navigate = useNavigate()
const navigate = useNavigate();
const handleCancel = () => {
navigate(-1)
navigate(-1);
};
useEffect(() => {
if (isSuccess) {
toast.success(t("validation.the_possess_done_successful"))
navigate(-1)
toast.success(t("validation.the_possess_done_successful"));
navigate(-1);
}
}, [isSuccess])
}, [isSuccess]);
if (dataLoading || QuestionsDataLoading) {
return <SpinContainer/>
return <SpinContainer />;
}
if (objectToEdit?.isBase) {
return (
<div className="exercise_add">
<FormikForm
handleSubmit={handleSubmit}
initialValues={getInitialValuesBase(objectToEdit)}
validationSchema={getValidationSchemaBase}
>
<main className="w-100 exercise_add_main">
{/* <Header/> */}
<header className="exercise_add_header mb-4">
<div>
{t("practical.edit")} {t("models.exercise")}{" "}
</div>
<div>
{t("header.exercise") }
</div>
<div>{t("header.exercise")}</div>
</header>
<BaseForm />
<div className="exercise_add_buttons">
@ -234,30 +236,24 @@ const EditPage: React.FC = () => {
</div>
</main>
</FormikForm>
</div>
);
}
return (
<div className="exercise_add">
<FormikForm
handleSubmit={handleSubmit}
initialValues={getInitialValues(objectToEdit)}
validationSchema={getValidationSchema}
>
<main className="w-100 exercise_add_main">
{/* <Header/> */}
<header className="exercise_add_header mb-4">
<div>
{t("practical.edit")} {t("models.exercise")}{" "}
</div>
<div>
{t("header.exercise") }
</div>
<div>{t("header.exercise")}</div>
</header>
<Form />
<div className="exercise_add_buttons">
@ -274,7 +270,6 @@ const EditPage: React.FC = () => {
</div>
</main>
</FormikForm>
</div>
);
};

View File

@ -9,24 +9,20 @@ import { QUESTION_OBJECT_KEY } from "../../../config/AppKey";
const AcceptModal: React.FC = () => {
const { isOpen, setIsOpen } = useModalState((state) => state);
const navigate = useNavigate()
const navigate = useNavigate();
const handleSubmit = () => {
localStorage.removeItem(QUESTION_OBJECT_KEY)
localStorage.removeItem(QUESTION_OBJECT_KEY);
console.log("Handle submit clicked");
setIsOpen("");
navigate(-1)
navigate(-1);
};
const handleCancel = () => {
setIsOpen("");
};
const [t] = useTranslation();
return (
<>
@ -38,29 +34,20 @@ const AcceptModal: React.FC = () => {
open={isOpen === ModalEnum?.QUESTION_ACCEPT}
onCancel={handleCancel}
>
<header>
{" "}
{t("practical.accept_back")}
</header>
<header> {t("practical.accept_back")}</header>
<main className="main_modal">
<div className="ValidationField w-100 mb-5">
<label className="text h1 ">
{t("practical.Are you sure you want to go back and not save any changes?")}{" "}
{t(
"practical.Are you sure you want to go back and not save any changes?",
)}{" "}
</label>
</div>
<div className="buttons">
<div onClick={handleCancel}>{t("practical.cancel")}</div>
<div
onClick={handleSubmit}
>
{t("practical.accept")}
</div>
<div onClick={handleSubmit}>{t("practical.accept")}</div>
</div>
</main>
</Modal>

View File

@ -11,69 +11,68 @@ import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
import MathInput from "./MathInput";
const Form = () => {
const formik = useFormikContext<any>();
const{setSuccess,Success,setSavedQuestionData} = useObjectToEdit()
const { setSuccess, Success, setSavedQuestionData } = useObjectToEdit();
useEffect(() => {
if (Success) {
formik.setErrors({});
formik.resetForm({ values: {} });
setSuccess(false)
setSuccess(false);
}
}, [Success]);
useEffect(() => {
setSavedQuestionData(formik.values)
}, [formik?.values])
setSavedQuestionData(formik.values);
}, [formik?.values]);
const handleAddChoice = () => {
console.log(formik?.values?.QuestionOptions?.length);
formik.setFieldValue('QuestionOptions', [...(formik?.values as any)?.QuestionOptions as Choice[],
formik.setFieldValue("QuestionOptions", [
...((formik?.values as any)?.QuestionOptions as Choice[]),
{
answer: null,
answer_image: null,
isCorrect: 0,
}])
}
const [t] = useTranslation()
},
]);
};
const [t] = useTranslation();
return (
<Row className="w-100">
<div className="exercise_form">
{/* <MathInput/> */}
<ValidationField className="textarea_exercise" name="content" label="details" type="TextArea" />
<ValidationField className="file_exercise" name="image" label="attachment" type="File" />
<div>
<ValidationField
className="textarea_exercise"
name="content"
label="details"
type="TextArea"
/>
<ValidationField
className="file_exercise"
name="image"
label="attachment"
type="File"
/>
<div></div>
</div>
</div>
<div className=" flex ">
</div>
{
(((formik?.values as any)?.QuestionOptions as Choice[])||[]) .map((item:Choice,index:number)=>{
return <ChoiceFields key={index} index={index} data={item}/>
}
)
}
<div className=" flex "></div>
{(((formik?.values as any)?.QuestionOptions as Choice[]) || []).map(
(item: Choice, index: number) => {
return <ChoiceFields key={index} index={index} data={item} />;
},
)}
{formik?.values?.QuestionOptions?.length < 5 && (
<p className="add_new_button">
<FaCirclePlus onClick={handleAddChoice} size={23} /> {t("header.add_new_choice")}
<FaCirclePlus onClick={handleAddChoice} size={23} />{" "}
{t("header.add_new_choice")}
</p>
)}
<DynamicTags />
</Row>
);
};

View File

@ -74,7 +74,9 @@ const ModalForm: React.FC = () => {
className={
objectToEdit?.id !== inputValue ? "disabled_button" : ""
}
disabled={Number(objectToEdit?.id) !== Number(inputValue) || isLoading}
disabled={
Number(objectToEdit?.id) !== Number(inputValue) || isLoading
}
onClick={handleSubmit}
>
{t("practical.delete")}

View File

@ -25,55 +25,56 @@ const Form = () => {
// console.log(formik?.errors);
const handleAddChoice = () => {
formik.setFieldValue('QuestionOptions', [...(formik?.values as any)?.QuestionOptions as Choice[],
formik.setFieldValue("QuestionOptions", [
...((formik?.values as any)?.QuestionOptions as Choice[]),
{
answer: null,
answer_image: null,
isCorrect:0
}])
}
const [t] = useTranslation()
isCorrect: 0,
},
]);
};
const [t] = useTranslation();
return (
<Row className="w-100">
<div className="exercise_form">
<ValidationField className="textarea_exercise" name="content" label="details" type="TextArea" />
<ValidationField className="file_exercise" name="image" label="attachment" type="File" />
<ValidationField
className="textarea_exercise"
name="content"
label="details"
type="TextArea"
/>
<ValidationField
className="file_exercise"
name="image"
label="attachment"
type="File"
/>
{/* <ValidationField name="isBase" label="isBase" type="Checkbox" /> */}
<div>
</div>
<div></div>
</div>
<div className=" flex ">
{/* <ValidationField name="min_mark_to_pass" label="min_mark_to_pass" type="Number" /> */}
{/* <ValidationField name="parent_id" label="parent_id" type="Select" option={[]} /> */}
</div>
{
(((formik?.values as any)?.QuestionOptions as Choice[])||[]) .map((item:Choice,index:number)=>{
return <ChoiceFields key={index} index={index} data={item}/>
}
)
}
{(((formik?.values as any)?.QuestionOptions as Choice[]) || []).map(
(item: Choice, index: number) => {
return <ChoiceFields key={index} index={index} data={item} />;
},
)}
{formik?.values?.QuestionOptions?.length < 5 && (
<p className="add_new_button">
<FaCirclePlus onClick={handleAddChoice} size={23} /> {t("header.add_new_choice")}
<FaCirclePlus onClick={handleAddChoice} size={23} />{" "}
{t("header.add_new_choice")}
</p>
)}
<DynamicTags />
</Row>
);
};

View File

@ -12,22 +12,23 @@ const CheckboxField = ({
className,
props,
}: any) => {
const formik = useFormikContext<any>()
const [t] = useTranslation()
const formik = useFormikContext<any>();
const [t] = useTranslation();
const CheckboxhandleChange = (value: any, index: number) => {
const allAreZero = formik?.values?.QuestionOptions?.some((item: any) => item.isCorrect === 1);
const allAreZero = formik?.values?.QuestionOptions?.some(
(item: any) => item.isCorrect === 1,
);
if (allAreZero) {
formik?.values.QuestionOptions.forEach((item: any, index: number) => {
formik.setFieldValue(`QuestionOptions[${index}].isCorrect`, 0);
});
}
formik.setFieldValue(`QuestionOptions[${name}].isCorrect`, value?.target?.checked ? 1 : 0);
formik.setFieldValue(
`QuestionOptions[${name}].isCorrect`,
value?.target?.checked ? 1 : 0,
);
};
return (
<div className={Group ? "d-inline mt-5 Checkbox" : ``}>

View File

@ -1,43 +1,60 @@
import React from 'react'
import { Choice } from '../../../../types/Item'
import ValidationField from '../../../../Components/ValidationField/ValidationField'
import { useFormikContext } from 'formik';
import { useTranslation } from 'react-i18next';
import { getCharFromNumber } from '../../../../utils/getCharFromNumber';
import CheckboxField from './CheckboxField';
import TextField from './TextField';
import File from './File';
import { FaCirclePlus, FaDeleteLeft } from 'react-icons/fa6';
import { FaTrash } from 'react-icons/fa';
import React from "react";
import { Choice } from "../../../../types/Item";
import ValidationField from "../../../../Components/ValidationField/ValidationField";
import { useFormikContext } from "formik";
import { useTranslation } from "react-i18next";
import { getCharFromNumber } from "../../../../utils/getCharFromNumber";
import CheckboxField from "./CheckboxField";
import TextField from "./TextField";
import File from "./File";
import { FaCirclePlus, FaDeleteLeft } from "react-icons/fa6";
import { FaTrash } from "react-icons/fa";
const ChoiceFields = ({index,data}:{index:number , data :Choice }) => {
const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
const formik = useFormikContext<any>();
const [t] = useTranslation()
const [t] = useTranslation();
const handleDeleteChoice = () => {
console.log(index);
console.log(formik.values.QuestionOptions[index]);
const updatedQuestionOptions = formik.values.QuestionOptions.filter((_:any, i:any) => i !== index);
const updatedQuestionOptions = formik.values.QuestionOptions.filter(
(_: any, i: any) => i !== index,
);
formik.setFieldValue('QuestionOptions', updatedQuestionOptions);
formik.setFieldValue("QuestionOptions", updatedQuestionOptions);
};
console.log(formik.values);
return (
<div className='ChoiceFields'>
<div className="ChoiceFields">
<TextField
className="textarea_exercise"
placeholder={"choice"}
label2={t(`input.choice`) + ` ` + `(${getCharFromNumber(index)})`}
name={index}
id={`choice_${index + 1}`}
type="TextArea"
/>
<File
className="file_exercise"
label={"attachment"}
name={index}
type="File"
/>
<TextField className="textarea_exercise" placeholder={"choice"} label2={t(`input.choice`) + ` ` + `(${(getCharFromNumber(index))})` } name={index} id={`choice_${index + 1}`} type="TextArea" />
<File className="file_exercise" label={"attachment"} name={index} type="File" />
<CheckboxField className="" label="The_correct_answer" name={index} type="Checkbox" />
<CheckboxField
className=""
label="The_correct_answer"
name={index}
type="Checkbox"
/>
<p className="delete_question_options">
<FaTrash onClick={handleDeleteChoice} size={17} />
</p>
</div>
)
}
);
};
export default ChoiceFields
export default ChoiceFields;

View File

@ -12,8 +12,7 @@ const File = ({
className,
props,
}: any) => {
const newName = `QuestionOptions[${name}].answer_image`
const newName = `QuestionOptions[${name}].answer_image`;
const { formik, t, isError, errorMsg } = useFormField(newName, props);
let imageUrl = formik?.values?.QuestionOptions[name]?.answer_image ?? null;
@ -24,18 +23,18 @@ const File = ({
if (!imageUrl) return [];
return [
typeof imageUrl === 'string'
typeof imageUrl === "string"
? {
uid: '-1',
name: 'uploaded-image',
status: 'done',
uid: "-1",
name: "uploaded-image",
status: "done",
url: imageUrl,
thumbUrl: imageUrl,
}
: {
uid: imageUrl.uid || '-1',
name: imageUrl.name || 'uploaded-image',
status: 'done',
uid: imageUrl.uid || "-1",
name: imageUrl.name || "uploaded-image",
status: "done",
originFileObj: imageUrl,
},
];
@ -47,8 +46,10 @@ const File = ({
if (value.fileList.length === 0) {
formik.setFieldValue(newName, null);
} else {
formik.setFieldValue(`QuestionOptions[${name}].answer_image`, value?.file?.originFileObj);
formik.setFieldValue(
`QuestionOptions[${name}].answer_image`,
value?.file?.originFileObj,
);
}
};
const customRequest = async ({ onSuccess, no_label, label_icon }: any) => {
@ -74,7 +75,6 @@ const File = ({
icon={<UploadOutlined />}
>
{placholder ?? t("input.Click_to_upload_the_image")}
</Button>
<div className="Error_color"> {isError ? "required" : ""}</div>
{errorMsg}

View File

@ -16,9 +16,9 @@ const TextField = ({
no_label,
label_icon,
id,
className
className,
}: any) => {
const newName = `QuestionOptions[${name}].answer`
const newName = `QuestionOptions[${name}].answer`;
const { formik, isError, errorMsg, t } = useFormField(newName, props);
const TextFilehandleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
@ -62,7 +62,6 @@ const TextField = ({
onChange={onChange || TextFilehandleChange}
style={{ height: 120 }}
id={id}
/>
</Form.Item>
</div>

View File

@ -15,7 +15,7 @@ const Form = () => {
const formik = useFormikContext<any>();
const { isOpen } = useModalState((state) => state);
// const {data} = useGetAllQuestion();
const{setSuccess,Success,setSavedQuestionData} = useObjectToEdit()
const { setSuccess, Success, setSavedQuestionData } = useObjectToEdit();
useEffect(() => {
if (Success) {
@ -23,111 +23,126 @@ const Form = () => {
formik.setErrors({});
formik.resetForm({ values: {} });
setSuccess(false)
setSuccess(false);
}
}, [Success]);
useEffect(() => {
setSavedQuestionData(formik.values)
}, [formik?.values])
setSavedQuestionData(formik.values);
}, [formik?.values]);
// console.log(formik?.errors);
console.log(formik?.values?.Questions, "formik?.values?.Questions");
const handleAddChoice = (parent_index: number) => {
console.log(parent_index);
formik.setFieldValue(`Questions.[${parent_index}].QuestionOptions`, [...(formik?.values as any)?.Questions?.[parent_index].QuestionOptions as Choice[],
formik.setFieldValue(`Questions.[${parent_index}].QuestionOptions`, [
...((formik?.values as any)?.Questions?.[parent_index]
.QuestionOptions as Choice[]),
{
answer: null,
answer_image: null,
isCorrect:0
}])
}
isCorrect: 0,
},
]);
};
const handleAddQuestion = () => {
formik.setFieldValue('Questions', [...(formik?.values as any)?.Questions as Choice[],
formik.setFieldValue("Questions", [
...((formik?.values as any)?.Questions as Choice[]),
{
content: "",
image: "",
parent: '',
parent: "",
isBase: 0,
max_mark: 1,
min_mark_to_pass: 1,
QuestionOptions: [{ answer: null, answer_image: null, isCorrect: 0 }],
tags: []
}])
tags: [],
},
]);
const max_mark = formik?.values?.max_mark + 1
const max_mark = formik?.values?.max_mark + 1;
formik.setFieldValue('max_mark', max_mark)
}
const [t] = useTranslation()
formik.setFieldValue("max_mark", max_mark);
};
const [t] = useTranslation();
console.log(formik.errors);
return (
<Row className="w-100">
<div className="exercise_form">
<ValidationField className="textarea_exercise" name="content" label="main_question" type="TextArea" />
<ValidationField className="file_exercise" name="image" label="attachment" type="File" />
<ValidationField
className="textarea_exercise"
name="content"
label="main_question"
type="TextArea"
/>
<ValidationField
className="file_exercise"
name="image"
label="attachment"
type="File"
/>
{/* <div className="">
<ValidationField name="max_mark" label="max_mark" type="Number" className="inputSmall" disabled />
<ValidationField name="min_mark_to_pass" label="min_mark_to_pass" className="inputSmall" type="Number" />
</div> */}
<div>
<div></div>
</div>
<div className=" flex "></div>
</div>
<div className=" flex ">
</div>
{
(((formik?.values as any)?.Questions)||[])?.map((item:Choice,parent_index:number)=>{
{((formik?.values as any)?.Questions || [])?.map(
(item: Choice, parent_index: number) => {
return (
<div key={parent_index}>
<div className="exercise_form">
<QuestionFIeld key={parent_index} index={parent_index} data={item}/>
<QuestionFIeld
key={parent_index}
index={parent_index}
data={item}
/>
</div>
{
(((formik?.values as any)?.Questions?.[parent_index]?.QuestionOptions)||[]) .map((item:Choice,index:number)=>{
{(
(formik?.values as any)?.Questions?.[parent_index]
?.QuestionOptions || []
).map((item: Choice, index: number) => {
return (
<ChoiceFields
key={index}
parent_index={parent_index}
index={index}
data={item}
/>
);
})}
return <ChoiceFields key={index} parent_index={parent_index} index={index} data={item}/>
}
)
}
{formik?.values?.Questions?.[parent_index]?.QuestionOptions?.length < 5 && (
{formik?.values?.Questions?.[parent_index]?.QuestionOptions
?.length < 5 && (
<p className="add_new_button">
<FaCirclePlus onClick={()=> handleAddChoice(parent_index)} size={23} /> {t("header.add_new_choice")}
<FaCirclePlus
onClick={() => handleAddChoice(parent_index)}
size={23}
/>{" "}
{t("header.add_new_choice")}
</p>
)}
<DynamicTags parent_index={parent_index} />
</div>
)
}
)
}
);
},
)}
<p className="add_new_button">
<FaCirclePlus onClick={handleAddQuestion} size={23} /> {t("header.add_new_question")}
<FaCirclePlus onClick={handleAddQuestion} size={23} />{" "}
{t("header.add_new_question")}
</p>
</Row>
);

View File

@ -13,32 +13,39 @@ const CheckboxField = ({
parent_index,
props,
}: any) => {
const formik = useFormikContext<any>()
const [t] = useTranslation()
const formik = useFormikContext<any>();
const [t] = useTranslation();
const CheckboxhandleChange = (value: any) => {
console.log(value?.target?.checked);
const allAreZero = formik?.values?.Questions?.[parent_index]?.QuestionOptions?.some((item: any) => item.isCorrect === 1);
const allAreZero = formik?.values?.Questions?.[
parent_index
]?.QuestionOptions?.some((item: any) => item.isCorrect === 1);
if (allAreZero) {
formik?.values?.Questions?.[parent_index]?.QuestionOptions.forEach((item: any,index:number) => {
formik.setFieldValue(`Questions[${parent_index}].QuestionOptions[${index}].isCorrect`, 0);
});
formik?.values?.Questions?.[parent_index]?.QuestionOptions.forEach(
(item: any, index: number) => {
formik.setFieldValue(
`Questions[${parent_index}].QuestionOptions[${index}].isCorrect`,
0,
);
},
);
}
formik.setFieldValue(`Questions[${parent_index}].QuestionOptions[${name}].isCorrect`, value?.target?.checked ? 1 : 0);
formik.setFieldValue(
`Questions[${parent_index}].QuestionOptions[${name}].isCorrect`,
value?.target?.checked ? 1 : 0,
);
};
return (
<div className={Group ? "d-inline mt-5 Checkbox" : ``}>
<Checkbox
onChange={onChange || CheckboxhandleChange}
disabled={isDisabled}
checked={formik.values?.Questions?.[parent_index]?.QuestionOptions?.[name]?.isCorrect === 1}
checked={
formik.values?.Questions?.[parent_index]?.QuestionOptions?.[name]
?.isCorrect === 1
}
className={className}
>
{t(`input.${label ? label : name}`)}

View File

@ -1,50 +1,79 @@
import React from 'react'
import { Choice } from '../../../../../types/Item'
import ValidationField from '../../../../../Components/ValidationField/ValidationField'
import { useFormikContext } from 'formik';
import { useTranslation } from 'react-i18next';
import { getCharFromNumber } from '../../../../../utils/getCharFromNumber';
import CheckboxField from './CheckboxField';
import TextField from './TextField';
import File from './File';
import { FaTrash } from 'react-icons/fa';
import { toast } from 'react-toastify';
import React from "react";
import { Choice } from "../../../../../types/Item";
import ValidationField from "../../../../../Components/ValidationField/ValidationField";
import { useFormikContext } from "formik";
import { useTranslation } from "react-i18next";
import { getCharFromNumber } from "../../../../../utils/getCharFromNumber";
import CheckboxField from "./CheckboxField";
import TextField from "./TextField";
import File from "./File";
import { FaTrash } from "react-icons/fa";
import { toast } from "react-toastify";
const ChoiceFields = ({index,parent_index,data}:{index:number ,parent_index:number, data :Choice }) => {
const ChoiceFields = ({
index,
parent_index,
data,
}: {
index: number;
parent_index: number;
data: Choice;
}) => {
const formik = useFormikContext<any>();
const [t] = useTranslation()
const [t] = useTranslation();
const handleDeleteChoice = () => {
const arrayLength = formik.values.Questions?.[parent_index].QuestionOptions?.length
const arrayLength =
formik.values.Questions?.[parent_index].QuestionOptions?.length;
console.log(arrayLength);
if(arrayLength === 1)
{
toast.error(t("validation.Sorry, the question must have at least one option"))
if (arrayLength === 1) {
toast.error(
t("validation.Sorry, the question must have at least one option"),
);
return;
}
const updatedQuestionOptions = formik.values.Questions?.[parent_index].QuestionOptions.filter((_:any, i:any) => i !== index);
formik.setFieldValue(`Questions[${parent_index}].QuestionOptions`, updatedQuestionOptions);
}
;
const updatedQuestionOptions = formik.values.Questions?.[
parent_index
].QuestionOptions.filter((_: any, i: any) => i !== index);
formik.setFieldValue(
`Questions[${parent_index}].QuestionOptions`,
updatedQuestionOptions,
);
};
return (
<div className='ChoiceFields'>
<div className="ChoiceFields">
<TextField
className="textarea_exercise"
placeholder={"choice"}
label2={t(`input.choice`) + ` ` + `(${getCharFromNumber(index)})`}
name={index}
parent_index={parent_index}
type="TextArea"
/>
<File
className="file_exercise"
label={"attachment"}
name={index}
type="File"
parent_index={parent_index}
/>
<TextField className="textarea_exercise" placeholder={"choice"} label2={t(`input.choice`) + ` ` + `(${(getCharFromNumber(index))})` } name={index} parent_index={parent_index} type="TextArea" />
<File className="file_exercise" label={"attachment"} name={index} type="File" parent_index={parent_index} />
<CheckboxField className="" label="The_correct_answer" name={index} type="Checkbox" parent_index={parent_index} />
<CheckboxField
className=""
label="The_correct_answer"
name={index}
type="Checkbox"
parent_index={parent_index}
/>
<p className="delete_question_options">
<FaTrash onClick={handleDeleteChoice} size={17} />
</p>
</div>
)
}
);
};
export default ChoiceFields
export default ChoiceFields;

View File

@ -13,29 +13,30 @@ const File = ({
parent_index,
props,
}: any) => {
const newName = `Questions[${parent_index}].QuestionOptions[${name}].answer_image`
const newName = `Questions[${parent_index}].QuestionOptions[${name}].answer_image`;
const { formik, t, isError, errorMsg } = useFormField(newName, props);
let imageUrl = formik?.values?.Questions?.[parent_index]?.QuestionOptions[name]?.answer_image ?? null;
let imageUrl =
formik?.values?.Questions?.[parent_index]?.QuestionOptions[name]
?.answer_image ?? null;
// console.log(imageUrl);
const fileList: UploadFile[] = useMemo(() => {
if (!imageUrl) return [];
return [
typeof imageUrl === 'string'
typeof imageUrl === "string"
? {
uid: '-1',
name: 'uploaded-image',
status: 'done',
uid: "-1",
name: "uploaded-image",
status: "done",
url: imageUrl,
thumbUrl: imageUrl,
}
: {
uid: imageUrl.uid || '-1',
name: imageUrl.name || 'uploaded-image',
status: 'done',
uid: imageUrl.uid || "-1",
name: imageUrl.name || "uploaded-image",
status: "done",
originFileObj: imageUrl,
},
];
@ -47,8 +48,10 @@ const File = ({
if (value.fileList.length === 0) {
formik.setFieldValue(newName, null);
} else {
formik.setFieldValue(`Questions[${parent_index}].QuestionOptions[${name}].answer_image`, value?.file?.originFileObj);
formik.setFieldValue(
`Questions[${parent_index}].QuestionOptions[${name}].answer_image`,
value?.file?.originFileObj,
);
}
};
const customRequest = async ({ onSuccess, no_label, label_icon }: any) => {
@ -74,7 +77,6 @@ const File = ({
icon={<UploadOutlined />}
>
{placholder ?? t("input.Click_to_upload_the_image")}
</Button>
<div className="Error_color"> {isError ? "required" : ""}</div>
{errorMsg}

View File

@ -16,9 +16,9 @@ const TextField = ({
no_label,
label_icon,
parent_index,
className
className,
}: any) => {
const newName = `Questions[${parent_index}].QuestionOptions[${name}].answer`
const newName = `Questions[${parent_index}].QuestionOptions[${name}].answer`;
const { formik, isError, errorMsg, t } = useFormField(newName, props);
const TextFilehandleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
@ -61,8 +61,6 @@ const TextField = ({
maxLength={1000}
onChange={onChange || TextFilehandleChange}
style={{ height: 120 }}
/>
</Form.Item>
</div>

View File

@ -25,98 +25,115 @@ const Form = () => {
}, [isOpen]);
// console.log(formik?.errors);
const [t] = useTranslation()
const [t] = useTranslation();
const handleAddChoice = (parent_index: number) => {
console.log(parent_index);
console.log(formik?.values?.Questions);
formik.setFieldValue(`Questions.[${parent_index}].QuestionOptions`, [...(formik?.values as any)?.Questions?.[parent_index].QuestionOptions as Choice[],
formik.setFieldValue(`Questions.[${parent_index}].QuestionOptions`, [
...((formik?.values as any)?.Questions?.[parent_index]
.QuestionOptions as Choice[]),
{
answer: null,
answer_image: null,
isCorrect:0
}])
}
isCorrect: 0,
},
]);
};
const handleAddQuestion = () => {
formik.setFieldValue('Questions', [...(formik?.values as any)?.Questions as Choice[],
formik.setFieldValue("Questions", [
...((formik?.values as any)?.Questions as Choice[]),
{
content: "",
image: "",
parent: '',
parent: "",
isBase: 0,
max_mark: 1,
min_mark_to_pass: 1,
QuestionOptions: [{ answer: null, answer_image: null, isCorrect: 0 }],
tags: []
}])
tags: [],
},
]);
const max_mark = formik?.values?.max_mark + 1
const max_mark = formik?.values?.max_mark + 1;
formik.setFieldValue('max_mark', max_mark)
}
formik.setFieldValue("max_mark", max_mark);
};
console.log(formik?.values);
return (
<Row className="w-100">
<div className="exercise_form">
<ValidationField className="textarea_exercise" name="content" label="main_question" type="TextArea" />
<ValidationField className="file_exercise" name="image" label="attachment" type="File" />
<ValidationField
className="textarea_exercise"
name="content"
label="main_question"
type="TextArea"
/>
<ValidationField
className="file_exercise"
name="image"
label="attachment"
type="File"
/>
{/* <div className="">
<ValidationField name="max_mark" label="max_mark" type="Number" className="inputSmall" disabled />
<ValidationField name="min_mark_to_pass" label="min_mark_to_pass" className="inputSmall" type="Number" />
</div> */}
<div>
<div></div>
</div>
<div className=" flex "></div>
</div>
<div className=" flex ">
</div>
{
(((formik?.values as any)?.Questions)||[])?.map((item:Choice,parent_index:number)=>{
{((formik?.values as any)?.Questions || [])?.map(
(item: Choice, parent_index: number) => {
return (
<div key={parent_index}>
<div className="exercise_form">
<QuestionFIeld key={parent_index} index={parent_index} data={item}/>
<QuestionFIeld
key={parent_index}
index={parent_index}
data={item}
/>
</div>
{
(((formik?.values as any)?.Questions?.[parent_index]?.QuestionOptions)||[]) .map((item:Choice,index:number)=>{
return <ChoiceFields key={index} parent_index={parent_index} index={index} data={item}/>
}
)
}
{formik?.values?.Questions?.[parent_index]?.QuestionOptions?.length < 5 && (
{(
(formik?.values as any)?.Questions?.[parent_index]
?.QuestionOptions || []
).map((item: Choice, index: number) => {
return (
<ChoiceFields
key={index}
parent_index={parent_index}
index={index}
data={item}
/>
);
})}
{formik?.values?.Questions?.[parent_index]?.QuestionOptions
?.length < 5 && (
<p className="add_new_button">
<FaCirclePlus onClick={()=> handleAddChoice(parent_index)} size={23} /> {t("header.add_new_choice")}
<FaCirclePlus
onClick={() => handleAddChoice(parent_index)}
size={23}
/>{" "}
{t("header.add_new_choice")}
</p>
)}
<DynamicTags parent_index={parent_index} />
</div>
)
}
)
}
);
},
)}
<p className="add_new_button">
<FaCirclePlus onClick={handleAddQuestion} size={23} /> {t("header.add_new_question")}
<FaCirclePlus onClick={handleAddQuestion} size={23} />{" "}
{t("header.add_new_question")}
</p>
</Row>
);

View File

@ -12,8 +12,7 @@ const File = ({
className,
props,
}: any) => {
const newName = `Questions[${name}].image`
const newName = `Questions[${name}].image`;
const { formik, t, isError, errorMsg } = useFormField(newName, props);
let imageUrl = formik?.values?.Questions?.[name]?.image ?? null;
@ -23,18 +22,18 @@ const File = ({
if (!imageUrl) return [];
return [
typeof imageUrl === 'string'
typeof imageUrl === "string"
? {
uid: '-1',
name: 'uploaded-image',
status: 'done',
uid: "-1",
name: "uploaded-image",
status: "done",
url: imageUrl,
thumbUrl: imageUrl,
}
: {
uid: imageUrl.uid || '-1',
name: imageUrl.name || 'uploaded-image',
status: 'done',
uid: imageUrl.uid || "-1",
name: imageUrl.name || "uploaded-image",
status: "done",
originFileObj: imageUrl,
},
];
@ -46,8 +45,10 @@ const File = ({
if (value.fileList.length === 0) {
formik.setFieldValue(newName, null);
} else {
formik.setFieldValue(`Questions[${name}].image`, value?.file?.originFileObj);
formik.setFieldValue(
`Questions[${name}].image`,
value?.file?.originFileObj,
);
}
};
const customRequest = async ({ onSuccess, no_label, label_icon }: any) => {
@ -73,7 +74,6 @@ const File = ({
icon={<UploadOutlined />}
>
{placholder ?? t("input.Click_to_upload_the_image")}
</Button>
<div className="Error_color"> {isError ? "required" : ""}</div>
{errorMsg}

View File

@ -1,47 +1,56 @@
import React, { useEffect } from 'react'
import { Choice } from '../../../../../types/Item'
import ValidationField from '../../../../../Components/ValidationField/ValidationField'
import { useFormikContext } from 'formik';
import { useTranslation } from 'react-i18next';
import { getCharFromNumber } from '../../../../../utils/getCharFromNumber';
import TextField from './TextField';
import File from './File';
import { FaTrash } from 'react-icons/fa';
import { useObjectToEdit } from '../../../../../zustand/ObjectToEditState';
import { toast } from 'react-toastify';
import React, { useEffect } from "react";
import { Choice } from "../../../../../types/Item";
import ValidationField from "../../../../../Components/ValidationField/ValidationField";
import { useFormikContext } from "formik";
import { useTranslation } from "react-i18next";
import { getCharFromNumber } from "../../../../../utils/getCharFromNumber";
import TextField from "./TextField";
import File from "./File";
import { FaTrash } from "react-icons/fa";
import { useObjectToEdit } from "../../../../../zustand/ObjectToEditState";
import { toast } from "react-toastify";
const QuestionFIeld = ({index,data}:{index:number , data :Choice }) => {
const QuestionFIeld = ({ index, data }: { index: number; data: Choice }) => {
const formik = useFormikContext<any>();
console.log(index);
const {setDeletedQuestions,DeletedQuestions} = useObjectToEdit()
const { setDeletedQuestions, DeletedQuestions } = useObjectToEdit();
const [t] = useTranslation()
const [t] = useTranslation();
useEffect(() => {
setDeletedQuestions([])
}, [window?.location.pathname])
setDeletedQuestions([]);
}, [window?.location.pathname]);
const handleDeleteQuestion = () => {
const DeleteQuestionId = formik.values.Questions?.[index];
if (DeleteQuestionId?.id) {
setDeletedQuestions([...DeletedQuestions,DeleteQuestionId])
setDeletedQuestions([...DeletedQuestions, DeleteQuestionId]);
}
const updatedQuestionOptions = formik.values.Questions.filter((_:any, i:any) => i !== index);
const updatedQuestionOptions = formik.values.Questions.filter(
(_: any, i: any) => i !== index,
);
formik.setFieldValue(`Questions`, updatedQuestionOptions);
};
return (
<div className='ChoiceFields'>
<TextField className="textarea_exercise" placeholder={"choice"} label2={t(`input.question`)+ ` ` +`${index + 1}`} name={index} type="TextArea" />
<File className="file_exercise" label={"attachment"} name={index} type="File" />
<div className="ChoiceFields">
<TextField
className="textarea_exercise"
placeholder={"choice"}
label2={t(`input.question`) + ` ` + `${index + 1}`}
name={index}
type="TextArea"
/>
<File
className="file_exercise"
label={"attachment"}
name={index}
type="File"
/>
<p className="delete_question_options">
<FaTrash onClick={handleDeleteQuestion} size={17} />
</p>
</div>
)
}
);
};
export default QuestionFIeld
export default QuestionFIeld;

View File

@ -15,9 +15,9 @@ const TextField = ({
props,
no_label,
label_icon,
className
className,
}: any) => {
const newName = `Questions[${name}].content`
const newName = `Questions[${name}].content`;
const { formik, isError, errorMsg, t } = useFormField(newName, props);
const TextFilehandleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
@ -60,8 +60,6 @@ const TextField = ({
maxLength={1000}
onChange={onChange || TextFilehandleChange}
style={{ height: 120 }}
/>
</Form.Item>
</div>

View File

@ -1,109 +1,107 @@
import { useFormikContext } from 'formik'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { FaCirclePlus } from 'react-icons/fa6'
import Tag from './Tag'
import { useObjectToEdit } from '../../../../../zustand/ObjectToEditState'
import { useGetAllTag } from '../../../../../api/tags'
import { useFormikContext } from "formik";
import React from "react";
import { useTranslation } from "react-i18next";
import { FaCirclePlus } from "react-icons/fa6";
import Tag from "./Tag";
import { useObjectToEdit } from "../../../../../zustand/ObjectToEditState";
import { useGetAllTag } from "../../../../../api/tags";
const DynamicTags = ({ parent_index }: { parent_index: number }) => {
const formik = useFormikContext<any>()
const [t] = useTranslation()
const { TagsSearch ,setTagsSearch,currentTag,currentParentIndex} = useObjectToEdit();
const formik = useFormikContext<any>();
const [t] = useTranslation();
const { TagsSearch, setTagsSearch, currentTag, currentParentIndex } =
useObjectToEdit();
const { data } = useGetAllTag({
name : TagsSearch
})
const suggests = data?.data
name: TagsSearch,
});
const suggests = data?.data;
const handleAddChoice = () => {
const length = formik?.values?.Questions?.[parent_index]?.tags.length;
const lastElement = formik?.values?.Questions?.[parent_index]?.tags[length - 1]?.name;
setTagsSearch(null)
const lastElement =
formik?.values?.Questions?.[parent_index]?.tags[length - 1]?.name;
setTagsSearch(null);
if (lastElement !== "") {
formik.setFieldValue(`Questions.[${parent_index}].tags`, [...(formik?.values as any)?.Questions?.[parent_index]?.tags as any[],
formik.setFieldValue(`Questions.[${parent_index}].tags`, [
...((formik?.values as any)?.Questions?.[parent_index]?.tags as any[]),
{
id: length + "_new",
name: "",
key:length
}])
key: length,
},
]);
} else {
}
}
};
// console.log(formik?.values);
// console.log(currentTag);
const handleChoice = (item: any) => {
const length = formik?.values?.Questions?.[parent_index]?.tags?.length;
console.log(currentTag);
formik.setFieldValue(`Questions.[${parent_index}].tags[${currentTag}]`, {...item,key:length});
formik.setFieldValue(`Questions.[${parent_index}].tags[${currentTag}]`, {
...item,
key: length,
});
setTagsSearch(null);
}
};
// console.log(formik?.values?.tags?.length);
return (
<div className='DynamicTags'>
{formik?.values?.Questions?.[parent_index]?.tags?.length < 1 &&
<div className="DynamicTags">
{formik?.values?.Questions?.[parent_index]?.tags?.length < 1 && (
<p className="add_new_button">
<FaCirclePlus size={23} onClick={handleAddChoice} /> {t("header.add_tag")}
<FaCirclePlus size={23} onClick={handleAddChoice} />{" "}
{t("header.add_tag")}
</p>
}
)}
<div className="tag_container">
<div className="tags">
{
(((formik?.values as any)?.Questions?.[parent_index]?.tags as any[])||[]) .map((item:any,index:number)=>{
{(
((formik?.values as any)?.Questions?.[parent_index]
?.tags as any[]) || []
).map((item: any, index: number) => {
return (
<Tag key={index} parent_index={parent_index} index={index} data={item}/>
)
}
)
}
<Tag
key={index}
parent_index={parent_index}
index={index}
data={item}
/>
);
})}
</div>
{formik?.values?.Questions?.[parent_index]?.tags?.length > 0 &&
{formik?.values?.Questions?.[parent_index]?.tags?.length > 0 && (
<p className="add_new_button">
<FaCirclePlus onClick={handleAddChoice} size={20} />
</p>
}
)}
</div>
{TagsSearch && currentParentIndex === parent_index &&
{TagsSearch && currentParentIndex === parent_index && (
<div className="suggests">
{suggests?.map((item: any, index: number) => {
console.log(currentParentIndex === parent_index);
return (
<div className='suggested' key={index} onClick={()=> handleChoice(item)}>
<div
className="suggested"
key={index}
onClick={() => handleChoice(item)}
>
{item?.name}
</div>
)
);
})}
</div>
}
)}
</div>
)
}
);
};
export default DynamicTags
export default DynamicTags;

View File

@ -1,14 +1,23 @@
import { useFormikContext } from 'formik';
import React, { useRef, useEffect } from 'react';
import { useObjectToEdit } from '../../../../../zustand/ObjectToEditState';
import { FaTrash } from 'react-icons/fa';
import { useFormikContext } from "formik";
import React, { useRef, useEffect } from "react";
import { useObjectToEdit } from "../../../../../zustand/ObjectToEditState";
import { FaTrash } from "react-icons/fa";
const Tag = ({ data, index,parent_index }: { data: any, index: number,parent_index:number }) => {
const Tag = ({
data,
index,
parent_index,
}: {
data: any;
index: number;
parent_index: number;
}) => {
const inputRef = useRef<HTMLInputElement>(null);
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const DEBOUNCE_DELAY = 500;
const formik = useFormikContext<any>();
const { setTagsSearch ,setCurrentTag,setCurrentParentIndex} = useObjectToEdit();
const { setTagsSearch, setCurrentTag, setCurrentParentIndex } =
useObjectToEdit();
console.log(formik?.values?.Questions);
useEffect(() => {
@ -20,16 +29,19 @@ const Tag = ({ data, index,parent_index }: { data: any, index: number,parent_ind
const handleEditInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// console.log(e.target.value);
formik.setFieldValue(`Questions.[${parent_index}].tags[${index}]`, {key:parent_index, name :e.target.value , id:`${parent_index}_key`});
setCurrentTag(index)
setCurrentParentIndex(parent_index)
formik.setFieldValue(`Questions.[${parent_index}].tags[${index}]`, {
key: parent_index,
name: e.target.value,
id: `${parent_index}_key`,
});
setCurrentTag(index);
setCurrentParentIndex(parent_index);
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
setTagsSearch(e.target.value)
setTagsSearch(e.target.value);
}, DEBOUNCE_DELAY);
};
@ -51,17 +63,14 @@ const Tag = ({ data, index,parent_index }: { data: any, index: number,parent_ind
setTagsSearch(null);
};
return (
<div className='tag'>
<div className="tag">
<input
ref={inputRef}
className="tagInput"
type="text"
value={formik?.values?.Questions?.[parent_index]?.tags[index]?.name}
onChange={handleEditInputChange}
/>
<FaTrash onClick={handleDeleteChoice} />
</div>
@ -69,6 +78,3 @@ const Tag = ({ data, index,parent_index }: { data: any, index: number,parent_ind
};
export default Tag;

View File

@ -1,11 +1,13 @@
import React, { useState } from 'react';
import MathJax from 'react-mathjax';
import React, { useState } from "react";
import MathJax from "react-mathjax";
const MathInput: React.FC = () => {
const [input, setInput] = useState<string>('a^2+b^2=c^2 (x+a)^n=x=(-b±√(b^2-4ac))/2a ∑_(k=0)^n▒〖(n¦k) x^k a^(n-k) 〗');
const [input, setInput] = useState<string>(
"a^2+b^2=c^2 (x+a)^n=x=(-b±√(b^2-4ac))/2a ∑_(k=0)^n▒〖(n¦k) x^k a^(n-k) 〗",
);
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const formattedInput = event.target.value.replace("_", ' _ ');
const formattedInput = event.target.value.replace("_", " _ ");
console.log(event.target.value);
setInput(formattedInput);

View File

@ -1,106 +1,92 @@
import { useFormikContext } from 'formik'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { FaCirclePlus } from 'react-icons/fa6'
import Tag from './Tag'
import { useObjectToEdit } from '../../../../zustand/ObjectToEditState'
import { useGetAllTag } from '../../../../api/tags'
import { useFormikContext } from "formik";
import React from "react";
import { useTranslation } from "react-i18next";
import { FaCirclePlus } from "react-icons/fa6";
import Tag from "./Tag";
import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
import { useGetAllTag } from "../../../../api/tags";
const DynamicTags = () => {
const formik = useFormikContext<any>()
const [t] = useTranslation()
const formik = useFormikContext<any>();
const [t] = useTranslation();
const { TagsSearch, setTagsSearch, currentTag } = useObjectToEdit();
const { data } = useGetAllTag({
name : TagsSearch
})
const suggests = data?.data
name: TagsSearch,
});
const suggests = data?.data;
console.log(TagsSearch);
const handleAddChoice = () => {
const length = formik?.values?.tags.length;
const lastElement = formik?.values?.tags[length - 1]?.name;
setTagsSearch
setTagsSearch;
if (lastElement !== "") {
formik.setFieldValue('tags', [...(formik?.values as any)?.tags as any[],
formik.setFieldValue("tags", [
...((formik?.values as any)?.tags as any[]),
{
id: length + "_new",
name: "",
key:length
}])
key: length,
},
]);
} else {
}
}
};
// console.log(formik?.values);
// console.log(currentTag);
const handleChoice = (item: any) => {
const length = formik.values.tags.length;
console.log(currentTag);
formik.setFieldValue(`tags[${currentTag}]`, { ...item, key: length });
setTagsSearch(null);
}
};
// console.log(formik?.values?.tags?.length);
return (
<div className='DynamicTags'>
{formik?.values?.tags?.length < 1 &&
<div className="DynamicTags">
{formik?.values?.tags?.length < 1 && (
<p className="add_new_button">
<FaCirclePlus size={23} onClick={handleAddChoice} /> {t("header.add_tag")}
<FaCirclePlus size={23} onClick={handleAddChoice} />{" "}
{t("header.add_tag")}
</p>
}
)}
<div className="tag_container">
<div className="tags">
{
(((formik?.values as any)?.tags as any[])||[]) .map((item:any,index:number)=>{
return (
<Tag key={index} index={index} data={item}/>
)
}
)
}
{(((formik?.values as any)?.tags as any[]) || []).map(
(item: any, index: number) => {
return <Tag key={index} index={index} data={item} />;
},
)}
</div>
{formik?.values?.tags?.length > 0 &&
{formik?.values?.tags?.length > 0 && (
<p className="add_new_button">
<FaCirclePlus onClick={handleAddChoice} size={20} />
</p>
}
)}
</div>
{TagsSearch &&
{TagsSearch && (
<div className="suggests">
{suggests?.map((item: any, index: number) => {
return (
<div className='suggested' key={index} onClick={()=> handleChoice(item)}>
<div
className="suggested"
key={index}
onClick={() => handleChoice(item)}
>
{item?.name}
</div>
)
);
})}
</div>
}
)}
</div>
)
}
);
};
export default DynamicTags
export default DynamicTags;

View File

@ -1,9 +1,9 @@
import { useFormikContext } from 'formik';
import React, { useRef, useEffect } from 'react';
import { useObjectToEdit } from '../../../../zustand/ObjectToEditState';
import { FaTrash } from 'react-icons/fa';
import { useFormikContext } from "formik";
import React, { useRef, useEffect } from "react";
import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
import { FaTrash } from "react-icons/fa";
const Tag = ({ data, index }: { data: any, index: number }) => {
const Tag = ({ data, index }: { data: any; index: number }) => {
const inputRef = useRef<HTMLInputElement>(null);
const formik = useFormikContext<any>();
const { setTagsSearch, setCurrentTag } = useObjectToEdit();
@ -19,15 +19,19 @@ const Tag = ({ data, index }: { data: any, index: number }) => {
// console.log(e.target.value);
formik.setFieldValue(`tags[${index}].name`, e.target.value);
// setTagsSearch(e.target.value)
formik.setFieldValue(`tags.[${index}]`, {key:index, name :e.target.value , id:`${index}_key`});
formik.setFieldValue(`tags.[${index}]`, {
key: index,
name: e.target.value,
id: `${index}_key`,
});
setCurrentTag(index)
setCurrentTag(index);
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
setTagsSearch(e.target.value)
setTagsSearch(e.target.value);
}, DEBOUNCE_DELAY);
};
@ -47,14 +51,14 @@ const Tag = ({ data, index }: { data: any, index: number }) => {
console.log(currentTags); // Log the updated tags array
// Update formik field value with the updated tags array
formik.setFieldValue('tags', currentTags);
formik.setFieldValue("tags", currentTags);
// Reset search state if needed
setTagsSearch(null);
};
return (
<div className='tag'>
<div className="tag">
<input
ref={inputRef}
className="tagInput"
@ -62,7 +66,6 @@ const Tag = ({ data, index }: { data: any, index: number }) => {
value={formik?.values?.tags[index]?.name}
onChange={handleEditInputChange}
onBlur={handleInputBlur}
/>
<FaTrash onClick={handleDeleteChoice} />
</div>
@ -70,6 +73,3 @@ const Tag = ({ data, index }: { data: any, index: number }) => {
};
export default Tag;

View File

@ -3,21 +3,18 @@ import { Question } from "../../../types/Item";
import { getLocalStorage } from "../../../utils/LocalStorage";
import { QUESTION_OBJECT_KEY } from "../../../config/AppKey";
export const getInitialValues = (objectToEdit: Question): any => {
const tags = objectToEdit?.tags?.map((item: any, index: number) => {
return { ...item, key: index }
return { ...item, key: index };
});
return {
id: objectToEdit?.id ?? null,
content: objectToEdit?.content ?? "",
image: objectToEdit?.image ?? "",
subject_id: objectToEdit?.subject_id ?? '',
subject_id: objectToEdit?.subject_id ?? "",
isBase: 0,
parent_id: objectToEdit?.parent_id ?? '',
parent_id: objectToEdit?.parent_id ?? "",
QuestionOptions: objectToEdit?.QuestionOptions ?? [],
tags: tags ?? [],
};
@ -28,21 +25,21 @@ export const getValidationSchema = () => {
return Yup.object().shape({
image: Yup.string().nullable(),
content: Yup.string().required("validation.required"),
QuestionOptions: Yup.array().of(
QuestionOptions: Yup.array()
.of(
Yup.object().shape({
answer: Yup.string().required("validation.required"),
answer_image: Yup.string().nullable(),
isCorrect: Yup.boolean()
})
).nullable('Params are required')
isCorrect: Yup.boolean(),
}),
)
.nullable("Params are required"),
});
};
export const getInitialValuesBase = (objectToEdit: Question): any => {
const tags = objectToEdit?.tags?.map((item: any, index: number) => {
return { ...item, key: index }
return { ...item, key: index };
});
console.log(objectToEdit);
@ -50,25 +47,24 @@ export const getInitialValuesBase = (objectToEdit: Question): any => {
const tags = item?.tags?.map((tag: any) => ({
id: tag?.id,
name: tag?.name,
key: `${tag?.id}_key_${tag?.name}`
key: `${tag?.id}_key_${tag?.name}`,
}));
return {
...item,
tags
tags,
};
});
const questions = newQuestions ?? [];
return {
id: objectToEdit?.id ?? null,
content: objectToEdit?.content ?? "",
image: objectToEdit?.image ?? "",
subject_id: objectToEdit?.subject_id ?? '',
subject_id: objectToEdit?.subject_id ?? "",
isBase: 1,
parent_id: objectToEdit?.parent_id ?? '',
parent_id: objectToEdit?.parent_id ?? "",
Questions: questions,
};
};
@ -82,32 +78,36 @@ export const getValidationSchemaBase = () => {
Yup.object().shape({
image: Yup.string().nullable(),
content: Yup.string().required("validation.required"),
QuestionOptions: Yup.array().of(
QuestionOptions: Yup.array()
.of(
Yup.object().shape({
answer: Yup.string().required("validation.required"),
answer_image: Yup.string().nullable(),
isCorrect: Yup.boolean()
})
).nullable('required')
})
isCorrect: Yup.boolean(),
}),
)
.nullable("required"),
}),
),
});
};
export function processTags(DataToSend: any) {
const oldTags = DataToSend?.tags?.map((item: any, index: number) => {
const oldTags = DataToSend?.tags
?.map((item: any, index: number) => {
if (typeof item?.id === "number") {
return item?.id;
}
}).filter((item:any) => item !== undefined);
})
.filter((item: any) => item !== undefined);
const newTags = DataToSend?.tags?.map((item: any, index: number) => {
const newTags = DataToSend?.tags
?.map((item: any, index: number) => {
if (typeof item?.id === "string" && item?.name !== "") {
return { name: item?.name };
}
}).filter((item:any) => item !== undefined);
})
.filter((item: any) => item !== undefined);
return { new: newTags, old: oldTags };
}

View File

@ -1,18 +1,17 @@
import { useTranslation } from "react-i18next";
import { lazy, Suspense } from 'react';
import { lazy, Suspense } from "react";
import { Spin } from "antd";
import DeleteModel from './Model/Delete'
import DeleteModel from "./Model/Delete";
import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../enums/params";
import { useGetAllUnit } from "../../api/unit";
import useSetPageTitle from "../../Hooks/useSetPageTitle";
import { useGetAllLesson } from "../../api/lesson";
const Table = lazy(() => import('./Table'));
const Table = lazy(() => import("./Table"));
const TableHeader = () => {
const [t] = useTranslation();
const { unit_id, lesson_id } = useParams<ParamsEnum>();
const { data: unit } = useGetAllUnit({ show: unit_id });
const { data: lesson } = useGetAllLesson({ show: lesson_id });
@ -27,12 +26,13 @@ const TableHeader = () => {
"/" +
t(`page_title.unit`) +
"/" +
`${unitName}`+"/"
+
`${unitName}` +
"/" +
t(`page_title.lesson`) +
"/" +
`${lessonName}`+ "/" +
t(`page_title.questions`)
`${lessonName}` +
"/" +
t(`page_title.questions`),
);
return (
@ -42,12 +42,10 @@ const TableHeader = () => {
<h6>
{t("models.Question")} {SubjectName} {unitName} {lessonName}
</h6>
</header>
<Table />
</Suspense>
<DeleteModel />
</div>
);
};

View File

@ -6,8 +6,11 @@ import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../enums/params";
const App: React.FC = () => {
const {lesson_id} = useParams<ParamsEnum>()
const response = useGetAllQuestion({ lesson_id:lesson_id, pagination: true });
const { lesson_id } = useParams<ParamsEnum>();
const response = useGetAllQuestion({
lesson_id: lesson_id,
pagination: true,
});
return <DataTable response={response} useColumns={useColumns} />;
};

View File

@ -9,29 +9,30 @@ import { useTranslation } from "react-i18next";
import { ABILITIES_ENUM } from "../../enums/abilities";
import { useNavigate } from "react-router-dom";
import { useModalState } from "../../zustand/Modal";
import { canAddQuestion, canDeleteQuestion, canEditQuestion } from "../../utils/hasAbilityFn";
import {
canAddQuestion,
canDeleteQuestion,
canEditQuestion,
} from "../../utils/hasAbilityFn";
export const useColumns = () => {
const { setObjectToEdit } = useObjectToEdit((state) => state);
const navigate = useNavigate()
const navigate = useNavigate();
const { setIsOpen } = useModalState((state) => state);
const handelAdd = () => {
setObjectToEdit({})
navigate(`${ABILITIES_ENUM?.QUESTION}/add`)
setObjectToEdit({});
navigate(`${ABILITIES_ENUM?.QUESTION}/add`);
};
const handelDelete = (data: any) => {
setObjectToEdit(data);
setIsOpen(ModalEnum?.QUESTION_DELETE);
};
const handleEdit = (record: any) => {
setObjectToEdit(record);
navigate(`${ABILITIES_ENUM?.QUESTION}/${record?.id}`)
navigate(`${ABILITIES_ENUM?.QUESTION}/${record?.id}`);
};
const [t] = useTranslation();
@ -49,14 +50,15 @@ export const useColumns = () => {
key: "name",
align: "center",
render: (text, record) => record?.content,
ellipsis:true
ellipsis: true,
},
{
title: t("columns.isBase"),
dataIndex: "isBase",
key: "isBase",
align: "center",
render: (text, record) => record?.isBase ? t("practical.yes") : t ("practical.no"),
render: (text, record) =>
record?.isBase ? t("practical.yes") : t("practical.no"),
},
{
title: `${t("columns.question_options_count")}`,
@ -67,10 +69,7 @@ export const useColumns = () => {
},
{
title: canAddQuestion ? (
<button
onClick={() => handelAdd() }
className="add_button"
>
<button onClick={() => handelAdd()} className="add_button">
{t("practical.add")} {t("models.Question")} <FaPlus />
</button>
) : (
@ -92,11 +91,7 @@ export const useColumns = () => {
color="#E0E0E0"
>
<span onClick={() => handleEdit(record)}>
<MdOutlineEdit
size={22}
style={{ color: "#A098AE" }}
/>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</span>
</Tooltip>
)}

View File

@ -8,7 +8,6 @@ import { useModalState } from "../../../zustand/Modal";
import useSearchQuery from "../../../api/utils/useSearchQuery";
const Form = () => {
const { isOpen } = useModalState((state) => state);
const formik = useFormikContext<any>();
useEffect(() => {
@ -22,7 +21,6 @@ const Form = () => {
<Row className="w-100">
<Col>
<ValidationField name="name" label="name" />
</Col>
<Col>
<ValidationField type="File" name="image" label="image" />

View File

@ -26,7 +26,6 @@ const ModalForm: React.FC = () => {
// console.log(values,"values");
mutate({
...values,
});
};

View File

@ -8,7 +8,6 @@ import { useFormikContext } from "formik";
import useSearchQuery from "../../../api/utils/useSearchQuery";
const Form = () => {
const { isOpen } = useModalState((state) => state);
const formik = useFormikContext();
useEffect(() => {
@ -21,7 +20,6 @@ const Form = () => {
<Row className="w-100">
<Col>
<ValidationField name="name" label="name" />
</Col>
<Col>
<ValidationField type="File" name="image" label="image" />

View File

@ -11,9 +11,7 @@ import { handelImageState } from "../../../utils/DataToSendImageState";
import { useTranslation } from "react-i18next";
const ModalForm: React.FC = () => {
const { objectToEdit, setObjectToEdit } = useObjectToEdit(
(state) => state,
);
const { objectToEdit, setObjectToEdit } = useObjectToEdit((state) => state);
const { isOpen, setIsOpen } = useModalState((state) => state);
const { mutate, isSuccess, isLoading } = useUpdateSubject();

View File

@ -1,26 +1,20 @@
import { ModalEnum } from '../../../enums/Model';
import useModalHandler from '../../../utils/useModalHandler';
import { FaPlus } from 'react-icons/fa';
import { useTranslation } from 'react-i18next';
import TablePage from './TablePage';
import { ModalEnum } from "../../../enums/Model";
import useModalHandler from "../../../utils/useModalHandler";
import { FaPlus } from "react-icons/fa";
import { useTranslation } from "react-i18next";
import TablePage from "./TablePage";
import AddSubjectModalForm from "../Model/AddModel";
import EditSubjectModalForm from "../Model/EditModel";
import DeleteSubjectModalForm from "../Model/Delete";
import useSetPageTitle from '../../../Hooks/useSetPageTitle';
import { canAddSubject } from '../../../utils/hasAbilityFn';
import useSetPageTitle from "../../../Hooks/useSetPageTitle";
import { canAddSubject } from "../../../utils/hasAbilityFn";
const TableWithHeader = () => {
const { handel_open_model } = useModalHandler();
const [t] = useTranslation();
useSetPageTitle(
t(`page_header.subject`),
);
useSetPageTitle(t(`page_header.subject`));
return (
<div className="TableWithHeader">
@ -41,7 +35,7 @@ const TableWithHeader = () => {
<EditSubjectModalForm />
<DeleteSubjectModalForm />
</div>
)
}
);
};
export default TableWithHeader
export default TableWithHeader;

View File

@ -85,7 +85,6 @@ export const useColumns = () => {
const className =
index % 2 === 0 ? "even-row buttonAction" : "odd-row buttonAction";
return (
<Space size="middle" className={className}>
{canEditSubject && (
@ -95,11 +94,7 @@ export const useColumns = () => {
color="#E0E0E0"
>
<span onClick={() => handleEdit(record)}>
<MdOutlineEdit
size={22}
style={{ color: "#A098AE" }}
/>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</span>
</Tooltip>
)}

View File

@ -6,24 +6,20 @@ import React, { lazy } from "react";
// import Home from "./Pages/Home/Page";
const Dummy = React.lazy(() => import("./Pages/Home/Dummy"));
const Subject = React.lazy(() => import("./Pages/subject/Table/Page"));
const Tags = React.lazy(() => import("./Pages/Tags/Page"));
const Unit = React.lazy(() => import("./Pages/Unit/Page"));
const Lesson = React.lazy(() => import("./Pages/lesson/Page"));
const Question = React.lazy(() => import('./Pages/question/Page'))
const AddQuestionPage = React.lazy(() => import('./Pages/question/AddPage'))
const EditQuestionPage = React.lazy(() => import('./Pages/question/EditPage'))
const Question = React.lazy(() => import("./Pages/question/Page"));
const AddQuestionPage = React.lazy(() => import("./Pages/question/AddPage"));
const EditQuestionPage = React.lazy(() => import("./Pages/question/EditPage"));
// const QuestionChildren = React.lazy(() => import('./Pages/question/children/Page'))
// const AddQuestionChildren = React.lazy(() => import('./Pages/question/children/Model/AddModel'))
// const EditQuestionChildren = React.lazy(() => import('./Pages/question/children/Model/EditModel'))
import { hasAbility } from "./utils/hasAbility";
import { ABILITIES_ENUM, ABILITIES_VALUES_ENUM } from "./enums/abilities";
import { ParamsEnum } from "./enums/params";
@ -40,7 +36,6 @@ export const menuItems: TMenuItem[] = [
prevPath: 0,
},
{
header: "page_header.subject",
element: <Subject />,
@ -61,14 +56,9 @@ export const menuItems: TMenuItem[] = [
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 0,
},
];
export const CrudRoute: TCrudRoute[] = [
{
header: "page_header.subject_details",
element: <Unit />,
@ -110,11 +100,8 @@ export const CrudRoute: TCrudRoute[] = [
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 2,
},
];
export const AppRoutes: Record<string, string> = Object.fromEntries(
menuItems.map((route) => [
route.path,

View File

@ -272,5 +272,4 @@ button:disabled {
.h1 {
text-align: center;
font-weight: bold;
}

View File

@ -1,4 +1,3 @@
@font-face {
font-family: "Poppins_Bold";
src: url("../../font/Poppins-Bold.ttf") format("truetype"); /* Specify the path to the font file */

View File

@ -83,7 +83,6 @@
min-width: 120px;
}
.SpinContainer {
@include Flex;
height: 100%;

View File

@ -1,5 +1,3 @@
.hidden {
display: none !important;
}

View File

@ -405,4 +405,3 @@
border-left: none !important;
}
}

View File

@ -1,4 +1,5 @@
.exercise_form,.ChoiceFields{
.exercise_form,
.ChoiceFields {
display: flex;
gap: 1vw;
width: 100%;
@ -8,11 +9,12 @@
.file_exercise {
min-width: 18vw;
max-width: 18vw;
.ant-upload-wrapper .ant-upload-list.ant-upload-list-picture .ant-upload-list-item{
.ant-upload-wrapper
.ant-upload-list.ant-upload-list-picture
.ant-upload-list-item {
min-width: 18vw;
max-width: 18vw;
}
}
}
@ -45,11 +47,8 @@
}
}
.tags {
gap: 10px;
}
.tag_container {
@ -70,14 +69,12 @@
}
.tag {
background: rgba(49, 130, 206, 0.15);
color: #3182CE;
color: #3182ce;
min-width: 50px;
padding: 3px 10px;
border-radius: 5px;
svg {
}
}
.tagInput {
all: unset;
@ -87,7 +84,6 @@
font-size: 13px;
}
.suggests {
display: flex;
gap: 20px;
@ -97,7 +93,7 @@
.suggested {
all: unset;
background-color: #FB7D5B;
background-color: #fb7d5b;
padding: 3px 10px;
border-radius: 5px;
color: white;
@ -105,9 +101,7 @@
text-align: center;
font-size: 11px;
cursor: pointer;
}
}
.exercise_add_header {

View File

@ -9,4 +9,4 @@
@import "./Coulmns.scss";
@import "./subject.scss";
@import "./Marks.scss";
@import './exercise.scss';
@import "./exercise.scss";

View File

@ -5,5 +5,4 @@ const API = {
LOGIN: `login`,
LOGOUT: `logout`,
};
export const useLoginAdmin = () =>
useAddMutation(KEY, API.LOGIN,false);
export const useLoginAdmin = () => useAddMutation(KEY, API.LOGIN, false);

View File

@ -15,7 +15,6 @@ const KEY = "exam";
export const useGetAllExam = (params?: any, options?: any) =>
useGetQuery(KEY, API.GET, params, options);
export const useAddExam = () => useAddMutation(KEY, API.ADD);
export const useUpdateExam = (params?: any) =>
useUpdateMutation(KEY, API.GET);
export const useUpdateExam = (params?: any) => useUpdateMutation(KEY, API.GET);
export const useDeleteExam = (params?: any) =>
useDeleteMutation(KEY, API.DELETE);

View File

@ -7,15 +7,12 @@ import { AxiosResponse } from "../../types/Axios";
function useAddMutation(
key: string,
url: string,
toast: boolean = true
toast: boolean = true,
): UseMutationResult<AxiosResponse, unknown, any, unknown> {
const axios = useAxios();
console.log(toast, key);
return useMutation<AxiosResponse, unknown, any, unknown>(
async (dataToSend) => {
const filterDataToSend = filterData(dataToSend);
@ -24,7 +21,6 @@ function useAddMutation(
"Content-Type": "multipart/form-data",
["X-Custom-Message"]: toast,
[HEADER_KEY]: key,
},
});
return data;

View File

@ -51,14 +51,12 @@ function useAxios() {
queryClient.invalidateQueries(key);
if (isToasted) {
toast.success(ResponseMessage);
}
setValidation([{}]);
}
return response;
},
function (error) {
const status = error?.request?.status;
const errorMsg = error?.response?.data?.message;
const errorField = error?.response?.data;

View File

@ -10,8 +10,7 @@ type DataToSend = {
function useDeleteMutation(
key: any,
url: string,
toast:boolean = true
toast: boolean = true,
): UseMutationResult<AxiosResponse, unknown, DataToSend, unknown> {
const axios = useAxios();
return useMutation<AxiosResponse, unknown, DataToSend, unknown>(
@ -19,7 +18,7 @@ function useDeleteMutation(
const { data } = await axios.delete(url + `/` + dataToSend?.id, {
headers: {
[HEADER_KEY]: key,
["X-Custom-Message"] : toast
["X-Custom-Message"]: toast,
},
});
return data;

View File

@ -15,7 +15,6 @@ function useGetQuery(
const { show, pagination, ...remainingParams } = params;
const location = useLocation();
const { page, per_page } = PaginationParams(location);

View File

@ -6,8 +6,7 @@ import { AxiosResponse } from "../../types/Axios";
const useUpdateMutation = (
key: string,
url: string,
toast:boolean = true
toast: boolean = true,
): UseMutationResult<AxiosResponse, any, any, any> => {
const axios = useAxios();
@ -28,7 +27,7 @@ const useUpdateMutation = (
headers: {
"Content-Type": "multipart/form-data",
[HEADER_KEY]: key,
["X-Custom-Message"] : toast
["X-Custom-Message"]: toast,
},
});
return data;

View File

@ -21,8 +21,7 @@ export const useGetRole = (params?: any, options?: any) =>
useGetQuery(KEY, API.GET, params, options);
export const useAddRole = () => useAddMutation(KEY, API.ADD);
export const useUpdateRole = (params?: any) =>
useUpdateMutation(KEY, API.GET);
export const useUpdateRole = (params?: any) => useUpdateMutation(KEY, API.GET);
export const useDeleteRole = (params?: any) =>
useDeleteMutation(KEY, API.DELETE);

View File

@ -15,7 +15,6 @@ const KEY = "tag";
export const useGetAllTag = (params?: any, options?: any) =>
useGetQuery(KEY, API.GET, params, options);
export const useAddTag = () => useAddMutation(KEY, API.ADD);
export const useUpdateTag = (params?: any) =>
useUpdateMutation(KEY, API.GET);
export const useUpdateTag = (params?: any) => useUpdateMutation(KEY, API.GET);
export const useDeleteTag = (params?: any) =>
useDeleteMutation(KEY, API.DELETE);

View File

@ -15,7 +15,6 @@ const KEY = "term";
export const useGetAllTerm = (params?: any, options?: any) =>
useGetQuery(KEY, API.GET, params, options);
export const useAddTerm = () => useAddMutation(KEY, API.ADD);
export const useUpdateTerm = (params?: any) =>
useUpdateMutation(KEY, API.GET);
export const useUpdateTerm = (params?: any) => useUpdateMutation(KEY, API.GET);
export const useDeleteTerm = (params?: any) =>
useDeleteMutation(KEY, API.DELETE);

View File

@ -14,7 +14,6 @@ const KEY = "unit";
export const useGetAllUnit = (params?: any, options?: any) =>
useGetQuery(KEY, API.GET, params, options);
export const useAddUnit = () => useAddMutation(KEY, API.ADD);
export const useUpdateUnit = (params?: any) =>
useUpdateMutation(KEY, API.GET);
export const useUpdateUnit = (params?: any) => useUpdateMutation(KEY, API.GET);
export const useDeleteUnit = (params?: any) =>
useDeleteMutation(KEY, API.DELETE);

View File

@ -1,3 +1,3 @@
export enum DateEnum {
FORMATE = "YYYY-MM-DD"
FORMATE = "YYYY-MM-DD",
}

View File

@ -127,23 +127,17 @@ export enum ModalEnum {
///exercise
EXERCISE_EDIT = "EXERCISE.edit",
EXERCISE_ADD = "EXERCISE.add",
EXERCISE_DELETE = "EXERCISE.delete",
///tags
TAGS_EDIT = "TAGS.edit",
TAGS_ADD = "TAGS.add",
TAGS_DELETE = "TAGS.delete",
///// Question
QUESTION_DELETE = "Question.delete",
QUESTION_ACCEPT = "Question.ACCEPT",
}

View File

@ -39,7 +39,7 @@ export enum ABILITIES_ENUM {
PRESENCE = "presence",
MAIN_PAGE = "main_page",
ROLE = "role",
QUESTION='Question',
QUESTION = "Question",
ADMIN = "admin",
////

Some files were not shown because too many files have changed in this diff Show More