Compare commits
5 Commits
e981ce7481
...
0f54e21546
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f54e21546 | ||
|
|
b7276a2c6a | ||
|
|
091c0bf15c | ||
|
|
0b827ba990 | ||
|
|
693c1cdb06 |
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
|
@ -13,6 +13,7 @@
|
||||||
"Popconfirm",
|
"Popconfirm",
|
||||||
"queryqlent",
|
"queryqlent",
|
||||||
"registraion",
|
"registraion",
|
||||||
|
"Sellcast",
|
||||||
"SENDNOTIFICATION",
|
"SENDNOTIFICATION",
|
||||||
"setdateparams",
|
"setdateparams",
|
||||||
"szhsin",
|
"szhsin",
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ const ImageBoxField = ({ name }: any) => {
|
||||||
<div className="VisibleHidden">hidden</div>
|
<div className="VisibleHidden">hidden</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="ImageBox">
|
<div className="ImageBox" onClick={handleButtonClick}>
|
||||||
{imagePreview ? (
|
{imagePreview ? (
|
||||||
<img src={imagePreview} onClick={handleButtonClick} alt="Preview" className="imagePreview" />
|
<img src={imagePreview} onClick={handleButtonClick} alt="Preview" className="imagePreview" />
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ const TextField = ({
|
||||||
) => {
|
) => {
|
||||||
formik.setFieldValue(name, e.target.value);
|
formik.setFieldValue(name, e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`ValidationField w-100 ${className ?? ""} `}>
|
<div className={`ValidationField w-100 ${className ?? ""} `}>
|
||||||
<ValidationFieldLabel
|
<ValidationFieldLabel
|
||||||
|
|
@ -45,8 +46,8 @@ const TextField = ({
|
||||||
size="large"
|
size="large"
|
||||||
showCount
|
showCount
|
||||||
maxLength={1000}
|
maxLength={1000}
|
||||||
|
autoSize={{ minRows: 4, maxRows: 10 }}
|
||||||
onChange={onChange || TextFilehandleChange}
|
onChange={onChange || TextFilehandleChange}
|
||||||
style={{ height: 120 }}
|
|
||||||
id={name}
|
id={name}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
.text,
|
.text,
|
||||||
.ant-form-item {
|
.ant-form-item {
|
||||||
margin-bottom: 7px !important;
|
margin-bottom: 7px !important;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 19px;
|
||||||
> span {
|
> span {
|
||||||
color: transparent;
|
color: transparent;
|
||||||
}
|
}
|
||||||
|
|
@ -65,3 +67,15 @@
|
||||||
.ant-input-textarea-affix-wrapper.ant-input-affix-wrapper {
|
.ant-input-textarea-affix-wrapper.ant-input-affix-wrapper {
|
||||||
height: 120px;
|
height: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//// malty select
|
||||||
|
///
|
||||||
|
.ant-select-multiple{
|
||||||
|
height: auto !important;
|
||||||
|
min-height: 40px;
|
||||||
|
.ant-select-selector{
|
||||||
|
min-height: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -72,11 +72,11 @@ const Header = () => {
|
||||||
>
|
>
|
||||||
|
|
||||||
<GoArrowSwitch className="m-2" />
|
<GoArrowSwitch className="m-2" />
|
||||||
|
|
||||||
</Popconfirm>
|
|
||||||
{isBseQuestion || values?.isBase === 1
|
{isBseQuestion || values?.isBase === 1
|
||||||
? t("header.malty_exercise")
|
? t("header.malty_exercise")
|
||||||
: t("header.exercise")}
|
: t("header.exercise")}
|
||||||
|
|
||||||
|
</Popconfirm>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import React from "react";
|
|
||||||
import SearchBar from "../../Components/Ui/SearchBar/SearchBar";
|
|
||||||
import { Button } from "antd";
|
import { Button } from "antd";
|
||||||
import { BsPlusCircleFill } from "react-icons/bs";
|
import { BsPlusCircleFill } from "react-icons/bs";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
@ -8,8 +7,7 @@ import useModalHandler from "../../utils/useModalHandler";
|
||||||
import { MdOutlineArrowForwardIos } from "react-icons/md";
|
import { MdOutlineArrowForwardIos } from "react-icons/md";
|
||||||
import { deletePathSegments } from "../../utils/deletePathSegments";
|
import { deletePathSegments } from "../../utils/deletePathSegments";
|
||||||
import { getPrevPathRoute } from "../../utils/getPrevPathRoute";
|
import { getPrevPathRoute } from "../../utils/getPrevPathRoute";
|
||||||
import { usePageTitleState } from "../../zustand/PageTitleState";
|
import PageTitleComponent from "./PageTitle";
|
||||||
import FillterForm from "../Ui/FillterForm";
|
|
||||||
|
|
||||||
const PageHeader = ({
|
const PageHeader = ({
|
||||||
canAdd,
|
canAdd,
|
||||||
|
|
@ -35,20 +33,20 @@ const PageHeader = ({
|
||||||
if (PrevPath === 0) {
|
if (PrevPath === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
navigate(deletePathSegments(location.pathname, PrevPath));
|
// navigate(deletePathSegments(location.pathname, PrevPath));
|
||||||
};
|
};
|
||||||
const handleNavigateToPage = (location: string) => {
|
const handleNavigateToPage = (location: string) => {
|
||||||
navigate(location);
|
// navigate(location);
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log();
|
console.log();
|
||||||
const { PageTitle } = usePageTitleState();
|
|
||||||
return (
|
return (
|
||||||
<div className="page_header">
|
<div className="page_header">
|
||||||
<header className="d-flex justify-content-between">
|
<header className="d-flex justify-content-between">
|
||||||
<span className="page_header_links" onClick={handelNavigate}>
|
<span className="page_header_links" onClick={handelNavigate}>
|
||||||
<h1 className="page_title">{t(`PageTitle.${pageTitle}`)}</h1>
|
<h1 className="page_title">{t(`PageTitle.${pageTitle}`)}</h1>
|
||||||
<span className="page_links">
|
<span className="page_links">
|
||||||
<MdOutlineArrowForwardIos /> {PageTitle}
|
<MdOutlineArrowForwardIos /> <PageTitleComponent/>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
{ addModal ? canAdd && (
|
{ addModal ? canAdd && (
|
||||||
|
|
|
||||||
30
src/Layout/Dashboard/PageTitle.tsx
Normal file
30
src/Layout/Dashboard/PageTitle.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
|
import { usePageTitleState } from '../../zustand/PageTitleState'
|
||||||
|
|
||||||
|
const PageTitleComponent = () => {
|
||||||
|
|
||||||
|
const {PageTitle,setPageTitle} = usePageTitleState()
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const location = useLocation()
|
||||||
|
const handleNavigate = (path:string)=>{
|
||||||
|
const currentPath = location.pathname ;
|
||||||
|
const newPath = currentPath?.split(path)?.[0] + path ;
|
||||||
|
if(newPath !== currentPath){
|
||||||
|
navigate(newPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className='PageTitle'>
|
||||||
|
{(Array.isArray(PageTitle) ? PageTitle : [])?.map((item,index)=>{
|
||||||
|
return (
|
||||||
|
<div key={index} className='PageTitleItems' onClick={()=>handleNavigate(item?.path)}>
|
||||||
|
{item?.name} /
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PageTitleComponent
|
||||||
|
|
@ -20,7 +20,10 @@ const TableHeader = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const deleteMutation = useDeleteGrade();
|
const deleteMutation = useDeleteGrade();
|
||||||
|
|
||||||
useSetPageTitle(t(`page_header.grade`));
|
useSetPageTitle([
|
||||||
|
{name:`${t(`page_header.home`)}`, path:"/"},
|
||||||
|
{name:`${t(`page_header.grade`)}`, path:"grade"}
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="TableWithHeader">
|
<div className="TableWithHeader">
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,11 @@ const DeleteModalForm = lazy(
|
||||||
|
|
||||||
const TableHeader = () => {
|
const TableHeader = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
useSetPageTitle(t(`page_header.param`));
|
|
||||||
|
useSetPageTitle([
|
||||||
|
{name:`${t(`page_header.home`)}`, path:"/"},
|
||||||
|
{name:`${t(`page_header.param`)}`, path:"param"}
|
||||||
|
]);
|
||||||
const deleteMutation = useDeleteParam();
|
const deleteMutation = useDeleteParam();
|
||||||
return (
|
return (
|
||||||
<div className="TableWithHeader">
|
<div className="TableWithHeader">
|
||||||
|
|
|
||||||
33
src/Pages/Admin/QuestionBank/Model/AddModel.tsx
Normal file
33
src/Pages/Admin/QuestionBank/Model/AddModel.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import React from "react";
|
||||||
|
import { getInitialValues, getValidationSchema } from "./formUtil";
|
||||||
|
import { ModalEnum } from "../../../../enums/Model";
|
||||||
|
import LayoutModel from "../../../../Layout/Dashboard/LayoutModel";
|
||||||
|
import { QueryStatusEnum } from "../../../../enums/QueryStatus";
|
||||||
|
import ModelForm from "./ModelForm";
|
||||||
|
import { useAddGrade } from "../../../../api/grade";
|
||||||
|
|
||||||
|
const AddModel: React.FC = () => {
|
||||||
|
const { mutate, status } = useAddGrade();
|
||||||
|
|
||||||
|
const handleSubmit = (values: any) => {
|
||||||
|
mutate({
|
||||||
|
...values,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<LayoutModel
|
||||||
|
status={status as QueryStatusEnum}
|
||||||
|
ModelEnum={ModalEnum.GRADE_ADD}
|
||||||
|
modelTitle="grade"
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
getInitialValues={getInitialValues({})}
|
||||||
|
getValidationSchema={getValidationSchema}
|
||||||
|
>
|
||||||
|
<ModelForm />
|
||||||
|
</LayoutModel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddModel;
|
||||||
38
src/Pages/Admin/QuestionBank/Model/EditModel.tsx
Normal file
38
src/Pages/Admin/QuestionBank/Model/EditModel.tsx
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import React from "react";
|
||||||
|
import { getInitialValues, getValidationSchema } from "./formUtil";
|
||||||
|
import { ModalEnum } from "../../../../enums/Model";
|
||||||
|
import LayoutModel from "../../../../Layout/Dashboard/LayoutModel";
|
||||||
|
import ModelForm from "./ModelForm";
|
||||||
|
import { QueryStatusEnum } from "../../../../enums/QueryStatus";
|
||||||
|
import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
|
||||||
|
import { useUpdateQuestion } from "../../../../api/Question";
|
||||||
|
import { handelImageState } from "../../../../utils/DataToSendImageState";
|
||||||
|
|
||||||
|
const EditModel: React.FC = () => {
|
||||||
|
const { mutate, status } = useUpdateQuestion();
|
||||||
|
const { objectToEdit } = useObjectToEdit((state) => state);
|
||||||
|
|
||||||
|
const handleSubmit = (values: any) => {
|
||||||
|
const Data_to_send = { ...values };
|
||||||
|
const handelImage = handelImageState(Data_to_send, "icon");
|
||||||
|
mutate(handelImage);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<LayoutModel
|
||||||
|
status={status as QueryStatusEnum}
|
||||||
|
ModelEnum={ModalEnum.QUESTION_BANK_EDIT}
|
||||||
|
modelTitle="QuestionBank"
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
getInitialValues={getInitialValues(objectToEdit)}
|
||||||
|
getValidationSchema={getValidationSchema}
|
||||||
|
isAddModal={false}
|
||||||
|
>
|
||||||
|
<ModelForm />
|
||||||
|
</LayoutModel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditModel;
|
||||||
20
src/Pages/Admin/QuestionBank/Model/FilterForm.tsx
Normal file
20
src/Pages/Admin/QuestionBank/Model/FilterForm.tsx
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import React from "react";
|
||||||
|
import ValidationField from "../../../../Components/ValidationField/ValidationField";
|
||||||
|
import { Col, Row } from "reactstrap";
|
||||||
|
import { useFormikContext } from "formik";
|
||||||
|
|
||||||
|
const FilterForm = () => {
|
||||||
|
const formik = useFormikContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Row>
|
||||||
|
<Col>
|
||||||
|
<ValidationField placeholder="name" label="name" name="name" />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FilterForm;
|
||||||
17
src/Pages/Admin/QuestionBank/Model/ModelForm.tsx
Normal file
17
src/Pages/Admin/QuestionBank/Model/ModelForm.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { Col, Row } from "reactstrap";
|
||||||
|
import ValidationField from "../../../../Components/ValidationField/ValidationField";
|
||||||
|
|
||||||
|
const Form = () => {
|
||||||
|
return (
|
||||||
|
<Row className="w-100">
|
||||||
|
<Col>
|
||||||
|
<ValidationField name="name" placeholder="name" label="name" />
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<ValidationField name="icon" type="File" />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Form;
|
||||||
19
src/Pages/Admin/QuestionBank/Model/formUtil.ts
Normal file
19
src/Pages/Admin/QuestionBank/Model/formUtil.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { Grade, GradeInitialValues } from "../../../../types/Grade";
|
||||||
|
|
||||||
|
export const getInitialValues = (
|
||||||
|
objectToEdit: Partial<Grade>,
|
||||||
|
): GradeInitialValues => {
|
||||||
|
return {
|
||||||
|
id: objectToEdit?.id,
|
||||||
|
name: objectToEdit?.name ?? "",
|
||||||
|
icon: objectToEdit?.icon ?? "",
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getValidationSchema = () => {
|
||||||
|
// validate input
|
||||||
|
return Yup.object().shape({
|
||||||
|
name: Yup.string().required("validation.required"),
|
||||||
|
});
|
||||||
|
};
|
||||||
49
src/Pages/Admin/QuestionBank/Page.tsx
Normal file
49
src/Pages/Admin/QuestionBank/Page.tsx
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { lazy, Suspense } from "react";
|
||||||
|
import { Spin } from "antd";
|
||||||
|
import useSetPageTitle from "../../../Hooks/useSetPageTitle";
|
||||||
|
import { ModalEnum } from "../../../enums/Model";
|
||||||
|
import { useDeleteQuestion } from "../../../api/Question";
|
||||||
|
import PageHeader from "../../../Layout/Dashboard/PageHeader";
|
||||||
|
import FilterLayout from "../../../Layout/Dashboard/FilterLayout";
|
||||||
|
import FilterForm from "./Model/FilterForm";
|
||||||
|
import { canAddQuestionBank } from "../../../utils/hasAbilityFn";
|
||||||
|
|
||||||
|
const Table = lazy(() => import("./Table"));
|
||||||
|
const AddModalForm = lazy(() => import("./Model/AddModel"));
|
||||||
|
const EditModalForm = lazy(() => import("./Model/EditModel"));
|
||||||
|
const DeleteModalForm = lazy(
|
||||||
|
() => import("../../../Layout/Dashboard/DeleteModels"),
|
||||||
|
);
|
||||||
|
|
||||||
|
const TableHeader = () => {
|
||||||
|
const [t] = useTranslation();
|
||||||
|
const deleteMutation = useDeleteQuestion();
|
||||||
|
|
||||||
|
|
||||||
|
useSetPageTitle([
|
||||||
|
{name:`${t(`page_header.home`)}`, path:"/"},
|
||||||
|
{name:`${t(`page_header.Question`)}`, path:"Question"}
|
||||||
|
]);
|
||||||
|
return (
|
||||||
|
<div className="TableWithHeader">
|
||||||
|
<Suspense fallback={<Spin />}>
|
||||||
|
<PageHeader
|
||||||
|
pageTitle="QuestionBank"
|
||||||
|
ModelAbility={ModalEnum?.QUESTION_BANK_ADD}
|
||||||
|
canAdd={canAddQuestionBank}
|
||||||
|
/>
|
||||||
|
<FilterLayout sub_children={<FilterForm />} filterTitle="table.QuestionBank" />
|
||||||
|
<Table />
|
||||||
|
<AddModalForm />
|
||||||
|
<EditModalForm />
|
||||||
|
<DeleteModalForm
|
||||||
|
deleteMutation={deleteMutation}
|
||||||
|
ModelEnum={ModalEnum?.QUESTION_BANK_DELETE}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableHeader;
|
||||||
18
src/Pages/Admin/QuestionBank/Table.tsx
Normal file
18
src/Pages/Admin/QuestionBank/Table.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { useColumns } from "./useTableColumns";
|
||||||
|
import React from "react";
|
||||||
|
import DataTable from "../../../Layout/Dashboard/Table/DataTable";
|
||||||
|
import { useGetAllQuestion } from "../../../api/Question";
|
||||||
|
import { useFilterState } from "../../../Components/Utils/Filter/FilterState";
|
||||||
|
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const { filterState } = useFilterState();
|
||||||
|
|
||||||
|
const response = useGetAllQuestion({
|
||||||
|
pagination: true,
|
||||||
|
...filterState,
|
||||||
|
});
|
||||||
|
|
||||||
|
return <DataTable response={response} useColumns={useColumns} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
||||||
123
src/Pages/Admin/QuestionBank/useTableColumns.tsx
Normal file
123
src/Pages/Admin/QuestionBank/useTableColumns.tsx
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
import { TableColumnsType } from "antd";
|
||||||
|
import { Question } from "../../../types/Item";
|
||||||
|
import { FaPlus } from "react-icons/fa";
|
||||||
|
import { ModalEnum } from "../../../enums/Model";
|
||||||
|
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||||
|
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 ActionButtons from "../../../Components/Table/ActionButtons";
|
||||||
|
|
||||||
|
export const useColumns = () => {
|
||||||
|
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { setIsOpen } = useModalState((state) => state);
|
||||||
|
|
||||||
|
const handelAdd = () => {
|
||||||
|
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}`);
|
||||||
|
};
|
||||||
|
const [t] = useTranslation();
|
||||||
|
|
||||||
|
const columns: TableColumnsType<Question> = [
|
||||||
|
{
|
||||||
|
title: t("columns.id"),
|
||||||
|
dataIndex: "id",
|
||||||
|
key: "id",
|
||||||
|
align: "center",
|
||||||
|
render: (text, record) => record?.id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.content")}`,
|
||||||
|
dataIndex: "content",
|
||||||
|
key: "content",
|
||||||
|
align: "center",
|
||||||
|
render: (text, record) => record?.content,
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.hint")}`,
|
||||||
|
dataIndex: "hint",
|
||||||
|
key: "hint",
|
||||||
|
align: "center",
|
||||||
|
render: (text, record) => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>{record?.hint ?? "karim"}</>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.tags")}`,
|
||||||
|
dataIndex: "tags",
|
||||||
|
key: "tags",
|
||||||
|
align: "center",
|
||||||
|
|
||||||
|
render: (text, record) => {
|
||||||
|
const tags = record?.tags?.map((item:any)=>{
|
||||||
|
return item?.name
|
||||||
|
}) ?? [];
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{tags.length > 0 ? (
|
||||||
|
tags.map((tag, index) => (
|
||||||
|
<span key={index}>
|
||||||
|
{tag}
|
||||||
|
{index < tags.length - 1 && ', '}
|
||||||
|
</span>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<span>_</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("columns.question_type"),
|
||||||
|
dataIndex: "isBase",
|
||||||
|
key: "isBase",
|
||||||
|
align: "center",
|
||||||
|
render: (text, record) =>
|
||||||
|
record?.isBase ? t("columns.base_question") : t("columns.normal_question"),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: "#",
|
||||||
|
key: "actions",
|
||||||
|
align: "center",
|
||||||
|
|
||||||
|
render: (_text, record, index) => {
|
||||||
|
return (
|
||||||
|
<ActionButtons
|
||||||
|
canDelete={canDeleteQuestion}
|
||||||
|
canEdit={canEditQuestion}
|
||||||
|
index={index}
|
||||||
|
onDelete={() => handelDelete(record)}
|
||||||
|
onEdit={() => handleEdit(record)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return columns;
|
||||||
|
};
|
||||||
|
|
@ -21,9 +21,12 @@ const SearchField = lazy(
|
||||||
);
|
);
|
||||||
|
|
||||||
const TableHeader = () => {
|
const TableHeader = () => {
|
||||||
const { handel_open_model } = useModalHandler();
|
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
useSetPageTitle(t(`page_header.report`));
|
|
||||||
|
useSetPageTitle([
|
||||||
|
{name:`${t(`page_header.home`)}`, path:"/"},
|
||||||
|
{name:`${t(`page_header.report`)}`, path:"report"}
|
||||||
|
]);
|
||||||
const deleteMutation = useDeleteTag();
|
const deleteMutation = useDeleteTag();
|
||||||
return (
|
return (
|
||||||
<div className="TableWithHeader">
|
<div className="TableWithHeader">
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,10 @@ const SearchField = lazy(
|
||||||
|
|
||||||
const TableHeader = () => {
|
const TableHeader = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
useSetPageTitle(t(`page_header.reseller`));
|
useSetPageTitle([
|
||||||
|
{name:`${t(`page_header.home`)}`, path:"/"},
|
||||||
|
{name:`${t(`page_header.reseller`)}`, path:"reseller"}
|
||||||
|
]);
|
||||||
const deleteMutation = useDeleteTag();
|
const deleteMutation = useDeleteTag();
|
||||||
return (
|
return (
|
||||||
<div className="TableWithHeader">
|
<div className="TableWithHeader">
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,10 @@ const TableHeader = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const deleteMutation = useDeleteStudent();
|
const deleteMutation = useDeleteStudent();
|
||||||
|
|
||||||
useSetPageTitle(t(`page_header.student`));
|
useSetPageTitle([
|
||||||
|
{name:`${t(`page_header.home`)}`, path:"/"},
|
||||||
|
{name:`${t(`page_header.student`)}`, path:"student"}
|
||||||
|
]);
|
||||||
return (
|
return (
|
||||||
<div className="TableWithHeader">
|
<div className="TableWithHeader">
|
||||||
<Suspense fallback={<Spin />}>
|
<Suspense fallback={<Spin />}>
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,15 @@ const EditModalForm = lazy(() => import("./Model/EditModel"));
|
||||||
const DeleteModalForm = lazy(
|
const DeleteModalForm = lazy(
|
||||||
() => import("../../../Layout/Dashboard/DeleteModels"),
|
() => import("../../../Layout/Dashboard/DeleteModels"),
|
||||||
);
|
);
|
||||||
const SearchField = lazy(
|
|
||||||
() => import("../../../Components/DataTable/SearchField"),
|
|
||||||
);
|
|
||||||
|
|
||||||
const TableHeader = () => {
|
const TableHeader = () => {
|
||||||
const { handel_open_model } = useModalHandler();
|
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
useSetPageTitle(t(`page_header.tags`));
|
|
||||||
|
useSetPageTitle([
|
||||||
|
{name:`${t(`page_header.home`)}`, path:"/"},
|
||||||
|
{name:`${t(`page_header.tags`)}`, path:"tag"}
|
||||||
|
]);
|
||||||
|
|
||||||
const deleteMutation = useDeleteTag();
|
const deleteMutation = useDeleteTag();
|
||||||
return (
|
return (
|
||||||
<div className="TableWithHeader">
|
<div className="TableWithHeader">
|
||||||
|
|
|
||||||
|
|
@ -35,15 +35,13 @@ const TableHeader = () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const gradeName = grade?.data?.name ?? "";
|
const gradeName = grade?.data?.name ?? "";
|
||||||
|
|
||||||
const SubjectName = Subject?.data?.name ?? "";
|
const SubjectName = Subject?.data?.name ?? "";
|
||||||
useSetPageTitle(
|
useSetPageTitle([
|
||||||
t(`page_header.grade`) +
|
{name:`${t(`page_header.home`)}`, path:"/"},
|
||||||
" / " +
|
{name:`${t(`page_header.grade`)}`, path:"grade"},
|
||||||
` ${t("header.subject_of_class")} (${gradeName})` +
|
{name:` ${t("header.subject_of_class")} (${gradeName})`, path:`grade/${grade_id}`},
|
||||||
" / " +
|
{name:SubjectName, path:`subject/${subject_id}`}
|
||||||
SubjectName,
|
]);
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="TableWithHeader">
|
<div className="TableWithHeader">
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,10 @@ const DeleteModalForm = lazy(
|
||||||
|
|
||||||
const TableHeader = () => {
|
const TableHeader = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
useSetPageTitle(t(`page_header.user`));
|
useSetPageTitle([
|
||||||
|
{name:`${t(`page_header.home`)}`, path:"/"},
|
||||||
|
{name:`${t(`page_header.user`)}`, path:"user"}
|
||||||
|
]);
|
||||||
const deleteMutation = useDeleteUser();
|
const deleteMutation = useDeleteUser();
|
||||||
return (
|
return (
|
||||||
<div className="TableWithHeader">
|
<div className="TableWithHeader">
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ const TableHeader = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const deleteMutation = useDeleteLesson();
|
const deleteMutation = useDeleteLesson();
|
||||||
|
|
||||||
const { unit_id, curriculum_id, grade_id, subject_id } =
|
const { unit_id, grade_id, subject_id } =
|
||||||
useParams<ParamsEnum>();
|
useParams<ParamsEnum>();
|
||||||
const { data: unit } = useGetAllUnit({ show: unit_id });
|
const { data: unit } = useGetAllUnit({ show: unit_id });
|
||||||
|
|
||||||
|
|
@ -41,15 +41,15 @@ const TableHeader = () => {
|
||||||
const SubjectName = Subject?.data?.name ?? "";
|
const SubjectName = Subject?.data?.name ?? "";
|
||||||
const unitName = unit?.data?.name ?? "";
|
const unitName = unit?.data?.name ?? "";
|
||||||
|
|
||||||
useSetPageTitle(
|
|
||||||
t(`page_header.grade`) +
|
useSetPageTitle([
|
||||||
" / " +
|
{name:`${t(`page_header.home`)}`, path:"/"},
|
||||||
` ${t("header.subject_of_class")} (${gradeName})` +
|
{name:`${t(`page_header.grade`)}`, path:"grade"},
|
||||||
" / " +
|
{name:` ${t("header.subject_of_class")} (${gradeName})`, path:`grade/${grade_id}`},
|
||||||
SubjectName +
|
{name:SubjectName, path:`subject/${subject_id}`},
|
||||||
" / " +
|
{name:unitName, path:`unit/${unit_id}`}
|
||||||
unitName,
|
]);
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="TableWithHeader">
|
<div className="TableWithHeader">
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
import React, { Suspense, lazy, useEffect } from "react";
|
import React, { Suspense, lazy, useEffect } from "react";
|
||||||
import { Spin } from "antd";
|
import { Spin } from "antd";
|
||||||
import FormikForm from "../../../Layout/Dashboard/FormikFormModel";
|
|
||||||
import {
|
import {
|
||||||
getInitialValues,
|
getInitialValues,
|
||||||
getValidationSchema,
|
getValidationSchema,
|
||||||
getInitialValuesBase,
|
getInitialValuesBase,
|
||||||
getValidationSchemaBase,
|
getValidationSchemaBase,
|
||||||
processTags,
|
processTags,
|
||||||
} from "./Model/formUtil";
|
} from "./formUtil";
|
||||||
import { useAddQuestion, useAddQuestionAsync } from "../../../api/Question";
|
import { useAddQuestion, useAddQuestionAsync } from "../../../api/Question";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
||||||
|
|
@ -21,7 +20,6 @@ import ModelForm from "./Model/ModelForm";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import { Form, Formik } from "formik";
|
import { Form, Formik } from "formik";
|
||||||
import { MdOutlineArrowForwardIos } from "react-icons/md";
|
import { MdOutlineArrowForwardIos } from "react-icons/md";
|
||||||
const AcceptModal = lazy(() => import("./Model/AcceptModal"));
|
|
||||||
|
|
||||||
const AddPage: React.FC = () => {
|
const AddPage: React.FC = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
@ -163,7 +161,8 @@ const AddPage: React.FC = () => {
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
navigate(-1);
|
navigate(-1);
|
||||||
};
|
};
|
||||||
const Loading = LoadingAsync || isLoading
|
const Loading = LoadingAsync || isLoading;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
setSuccess(true);
|
setSuccess(true);
|
||||||
|
|
@ -211,9 +210,7 @@ const AddPage: React.FC = () => {
|
||||||
</Form>
|
</Form>
|
||||||
)}
|
)}
|
||||||
</Formik>
|
</Formik>
|
||||||
<Suspense fallback={<Spin />}>
|
|
||||||
<AcceptModal />
|
|
||||||
</Suspense>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -264,9 +261,6 @@ const AddPage: React.FC = () => {
|
||||||
)}
|
)}
|
||||||
</Formik>
|
</Formik>
|
||||||
|
|
||||||
<Suspense fallback={<Spin />}>
|
|
||||||
<AcceptModal />
|
|
||||||
</Suspense>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Modal, Spin } from "antd";
|
import { Modal, Spin } from "antd";
|
||||||
import FormikForm from "../../../Layout/Dashboard/FormikFormModel";
|
|
||||||
import {
|
import {
|
||||||
getInitialValues,
|
getInitialValues,
|
||||||
getValidationSchema,
|
getValidationSchema,
|
||||||
getInitialValuesBase,
|
getInitialValuesBase,
|
||||||
getValidationSchemaBase,
|
getValidationSchemaBase,
|
||||||
processTags,
|
processTags,
|
||||||
} from "./Model/formUtil";
|
} from "./formUtil";
|
||||||
import {
|
import {
|
||||||
useAddQuestion,
|
useAddQuestion,
|
||||||
useDeleteQuestion,
|
useDeleteQuestion,
|
||||||
|
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import { Modal } from "antd";
|
|
||||||
import { useModalState } from "../../../../zustand/Modal";
|
|
||||||
import { ModalEnum } from "../../../../enums/Model";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import { QUESTION_OBJECT_KEY } from "../../../../config/AppKey";
|
|
||||||
|
|
||||||
const AcceptModal: React.FC = () => {
|
|
||||||
const { isOpen, setIsOpen } = useModalState((state) => state);
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const handleSubmit = () => {
|
|
||||||
localStorage.removeItem(QUESTION_OBJECT_KEY);
|
|
||||||
console.log("Handle submit clicked");
|
|
||||||
setIsOpen("");
|
|
||||||
|
|
||||||
navigate(-1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCancel = () => {
|
|
||||||
setIsOpen("");
|
|
||||||
};
|
|
||||||
|
|
||||||
const [t] = useTranslation();
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Modal
|
|
||||||
className="ModalForm"
|
|
||||||
centered
|
|
||||||
width={"40vw"}
|
|
||||||
footer={null}
|
|
||||||
open={isOpen === ModalEnum?.QUESTION_ACCEPT}
|
|
||||||
onCancel={handleCancel}
|
|
||||||
>
|
|
||||||
<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?",
|
|
||||||
)}{" "}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="buttons">
|
|
||||||
<div onClick={handleCancel}>{t("practical.cancel")}</div>
|
|
||||||
<div onClick={handleSubmit}>{t("practical.accept")}</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</Modal>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AcceptModal;
|
|
||||||
|
|
@ -70,6 +70,7 @@ const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
|
||||||
type="TextArea"
|
type="TextArea"
|
||||||
style={{ width: "100%" , height: 60,resize:"none" }}
|
style={{ width: "100%" , height: 60,resize:"none" }}
|
||||||
showCount={false}
|
showCount={false}
|
||||||
|
autoSize={{ minRows: 2, maxRows: 10 }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import useFormField from "../../../../../../Hooks/useFormField";
|
import { Checkbox } from "antd";
|
||||||
import { Checkbox, Form } from "antd";
|
import { useFormikContext } from "formik";
|
||||||
import { useFormik, useFormikContext } from "formik";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
const CheckboxField = ({
|
const CheckboxField = ({
|
||||||
name,
|
name,
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,7 @@ import { useTranslation } from "react-i18next";
|
||||||
import { getCharFromNumber } from "../../../../../../utils/getCharFromNumber";
|
import { getCharFromNumber } from "../../../../../../utils/getCharFromNumber";
|
||||||
import CheckboxField from "./CheckboxField";
|
import CheckboxField from "./CheckboxField";
|
||||||
import TextField from "./TextField";
|
import TextField from "./TextField";
|
||||||
import File from "./File";
|
|
||||||
import { FaTrash } from "react-icons/fa";
|
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import HintField from "./HintField";
|
|
||||||
import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
||||||
import { GoTrash } from "react-icons/go";
|
import { GoTrash } from "react-icons/go";
|
||||||
|
|
||||||
|
|
@ -92,6 +89,7 @@ const ChoiceFields = ({
|
||||||
type="TextArea"
|
type="TextArea"
|
||||||
style={{ width: "100%" , height: 60,resize:"none" }}
|
style={{ width: "100%" , height: 60,resize:"none" }}
|
||||||
showCount={false}
|
showCount={false}
|
||||||
|
autoSize={{ minRows: 2, maxRows: 10 }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
import { Button, Upload, UploadFile } from "antd";
|
|
||||||
import useFormField from "../../../../../../Hooks/useFormField";
|
|
||||||
import { UploadOutlined } from "@ant-design/icons";
|
|
||||||
import { useMemo } from "react";
|
|
||||||
|
|
||||||
const File = ({
|
|
||||||
name,
|
|
||||||
label,
|
|
||||||
onChange,
|
|
||||||
isDisabled,
|
|
||||||
placholder,
|
|
||||||
className,
|
|
||||||
parent_index,
|
|
||||||
props,
|
|
||||||
}: any) => {
|
|
||||||
const newName = `Questions[${parent_index}].answers[${name}].answer_image`;
|
|
||||||
|
|
||||||
const { formik, t, isError, errorMsg } = useFormField(newName, props);
|
|
||||||
let imageUrl =
|
|
||||||
formik?.values?.Questions?.[parent_index]?.answers[name]?.answer_image ??
|
|
||||||
null;
|
|
||||||
// console.log(imageUrl);
|
|
||||||
|
|
||||||
const fileList: UploadFile[] = useMemo(() => {
|
|
||||||
if (!imageUrl) return [];
|
|
||||||
|
|
||||||
return [
|
|
||||||
typeof imageUrl === "string"
|
|
||||||
? {
|
|
||||||
uid: "-1",
|
|
||||||
name: "uploaded-image",
|
|
||||||
status: "done",
|
|
||||||
url: imageUrl,
|
|
||||||
thumbUrl: imageUrl,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
uid: imageUrl.uid || "-1",
|
|
||||||
name: imageUrl.name || "uploaded-image",
|
|
||||||
status: "done",
|
|
||||||
originFileObj: imageUrl,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}, [imageUrl]);
|
|
||||||
// console.log(1);
|
|
||||||
|
|
||||||
const FilehandleChange = (value: any) => {
|
|
||||||
// console.log(value,"filevalue");
|
|
||||||
if (value.fileList.length === 0) {
|
|
||||||
formik.setFieldValue(newName, null);
|
|
||||||
} else {
|
|
||||||
formik.setFieldValue(
|
|
||||||
`Questions[${parent_index}].answers[${name}].answer_image`,
|
|
||||||
value?.file?.originFileObj,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const customRequest = async ({ onSuccess, no_label, label_icon }: any) => {
|
|
||||||
onSuccess();
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className={`ValidationField upload_image_button ${className ?? ""} `}>
|
|
||||||
<label htmlFor={name} className="text">
|
|
||||||
{t(`input.${label || name}`)}
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<Upload
|
|
||||||
disabled={isDisabled}
|
|
||||||
listType="picture"
|
|
||||||
maxCount={1}
|
|
||||||
fileList={[...fileList]}
|
|
||||||
onChange={onChange || FilehandleChange}
|
|
||||||
customRequest={customRequest}
|
|
||||||
className={` w-100`}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
className={isError ? "isError w-100 " : " w-100"}
|
|
||||||
icon={<UploadOutlined />}
|
|
||||||
>
|
|
||||||
{placholder ?? t("input.Click_to_upload_the_image")}
|
|
||||||
</Button>
|
|
||||||
<div className="Error_color"> {isError ? "required" : ""}</div>
|
|
||||||
{errorMsg}
|
|
||||||
</Upload>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default File;
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
import { Form, Input } from "antd";
|
|
||||||
import React from "react";
|
|
||||||
import useFormField from "../../../../../../Hooks/useFormField";
|
|
||||||
import { MdOutlineEdit } from "react-icons/md";
|
|
||||||
import { Field } from "formik";
|
|
||||||
|
|
||||||
const HintField = ({
|
|
||||||
name,
|
|
||||||
label,
|
|
||||||
label2,
|
|
||||||
placeholder,
|
|
||||||
isDisabled,
|
|
||||||
onChange,
|
|
||||||
props,
|
|
||||||
parent_index,
|
|
||||||
id,
|
|
||||||
className,
|
|
||||||
}: any) => {
|
|
||||||
const newName = `Questions[${parent_index}].answers[${name}].hint`;
|
|
||||||
|
|
||||||
const { formik, isError, errorMsg, t } = useFormField(newName, props);
|
|
||||||
const TextFilehandleChange = (
|
|
||||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
|
||||||
) => {
|
|
||||||
// console.log('Change:', e.target.value);
|
|
||||||
formik.setFieldValue(newName, e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={`ValidationField w-100 ${className ?? ""} `}>
|
|
||||||
<label htmlFor={name} className="text">
|
|
||||||
{label2 ? label2 : t(`input.${label ? label : name}`)}
|
|
||||||
</label>
|
|
||||||
<Form.Item
|
|
||||||
hasFeedback
|
|
||||||
validateStatus={isError ? "error" : ""}
|
|
||||||
help={isError ? errorMsg : ""}
|
|
||||||
>
|
|
||||||
<Field
|
|
||||||
as={Input}
|
|
||||||
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
|
||||||
name={newName}
|
|
||||||
disabled={isDisabled}
|
|
||||||
size="large"
|
|
||||||
onChange={onChange || TextFilehandleChange}
|
|
||||||
style={{ width: 200 }}
|
|
||||||
id={id}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default React.memo(HintField);
|
|
||||||
|
|
@ -87,6 +87,12 @@ const Form = () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (Success) {
|
||||||
|
formik.resetForm()
|
||||||
|
setSuccess(false);
|
||||||
|
}
|
||||||
|
}, [Success]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row className="w-100 exercise_form_container">
|
<Row className="w-100 exercise_form_container">
|
||||||
|
|
@ -136,6 +142,7 @@ const Form = () => {
|
||||||
label="hint_question"
|
label="hint_question"
|
||||||
type="TextArea"
|
type="TextArea"
|
||||||
style={{ width: "100%" , height: 60,resize:"none" }}
|
style={{ width: "100%" , height: 60,resize:"none" }}
|
||||||
|
autoSize={{ minRows: 2, maxRows: 10 }}
|
||||||
showCount={false}
|
showCount={false}
|
||||||
/>
|
/>
|
||||||
<MaltySelectTag parent_index={parent_index} />
|
<MaltySelectTag parent_index={parent_index} />
|
||||||
|
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
import { Button, Upload, UploadFile } from "antd";
|
|
||||||
import useFormField from "../../../../../../Hooks/useFormField";
|
|
||||||
import { UploadOutlined } from "@ant-design/icons";
|
|
||||||
import { useMemo } from "react";
|
|
||||||
|
|
||||||
const File = ({
|
|
||||||
name,
|
|
||||||
label,
|
|
||||||
onChange,
|
|
||||||
isDisabled,
|
|
||||||
placholder,
|
|
||||||
className,
|
|
||||||
props,
|
|
||||||
}: any) => {
|
|
||||||
const newName = `Questions[${name}].image`;
|
|
||||||
|
|
||||||
const { formik, t, isError, errorMsg } = useFormField(newName, props);
|
|
||||||
let imageUrl = formik?.values?.Questions?.[name]?.image ?? null;
|
|
||||||
// console.log(imageUrl);
|
|
||||||
|
|
||||||
const fileList: UploadFile[] = useMemo(() => {
|
|
||||||
if (!imageUrl) return [];
|
|
||||||
|
|
||||||
return [
|
|
||||||
typeof imageUrl === "string"
|
|
||||||
? {
|
|
||||||
uid: "-1",
|
|
||||||
name: "uploaded-image",
|
|
||||||
status: "done",
|
|
||||||
url: imageUrl,
|
|
||||||
thumbUrl: imageUrl,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
uid: imageUrl.uid || "-1",
|
|
||||||
name: imageUrl.name || "uploaded-image",
|
|
||||||
status: "done",
|
|
||||||
originFileObj: imageUrl,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}, [imageUrl]);
|
|
||||||
// console.log(1);
|
|
||||||
|
|
||||||
const FilehandleChange = (value: any) => {
|
|
||||||
// console.log(value,"filevalue");
|
|
||||||
if (value.fileList.length === 0) {
|
|
||||||
formik.setFieldValue(newName, null);
|
|
||||||
} else {
|
|
||||||
formik.setFieldValue(
|
|
||||||
`Questions[${name}].image`,
|
|
||||||
value?.file?.originFileObj,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const customRequest = async ({ onSuccess, no_label, label_icon }: any) => {
|
|
||||||
onSuccess();
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className={`ValidationField upload_image_button ${className ?? ""} `}>
|
|
||||||
<label htmlFor={name} className="text">
|
|
||||||
{t(`input.${label || name}`)}
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<Upload
|
|
||||||
disabled={isDisabled}
|
|
||||||
listType="picture"
|
|
||||||
maxCount={1}
|
|
||||||
fileList={[...fileList]}
|
|
||||||
onChange={onChange || FilehandleChange}
|
|
||||||
customRequest={customRequest}
|
|
||||||
className={` w-100`}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
className={isError ? "isError w-100 " : " w-100"}
|
|
||||||
icon={<UploadOutlined />}
|
|
||||||
>
|
|
||||||
{placholder ?? t("input.Click_to_upload_the_image")}
|
|
||||||
</Button>
|
|
||||||
<div className="Error_color"> {isError ? "required" : ""}</div>
|
|
||||||
{errorMsg}
|
|
||||||
</Upload>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default File;
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
import { Form, Input } from "antd";
|
|
||||||
import React from "react";
|
|
||||||
import useFormField from "../../../../../../Hooks/useFormField";
|
|
||||||
import { MdOutlineEdit } from "react-icons/md";
|
|
||||||
import { Field } from "formik";
|
|
||||||
|
|
||||||
const HintField = ({
|
|
||||||
name,
|
|
||||||
label,
|
|
||||||
label2,
|
|
||||||
placeholder,
|
|
||||||
isDisabled,
|
|
||||||
onChange,
|
|
||||||
props,
|
|
||||||
id,
|
|
||||||
className,
|
|
||||||
}: any) => {
|
|
||||||
const newName = `Questions[${name}].hint`;
|
|
||||||
const { formik, isError, errorMsg, t } = useFormField(newName, props);
|
|
||||||
const TextFilehandleChange = (
|
|
||||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
|
||||||
) => {
|
|
||||||
// console.log('Change:', e.target.value);
|
|
||||||
formik.setFieldValue(newName, e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={`ValidationField w-100 ${className ?? ""} `}>
|
|
||||||
<label htmlFor={name} className="text">
|
|
||||||
{label2 ? label2 : t(`input.${label ? label : name}`)}
|
|
||||||
</label>
|
|
||||||
<Form.Item
|
|
||||||
hasFeedback
|
|
||||||
validateStatus={isError ? "error" : ""}
|
|
||||||
help={isError ? errorMsg : ""}
|
|
||||||
>
|
|
||||||
<Field
|
|
||||||
as={Input}
|
|
||||||
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
|
||||||
name={newName}
|
|
||||||
disabled={isDisabled}
|
|
||||||
size="large"
|
|
||||||
onChange={onChange || TextFilehandleChange}
|
|
||||||
style={{ width: 200 }}
|
|
||||||
id={id}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default React.memo(HintField);
|
|
||||||
|
|
@ -1,16 +1,10 @@
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Choice } from "../../../../../../types/Item";
|
import { Choice } from "../../../../../../types/Item";
|
||||||
import ValidationField from "../../../../../../Components/ValidationField/ValidationField";
|
|
||||||
import { useFormikContext } from "formik";
|
import { useFormikContext } from "formik";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { getCharFromNumber } from "../../../../../../utils/getCharFromNumber";
|
import { getCharFromNumber } from "../../../../../../utils/getCharFromNumber";
|
||||||
import TextField from "./TextField";
|
import TextField from "./TextField";
|
||||||
import File from "./File";
|
|
||||||
import { FaTrash } from "react-icons/fa";
|
|
||||||
import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState";
|
||||||
import { toast } from "react-toastify";
|
|
||||||
import CheckboxField from "./CheckboxField";
|
|
||||||
import HintField from "./HintField";
|
|
||||||
import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
||||||
import { GoTrash } from "react-icons/go";
|
import { GoTrash } from "react-icons/go";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
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 { data } = useGetAllTag({
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (lastElement !== "") {
|
|
||||||
formik.setFieldValue(`Questions.[${parent_index}].tags`, [
|
|
||||||
...((formik?.values as any)?.Questions?.[parent_index]?.tags as any[]),
|
|
||||||
|
|
||||||
{
|
|
||||||
id: length + "_new",
|
|
||||||
name: "",
|
|
||||||
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,
|
|
||||||
});
|
|
||||||
setTagsSearch(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
// console.log(formik?.values?.tags?.length);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<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")}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="tag_container">
|
|
||||||
<div className="tags">
|
|
||||||
{(
|
|
||||||
((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}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{formik?.values?.Questions?.[parent_index]?.tags?.length > 0 && (
|
|
||||||
<p className="add_new_button">
|
|
||||||
<FaCirclePlus onClick={handleAddChoice} size={20} />
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{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)}
|
|
||||||
>
|
|
||||||
{item?.name}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DynamicTags;
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
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 inputRef = useRef<HTMLInputElement>(null);
|
|
||||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
||||||
const DEBOUNCE_DELAY = 500;
|
|
||||||
const formik = useFormikContext<any>();
|
|
||||||
const { setTagsSearch, setCurrentTag, setCurrentParentIndex } =
|
|
||||||
useObjectToEdit();
|
|
||||||
console.log(formik?.values?.Questions);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (inputRef.current) {
|
|
||||||
inputRef.current.style.width = `${(formik?.values?.Questions?.[parent_index]?.tags[index]?.name?.length + 1) * 8}px`;
|
|
||||||
}
|
|
||||||
}, [formik?.values?.Questions?.[parent_index]?.tags[index]?.name]);
|
|
||||||
|
|
||||||
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);
|
|
||||||
if (timeoutRef.current) {
|
|
||||||
clearTimeout(timeoutRef.current);
|
|
||||||
}
|
|
||||||
|
|
||||||
timeoutRef.current = setTimeout(() => {
|
|
||||||
setTagsSearch(e.target.value);
|
|
||||||
}, DEBOUNCE_DELAY);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteChoice = () => {
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
// Create a copy of current tags array
|
|
||||||
const currentTags = [...formik.values.tags];
|
|
||||||
|
|
||||||
// Remove the item at the specified index from the array
|
|
||||||
currentTags.splice(index, 1);
|
|
||||||
|
|
||||||
console.log(currentTags); // Log the updated tags array
|
|
||||||
|
|
||||||
// Update formik field value with the updated tags array
|
|
||||||
formik.setFieldValue(`Questions.[${parent_index}].tags`, currentTags);
|
|
||||||
|
|
||||||
// Reset search state if needed
|
|
||||||
setTagsSearch(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Tag;
|
|
||||||
|
|
@ -77,6 +77,7 @@ const Form = () => {
|
||||||
type="TextArea"
|
type="TextArea"
|
||||||
style={{ width: "100%" , height: 60,resize:"none" }}
|
style={{ width: "100%" , height: 60,resize:"none" }}
|
||||||
showCount={false}
|
showCount={false}
|
||||||
|
autoSize={{ minRows: 2, maxRows: 10 }}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
<SelectTag />
|
<SelectTag />
|
||||||
|
|
|
||||||
|
|
@ -42,17 +42,15 @@ const TableHeader = () => {
|
||||||
const unitName = unit?.data?.name ?? "";
|
const unitName = unit?.data?.name ?? "";
|
||||||
const LessonName = Lesson?.data?.name ?? "";
|
const LessonName = Lesson?.data?.name ?? "";
|
||||||
|
|
||||||
useSetPageTitle(
|
useSetPageTitle([
|
||||||
t(`page_header.grade`) +
|
{name:`${t(`page_header.home`)}`, path:"/"},
|
||||||
" / " +
|
{name:`${t(`page_header.grade`)}`, path:"grade"},
|
||||||
` ${t("header.subject_of_class")} (${gradeName})` +
|
{name:` ${t("header.subject_of_class")} (${gradeName})`, path:`grade/${grade_id}`},
|
||||||
" / " +
|
{name:SubjectName, path:`subject/${subject_id}`},
|
||||||
SubjectName +
|
{name:unitName, path:`unit/${unit_id}`},
|
||||||
" / " +
|
{name:LessonName, path:`lesson/${lesson_id }`}
|
||||||
unitName +
|
]);
|
||||||
" / " +
|
|
||||||
LessonName,
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="TableWithHeader">
|
<div className="TableWithHeader">
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ const App: React.FC = () => {
|
||||||
const { filterState } = useFilterState();
|
const { filterState } = useFilterState();
|
||||||
|
|
||||||
const response = useGetAllQuestion({
|
const response = useGetAllQuestion({
|
||||||
lesson_id: lesson_id,
|
lessonsIds: [lesson_id],
|
||||||
pagination: true,
|
pagination: true,
|
||||||
...filterState,
|
...filterState,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import * as Yup from "yup";
|
import * as Yup from "yup";
|
||||||
import { Question } from "../../../../types/Item";
|
import { Question } from "../../../types/Item";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
export const getInitialValues = (objectToEdit: Question): any => {
|
export const getInitialValues = (objectToEdit: Question): any => {
|
||||||
|
|
@ -45,19 +45,59 @@ export const useColumns = () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: `${t("columns.content")}`,
|
title: `${t("columns.content")}`,
|
||||||
dataIndex: "name",
|
dataIndex: "content",
|
||||||
key: "name",
|
key: "content",
|
||||||
align: "center",
|
align: "center",
|
||||||
render: (text, record) => record?.content,
|
render: (text, record) => record?.content,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("columns.isBase"),
|
title: `${t("columns.hint")}`,
|
||||||
|
dataIndex: "hint",
|
||||||
|
key: "hint",
|
||||||
|
align: "center",
|
||||||
|
render: (text, record) => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>{record?.hint ?? "_"}</>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.tags")}`,
|
||||||
|
dataIndex: "tags",
|
||||||
|
key: "tags",
|
||||||
|
align: "center",
|
||||||
|
|
||||||
|
render: (text, record) => {
|
||||||
|
const tags = record?.tags?.map((item:any)=>{
|
||||||
|
return item?.name
|
||||||
|
}) ?? [];
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{tags.length > 0 ? (
|
||||||
|
tags.map((tag, index) => (
|
||||||
|
<span key={index}>
|
||||||
|
{tag}
|
||||||
|
{index < tags.length - 1 && ', '}
|
||||||
|
</span>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<span>_</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("columns.question_type"),
|
||||||
dataIndex: "isBase",
|
dataIndex: "isBase",
|
||||||
key: "isBase",
|
key: "isBase",
|
||||||
align: "center",
|
align: "center",
|
||||||
render: (text, record) =>
|
render: (text, record) =>
|
||||||
record?.isBase ? t("practical.yes") : t("practical.no"),
|
record?.isBase ? t("columns.base_question") : t("columns.normal_question"),
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,15 @@ const TableWithHeader = () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const gradeName = grade?.data?.name ?? "";
|
const gradeName = grade?.data?.name ?? "";
|
||||||
useSetPageTitle(
|
|
||||||
t(`page_header.grade`) +
|
|
||||||
" / " +
|
useSetPageTitle([
|
||||||
` ${t("header.subject_of_class")} (${gradeName})`,
|
{name:`${t(`page_header.home`)}`, path:"/"},
|
||||||
);
|
{name:`${t(`page_header.grade`)}`, path:"grade"},
|
||||||
|
{name:` ${t("header.subject_of_class")} (${gradeName})`, path:`grade/${grade_id}`}
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="TableWithHeader">
|
<div className="TableWithHeader">
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,5 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import { Form, useFormikContext } from "formik";
|
||||||
import { Form, Field, useFormikContext } from "formik";
|
|
||||||
import Image from "../../Components/Ui/Image";
|
|
||||||
import { Input } from "antd";
|
|
||||||
import AuthSelect from "../../Components/Ui/Custom/AuthSelect";
|
|
||||||
// import { useGetAllCycle } from "../../api/cycle";
|
|
||||||
// import { useGetAllBranch } from "../../api/branch";
|
|
||||||
import { useGetAllTerm } from "../../api/term";
|
|
||||||
import { FormValues } from "../../types/Auth";
|
|
||||||
import {
|
|
||||||
BRANCH_OBJECT_KEY,
|
|
||||||
CYCLE_OBJECT_KEY,
|
|
||||||
TERM_OBJECT_KEY,
|
|
||||||
} from "../../config/AppKey";
|
|
||||||
import useFormatAuthDataToSelect from "../../utils/useFormatAuthDataToSelect";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import ValidationField from "../../Components/ValidationField/ValidationField";
|
import ValidationField from "../../Components/ValidationField/ValidationField";
|
||||||
|
|
||||||
|
|
@ -22,6 +9,9 @@ type FormFieldType = {
|
||||||
|
|
||||||
const FormField = ({ isLoading }: FormFieldType) => {
|
const FormField = ({ isLoading }: FormFieldType) => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
|
const {isValid} = useFormikContext();
|
||||||
|
console.log(isValid,"isValid");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form className="AuthForm">
|
<Form className="AuthForm">
|
||||||
{/* <Image style={{background:"#000"}} src="../App/Logo.png" /> */}
|
{/* <Image style={{background:"#000"}} src="../App/Logo.png" /> */}
|
||||||
|
|
@ -45,7 +35,7 @@ const FormField = ({ isLoading }: FormFieldType) => {
|
||||||
/>
|
/>
|
||||||
</div> */}
|
</div> */}
|
||||||
|
|
||||||
<button disabled={isLoading} type="submit" className="auth_submit_button">
|
<button disabled={ !isValid || isLoading} type="submit" className="auth_submit_button">
|
||||||
{t("practical.login")}
|
{t("practical.login")}
|
||||||
</button>
|
</button>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ const LoginForm = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="LoginForm">
|
<div className="LoginForm">
|
||||||
<Formik initialValues={initialValues} onSubmit={handelSubmit} validationSchema={validationSchema} >
|
<Formik initialValues={initialValues} onSubmit={handelSubmit} isInitialValid={false} validationSchema={validationSchema} >
|
||||||
{(formikProps) => <FormField isLoading={isLoading} />}
|
{(formikProps) => <FormField isLoading={isLoading} />}
|
||||||
</Formik>
|
</Formik>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { ABILITIES_ENUM } from "../../enums/abilities";
|
||||||
import useSetPageTitle from "../../Hooks/useSetPageTitle";
|
import useSetPageTitle from "../../Hooks/useSetPageTitle";
|
||||||
import useFilter from "../../Components/FilterField/components/useFilter";
|
import useFilter from "../../Components/FilterField/components/useFilter";
|
||||||
import { Button, Popconfirm } from "antd";
|
import { Button, Popconfirm } from "antd";
|
||||||
|
import PageTitle from "../../Layout/Dashboard/PageTitle";
|
||||||
|
|
||||||
const Dummy = () => {
|
const Dummy = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
|
|
@ -11,8 +12,7 @@ const Dummy = () => {
|
||||||
const { FilterButton, FilterBody } = useFilter();
|
const { FilterButton, FilterBody } = useFilter();
|
||||||
return (
|
return (
|
||||||
<div className="DummyHomePage">
|
<div className="DummyHomePage">
|
||||||
{/* <FilterButton />
|
<PageTitle/>
|
||||||
<FilterBody>karim</FilterBody> */}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ const EditReSeller = React.lazy(
|
||||||
const User = React.lazy(() => import("./Pages/Admin/User/Page"));
|
const User = React.lazy(() => import("./Pages/Admin/User/Page"));
|
||||||
|
|
||||||
const Param = React.lazy(() => import("./Pages/Admin/Param/Page"));
|
const Param = React.lazy(() => import("./Pages/Admin/Param/Page"));
|
||||||
|
const QuestionBank = React.lazy(() => import("./Pages/Admin/QuestionBank/Page"));
|
||||||
|
|
||||||
/// RESELLER ///
|
/// RESELLER ///
|
||||||
const Student_Package = React.lazy(
|
const Student_Package = React.lazy(
|
||||||
|
|
@ -129,6 +130,18 @@ export const menuItems: TMenuItem[] = [
|
||||||
prevPath: 0,
|
prevPath: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
header: "page_header.questionBank",
|
||||||
|
element: <QuestionBank />,
|
||||||
|
icon: <FaSellcast />,
|
||||||
|
text: "sidebar.questionBank",
|
||||||
|
path: `/${ABILITIES_ENUM?.QUESTION}`,
|
||||||
|
abilities: ABILITIES_ENUM?.QUESTION,
|
||||||
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
|
prevPath: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
/// RESELLER /////
|
/// RESELLER /////
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@
|
||||||
}
|
}
|
||||||
.page_links {
|
.page_links {
|
||||||
color: var(--opacity);
|
color: var(--opacity);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -16,3 +19,12 @@
|
||||||
.filter_header_top {
|
.filter_header_top {
|
||||||
color: #202c4b;
|
color: #202c4b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.PageTitle{
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
.PageTitleItems{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -127,12 +127,14 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 14px 10px;
|
padding: 14px 20px;
|
||||||
background: #f2f4f8;
|
background: #f2f4f8;
|
||||||
border-radius: 10px 10px 0 0;
|
border-radius: 10px 10px 0 0;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
box-shadow: 0px 0px 4px 2px rgba(0, 0, 0, 0.1);
|
box-shadow: 0px 0px 4px 2px rgba(0, 0, 0, 0.1);
|
||||||
|
div{
|
||||||
|
margin-left: 25px;
|
||||||
|
}
|
||||||
img {
|
img {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
@ -246,3 +248,10 @@
|
||||||
padding: 30px 2vw 10px 2vw;
|
padding: 30px 2vw 10px 2vw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.SelectTag{
|
||||||
|
label{
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 19px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,4 +5,4 @@ const API = {
|
||||||
LOGIN: `login`,
|
LOGIN: `login`,
|
||||||
LOGOUT: `logout`,
|
LOGOUT: `logout`,
|
||||||
};
|
};
|
||||||
export const useLoginAdmin = () => useAddMutation(KEY, API.LOGIN, false);
|
export const useLoginAdmin = () => useAddMutation(KEY, API.LOGIN, true);
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,8 @@ function useAxios() {
|
||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
|
console.log(error?.response);
|
||||||
|
|
||||||
const status = error?.request?.status;
|
const status = error?.request?.status;
|
||||||
const errorMsg = error?.response?.data?.message;
|
const errorMsg = error?.response?.data?.message;
|
||||||
const errorField = error?.response?.data;
|
const errorField = error?.response?.data;
|
||||||
|
|
|
||||||
|
|
@ -186,4 +186,11 @@ export enum ModalEnum {
|
||||||
Student_Package_EDIT = "Student_Package.edit",
|
Student_Package_EDIT = "Student_Package.edit",
|
||||||
Student_Package_ADD = "Student_Package.add",
|
Student_Package_ADD = "Student_Package.add",
|
||||||
Student_Package_DELETE = "Student_Package.delete",
|
Student_Package_DELETE = "Student_Package.delete",
|
||||||
|
|
||||||
|
|
||||||
|
///QuestionBank
|
||||||
|
|
||||||
|
QUESTION_BANK_ADD = "QuestionBank.add",
|
||||||
|
QUESTION_BANK_EDIT = "QuestionBank.edit",
|
||||||
|
QUESTION_BANK_DELETE = "QuestionBank.delete",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ export enum ABILITIES_ENUM {
|
||||||
User = "user",
|
User = "user",
|
||||||
RE_SELLER = "reseller",
|
RE_SELLER = "reseller",
|
||||||
Student_Package = "student_package",
|
Student_Package = "student_package",
|
||||||
|
QUESTION_BANK = "QuestionBank"
|
||||||
|
|
||||||
////
|
////
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,12 @@
|
||||||
"subject":"المادة",
|
"subject":"المادة",
|
||||||
"quiz_status":"حالة الاختبار",
|
"quiz_status":"حالة الاختبار",
|
||||||
"creator_name":"اسم المنشئ",
|
"creator_name":"اسم المنشئ",
|
||||||
"created_by":"أنشئ بواسطة"
|
"created_by":"أنشئ بواسطة",
|
||||||
|
"question_type": "نوع تمرين",
|
||||||
|
"base_question": " تمرين متعدد ",
|
||||||
|
"normal_question": " تمرين عادي",
|
||||||
|
"hint":"شرح ",
|
||||||
|
"tags":"كلمات مفتاحية"
|
||||||
},
|
},
|
||||||
"practical": {
|
"practical": {
|
||||||
"to_confirm_deletion_please_re_enter": "لتأكيد الحذف، يرجى إعادة الإدخال",
|
"to_confirm_deletion_please_re_enter": "لتأكيد الحذف، يرجى إعادة الإدخال",
|
||||||
|
|
@ -753,7 +758,8 @@
|
||||||
"reseller": "البائعين",
|
"reseller": "البائعين",
|
||||||
"param": "معامل",
|
"param": "معامل",
|
||||||
"student_package": "حزمة الطالب",
|
"student_package": "حزمة الطالب",
|
||||||
"quiz":"الاختبارات"
|
"quiz":"الاختبارات",
|
||||||
|
"questionBank":"بنك الأسئلة"
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
"some_thing_went_wrong": "حدث خطأ ما",
|
"some_thing_went_wrong": "حدث خطأ ما",
|
||||||
|
|
@ -788,17 +794,18 @@
|
||||||
"grade": "الصفوف",
|
"grade": "الصفوف",
|
||||||
"report": "تقرير",
|
"report": "تقرير",
|
||||||
"tags": "كلمات مفتاحية",
|
"tags": "كلمات مفتاحية",
|
||||||
"reseller":"البائعين"
|
"reseller":"البائعين",
|
||||||
|
"QuestionBank":"بنك الأسئلة"
|
||||||
},
|
},
|
||||||
"page_header": {
|
"page_header": {
|
||||||
"dashboard": "لوحة القيادة / الصفحة الرئيسية",
|
"home": "لوحة القيادة",
|
||||||
"course": " لوحة القيادة / الصفوف ",
|
"course": " الصفوف ",
|
||||||
"teacher": " لوحة القيادة / المعلمون",
|
"teacher": " المعلمون",
|
||||||
"payment": " لوحة القيادة / الدفعات",
|
"payment": " الدفعات",
|
||||||
"branch": " لوحة القيادة / الفروع",
|
"branch": " الفروع",
|
||||||
"role": " لوحة القيادة / الادوار",
|
"role": " الادوار",
|
||||||
"student": " لوحة القيادة / قائمة الطلاب ",
|
"student": " قائمة الطلاب ",
|
||||||
"admin": " لوحة القيادة / المسؤولون",
|
"admin": " المسؤولون",
|
||||||
"student_details": "تفاصيل الطالب",
|
"student_details": "تفاصيل الطالب",
|
||||||
"create_student": "إنشاء طالب",
|
"create_student": "إنشاء طالب",
|
||||||
"course_details": "تفاصيل الصف",
|
"course_details": "تفاصيل الصف",
|
||||||
|
|
@ -806,32 +813,34 @@
|
||||||
"student_payment": "دفع الطالب",
|
"student_payment": "دفع الطالب",
|
||||||
"student_note": "ملاحظات الطالب",
|
"student_note": "ملاحظات الطالب",
|
||||||
"student_status": "حالة الطالب",
|
"student_status": "حالة الطالب",
|
||||||
"education_class": "لوحة القيادة / الصفوف / الشعب",
|
"education_class": "الصفوف / الشعب",
|
||||||
"education_class_details": " لوحة القيادة / الصفوف / الشعب / تفاصيل الشعبة",
|
"education_class_details": " الصفوف / الشعب / تفاصيل الشعبة",
|
||||||
"subject_details": " لوحة القيادة / تفاصيل المادة ",
|
"subject_details": " تفاصيل المادة ",
|
||||||
"cycle": "لوحة القيادة / السنة دراسية ",
|
"cycle": " السنة دراسية ",
|
||||||
"term": "لوحة القيادة / الفصل ",
|
"term": "الفصل ",
|
||||||
"unit_details": "لوحة القيادة / تفاصيل المادة / تفاصيل الوحدة",
|
"unit_details": "تفاصيل المادة / تفاصيل الوحدة",
|
||||||
"lesson_details": "لوحة القيادة / تفاصيل المادة / تفاصيل الوحدة / تفاصيل الدرس",
|
"lesson_details": "تفاصيل المادة / تفاصيل الوحدة / تفاصيل الدرس",
|
||||||
"exercise_add": "لوحة القيادة / تفاصيل الدرس / إضافة تمارين ",
|
"exercise_add": "تفاصيل الدرس / إضافة تمارين ",
|
||||||
"subject": "لوحة القيادة / المادة",
|
"subject": "المادة",
|
||||||
"tags": "لوحة القيادة / كلمات مفتاحية",
|
"tags": "كلمات مفتاحية",
|
||||||
"Question": "لوحة القيادة /اسئلة ",
|
"Question": "سئلة ",
|
||||||
"add_Question": "لوحة القيادة /إضافة اسئلة ",
|
"add_Question": "ضافة اسئلة ",
|
||||||
"edit_Question": "لوحة القيادة /تعديل اسئلة ",
|
"edit_Question": "عديل اسئلة ",
|
||||||
"grade": "لوحة القيادة / الصفوف",
|
"grade": "الصفوف",
|
||||||
"report": "تقرير",
|
"report": "تقرير",
|
||||||
"users": "لوحة القيادة / المستخدمون",
|
"users": "المستخدمون",
|
||||||
"reseller": " لوحة القيادة / البائعين",
|
"reseller": " البائعين",
|
||||||
"add_reseller": " لوحة القيادة / البائعين / إضافة بائع ",
|
"add_reseller": " البائعين / إضافة بائع ",
|
||||||
"param": "معامل",
|
"param": "معامل",
|
||||||
"student_package": "حزمة الطالب"
|
"student_package": "حزمة الطالب",
|
||||||
|
"QuestionBank":"بنك الأسئلة"
|
||||||
},
|
},
|
||||||
"table": {
|
"table": {
|
||||||
"student": "قائمة الطلاب",
|
"student": "قائمة الطلاب",
|
||||||
"reseller": "البائعين",
|
"reseller": "البائعين",
|
||||||
"grade": "قائمة الصفوف",
|
"grade": "قائمة الصفوف",
|
||||||
"subjects": "مواد الصف"
|
"subjects": "مواد الصف",
|
||||||
|
"QuestionBank":"بنك الأسئلة"
|
||||||
},
|
},
|
||||||
"alphabet": {
|
"alphabet": {
|
||||||
"A": "A",
|
"A": "A",
|
||||||
|
|
|
||||||
|
|
@ -677,3 +677,25 @@ export const canDeleteStudent_Package = hasAbility(
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// QuestionBank
|
||||||
|
|
||||||
|
export const canAddQuestionBank = hasAbility(
|
||||||
|
ABILITIES_ENUM.QUESTION_BANK,
|
||||||
|
ABILITIES_VALUES_ENUM.STORE,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const canEditQuestionBank = hasAbility(
|
||||||
|
ABILITIES_ENUM.QUESTION_BANK,
|
||||||
|
ABILITIES_VALUES_ENUM.UPDATE,
|
||||||
|
);
|
||||||
|
export const canDeleteQuestionBank = hasAbility(
|
||||||
|
ABILITIES_ENUM.QUESTION_BANK,
|
||||||
|
ABILITIES_VALUES_ENUM.DELETE,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const canShowQuestionBank = hasAbility(
|
||||||
|
ABILITIES_ENUM.QUESTION_BANK,
|
||||||
|
ABILITIES_VALUES_ENUM.SHOW,
|
||||||
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user