change it

This commit is contained in:
karimaldeen 2024-09-08 22:24:57 +03:00
parent c21796cfc1
commit 10af7490a1
31 changed files with 323 additions and 91 deletions

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.41177 10.8602C9.60628 10.8602 9.77726 10.7862 9.92471 10.6381C10.0722 10.49 10.1462 10.3191 10.1468 10.1252C10.1475 9.9313 10.0734 9.76031 9.92471 9.61224C9.776 9.46416 9.60502 9.39012 9.41177 9.39012C9.21851 9.39012 9.04753 9.46416 8.89882 9.61224C8.75012 9.76031 8.67608 9.9313 8.67671 10.1252C8.67733 10.3191 8.75137 10.49 8.89882 10.6381C9.04628 10.7862 9.21726 10.8609 9.41177 10.8602ZM8.99576 8.20988H9.82777C9.85224 7.81522 9.91467 7.51812 10.0151 7.31859C10.1148 7.11906 10.3555 6.84047 10.7369 6.48282C11.1347 6.12141 11.4121 5.79828 11.5689 5.51341C11.7258 5.22981 11.8042 4.90384 11.8042 4.53553C11.8042 3.90181 11.5784 3.37381 11.1266 2.95153C10.6748 2.52863 10.1032 2.31718 9.41177 2.31718C8.8891 2.31718 8.42479 2.45835 8.01882 2.74071C7.61286 3.02306 7.30384 3.408 7.09177 3.89553L7.85506 4.23153C8.03263 3.86384 8.2491 3.58777 8.50447 3.4033C8.75984 3.21883 9.06227 3.1269 9.41177 3.12753C9.86102 3.12753 10.2334 3.26055 10.5289 3.52659C10.8238 3.79263 10.9713 4.13616 10.9713 4.55718C10.9713 4.81318 10.8998 5.0513 10.7567 5.27153C10.613 5.49177 10.3661 5.75686 10.016 6.06682C9.61945 6.41318 9.35028 6.73098 9.20847 7.02024C9.06667 7.30949 8.99576 7.70604 8.99576 8.20988ZM4.34447 13.1765C3.9109 13.1765 3.54918 13.0315 3.2593 12.7416C2.96941 12.4518 2.82416 12.09 2.82353 11.6565V1.52C2.82353 1.08706 2.96879 0.725335 3.2593 0.434825C3.54981 0.144316 3.91153 -0.000625423 4.34447 2.0284e-06H14.48C14.9129 2.0284e-06 15.2747 0.144943 15.5652 0.434825C15.8557 0.724708 16.0006 1.08643 16 1.52V11.6565C16 12.0894 15.8551 12.4508 15.5652 12.7407C15.2753 13.0306 14.9133 13.1758 14.4791 13.1765H4.34447ZM4.34447 12.2353H14.48C14.6243 12.2353 14.757 12.1751 14.8781 12.0546C14.9992 11.9341 15.0595 11.8014 15.0588 11.6565V1.52C15.0588 1.37569 14.9986 1.24298 14.8781 1.12188C14.7576 1.00079 14.6246 0.940551 14.4791 0.941178H4.34447C4.19953 0.941178 4.06651 1.00141 3.94541 1.12188C3.82432 1.24235 3.76408 1.37506 3.76471 1.52V11.6565C3.76471 11.8008 3.82494 11.9335 3.94541 12.0546C4.06588 12.1757 4.19859 12.2359 4.34353 12.2353M1.52 16C1.08706 16 0.725335 15.8551 0.434825 15.5652C0.144316 15.2753 -0.000625423 14.9136 2.0284e-06 14.48V3.40235H0.941178V14.48C0.941178 14.6243 1.00141 14.757 1.12188 14.8781C1.24235 14.9992 1.37506 15.0595 1.52 15.0588H12.5976V16H1.52Z" fill="#202C4B"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,25 +1,34 @@
import { useFormikContext } from "formik"; import { useFormikContext } from "formik";
import { useTranslation } from "react-i18next"; import { useState, useRef, useEffect } from "react";
import { useState, useRef } from "react";
import './ImageBoxField.scss'; import './ImageBoxField.scss';
import ImageIcon from "./ImageIcon"; import ImageIcon from "./ImageIcon";
import ImageCancelIcon from "./ImageCancelIcon"; import ImageCancelIcon from "./ImageCancelIcon";
import { getNestedValue } from "../../../utils/getNestedValue";
import { generateImagePreview } from "./generateImagePreview";
// Helper function to generate image preview from a File
const ImageBoxField = ({ name }: any) => { const ImageBoxField = ({ name }: any) => {
const formik = useFormikContext<any>(); const formik = useFormikContext<any>();
const [imagePreview, setImagePreview] = useState<string | null>(""); const value = getNestedValue(formik.values, name);
const [t] = useTranslation(); const [imagePreview, setImagePreview] = useState<string | null>(null);
const fileInputRef = useRef<HTMLInputElement | null>(null); const fileInputRef = useRef<HTMLInputElement | null>(null);
useEffect(() => {
if (value instanceof File) {
generateImagePreview(value, setImagePreview);
} else if (typeof value === 'string') {
setImagePreview(value);
} else {
setImagePreview(null);
}
}, [value]);
const handleFileChange = (event: any) => { const handleFileChange = (event: any) => {
const file = event.target.files[0]; const file = event.target.files[0];
if (file) { if (file) {
const reader = new FileReader(); generateImagePreview(file, setImagePreview);
reader.onloadend = () => {
setImagePreview(reader.result as string);
};
reader.readAsDataURL(file);
formik.setFieldValue(name, file); formik.setFieldValue(name, file);
} }
}; };
@ -49,7 +58,9 @@ const ImageBoxField = ({ name }: any) => {
<ImageIcon onClick={handleButtonClick} className="ImageBoxIcon" /> <ImageIcon onClick={handleButtonClick} className="ImageBoxIcon" />
</> </>
) : ( ) : (
<></> <div className="VisibleHidden">
hidden
</div>
)} )}
</div> </div>
<div className="ImageBox"> <div className="ImageBox">
@ -62,7 +73,7 @@ const ImageBoxField = ({ name }: any) => {
<input <input
id={`file-input-${name}`} id={`file-input-${name}`}
type="file" type="file"
accept="image/*" accept="image/png, image/jpeg, image/webp"
style={{ display: "none" }} style={{ display: "none" }}
onChange={handleFileChange} onChange={handleFileChange}
ref={fileInputRef} ref={fileInputRef}

View File

@ -0,0 +1,7 @@
export const generateImagePreview = (file: File, setImagePreview: (result: string) => void) => {
const reader = new FileReader();
reader.onloadend = () => {
setImagePreview(reader.result as string);
};
reader.readAsDataURL(file);
};

View File

@ -62,7 +62,7 @@ const SearchField: React.FC<Props> = ({ placeholder, searchBy }) => {
return ( return (
<div className={`search-field ${isOpen ? "open" : ""}`}> <div className={`search-field ${isOpen ? "open" : ""}`}>
<div className="search-header" onClick={handleToggleDropdown}> <div className="search-header" onClick={handleToggleDropdown}>
<IoSearch className="search__icon" /> {/* <IoSearch className="search__icon" /> */}
<input <input
ref={inputRef} ref={inputRef}
type="text" type="text"

View File

@ -11,12 +11,14 @@ interface Props {
options: Option[]; options: Option[];
placeholder: string; placeholder: string;
onSelect?: (option: Option) => void; onSelect?: (option: Option) => void;
withIcon?:boolean
} }
const SearchFieldWithSelect: React.FC<Props> = ({ const SearchFieldWithSelect: React.FC<Props> = ({
options, options,
placeholder, placeholder,
onSelect, onSelect,
withIcon=false
}) => { }) => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [selectedOption, setSelectedOption] = useState<Option | null>(null); const [selectedOption, setSelectedOption] = useState<Option | null>(null);
@ -58,17 +60,16 @@ const SearchFieldWithSelect: React.FC<Props> = ({
return ( return (
<div ref={node} className={`search-field ${isOpen ? "open" : ""}`}> <div ref={node} className={`search-field ${isOpen ? "open" : ""}`}>
<div className="search-header" onClick={toggleDropdown}> <div className="search-header" onClick={toggleDropdown}>
<IoSearch className="search__icon" /> {withIcon && <IoSearch className="search__icon" />}
{/* <p className="search__input_text">{placeholder}</p> */}
<input <input
type="text" type="text"
className="search__input search__input_text" className="search__input search__input_text"
placeholder={selectedOption ? selectedOption.label : ""} placeholder={selectedOption ? selectedOption.label : placeholder}
// placeholder={selectedOption ? selectedOption.label : placeholder}
value={searchTerm} value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
/> />
<p className="search__input_text">{placeholder}</p>
{/* <IoMdArrowDropdown className={`search_select_icon ${isOpen ? 'open' : ''}`} /> */}
</div> </div>
{(isOpen || (searchTerm !== "" && filteredOptions.length > 0)) && ( {(isOpen || (searchTerm !== "" && filteredOptions.length > 0)) && (
<div className="search-options"> <div className="search-options">
@ -80,7 +81,7 @@ const SearchFieldWithSelect: React.FC<Props> = ({
onClick={() => handleOptionClick(option)} onClick={() => handleOptionClick(option)}
> >
<div>{option.label}</div> <div>{option.label}</div>
<IoSearch className="search__icon" /> {/* {withIcon && <IoSearch className="search__icon" />} */}
</div> </div>
))} ))}
</div> </div>

View File

@ -26,9 +26,12 @@ const Header = () => {
return ( return (
<header className="exercise_add_header mb-4"> <header className="exercise_add_header mb-4">
<article>
<img src="/Icon/QuestionIcon.svg" alt="" />
<div> <div>
{t("practical.add")} {t("models.exercise")}{" "} {t("practical.add")} {t("models.exercise")}{" "}
</div> </div>
</article>
<div> <div>
<GoArrowSwitch onClick={handleChange} className="m-2" /> <GoArrowSwitch onClick={handleChange} className="m-2" />
{isBseQuestion || values?.isBase === 1 {isBseQuestion || values?.isBase === 1

View File

@ -9,6 +9,7 @@ import OrderBySelect from '../../Components/Filter/OrderBySelect';
import LayoutFilterModal from './LayoutFilterModal'; import LayoutFilterModal from './LayoutFilterModal';
import { BiFilterAlt } from 'react-icons/bi'; import { BiFilterAlt } from 'react-icons/bi';
import { MdKeyboardArrowDown } from "react-icons/md"; import { MdKeyboardArrowDown } from "react-icons/md";
import SearchField from '../../Components/DataTable/SearchField';
const FilterLayout = ({filterTitle, sub_children}:{filterTitle:string,sub_children:any}) => { const FilterLayout = ({filterTitle, sub_children}:{filterTitle:string,sub_children:any}) => {
const {t} = useTranslation(); const {t} = useTranslation();
@ -48,8 +49,8 @@ const FilterLayout = ({filterTitle, sub_children}:{filterTitle:string,sub_childr
<p>{t("ادخالات")}</p> <p>{t("ادخالات")}</p>
</span> </span>
<div className="header_search"> <div className="header_search">
<SearchFieldWithSelect <SearchField
options={translateArray} searchBy=''
placeholder={t("practical.search_here")} placeholder={t("practical.search_here")}
/> />
</div> </div>

View File

@ -40,6 +40,7 @@ const NavBar = ({isOpen}:{isOpen:boolean}) => {
<SearchFieldWithSelect <SearchFieldWithSelect
options={translateArray} options={translateArray}
placeholder={t("practical.search_here")} placeholder={t("practical.search_here")}
withIcon
/> />
</div> </div>
<NavBarRightSide /> <NavBarRightSide />

View File

@ -26,7 +26,7 @@ const AddModel: React.FC = () => {
handleSubmit={handleSubmit} handleSubmit={handleSubmit}
getInitialValues={getInitialValues({})} getInitialValues={getInitialValues({})}
getValidationSchema={getValidationSchema} getValidationSchema={getValidationSchema}
width="40vw" width="500px"
> >
<ModelForm /> <ModelForm />
</LayoutModel> </LayoutModel>

View File

@ -32,7 +32,7 @@ const EditModel: React.FC = () => {
getInitialValues={getInitialValues(objectToEdit)} getInitialValues={getInitialValues(objectToEdit)}
getValidationSchema={getValidationSchema} getValidationSchema={getValidationSchema}
isAddModal={false} isAddModal={false}
width="40vw" width="500px"
> >
<ModelForm /> <ModelForm />
</LayoutModel> </LayoutModel>

View File

@ -25,6 +25,7 @@ const TableHeader = () => {
return ( return (
<div className="TableWithHeader"> <div className="TableWithHeader">
<Suspense fallback={<Spin />}> <Suspense fallback={<Spin />}>
<PageHeader <PageHeader
pageTitle="grade" pageTitle="grade"
ModelAbility={ModalEnum?.GRADE_ADD} ModelAbility={ModalEnum?.GRADE_ADD}

View File

@ -34,7 +34,7 @@ const AddModel: React.FC = () => {
handleSubmit={handleSubmit} handleSubmit={handleSubmit}
getInitialValues={getInitialValues({})} getInitialValues={getInitialValues({})}
getValidationSchema={getValidationSchema} getValidationSchema={getValidationSchema}
width="60vw"
> >
<ModelForm /> <ModelForm />
</LayoutModel> </LayoutModel>

View File

@ -27,7 +27,7 @@ const EditModel: React.FC = () => {
getInitialValues={getInitialValues(objectToEdit)} getInitialValues={getInitialValues(objectToEdit)}
getValidationSchema={getValidationSchema} getValidationSchema={getValidationSchema}
isAddModal={false} isAddModal={false}
width="60vw"
> >
<ModelForm /> <ModelForm />
</LayoutModel> </LayoutModel>

View File

@ -5,7 +5,7 @@ import { enumToArray } from "../../../../api/utils/enumToArray";
const Form = () => { const Form = () => {
const termsArray = enumToArray(TermEnum); const termsArray = enumToArray(TermEnum);
console.log(termsArray, "termsArray"); console.log(termsArray);
return ( return (
<Row className="w-100"> <Row className="w-100">

View File

@ -17,6 +17,7 @@ import {
} from "../../../utils/hasAbilityFn"; } from "../../../utils/hasAbilityFn";
import ActionButtons from "../../../Components/Table/ActionButtons"; import ActionButtons from "../../../Components/Table/ActionButtons";
import { Unit } from "../../../types/Unit"; import { Unit } from "../../../types/Unit";
import { ConvertEnumToTranslate } from "../../../utils/ConvertEnumToTranslate";
export const useColumns = () => { export const useColumns = () => {
const { handel_open_model } = useModalHandler(); const { handel_open_model } = useModalHandler();
@ -52,7 +53,7 @@ export const useColumns = () => {
dataIndex: "name", dataIndex: "name",
key: "name", key: "name",
align: "center", align: "center",
render: (text, record) => record?.name, render: (text) => text,
}, },
{ {
@ -60,20 +61,10 @@ export const useColumns = () => {
dataIndex: "term", dataIndex: "term",
key: "term", key: "term",
align: "center", align: "center",
render: (text, record) => record?.term, render: (text) => t(ConvertEnumToTranslate(text)),
}, },
{ {
// canAddUnit ? (
// <button
// onClick={() => handel_open_model(ModalEnum?.UNIT_ADD)}
// className="add_button"
// >
// {t("practical.add")} {t("models.unit")} <FaPlus />
// </button>
// ) : (
// ""
// ),
title: t("columns.procedure"), title: t("columns.procedure"),
key: "actions", key: "actions",

View File

@ -37,6 +37,7 @@ const CheckboxField = ({
disabled={isDisabled} disabled={isDisabled}
checked={formik.values?.QuestionOptions?.[name]?.isCorrect === 1} checked={formik.values?.QuestionOptions?.[name]?.isCorrect === 1}
className={className} className={className}
> >
{t(`input.${label ? label : name}`)} {t(`input.${label ? label : name}`)}
</Checkbox> </Checkbox>

View File

@ -10,6 +10,7 @@ import File from "./File";
import { FaCirclePlus, FaDeleteLeft } from "react-icons/fa6"; import { FaCirclePlus, FaDeleteLeft } from "react-icons/fa6";
import { GoTrash } from "react-icons/go"; import { GoTrash } from "react-icons/go";
import { LuImagePlus } from "react-icons/lu"; import { LuImagePlus } from "react-icons/lu";
import ImageBoxField from "../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => { const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
const formik = useFormikContext<any>(); const formik = useFormikContext<any>();
@ -26,37 +27,41 @@ const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
formik.setFieldValue("QuestionOptions", updatedQuestionOptions); formik.setFieldValue("QuestionOptions", updatedQuestionOptions);
}; };
console.log(formik.values);
return ( return (
<div className="ChoiceFields"> <div className="ChoiceFields">
<TextField <TextField
className="textarea_exercise" className="textarea_exercise"
placeholder={"choice"} placeholder={"choice"}
label2={t(`input.choice`) + ` ` + `(${getCharFromNumber(index)})`} label2={t(`input.choice`) + ` ` + `( ${t(`alphabet.${getCharFromNumber(index)}`)} )`}
name={index} name={index}
id={`choice_${index + 1}`} id={`choice_${index + 1}`}
type="TextArea" type="TextArea"
/> />
<File {/* <File
className="file_exercise" className="file_exercise"
label={"attachment"} label={"attachment"}
name={index} name={index}
type="File" type="File"
placeholder="" placeholder=""
icon={<LuImagePlus/>} icon={<LuImagePlus/>}
/> /> */}
<ImageBoxField name={`QuestionOptions.${index}.answer_image`} />
<div className="answer_status">
<CheckboxField <CheckboxField
className="" className=""
label="The_correct_answer" label="The_correct_answer"
name={index} name={index}
type="Checkbox" type="Checkbox"
/> />
<p className="delete_question_options"> <p className="delete_question_options">
{t("header.delete_choice")} {t("header.delete_choice")}
<GoTrash className="trash_icon" onClick={handleDeleteChoice} size={17} /> <GoTrash className="trash_icon" onClick={handleDeleteChoice} size={17} />
</p> </p>
</div>
</div> </div>
); );
}; };

View File

@ -9,6 +9,8 @@ import DynamicTags from "./Tags/DynamicTags";
import { useObjectToEdit } from "../../../../zustand/ObjectToEditState"; import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
import { useEffect } from "react"; import { useEffect } from "react";
import { LuImagePlus } from "react-icons/lu"; import { LuImagePlus } from "react-icons/lu";
import ImageBoxField from "../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
import SelectTag from "./Tags/SelectTag";
const Form = () => { const Form = () => {
const [t] = useTranslation() const [t] = useTranslation()
@ -41,8 +43,9 @@ const Form = () => {
return ( return (
<Row className="w-100 exercise_form_container"> <Row className="w-100 exercise_form_container">
<div className="exercise_form"> <div className="exercise_form">
<ValidationField className="textarea_exercise" name="content" label="details" type="TextArea" /> <ValidationField className="textarea_exercise" name="answer_content" label="answer_content" type="TextArea" />
<ValidationField className="file_exercise" name="image" label="attachment" icon={<LuImagePlus/>} placeholder="" type="File" /> <ImageBoxField name="image" />
</div> </div>
{ {
(((formik?.values as any)?.QuestionOptions as Choice[])||[]) .map((item:Choice,index:number)=>{ (((formik?.values as any)?.QuestionOptions as Choice[])||[]) .map((item:Choice,index:number)=>{
@ -53,7 +56,8 @@ const Form = () => {
<FaCirclePlus onClick={handleAddChoice} size={23} /> {t("header.add_new_choice")} <FaCirclePlus onClick={handleAddChoice} size={23} /> {t("header.add_new_choice")}
</p> </p>
)} )}
<DynamicTags/> {/* <DynamicTags/> */}
{/* <SelectTag/> */}
</Row> </Row>
); );
}; };

View File

@ -14,7 +14,6 @@ const DynamicTags = () => {
name: TagsSearch, name: TagsSearch,
}); });
const suggests = data?.data; const suggests = data?.data;
console.log(TagsSearch);
const handleAddChoice = () => { const handleAddChoice = () => {
const length = formik?.values?.tags.length; const length = formik?.values?.tags.length;

View File

@ -0,0 +1,78 @@
import React, { useState, useMemo } from 'react';
import { Select, Spin } from 'antd';
import { useGetAllTag } from '../../../../../api/tags';
import { useDebounce } from '../../../../../utils/useDebounce';
import { useTranslation } from 'react-i18next';
const SelectTag: React.FC = () => {
const [searchValue, setSearchValue] = useState<string>('');
const [fieldValue, setFieldValue] = useState<string>('');
const handleChange = (value: string[]) => {
setSearchValue('');
setFieldValue('');
};
const handleSearch = useDebounce((value: string) => {
setSearchValue(value);
});
const handleFieldChange = (value: string) => {
setFieldValue(value);
};
const handleBlur = () => {
setSearchValue('');
setFieldValue('');
};
const { data, isLoading } = useGetAllTag({
name: searchValue,
});
const [t] = useTranslation();
const options = useMemo(() => {
const apiOptions = data?.data ?? [];
if (searchValue && !apiOptions.some((opt: any) => opt.name === searchValue)) {
return [...apiOptions, { id: searchValue, name: searchValue }];
}
return apiOptions;
}, [data, searchValue]);
return (
<div className='SelectTag'>
<label htmlFor="">
{t("models.tag")}
</label>
<Select
mode="multiple"
allowClear
style={{ width: '100%' ,height:"40px"}}
placeholder="Please select"
fieldNames={{ label: 'name', value: 'id' }}
onChange={handleChange}
options={options}
loading={isLoading}
notFoundContent={isLoading ? <Spin /> : t("practical.not_found")}
onSearch={(value) => {
handleSearch(value);
handleFieldChange(value);
}}
searchValue={fieldValue}
onDropdownVisibleChange={(open) => {
if (!open) {
handleBlur();
}
}}
/>
</div>
);
};
export default SelectTag;

View File

@ -7,7 +7,7 @@ import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import ActionButtons from "../../../../Components/Table/ActionButtons"; import ActionButtons from "../../../../Components/Table/ActionButtons";
import { canDeleteSubject, canEditSubject } from "../../../../utils/hasAbilityFn"; import { canDeleteSubject, canEditSubject, canShowSubject } from "../../../../utils/hasAbilityFn";
import { ABILITIES_ENUM } from "../../../../enums/abilities"; import { ABILITIES_ENUM } from "../../../../enums/abilities";
import { Subject } from "../../../../types/Subject"; import { Subject } from "../../../../types/Subject";
@ -25,13 +25,17 @@ export const useColumns = () => {
setIsOpen(ModalEnum?.SUBJECT_EDIT); setIsOpen(ModalEnum?.SUBJECT_EDIT);
}; };
const handelShow = (record: Subject) => {
navigate(`${ABILITIES_ENUM?.SUBJECT}/${record?.id}`);
};
const [t] = useTranslation(); const [t] = useTranslation();
const columns: TableColumnsType<Subject> = [ const columns: TableColumnsType<Subject> = [
{ {
title: t("columns.id"), title: t("columns.id"),
dataIndex: "id", dataIndex: "id",
key: "id", key: "id",
align: "start", align: "center",
}, },
{ {
title: t("columns.subject_name"), title: t("columns.subject_name"),
@ -50,23 +54,6 @@ export const useColumns = () => {
}, },
}, },
{
title: t("columns.card"),
key: "name",
align: "center",
className: "SeeMoreEyeColumn",
render: (text, record) => {
const handelnavigate = () => {
navigate(`${ABILITIES_ENUM?.SUBJECT}/${record?.id}`);
};
return (
<div onClick={() => handelnavigate()} className="SeeMoreEye">
<FaEye />
</div>
);
},
},
{ {
title: t("columns.procedure"), title: t("columns.procedure"),
key: "actions", key: "actions",
@ -77,9 +64,11 @@ export const useColumns = () => {
<ActionButtons <ActionButtons
canDelete={canEditSubject} canDelete={canEditSubject}
canEdit={canDeleteSubject} canEdit={canDeleteSubject}
canShow={canShowSubject}
index={index} index={index}
onDelete={() => handelDelete(record)} onDelete={() => handelDelete(record)}
onEdit={() => handleEdit(record)} onEdit={() => handleEdit(record)}
onShow={() => handelShow(record)}
/> />
); );
}, },

View File

@ -298,4 +298,9 @@ button:disabled {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
}
.VisibleHidden{
visibility: hidden;
} }

View File

@ -2,9 +2,11 @@
position: relative; position: relative;
z-index: 999; z-index: 999;
border-radius: 10px; border-radius: 10px;
box-shadow: 2px 2px 2px 3px rgba(0, 0, 0, 0.02); // box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.001);
width: 18vw; width: 220px;
direction: ltr; // direction: ltr;
color: #6A7287B2;
} }
.NavBar { .NavBar {
.search-header { .search-header {
@ -22,13 +24,13 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 0.4vw; gap: 0.4vw;
padding-inline: 5%; padding-inline: 5px;
cursor: pointer; cursor: pointer;
background-color: var(--bg); background-color: var(--bg);
font-weight: bold; font-weight: bold;
border-radius: 10px; border-radius: 10px;
width: 18vw; // width: 18vw;
height: 3vw; height: 40px;
transition: 0.5s ease-in-out; transition: 0.5s ease-in-out;
} }
@ -38,7 +40,7 @@
} }
.search__input { .search__input {
font-size: 1vw; font-size: 14px;
width: 70%; width: 70%;
height: 100%; height: 100%;
background-color: transparent; background-color: transparent;
@ -68,7 +70,7 @@
overflow: auto; overflow: auto;
scroll-behavior: smooth; scroll-behavior: smooth;
scroll-padding: 10rem; scroll-padding: 10rem;
direction: ltr; direction: rtl;
scroll-behavior: smooth; scroll-behavior: smooth;
scroll-padding: 10rem; scroll-padding: 10rem;
&::-webkit-scrollbar { &::-webkit-scrollbar {
@ -77,14 +79,14 @@
/* Handle */ /* Handle */
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
background-color: var(--primary); background-color: transparent;
border-radius: 5px; /* Adjust border-radius as needed */ border-radius: 5px; /* Adjust border-radius as needed */
} }
/* Track */ /* Track */
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
border-radius: 5px; /* Adjust border-radius as needed */ border-radius: 5px; /* Adjust border-radius as needed */
background-color: #d3d5d7; /* Set to desired background color */ background-color: transparent; /* Set to desired background color */
} }
} }
@ -129,7 +131,7 @@
cursor: pointer; cursor: pointer;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-start;
gap: 0.4vw; gap: 0.4vw;
} }
@ -143,3 +145,16 @@
color: #fff !important; color: #fff !important;
} }
.NavBar{
.header_search{
.search-field{
input::placeholder{
color: white !important;
color: white !important;
}
}
}
}

View File

@ -43,7 +43,8 @@
} }
} }
.search-field{ .search-field{
box-shadow: 2px 2px 7px 2px rgba(0, 0, 0, 0.1); // box-shadow: 2px 2px 7px 2px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(0, 0, 0, 0.1);
.search__icon{ .search__icon{
color: var(--primary); color: var(--primary);
} }

View File

@ -21,7 +21,7 @@
gap: 1vw; gap: 1vw;
width: 100%; width: 100%;
.textarea_exercise { .textarea_exercise {
max-width: 40vw; max-width: 50vw;
} }
.file_exercise { .file_exercise {
min-width: 10vw; min-width: 10vw;
@ -141,10 +141,46 @@
.delete_question_options{ .delete_question_options{
margin-top: 25px; margin-top: 25px;
color: var(--warning); color: var(--warning);
position: absolute;
left: 100px;
padding-left: 10px; padding-left: 10px;
.trash_icon{ .trash_icon{
margin-right: 10px !important; margin-right: 10px !important;
} }
} }
.answer_status{
display: flex;
flex-direction: column;
justify-content: space-between;
padding-block: 30px;
align-items: flex-end;
}
.add_new_button{
svg{
color: var(--primary);
}
}
.exercise_add_header{
article{
display: flex;
align-items: center;
text-wrap: nowrap;
gap: 10px;
padding-inline: 20px;
font-weight: bold;
img{
width: 20px;
}
}
}
.SelectTag{
display: flex;
flex-direction: column;
gap: 10px;
margin-block: 10px;
}

View File

@ -1,6 +1,6 @@
export const enumToArray = (enumObj: any) => { export const enumToArray = (enumObj: any) => {
return Object.keys(enumObj).map((key) => ({ return Object.keys(enumObj).map((key) => ({
value: enumObj[key], value: enumObj[key],
label: enumObj[key], label: `select.enums.${enumObj[key]}`,
})); }));
}; };

View File

@ -239,7 +239,7 @@
"Pass": "نجاح", "Pass": "نجاح",
"users": "المستخدمين", "users": "المستخدمين",
"branchAdmin": "مسؤول الفروع", "branchAdmin": "مسؤول الفروع",
"grade": "الصفوف", "grade": "الدرجات",
"homeworkAttachment": "مرفق الواجب المنزلي", "homeworkAttachment": "مرفق الواجب المنزلي",
"lateArrival": "وصول متأخر", "lateArrival": "وصول متأخر",
"noteAttachment": "مرفق الملاحظة", "noteAttachment": "مرفق الملاحظة",
@ -248,7 +248,7 @@
"subjectAttachment": "مرفق المادة", "subjectAttachment": "مرفق المادة",
"exercise": "تمارين", "exercise": "تمارين",
"exerciseAnswer": "إجابة التمارين", "exerciseAnswer": "إجابة التمارين",
"tag": "العلامات", "tag": "كلمات مفتاحية",
"Exam": "امتحانات", "Exam": "امتحانات",
"ExamType": "نوع الامتحانات", "ExamType": "نوع الامتحانات",
"studentParent": "ولي أمر الطالب", "studentParent": "ولي أمر الطالب",
@ -372,7 +372,8 @@
"main_question": "النص الأساسي ", "main_question": "النص الأساسي ",
"question": "السؤال", "question": "السؤال",
"id": "الرقم التعريفي", "id": "الرقم التعريفي",
"icon": "الايقونة" "icon": "الايقونة",
"answer_content":"نص السؤال"
}, },
"select": { "select": {
"Payments": { "Payments": {
@ -624,6 +625,10 @@
"Admin_type": { "Admin_type": {
"admin": "المسؤول", "admin": "المسؤول",
"branchAdmin": "مسؤول الفروع" "branchAdmin": "مسؤول الفروع"
},
"enums":{
"first_term":"الفصل الأول",
"second_term":"الفصل الثاني"
} }
}, },
"array": { "array": {
@ -674,7 +679,7 @@
"tags": "كلمات مفتاحية", "tags": "كلمات مفتاحية",
"main_menu": "القائمة الرئيسية", "main_menu": "القائمة الرئيسية",
"setting": "الإعدادات", "setting": "الإعدادات",
"grade": "الصفوف", "grade": "الدرجات",
"curriculum": "مقرر", "curriculum": "مقرر",
"package": "حزمة", "package": "حزمة",
"subjects":"مواد", "subjects":"مواد",
@ -737,8 +742,37 @@
"Question": "لوحة القيادة /اسئلة ", "Question": "لوحة القيادة /اسئلة ",
"add_Question": "لوحة القيادة /إضافة اسئلة ", "add_Question": "لوحة القيادة /إضافة اسئلة ",
"edit_Question": "لوحة القيادة /تعديل اسئلة ", "edit_Question": "لوحة القيادة /تعديل اسئلة ",
"grade":"الصفوف", "grade":"الدرجات",
"report":"تقرير", "report":"تقرير",
"user":"مستخدم" "user":"مستخدم"
},
"alphabet":{
"A": "أ",
"B": "ب",
"C": "ت",
"D": "ث",
"E": "ج",
"F": "ح",
"G": "خ",
"H": "د",
"I": "ذ",
"J": "ر",
"K": "ز",
"L": "س",
"M": "ش",
"N": "ص",
"O": "ض",
"P": "ط",
"Q": "ظ",
"R": "ع",
"S": "غ",
"T": "ف",
"U": "ق",
"V": "ك",
"W": "ل",
"X": "م",
"Y": "ن",
"Z": "ه"
} }
} }

View File

@ -0,0 +1,7 @@
export function ConvertEnumToTranslate(enum_value:string):string{
return `select.enums.${enum_value}`
}

View File

@ -0,0 +1,10 @@
export const getNestedValue = (obj: any, path: string): any => {
return path.split('.').reduce((acc, part) => {
const arrayMatch = part.match(/(\w+)\[(\d+)\]/);
if (arrayMatch) {
const [, key, index] = arrayMatch;
return acc && acc[key] && acc[key][index];
}
return acc && acc[part];
}, obj);
};

View File

@ -112,6 +112,10 @@ export const canDeleteSubject = hasAbility(
ABILITIES_VALUES_ENUM.DELETE, ABILITIES_VALUES_ENUM.DELETE,
); );
export const canShowSubject = hasAbility(
ABILITIES_ENUM.SUBJECT,
ABILITIES_VALUES_ENUM.SHOW,
)
/// Role /// Role
export const canAddRole = hasAbility( export const canAddRole = hasAbility(

25
src/utils/useDebounce.ts Normal file
View File

@ -0,0 +1,25 @@
import { useCallback, useRef } from 'react';
export const DEBOUNCE_DELAY = 500;
export const useDebounce = (
callback: (...args: any[]) => void,
delay: number = DEBOUNCE_DELAY,
) => {
const timeoutRef = useRef<any>(null);
const debouncedCallback = useCallback(
(...args: any[]) => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
callback(...args);
}, delay);
},
[callback, delay],
);
return debouncedCallback;
};