Compare commits

...

8 Commits

Author SHA1 Message Date
karimaldeen
3bdfdf799e fixes 2024-09-25 00:24:26 +03:00
karimaldeen
53d3908f00 Merge branch 'dev' of https://git.point-dev.net/Karimaldeen/Quiz_dashboard into dev 2024-09-25 00:06:22 +03:00
karimaldeen
10e1e28c69 finish map#178 2024-09-24 15:43:20 +03:00
karimaldeen
d71e5c4fce Merge branch 'dev' of https://git.point-dev.net/Karimaldeen/Quiz_dashboard into dev 2024-09-24 15:25:26 +03:00
karimaldeen
c3edef43d5 add map 2024-09-24 15:22:41 +03:00
karimaldeen
eb86869d89 add city and area pages 2024-09-24 15:19:48 +03:00
karimaldeen
3bf0308631 end role and permission # 166 2024-09-24 14:54:27 +03:00
karimaldeen
9a6e5bc53d end #166 2024-09-24 10:59:02 +03:00
51 changed files with 4457 additions and 164 deletions

3272
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@
"@dnd-kit/sortable": "^8.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@types/katex": "^0.16.7",
"@uiw/react-markdown-preview": "^5.1.3",
"antd": "^5.17.4",
"axios": "^1.7.2",
"better-react-mathjax": "^2.0.3",
@ -18,6 +19,7 @@
"i18next": "^23.11.5",
"install": "^0.13.0",
"katex": "^0.16.11",
"leaflet": "^1.9.4",
"lottie-react": "^2.4.0",
"mathjax": "^3.2.2",
"mathjax-full": "^3.2.2",
@ -35,6 +37,7 @@
"react-katex": "^3.0.1",
"react-latex": "^2.0.0",
"react-latex-next": "^3.0.0",
"react-leaflet": "^4.2.1",
"react-mathjax": "^1.0.1",
"react-mathjax-preview": "^2.2.6",
"react-mathjax2": "^0.0.2",

View File

@ -55,7 +55,7 @@ const AddLaTexModal = ({name,setLatex,Latex,setIsModalOpen,isModalOpen,setCurren
<TextArea
size="large"
showCount
maxLength={1000}
maxLength={5000}
autoSize={{ minRows: 4, maxRows: 10 }}
style={{height:"400px"}}
onChange={handleChangeInputLatex}

View File

@ -78,7 +78,7 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
<TextArea
size="large"
showCount
maxLength={1000}
maxLength={5000}
autoSize={{ minRows: 6, maxRows: 10 }}
style={{ height: "400px" }}
onChange={handleChangeInput}

View File

@ -0,0 +1,36 @@
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 { useAddArea } from "../../../../api/Area";
import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../../../enums/params";
const AddModel: React.FC = () => {
const { mutate, status } = useAddArea();
const {city_id} = useParams<ParamsEnum>()
const handleSubmit = (values: any) => {
mutate({
...values,
city_id
});
};
return (
<>
<LayoutModel
status={status as QueryStatusEnum}
ModelEnum={ModalEnum.AREA_ADD}
modelTitle="Area"
handleSubmit={handleSubmit}
getInitialValues={getInitialValues({})}
getValidationSchema={getValidationSchema}
>
<ModelForm />
</LayoutModel>
</>
);
};
export default AddModel;

View 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 { useUpdateArea } from "../../../../api/Area";
import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../../../enums/params";
const EditModel: React.FC = () => {
const { mutate, status } = useUpdateArea();
const { objectToEdit } = useObjectToEdit((state) => state);
const {city_id} = useParams<ParamsEnum>()
const handleSubmit = (values: any) => {
const Data_to_send = { ...values,city_id };
mutate(Data_to_send);
};
return (
<>
<LayoutModel
status={status as QueryStatusEnum}
ModelEnum={ModalEnum.AREA_EDIT}
modelTitle="Area"
handleSubmit={handleSubmit}
getInitialValues={getInitialValues(objectToEdit)}
getValidationSchema={getValidationSchema}
isAddModal={false}
>
<ModelForm />
</LayoutModel>
</>
);
};
export default EditModel;

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

View File

@ -0,0 +1,15 @@
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>
</Row>
);
};
export default Form;

View File

@ -0,0 +1,18 @@
import * as Yup from "yup";
import { Area, AreaInitialValues } from "../../../../types/Area";
export const getInitialValues = (
objectToEdit: Partial<Area>,
): AreaInitialValues => {
return {
id: objectToEdit?.id,
name: objectToEdit?.name ?? "",
};
};
export const getValidationSchema = () => {
// validate input
return Yup.object().shape({
name: Yup.string().required("validation.required"),
});
};

View File

@ -0,0 +1,51 @@
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 { useDeleteArea } from "../../../api/Area";
import PageHeader from "../../../Layout/Dashboard/PageHeader";
import FilterLayout from "../../../Layout/Dashboard/FilterLayout";
import FilterForm from "./Model/FilterForm";
import { canAddArea } from "../../../utils/hasAbilityFn";
import { ParamsEnum } from "../../../enums/params";
import { useParams } from "react-router-dom";
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 = useDeleteArea();
const {city_id} = useParams<ParamsEnum>()
useSetPageTitle([
{name:`${t(`page_header.home`)}`, path:"/"},
{name:`${t(`page_header.Area`)}`, path:`city/${city_id}`},
]);
return (
<div className="TableWithHeader">
<Suspense fallback={<Spin />}>
<PageHeader
pageTitle="Area"
ModelAbility={ModalEnum?.AREA_ADD}
canAdd={canAddArea}
/>
<FilterLayout sub_children={<FilterForm />} filterTitle="table.Area" haveFilter={false} />
<Table />
<AddModalForm />
<EditModalForm />
<DeleteModalForm
deleteMutation={deleteMutation}
ModelEnum={ModalEnum?.AREA_DELETE}
/>
</Suspense>
</div>
);
};
export default TableHeader;

View File

@ -0,0 +1,28 @@
import { useColumns } from "./useTableColumns";
import React from "react";
import DataTable from "../../../Layout/Dashboard/Table/DataTable";
import { useGetAllArea } from "../../../api/Area";
import { useFilterState } from "../../../Components/Utils/Filter/FilterState";
import { useFilterStateState } from "../../../zustand/Filter";
import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../../enums/params";
const App: React.FC = () => {
const { filterState } = useFilterState();
const { Filter } = useFilterStateState();
const {city_id} = useParams<ParamsEnum>()
const name = Filter?.name ;
const sort_by = Filter?.sort_by ;
const response = useGetAllArea({
pagination: true,
...filterState,
city_id,
name,
sort_by
});
return <DataTable response={response} useColumns={useColumns} />;
};
export default App;

View File

@ -0,0 +1,80 @@
import { TableColumnsType } from "antd";
import useModalHandler from "../../../utils/useModalHandler";
import { ModalEnum } from "../../../enums/Model";
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import {
canDeleteArea,
canEditArea,
canShowArea,
} from "../../../utils/hasAbilityFn";
import ActionButtons from "../../../Components/Table/ActionButtons";
import ColumnsImage from "../../../Components/Columns/ColumnsImage";
import { Area } from "../../../types/Area";
import { useFilterStateState } from "../../../zustand/Filter";
export const useColumns = () => {
const { handel_open_model } = useModalHandler();
const { setObjectToEdit } = useObjectToEdit((state) => state);
const navigate = useNavigate();
const { setFilter } = useFilterStateState();
const handelShow = (record: Area) => {
setFilter({})
navigate(`${record?.id}`);
};
const handelDelete = (data: Area) => {
setObjectToEdit(data);
handel_open_model(ModalEnum?.AREA_DELETE);
};
const handleEdit = (record: Area) => {
setObjectToEdit(record);
handel_open_model(ModalEnum?.AREA_EDIT);
};
const [t] = useTranslation();
const columns: TableColumnsType<Area> = [
{
title: t("columns.id"),
dataIndex: "id",
key: "id",
align: "center",
render: (_text, record) => record?.id,
},
{
title: `${t("columns.name")}`,
dataIndex: "name",
key: "name",
align: "center",
render: (_text, record) => record?.name,
ellipsis:true
},
{
title: t("columns.procedure"),
key: "actions",
align: "center",
width: "25vw",
render: (_text, record, index) => {
return (
<ActionButtons
canDelete={canDeleteArea}
canEdit={canEditArea}
canShow={false}
index={index}
onDelete={() => handelDelete(record)}
onEdit={() => handleEdit(record)}
/>
);
},
},
];
return columns;
};

View 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 { useAddCity } from "../../../../api/City";
const AddModel: React.FC = () => {
const { mutate, status } = useAddCity();
const handleSubmit = (values: any) => {
mutate({
...values,
});
};
return (
<>
<LayoutModel
status={status as QueryStatusEnum}
ModelEnum={ModalEnum.CITY_ADD}
modelTitle="City"
handleSubmit={handleSubmit}
getInitialValues={getInitialValues({})}
getValidationSchema={getValidationSchema}
>
<ModelForm />
</LayoutModel>
</>
);
};
export default AddModel;

View File

@ -0,0 +1,37 @@
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 { useUpdateCity } from "../../../../api/City";
import { handelImageState } from "../../../../utils/DataToSendImageState";
const EditModel: React.FC = () => {
const { mutate, status } = useUpdateCity();
const { objectToEdit } = useObjectToEdit((state) => state);
const handleSubmit = (values: any) => {
const Data_to_send = { ...values };
mutate(Data_to_send);
};
return (
<>
<LayoutModel
status={status as QueryStatusEnum}
ModelEnum={ModalEnum.CITY_EDIT}
modelTitle="City"
handleSubmit={handleSubmit}
getInitialValues={getInitialValues(objectToEdit)}
getValidationSchema={getValidationSchema}
isAddModal={false}
>
<ModelForm />
</LayoutModel>
</>
);
};
export default EditModel;

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

View File

@ -0,0 +1,15 @@
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>
</Row>
);
};
export default Form;

View File

@ -0,0 +1,18 @@
import * as Yup from "yup";
import { City, CityInitialValues } from "../../../../types/City";
export const getInitialValues = (
objectToEdit: Partial<City>,
): CityInitialValues => {
return {
id: objectToEdit?.id,
name: objectToEdit?.name ?? "",
};
};
export const getValidationSchema = () => {
// validate input
return Yup.object().shape({
name: Yup.string().required("validation.required"),
});
};

View 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 { useDeleteCity } from "../../../api/City";
import PageHeader from "../../../Layout/Dashboard/PageHeader";
import FilterLayout from "../../../Layout/Dashboard/FilterLayout";
import FilterForm from "./Model/FilterForm";
import { canAddCity } 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 = useDeleteCity();
useSetPageTitle([
{name:`${t(`page_header.home`)}`, path:"/"},
{name:`${t(`page_header.City`)}`, path:"City"}
]);
return (
<div className="TableWithHeader">
<Suspense fallback={<Spin />}>
<PageHeader
pageTitle="City"
ModelAbility={ModalEnum?.CITY_ADD}
canAdd={canAddCity}
/>
<FilterLayout sub_children={<FilterForm />} filterTitle="table.City" />
<Table />
<AddModalForm />
<EditModalForm />
<DeleteModalForm
deleteMutation={deleteMutation}
ModelEnum={ModalEnum?.CITY_DELETE}
/>
</Suspense>
</div>
);
};
export default TableHeader;

View File

@ -0,0 +1,23 @@
import { useColumns } from "./useTableColumns";
import React from "react";
import DataTable from "../../../Layout/Dashboard/Table/DataTable";
import { useGetAllCity } from "../../../api/City";
import { useFilterState } from "../../../Components/Utils/Filter/FilterState";
import { useFilterStateState } from "../../../zustand/Filter";
const App: React.FC = () => {
const { filterState } = useFilterState();
const { Filter } = useFilterStateState();
const name = Filter?.name ;
const sort_by = Filter?.sort_by ;
const response = useGetAllCity({
pagination: true,
...filterState,
name,
sort_by
});
return <DataTable response={response} useColumns={useColumns} />;
};
export default App;

View File

@ -0,0 +1,81 @@
import { TableColumnsType } from "antd";
import useModalHandler from "../../../utils/useModalHandler";
import { ModalEnum } from "../../../enums/Model";
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import {
canDeleteCity,
canEditCity,
canShowCity,
} from "../../../utils/hasAbilityFn";
import ActionButtons from "../../../Components/Table/ActionButtons";
import ColumnsImage from "../../../Components/Columns/ColumnsImage";
import { City } from "../../../types/City";
import { useFilterStateState } from "../../../zustand/Filter";
export const useColumns = () => {
const { handel_open_model } = useModalHandler();
const { setObjectToEdit } = useObjectToEdit((state) => state);
const navigate = useNavigate();
const { setFilter } = useFilterStateState();
const handelShow = (record: City) => {
setFilter({})
navigate(`${record?.id}`);
};
const handelDelete = (data: City) => {
setObjectToEdit(data);
handel_open_model(ModalEnum?.CITY_DELETE);
};
const handleEdit = (record: City) => {
setObjectToEdit(record);
handel_open_model(ModalEnum?.CITY_EDIT);
};
const [t] = useTranslation();
const columns: TableColumnsType<City> = [
{
title: t("columns.id"),
dataIndex: "id",
key: "id",
align: "center",
render: (_text, record) => record?.id,
},
{
title: `${t("columns.name")}`,
dataIndex: "name",
key: "name",
align: "center",
render: (_text, record) => record?.name,
ellipsis:true
},
{
title: t("columns.procedure"),
key: "actions",
align: "center",
width: "25vw",
render: (_text, record, index) => {
return (
<ActionButtons
canDelete={canDeleteCity}
canEdit={canEditCity}
canShow={canShowCity}
index={index}
onDelete={() => handelDelete(record)}
onEdit={() => handleEdit(record)}
onShow={() => handelShow(record)}
/>
);
},
},
];
return columns;
};

View File

@ -2,6 +2,8 @@ import React from "react";
import { useTranslation } from "react-i18next";
import { FaImage } from "react-icons/fa";
import ImageBoxField from "./ImageBoxField/ImageBoxField";
import ValidationField from "../../../../Components/ValidationField/ValidationField";
import MyMap from "../field/MyMap";
const AttachmentForm = () => {
const [t] = useTranslation();
@ -12,10 +14,17 @@ const AttachmentForm = () => {
<FaImage />
<h4>{t("header.attachment")}</h4>
</header>
<div className="AttachmentFormBody ">
<main className="main_form_body">
<ImageBoxField name="personal_image" />
<ImageBoxField name="id_image" />
</main>
<div className="MapField">
<ValidationField name="lat" placeholder="lat" label="lat" />
<ValidationField name="lng" placeholder="lng" label="lng" />
<MyMap/>
</div>
</div>
</div>
);
};

View File

@ -23,6 +23,8 @@ interface PersonalDetailsForm {
username: string | null;
password: string | null;
area_id: number | null;
lat:number,
lng:number
}
interface PersonalDetailsEditForm {
@ -35,10 +37,12 @@ interface PersonalDetailsEditForm {
card_number: string | null;
user: User;
area_id: number | null;
lat:number,
lng:number
}
export const getInitialValues = (objectToEdit: Partial<PersonalDetailsForm>) => {
const location = objectToEdit?.location?.[0] || { lat: 0, lng: 0 };
const location = objectToEdit?.location?.[0] || { lat: 33.5138, lng: 36.2765 };
return {
id: objectToEdit?.id ?? 0,
first_name: objectToEdit?.first_name ?? null,
@ -51,6 +55,8 @@ export const getInitialValues = (objectToEdit: Partial<PersonalDetailsForm>) =>
username: objectToEdit?.username ?? null,
password: objectToEdit?.password ?? null,
area_id: objectToEdit?.area_id ?? null,
lat: location.lat ?? 33.5138,
lng: location.lng ?? 36.2765,
};
};

View File

@ -0,0 +1,81 @@
import React, { useState, useEffect } from 'react';
import { MapContainer, TileLayer, Marker, Popup, useMapEvents, useMap } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';
import L from 'leaflet';
import { Input, Button } from 'antd';
import { useFormikContext } from 'formik';
import { ReSellerInitialValues } from '../../../../types/ReSeller';
import { useTranslation } from 'react-i18next';
// Fix for marker icon issue
//@ts-ignore
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
iconRetinaUrl: 'https://unpkg.com/leaflet/dist/images/marker-icon-2x.png',
iconUrl: 'https://unpkg.com/leaflet/dist/images/marker-icon.png',
shadowUrl: 'https://unpkg.com/leaflet/dist/images/marker-shadow.png',
});
const LocationMarker: React.FC = () => {
const { setFieldValue } = useFormikContext<ReSellerInitialValues>();
useMapEvents({
click(e) {
const { lat, lng } = e.latlng;
setFieldValue('lat', lat); // Update latitude in Formik
setFieldValue('lng', lng); // Update longitude in Formik
},
});
return null;
};
const CenterMapOnPosition: React.FC<{ position: [number, number] }> = ({ position }) => {
const map = useMap();
useEffect(() => {
map.setView(position, map.getZoom());
}, [position, map]);
return null;
};
const MyMap: React.FC = () => {
const [showMap, setShowMap] = useState(false); // State to control map visibility
const [currentPosition] = useState<[number, number] | null>(null); // State to hold current position
const { values } = useFormikContext<ReSellerInitialValues>();
const { lat, lng } = values as any;
const position: [number, number] = [lat, lng];
const [t] = useTranslation()
return (
<div className='mb-4'>
<div className='MapInputs '>
<Button className='mb-4' onClick={() => setShowMap(!showMap)} type="primary">
{showMap ? `${t("practical.Hide")} ${t("practical.Map")}` : `${t("practical.Show")} ${t("practical.Map")}`}
</Button>
</div>
{showMap && (
<MapContainer
center={currentPosition || position} // Use currentPosition if available, otherwise fallback to form values
zoom={13}
style={{ height: "200px", width: "100%" }}
>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={currentPosition || position}>
</Marker>
<LocationMarker />
<CenterMapOnPosition position={currentPosition || position} />
</MapContainer>
)}
</div>
);
};
export default MyMap;

View File

@ -0,0 +1,21 @@
export const formatAbilityData = (Data: any[]) => {
const newArray: Array<{ name: any; [key: string]: boolean }> = [];
console.log(Data, "Data");
for (let i = 0; i < Data.length; i++) {
const currentObject = Data?.[i];
console.log(currentObject);
const newObjectShape = {
name: currentObject?.name,
delete: typeof currentObject?.delete === "boolean" ? false : "disabled",
index: typeof currentObject?.index === "boolean" ? false : "disabled",
show: typeof currentObject?.show === "boolean" ? false : "disabled",
store: typeof currentObject?.store === "boolean" ? false : "disabled",
update: typeof currentObject?.update === "boolean" ? false : "disabled",
} as any;
console.log(newObjectShape);
newArray.push(newObjectShape);
}
return newArray;
};

View File

@ -0,0 +1,14 @@
export const formatArrayToPermissions = ( newArray: Array<{ name: any; [key: string]: boolean }>): string[] => {
const Data: string[] = [];
newArray.forEach((obj) => {
const permission = obj.name;
Object.keys(obj).forEach((key) => {
if (key !== "name" && key !== "ALL" && obj[key] && obj[key] === true) {
Data.push(`${permission}::${key}`);
}
});
});
return Data;
};

View File

@ -0,0 +1,54 @@
export const mergePermissionsWithAbilities = (
newShapeArray: Record<any, any>[],
Ability: Record<any, boolean | "disabled" | "string">[]
) => {
const newShapeMap = new Map(newShapeArray.map((item) => [item.name, item]));
console.log(newShapeMap, "newShapeMap");
return Ability.map((abilityItem) => {
const correspondingNewShape = newShapeMap.get(abilityItem.name);
console.log(correspondingNewShape);
let ALL = false;
if (correspondingNewShape) {
if (
correspondingNewShape["index"] &&
correspondingNewShape["show"] &&
correspondingNewShape["store"] &&
correspondingNewShape["update"] &&
correspondingNewShape["delete"]
) {
ALL = true;
}
console.log(correspondingNewShape);
return {
...abilityItem,
delete:
typeof correspondingNewShape.delete === "boolean"
? correspondingNewShape.delete
: "disabled",
index:
typeof correspondingNewShape.index === "boolean"
? correspondingNewShape.index
: "disabled",
show:
typeof correspondingNewShape.show === "boolean"
? correspondingNewShape.show
: "disabled",
store:
typeof correspondingNewShape.store === "boolean"
? correspondingNewShape.store
: "disabled",
update:
typeof correspondingNewShape.update === "boolean"
? correspondingNewShape.update
: "disabled",
ALL: ALL,
};
}
// Return original ability item if no match found
return abilityItem;
});
};

View File

@ -0,0 +1,31 @@
export const transformPermissions = (Data: string[]) => {
const newArray: Array<{ name: any; [key: string]: boolean }> = [];
const hashMap = new Map<string, number>();
for (let i = 0; i < Data.length; i++) {
const [permission, value] = Data[i].split("::");
const existingIndex = hashMap.get(permission);
if (existingIndex !== undefined) {
if (value) {
newArray[existingIndex][value] = true;
}
if (
newArray[existingIndex]["index"] &&
newArray[existingIndex]["show"] &&
newArray[existingIndex]["store"] &&
newArray[existingIndex]["update"] &&
newArray[existingIndex]["delete"]
) {
newArray[existingIndex]["ALL"] = true;
}
} else {
const newObject = value
? ({ name: permission, [value]: true } as any)
: { name: permission };
newArray.push(newObject);
hashMap.set(permission, newArray.length - 1);
}
}
return newArray;
};

View File

@ -2,12 +2,14 @@ import React from 'react'
import DataTable from '../../../../Layout/Dashboard/Table/DataTable'
import { useColumns } from './useTableColumns'
import { useFormikContext } from 'formik'
import { TableProps } from 'antd'
const FormTable = ({response}:{response:any}) => {
interface IFormTable extends TableProps {
response:any
}
const FormTable = ({response,...props}:IFormTable) => {
const {values} = useFormikContext<any>()
console.log(response);
const data = response?.data?.data?.abilities ;
console.log(data);
return (
<div>
@ -15,11 +17,11 @@ const FormTable = ({response}:{response:any}) => {
<DataTable
response={response}
useColumns={useColumns}
dataSource={data}
dataSource={values}
pagination={false}
loading={false}
rowKey={"name"}
{...props}
/>
</div>

View File

@ -22,11 +22,11 @@ const TableHeader = () => {
pageTitle="role"
addModal={false}
/>
<FilterLayout
{/* <FilterLayout
sub_children={""}
filterTitle="page_header.permissions"
haveFilter={false}
/>
/> */}
<Table />
</Suspense>

View File

@ -1,13 +1,19 @@
import React from "react";
import React, { Suspense } from "react";
import { useFilterState } from "../../../../Components/Utils/Filter/FilterState";
import { useFilterStateState } from "../../../../zustand/Filter";
import { useAddPermissions, useGetAllPermissions } from "../../../../api/Permissions";
import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../../../enums/params";
import { Form, Formik } from "formik";
import FormTable from "./FormTable";
import { useTranslation } from "react-i18next";
import { useGetAllRole } from "../../../../api/role";
import { useGetAllRole, useUpdateRole } from "../../../../api/role";
import { useGetAllAbility } from "../../../../api/Ability";
import LoadingLottie from "../../../../Components/Lottie/Loading/LoadingLottie";
import { Button } from "antd";
import { transformPermissions } from "./FN/transformPermissions";
import { formatAbilityData } from "./FN/formatAbilityData";
import { mergePermissionsWithAbilities } from "./FN/mergePermissionsWithAbilities";
import { formatArrayToPermissions } from "./FN/formatArrayToPermission";
const App: React.FC = () => {
const { role_id } = useParams<ParamsEnum>();
@ -16,92 +22,73 @@ const App: React.FC = () => {
const name = Filter?.name;
const sort_by = Filter?.sort_by;
const Data = [
"absence::delete",
"absence::index",
"absence::show",
"absence::store",
"absence::update",
"admin::delete",
"admin::index",
"admin::show",
"admin::update",
];
const response = useGetAllRole({
pagination: true,
show:role_id,
show: role_id,
name,
sort_by,
...filterState,
});
/// time complexity O(n) -_-
const { data, isLoading } = useGetAllAbility();
const AllAbilityData = data?.data ?? [];
const currentData = response?.data?.data?.abilities ?? [];
const changePermissionShape = (Data:string[])=>{
const newArray: Array<{ name: any; [key: string]: boolean }> = [];
const hashMap = new Map<string, number>();
for (let i = 0; i < Data.length; i++) {
const [permission, value] = Data[i].split("::");
const existingIndex = hashMap.get(permission);
const AllAbility = transformPermissions(AllAbilityData ?? []);
if (existingIndex !== undefined) {
newArray[existingIndex][value] = true;
if(newArray[existingIndex]["index"] && newArray[existingIndex]["show"] && newArray[existingIndex]["store"] && newArray[existingIndex]["update"] && newArray[existingIndex]["delete"]){
newArray[existingIndex]["ALL"] = true;
}
} else {
const newObject = { name: permission, [value]: true } as any;
newArray.push(newObject);
hashMap.set(permission, newArray.length - 1);
}
}
return newArray
}
const newShapeArray = changePermissionShape(Data)
const Ability = formatAbilityData(AllAbility) ?? [];
const newShapeArray = transformPermissions([...currentData]);
const [t] = useTranslation()
console.log(response,"response");
const finalShape = mergePermissionsWithAbilities(newShapeArray, Ability);
const reverseChangePermissionShape = (
newArray: Array<{ name: any; [key: string]: boolean }>
): string[] => {
const Data: string[] = [];
const [t] = useTranslation();
newArray.forEach((obj) => {
const permission = obj.name;
Object.keys(obj).forEach((key) => {
if (key !== "name" && key !== "ALL" && obj[key]) {
Data.push(`${permission}::${key}`);
}
const { mutate, isLoading: UpdateLoading } = useUpdateRole();
const handelSubmit = (values: any) => {
console.log(values);
const dataToSend = formatArrayToPermissions(values);
console.log(dataToSend);
mutate({
id: role_id,
abilities: dataToSend?.length > 0 ? dataToSend : "",
});
});
return Data;
};
const {mutate} = useAddPermissions()
const handelSubmit = (values:any)=>{
const dataToSend = reverseChangePermissionShape(values);
mutate(dataToSend)
}
const disabled =
isLoading || response.isLoading || response.isRefetching || UpdateLoading;
return (
<Formik initialValues={newShapeArray} onSubmit={handelSubmit} enableReinitialize>
{({handleSubmit})=>{
<Formik initialValues={finalShape} onSubmit={handelSubmit} enableReinitialize>
{({ dirty }) => {
return (
<Form>
<FormTable response={response} />
<div className="permissions_submit_button">
<button className="button" onClick={()=> handleSubmit()
} type="submit" >{t("practical.submit")}</button>
<div className="permissions_submit_button mt-4">
<Button
className="button"
disabled={disabled || !dirty}
htmlType="submit"
>
{t("practical.submit")}
</Button>
</div>
</Form>
)
}}
<FormTable
response={response}
loading={{
spinning: disabled,
indicator: (
<Suspense fallback={<></>}>
<LoadingLottie />
</Suspense>
),
size: "large",
}}
/>
</Form>
);
}}
</Formik>
);
};

View File

@ -13,6 +13,10 @@ export const useColumns = () => {
cloneValue[index] = {};
}
cloneValue[index][type] = !cloneValue[index][type];
if(!cloneValue[index][type]){
cloneValue[index]["ALL"] = false
}
setValues(cloneValue)
};
@ -24,22 +28,22 @@ export const useColumns = () => {
if(cloneValue[index]["ALL"]){
cloneValue[index] = {
name:cloneValue[index]?.name ,
delete: false,
index: false,
show: false,
store: false,
update: false,
delete: typeof cloneValue[index]?.delete === "boolean" ? false : "disabled" ,
index: typeof cloneValue[index]?.index === "boolean" ? false : "disabled" ,
show: typeof cloneValue[index]?.show === "boolean" ? false : "disabled" ,
store: typeof cloneValue[index]?.store === "boolean" ? false : "disabled" ,
update: typeof cloneValue[index]?.update === "boolean" ? false : "disabled" ,
ALL: false
}
}else{
cloneValue[index] = {
name:cloneValue[index]?.name ,
delete: true,
index: true,
show: true,
store: true,
update: true,
delete: typeof cloneValue[index]?.delete === "boolean" ? true : "disabled" ,
index: typeof cloneValue[index]?.index === "boolean" ? true : "disabled" ,
show: typeof cloneValue[index]?.show === "boolean" ? true : "disabled" ,
store: typeof cloneValue[index]?.store === "boolean" ? true : "disabled" ,
update: typeof cloneValue[index]?.update === "boolean" ? true : "disabled" ,
ALL: true
}
@ -58,10 +62,9 @@ setValues(cloneValue)
const CheckBoxField = ({record,type,index}:{record:any,type:string,index:number})=>{
const isChecked = record?.[type] ;
return <Checkbox onChange={()=>onChange(type,index)} checked={isChecked} />;
const isChecked = record?.[type] === true ;
const isDisabled = record?.[type] === "disabled" ;
return <Checkbox onChange={()=>onChange(type,index)} checked={isChecked} disabled={isDisabled} />;
}
@ -71,11 +74,31 @@ setValues(cloneValue)
return !!item?.index && !!item?.show && !!item?.store && !!item?.update && !!item?.delete
})
const onChangeAllPermissions = ()=>{
const newShape =cloneValue?.map((item:any)=>{
const newShape =cloneValue?.map((item:any,index:number)=>{
if(IsAllValuesTrue){
return {...item,delete: false,index: false,show: false,store: false,update: false,ALL: false}
console.log(item);
return {
...item,
delete: typeof item?.delete === "boolean" ? false : "disabled",
index: typeof item?.index === "boolean" ? false : "disabled",
show: typeof item?.show === "boolean" ? false : "disabled",
store: typeof item?.store === "boolean" ? false : "disabled",
update: typeof item?.update === "boolean" ? false : "disabled",
ALL: false
}
}else{
return {...item,delete: true,index: true,show: true,store: true,update: true,ALL: true}
console.log(item);
return {
...item,
delete: typeof item?.delete === "boolean" ? true : "disabled",
index: typeof item?.index === "boolean" ? true : "disabled",
show: typeof item?.show === "boolean" ? true : "disabled",
store: typeof item?.store === "boolean" ? true : "disabled",
update: typeof item?.update === "boolean" ? true : "disabled",
ALL: true
}
}
})
setValues(newShape)
@ -83,8 +106,6 @@ setValues(cloneValue)
return <Checkbox onChange={()=>onChangeAllPermissions()} checked={IsAllValuesTrue} />;
}
const columns: TableColumnsType<any> = [
{
@ -92,6 +113,9 @@ setValues(cloneValue)
dataIndex: "name",
key: "name",
align: "center",
render: (_text,record,index) => {
return ( <> {t(`models.${record?.name}`)} </> );
},
},
{
title: t("columns.add"),

View File

@ -44,12 +44,6 @@ export const useColumns = () => {
key: "name",
align: "center",
},
{
title: t("columns.created_at"),
dataIndex: "created_at",
key: "created_at",
align: "center",
},
{
title: t("columns.procedure"),

View File

@ -1,16 +1,23 @@
import React from "react";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import MathMLPreview from "./MathMLPreview";
import { Field, Form, Formik } from "formik";
import Test from "./Test";
import MarkdownPreview from '@uiw/react-markdown-preview';
import { BlockMath } from "react-katex";
const Dummy = () => {
const [t] = useTranslation();
const [markdown, setMarkdown] = useState<string>(' \nV_{sphere} = \\frac{4}{3}\\pi r^3\n');
return (
<div className="DummyHomePage">
<MathMLPreview/>
<MarkdownPreview style={{background:"transparent" ,color:"black"}} source={"This is an <u>underlined</u> text."} />
<BlockMath>
{markdown}
</BlockMath>
</div>
);
};

29
src/Pages/Home/Test.tsx Normal file
View File

@ -0,0 +1,29 @@
import { Input } from 'antd';
import React, { useState } from 'react'
const Test = React.memo(
({field,form}:{field:any,form:any}) => {
const name = field.name ;
const {setFieldValue,getFieldProps} = form
console.log(name);
const value = getFieldProps(`${name}`).value
const [CurrentValue, setCurrentValue] = useState(value)
const handleChange=(e: React.ChangeEvent<HTMLInputElement>)=>{
setCurrentValue(e.target.value)
}
const onBlur=()=>{
setFieldValue(`${name}`,CurrentValue)
}
return (
<>
<Input onChange={(e)=>handleChange(e)} value={CurrentValue} type="text" name="" id="" onBlur={onBlur} />
</>
)
},(prevProps:any,nextProps:any)=>{
const prevValue = prevProps.field.value;
const nextValue = nextProps.field.value;
return prevValue === nextValue
})
export default Test

View File

@ -68,7 +68,7 @@ console.log(PackagesInfo);
</div>
<button
className="add_button"
disabled={status === QueryStatusEnum.LOADING || !formik.dirty}
disabled={status === QueryStatusEnum.LOADING || !formik.dirty || !values?.package_id}
onClick={handleNext}
>
{t(`practical.sale`)}

View File

@ -14,7 +14,7 @@ const Form = ({status}:{status?:any}) => {
const {values,setFieldValue} = useFormikContext<any>()
console.log(values?.currentModalIndex);
const { isOpen, setIsOpen } = useModalState((state) => state);
const { setObjectToEdit } = useObjectToEdit();
const { setObjectToEdit,objectToEdit } = useObjectToEdit();
const {t} = useTranslation();
const formik = useFormikContext();
const handleNext = ()=>{
@ -27,6 +27,14 @@ const Form = ({status}:{status?:any}) => {
setObjectToEdit({});
};
const student_info = objectToEdit?.data?.data
const PackagesInfo = student_info?.packages.map((info:any) => ({
id: info?.id,
name: info.name + " " + `( ${info?.original_price} )`
}));
return (
values?.currentModalIndex == 2 &&
@ -49,9 +57,11 @@ const Form = ({status}:{status?:any}) => {
<ValidationField
placeholder="choose"
label="package"
name="package"
name="package_id"
type="Select"
option={[]}
option={PackagesInfo}
disabled
allowClear={false}
/>
</div>
{/* {values?.currentModalIndex} */}

View File

@ -38,9 +38,11 @@ const Form = () => {
setIsOpen("");
setObjectToEdit({});
};
console.log(data?.data);
useEffect(() => {
if(isSuccess == true){
if(!!data?.data?.phone_number){
setFieldValue( "currentModalIndex" , values?.currentModalIndex + 1 )
setObjectToEdit({data})
setTriggerApi(false)
@ -51,7 +53,7 @@ const Form = () => {
}
}, [isSuccess])
}, [data?.data])
return (

View File

@ -1,5 +1,5 @@
import { TCrudRoute, TMenuItem } from "./types/App";
import { FaCashRegister, FaHome, FaMoneyBill, FaPaperclip, FaSellcast, FaTag, FaUser, FaUserShield } from "react-icons/fa";
import { FaCashRegister, FaCity, FaHome, FaMoneyBill, FaPaperclip, FaSellcast, FaTag, FaUser, FaUserShield } from "react-icons/fa";
import { GoDotFill } from "react-icons/go";
import { MdOutlineSell } from "react-icons/md";
import { CgProfile } from "react-icons/cg";
@ -9,7 +9,9 @@ import React from "react";
const Dummy = React.lazy(() => import("./Pages/Home/Dummy"));
const Grade = React.lazy(() => import("./Pages/Admin/Grade/Page"));
const Curriculum = React.lazy(() => import("./Pages/Admin/Curriculum/Page"));
const City = React.lazy(() => import("./Pages/Admin/City/Page"));
const Area = React.lazy(() => import("./Pages/Admin/Area/Page"));
const Subject = React.lazy(() => import("./Pages/Admin/subject/Table/Page"));
const Tags = React.lazy(() => import("./Pages/Admin/Tags/Page"));
const Unit = React.lazy(() => import("./Pages/Admin/Unit/Page"));
@ -135,7 +137,19 @@ export const menuItems: TMenuItem[] = [
abilities: ABILITIES_ENUM?.RE_SELLER,
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 0,
},
{
header: "page_header.city",
element: <City />,
icon: <FaCity />,
text: "sidebar.city",
path: `/${ABILITIES_ENUM?.CITY}`,
abilities: ABILITIES_ENUM?.CITY,
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 0,
},
// {
// header: "page_header.report",
// element: <Report />,
@ -358,6 +372,15 @@ export const CrudRoute: TCrudRoute[] = [
prevPath: 0,
type: UserTypeEnum.RE_SELLER,
},
{
header: "page_header.Area",
element: <Area />,
path: `/${ABILITIES_ENUM?.CITY}/:${ParamsEnum?.CITY_ID}`,
abilities: ABILITIES_ENUM?.AREA,
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 1,
},
];
export const AppRoutes: Record<string, string> = Object.fromEntries(

View File

@ -42,3 +42,7 @@
.PageTitleLastItem {
color: #202C4B !important;
}
.permissions_submit_button{
transform: translateY(-40px);
}

View File

@ -83,3 +83,24 @@
.MapField{
display: flex;
flex-wrap: wrap;
flex-direction: column;
min-height: 400px;
}
.AttachmentFormBody{
display: flex;
margin-top: 20px;
padding-left: 50px;
.ImageBoxField{
min-width: 200px;
}
>*{
min-width: 50%;
}
}

21
src/api/Ability.ts Normal file
View File

@ -0,0 +1,21 @@
import useAddMutation from "./helper/useAddMutation";
import useDeleteMutation from "./helper/useDeleteMutation";
import useGetQuery from "./helper/useGetQuery";
import useUpdateMutation from "./helper/useUpdateMutation";
const API = {
GET: "/ability",
ADD: "/ability",
DELETE: "/ability",
UPDATE: "/ability",
};
const KEY = "ability";
export const useGetAllAbility = (params?: any, options?: any) =>
useGetQuery(KEY, API.GET, params, options);
export const useAddAbility = () => useAddMutation(KEY, API.ADD);
export const useUpdateAbility = (params?: any) =>
useUpdateMutation(KEY, API.GET);
export const useDeleteAbility = (params?: any) =>
useDeleteMutation(KEY, API.DELETE);

20
src/api/Area.ts Normal file
View File

@ -0,0 +1,20 @@
import useAddMutation from "./helper/useAddMutation";
import useDeleteMutation from "./helper/useDeleteMutation";
import useGetQuery from "./helper/useGetQuery";
import useUpdateMutation from "./helper/useUpdateMutation";
const API = {
GET: "/area",
ADD: "/area",
DELETE: "/area",
UPDATE: "/area",
};
const KEY = "Area";
export const useGetAllArea = (params?: any, options?: any) =>
useGetQuery(KEY, API.GET, params, options);
export const useAddArea = () => useAddMutation(KEY, API.ADD);
export const useUpdateArea = (params?: any) => useUpdateMutation(KEY, API.GET);
export const useDeleteArea = (params?: any) =>
useDeleteMutation(KEY, API.DELETE);

20
src/api/City.ts Normal file
View File

@ -0,0 +1,20 @@
import useAddMutation from "./helper/useAddMutation";
import useDeleteMutation from "./helper/useDeleteMutation";
import useGetQuery from "./helper/useGetQuery";
import useUpdateMutation from "./helper/useUpdateMutation";
const API = {
GET: "/city",
ADD: "/city",
DELETE: "/city",
UPDATE: "/city",
};
const KEY = "city";
export const useGetAllCity = (params?: any, options?: any) =>
useGetQuery(KEY, API.GET, params, options);
export const useAddCity = () => useAddMutation(KEY, API.ADD);
export const useUpdateCity = (params?: any) => useUpdateMutation(KEY, API.GET);
export const useDeleteCity = (params?: any) =>
useDeleteMutation(KEY, API.DELETE);

View File

@ -4,13 +4,13 @@ import useGetQuery from "./helper/useGetQuery";
import useUpdateMutation from "./helper/useUpdateMutation";
const API = {
GET: "/permissions",
ADD: "/permissions",
DELETE: "/permissions",
UPDATE: "/permissions",
GET: "/permission",
ADD: "/permission",
DELETE: "/permission",
UPDATE: "/permission",
};
const KEY = "Permissions";
const KEY = "Permission";
export const useGetAllPermissions = (params?: any, options?: any) =>
useGetQuery(KEY, API.GET, params, options);

View File

@ -211,6 +211,20 @@ export enum ModalEnum {
PERMISSION_ADD = "PERMISSION.add",
PERMISSION_DELETE = "PERMISSION.delete",
/// CITY
CITY_EDIT = "CITY.edit",
CITY_ADD = "CITY.add",
CITY_DELETE = "CITY.delete",
/// AREA
AREA_EDIT = "AREA.edit",
AREA_ADD = "AREA.add",
AREA_DELETE = "AREA.delete",
/// sales

View File

@ -58,7 +58,9 @@ export enum ABILITIES_ENUM {
Collections = "collections",
SETTING = "setting",
Email = "email",
Phone = "phone"
Phone = "phone",
CITY = "city",
AREA = "area"
////
}

View File

@ -13,4 +13,5 @@ export enum ParamsEnum {
CHILDREN_QUESTION_ID = "children_question_id",
RE_SELLER_ID = "re_seller_id",
ROLE_ID = "role_id",
CITY_ID = "city_id",
}

View File

@ -310,6 +310,9 @@
"This will close your account. Your account will be interactive when you log in again":"سيؤدي هذا إلى إغلاق حسابك. سيكون حسابك تفاعليا عند تسجيل الدخول مرة أخرى",
"Your account will be permanently deleted":"سيتم حذف حسابك نهائيا",
"search":"بحث",
"Map":"الخريطة",
"Show":"عرض",
"Hide":"اخفاء",
"sale":"بيع"
},
"Table": {
@ -392,6 +395,14 @@
"collections": "التحصيلات",
"phone_number":"رقم الهاتف",
"email_address":"عنوان البريد الإلكتروني",
"ability": "القدرات",
"answer": "إجابة",
"area": "منطقة",
"coupon": "قسيمة",
"package": "حزمة",
"packageItem": "عنصر الحزمة",
"Area":"المنطقة",
"City":"مدينة",
"add_sales":"إضافة عملية بيع",
"are_you_sure_about_sale":"هل أنت متأكد من عملية البيع ؟"
},
@ -862,7 +873,9 @@
"users":"المستخدمون",
"managers":"مدراء",
"sales":"المبيعات",
"collections": "التحصيلات"
"collections": "التحصيلات",
"Area":"المنطقة",
"city":"مدينة"
},
"message": {
"some_thing_went_wrong": "حدث خطأ ما",
@ -908,6 +921,8 @@
"collections": "التحصيلات",
"sales":"المبيعات",
"edit_manager":"تعديل مدير",
"City":"مدينة",
"Area":"المنطقة",
"setting":"الإعدادات",
"edit_reseller":"تعديل البائع"
},
@ -956,7 +971,9 @@
"managers":"مدراء",
"collections": "التحصيلات",
"sales":"المبيعات",
"setting":"الإعدادات"
"setting":"الإعدادات",
"City":"مدينة",
"Area":"المنطقة"
},
"table": {
"student": "قائمة الطلاب",
@ -971,6 +988,8 @@
"setting":"الإعدادات",
"file_setting":"إعدادات الملف",
"security_setting":"إعدادات الأمان",
"Area":"المنطقة",
"City":"مدينة",
"notification":"الاشعارات",
"upload_your_photo_and_personal_data_here":"قم بتحميل صورتك وبياناتك الشخصية هنا",
"get_notified_of_whats_happening_now_you_can_turn_it_off_at_any_time":"احصل على إشعار بما يحدث الآن ، يمكنك إيقاف تشغيله في أي وقت"

17
src/types/Area.ts Normal file
View File

@ -0,0 +1,17 @@
import { Nullable } from "./App";
// Define the Teacher interface
export interface Area {
id: number; // Unique identifier for the user
name: string; // Name of the user
}
export interface InitialValues {
id: number; // Unique identifier for the user
name: string; // Name of the user
}
export type AreaInitialValues = Partial<Nullable<InitialValues>>;

17
src/types/City.ts Normal file
View File

@ -0,0 +1,17 @@
import { Nullable } from "./App";
// Define the Teacher interface
export interface City {
id: number; // Unique identifier for the user
name: string; // Name of the user
}
export interface InitialValues {
id: number; // Unique identifier for the user
name: string; // Name of the user
}
export type CityInitialValues = Partial<Nullable<InitialValues>>;

View File

@ -24,6 +24,57 @@ export const canIndexEduClass = hasAbility(
ABILITIES_VALUES_ENUM.INDEX,
);
///// City
export const canAddCity = hasAbility(
ABILITIES_ENUM.EDUCATION_CLASS,
ABILITIES_VALUES_ENUM.STORE,
);
export const canEditCity = hasAbility(
ABILITIES_ENUM.EDUCATION_CLASS,
ABILITIES_VALUES_ENUM.UPDATE,
);
export const canDeleteCity = hasAbility(
ABILITIES_ENUM.EDUCATION_CLASS,
ABILITIES_VALUES_ENUM.DELETE,
);
export const canShowCity = hasAbility(
ABILITIES_ENUM.EDUCATION_CLASS,
ABILITIES_VALUES_ENUM.SHOW,
);
export const canIndexCity = hasAbility(
ABILITIES_ENUM.EDUCATION_CLASS,
ABILITIES_VALUES_ENUM.INDEX,
);
///// Area
export const canAddArea = hasAbility(
ABILITIES_ENUM.EDUCATION_CLASS,
ABILITIES_VALUES_ENUM.STORE,
);
export const canEditArea = hasAbility(
ABILITIES_ENUM.EDUCATION_CLASS,
ABILITIES_VALUES_ENUM.UPDATE,
);
export const canDeleteArea = hasAbility(
ABILITIES_ENUM.EDUCATION_CLASS,
ABILITIES_VALUES_ENUM.DELETE,
);
export const canShowArea = hasAbility(
ABILITIES_ENUM.EDUCATION_CLASS,
ABILITIES_VALUES_ENUM.SHOW,
);
export const canIndexArea = hasAbility(
ABILITIES_ENUM.EDUCATION_CLASS,
ABILITIES_VALUES_ENUM.INDEX,
);
///// Course
export const canAddCourse = hasAbility(
@ -273,15 +324,6 @@ export const canShowStudent = hasAbility(
ABILITIES_VALUES_ENUM.SHOW,
);
export const canImportStudent = hasAbility(
ABILITIES_ENUM.STUDENT,
ABILITIES_VALUES_ENUM.IMPORT_STUDENTS,
);
export const canMoveStudent = hasAbility(
ABILITIES_ENUM.STUDENT,
ABILITIES_VALUES_ENUM.MOVE_STUDENTS,
);
/// Manager