end seller page
This commit is contained in:
parent
7e8fa6431c
commit
8f993912fc
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
|
@ -10,6 +10,7 @@
|
||||||
"Groupbutton",
|
"Groupbutton",
|
||||||
"handelnavigate",
|
"handelnavigate",
|
||||||
"Karim",
|
"Karim",
|
||||||
|
"latlng",
|
||||||
"queryqlent",
|
"queryqlent",
|
||||||
"registraion",
|
"registraion",
|
||||||
"SENDNOTIFICATION",
|
"SENDNOTIFICATION",
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
"formik": "^2.4.6",
|
"formik": "^2.4.6",
|
||||||
"html-to-image": "^1.11.11",
|
"html-to-image": "^1.11.11",
|
||||||
"i18next": "^23.11.5",
|
"i18next": "^23.11.5",
|
||||||
|
"leaflet": "^1.9.4",
|
||||||
"path-to-regexp": "^6.2.2",
|
"path-to-regexp": "^6.2.2",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
|
|
@ -26,6 +27,7 @@
|
||||||
"react-dragula": "^1.1.17",
|
"react-dragula": "^1.1.17",
|
||||||
"react-i18next": "^13.5.0",
|
"react-i18next": "^13.5.0",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
|
"react-leaflet": "^4.2.1",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
|
|
@ -66,6 +68,7 @@
|
||||||
"@testing-library/jest-dom": "^5.17.0",
|
"@testing-library/jest-dom": "^5.17.0",
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
|
"@types/leaflet": "^1.9.12",
|
||||||
"@types/node": "^20.14.0",
|
"@types/node": "^20.14.0",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
|
|
|
||||||
8799
pnpm-lock.yaml
8799
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -49,7 +49,7 @@ const TableHeader = () => {
|
||||||
<Table />
|
<Table />
|
||||||
<DeleteModalForm
|
<DeleteModalForm
|
||||||
deleteMutation={deleteMutation}
|
deleteMutation={deleteMutation}
|
||||||
ModelEnum={ModalEnum?.Package_DELETE}
|
ModelEnum={ModalEnum?.PACKAGE_DELETE}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,11 @@ export const useColumns = () => {
|
||||||
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||||
const handelDelete = (record: any) => {
|
const handelDelete = (record: any) => {
|
||||||
setObjectToEdit(record);
|
setObjectToEdit(record);
|
||||||
setIsOpen(ModalEnum?.Package_DELETE);
|
setIsOpen(ModalEnum?.PACKAGE_DELETE);
|
||||||
};
|
};
|
||||||
const handleEdit = (record: any) => {
|
const handleEdit = (record: any) => {
|
||||||
setObjectToEdit(record);
|
setObjectToEdit(record);
|
||||||
setIsOpen(ModalEnum?.Package_EDIT);
|
setIsOpen(ModalEnum?.PACKAGE_EDIT);
|
||||||
navigate(`${record?.id}`)
|
navigate(`${record?.id}`)
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ const TableHeader = () => {
|
||||||
<Table />
|
<Table />
|
||||||
<DeleteModalForm
|
<DeleteModalForm
|
||||||
deleteMutation={deleteMutation}
|
deleteMutation={deleteMutation}
|
||||||
ModelEnum={ModalEnum?.Package_DELETE}
|
ModelEnum={ModalEnum?.PACKAGE_DELETE}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { TableColumnsType } from "antd";
|
import { TableColumnsType } from "antd";
|
||||||
import { ModalEnum } from "../../enums/Model";
|
import { ModalEnum } from "../../enums/Model";
|
||||||
import { useObjectToEdit } from "../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../zustand/ObjectToEditState";``
|
||||||
import { useModalState } from "../../zustand/Modal";
|
import { useModalState } from "../../zustand/Modal";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { canDeletePackage,canEditPackage, canShowPackage } from "../../utils/hasAbilityFn";
|
import { canDeletePackage,canEditPackage, canShowPackage } from "../../utils/hasAbilityFn";
|
||||||
|
|
@ -16,18 +16,18 @@ export const useColumns = () => {
|
||||||
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||||
const handelDelete = (record: any) => {
|
const handelDelete = (record: any) => {
|
||||||
setObjectToEdit(record);
|
setObjectToEdit(record);
|
||||||
setIsOpen(ModalEnum?.Package_DELETE);
|
setIsOpen(ModalEnum?.PACKAGE_DELETE);
|
||||||
};
|
};
|
||||||
const handleEdit = (record: any) => {
|
const handleEdit = (record: any) => {
|
||||||
setObjectToEdit(record);
|
setObjectToEdit(record);
|
||||||
navigate(`${record?.id}`)
|
navigate(`${record?.id}`)
|
||||||
|
|
||||||
};
|
};
|
||||||
const handleShow = (record: any) => {
|
// const handleShow = (record: any) => {
|
||||||
setObjectToEdit(record);
|
// setObjectToEdit(record);
|
||||||
navigate(`${record?.id}/${ABILITIES_ENUM?.PACKAGE_ITEM}`)
|
// navigate(`${record?.id}/${ABILITIES_ENUM?.PACKAGE_ITEM}`)
|
||||||
|
|
||||||
};
|
// };
|
||||||
|
|
||||||
const columns: TableColumnsType<any> = [
|
const columns: TableColumnsType<any> = [
|
||||||
{
|
{
|
||||||
|
|
@ -58,11 +58,11 @@ export const useColumns = () => {
|
||||||
<ActionButtons
|
<ActionButtons
|
||||||
canDelete={canEditPackage}
|
canDelete={canEditPackage}
|
||||||
canEdit={canDeletePackage}
|
canEdit={canDeletePackage}
|
||||||
canShow={canShowPackage}
|
// canShow={canShowPackage}
|
||||||
index={index}
|
index={index}
|
||||||
onDelete={() => handelDelete(record)}
|
onDelete={() => handelDelete(record)}
|
||||||
onEdit={() => handleEdit(record)}
|
onEdit={() => handleEdit(record)}
|
||||||
onShow={() => handleShow(record)}
|
// onShow={() => handleShow(record)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
36
src/Pages/ReSeller/Model/AddModel.tsx
Normal file
36
src/Pages/ReSeller/Model/AddModel.tsx
Normal 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 { useAddReSeller } from "../../../api/ReSeller";
|
||||||
|
|
||||||
|
const AddModel: React.FC = () => {
|
||||||
|
const { mutate, status } = useAddReSeller();
|
||||||
|
|
||||||
|
const handleSubmit = (values: any) => {
|
||||||
|
const newValue = JSON.parse(JSON.stringify({...values}))
|
||||||
|
const location = {lat:newValue?.lat,lng:newValue?.lng}
|
||||||
|
mutate({
|
||||||
|
...newValue,
|
||||||
|
location
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<LayoutModel
|
||||||
|
status={status as QueryStatusEnum}
|
||||||
|
ModelEnum={ModalEnum.RE_SELLER_ADD}
|
||||||
|
modelTitle="ReSeller"
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
getInitialValues={getInitialValues({})}
|
||||||
|
getValidationSchema={getValidationSchema}
|
||||||
|
>
|
||||||
|
<ModelForm />
|
||||||
|
</LayoutModel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddModel;
|
||||||
40
src/Pages/ReSeller/Model/EditModel.tsx
Normal file
40
src/Pages/ReSeller/Model/EditModel.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import React from "react";
|
||||||
|
import { getInitialValues, getValidationSchema, getValidationSchemaEdit } 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 { useUpdateReSeller } from "../../../api/ReSeller";
|
||||||
|
import { handelImageState } from "../../../utils/DataToSendImageState";
|
||||||
|
|
||||||
|
const EditModel: React.FC = () => {
|
||||||
|
const { mutate, status } = useUpdateReSeller();
|
||||||
|
const { objectToEdit } = useObjectToEdit((state) => state);
|
||||||
|
|
||||||
|
const handleSubmit = (values: any) => {
|
||||||
|
const newValue = JSON.parse(JSON.stringify({...values}))
|
||||||
|
const location = {lat:newValue?.lat,lng:newValue?.lng}
|
||||||
|
mutate({
|
||||||
|
...newValue,
|
||||||
|
location
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<LayoutModel
|
||||||
|
status={status as QueryStatusEnum}
|
||||||
|
ModelEnum={ModalEnum.RE_SELLER_EDIT}
|
||||||
|
modelTitle="ReSeller"
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
getInitialValues={getInitialValues(objectToEdit)}
|
||||||
|
getValidationSchema={getValidationSchemaEdit}
|
||||||
|
isAddModal={false}
|
||||||
|
>
|
||||||
|
<ModelForm isEdit={true} />
|
||||||
|
</LayoutModel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditModel;
|
||||||
30
src/Pages/ReSeller/Model/ModelForm.tsx
Normal file
30
src/Pages/ReSeller/Model/ModelForm.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { Col, Row } from "reactstrap";
|
||||||
|
import ValidationField from "../../../Components/ValidationField/ValidationField";
|
||||||
|
import MyMap from "./field/MyMap";
|
||||||
|
|
||||||
|
const Form = ({isEdit = false}:{isEdit?:boolean}) => {
|
||||||
|
return (
|
||||||
|
<Row className="w-100">
|
||||||
|
<Col>
|
||||||
|
<ValidationField name="first_name" placeholder="first_name" label="first_name" />
|
||||||
|
<ValidationField name="last_name" placeholder="last_name" label="last_name" />
|
||||||
|
<ValidationField name="username" placeholder="username" label="username" />
|
||||||
|
{!isEdit &&
|
||||||
|
<ValidationField name="password" placeholder="password" label="password" />
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<ValidationField name="contact_number1" placeholder="contact_number1" label="contact_number1" />
|
||||||
|
<ValidationField name="contact_number2" placeholder="contact_number2" label="contact_number2" />
|
||||||
|
|
||||||
|
<ValidationField name="lat" placeholder="lat" label="lat" />
|
||||||
|
<ValidationField name="lng" placeholder="lng" label="lng" />
|
||||||
|
<MyMap/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Form;
|
||||||
81
src/Pages/ReSeller/Model/field/MyMap.tsx
Normal file
81
src/Pages/ReSeller/Model/field/MyMap.tsx
Normal 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 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;
|
||||||
67
src/Pages/ReSeller/Model/formUtil.ts
Normal file
67
src/Pages/ReSeller/Model/formUtil.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { ReSeller, ReSellerInitialValues } from "../../../types/ReSeller";
|
||||||
|
|
||||||
|
export const getInitialValues = (
|
||||||
|
objectToEdit: Partial<ReSeller>,
|
||||||
|
): ReSellerInitialValues => {
|
||||||
|
console.log(objectToEdit,"objectToEdit");
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
id: objectToEdit?.id,
|
||||||
|
first_name: objectToEdit?.first_name ?? "",
|
||||||
|
last_name: objectToEdit?.last_name ?? "",
|
||||||
|
lat: objectToEdit?.location?.lat ?? 33.5138,
|
||||||
|
lng: objectToEdit?.location?.lng ?? 36.2765,
|
||||||
|
contact_number1:objectToEdit?.contact_number1 ?? null,
|
||||||
|
contact_number2:objectToEdit?.contact_number2 ?? null ,
|
||||||
|
username: objectToEdit?.user?.username ?? null ,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getValidationSchema = () => {
|
||||||
|
// validate input
|
||||||
|
return Yup.object().shape({
|
||||||
|
first_name: Yup.string().required("validation.required"),
|
||||||
|
last_name: Yup.string().required("validation.required"),
|
||||||
|
contact_number1: Yup.string()
|
||||||
|
.matches(/^([0-9\s\-\+\(\)]*)$/, 'validation.Please enter a valid phone number (e.g., +1 123-456-7890)') // Regex for phone number
|
||||||
|
.min(10, "validation.must_be_at_least_10_characters_long") // Minimum length
|
||||||
|
.max(15, "validation.must_not_exceed_15_characters_long") // Maximum length
|
||||||
|
.required("validation.required"), // Required field
|
||||||
|
|
||||||
|
contact_number2: Yup.string()
|
||||||
|
.matches(/^([0-9\s\-\+\(\)]*)$/, 'validation.Please enter a valid phone number (e.g., +1 123-456-7890)') // Regex for phone number
|
||||||
|
.min(10, "validation.must_be_at_least_10_characters_long") // Minimum length
|
||||||
|
.max(15, "validation.must_not_exceed_15_characters_long") // Maximum length
|
||||||
|
.required("validation.required"), // Required field
|
||||||
|
|
||||||
|
password: Yup.string().min(8,"validation.Password_must_be_at_least_8_characters_long").required("validation.required"),
|
||||||
|
username: Yup.string().required("validation.required"),
|
||||||
|
lat: Yup.string().required("validation.required"),
|
||||||
|
lng: Yup.string().required("validation.required"),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getValidationSchemaEdit = () => {
|
||||||
|
// validate input
|
||||||
|
return Yup.object().shape({
|
||||||
|
first_name: Yup.string().required("validation.required"),
|
||||||
|
last_name: Yup.string().required("validation.required"),
|
||||||
|
contact_number1: Yup.string()
|
||||||
|
.matches(/^([0-9\s\-\+\(\)]*)$/, 'validation.Please enter a valid phone number (e.g., +1 123-456-7890)') // Regex for phone number
|
||||||
|
.min(10, "validation.must_be_at_least_10_characters_long") // Minimum length
|
||||||
|
.max(15, "validation.must_not_exceed_15_characters_long") // Maximum length
|
||||||
|
.required("validation.required"), // Required field
|
||||||
|
|
||||||
|
contact_number2: Yup.string()
|
||||||
|
.matches(/^([0-9\s\-\+\(\)]*)$/, 'validation.Please enter a valid phone number (e.g., +1 123-456-7890)') // Regex for phone number
|
||||||
|
.min(10, "validation.must_be_at_least_10_characters_long") // Minimum length
|
||||||
|
.max(15, "validation.must_not_exceed_15_characters_long") // Maximum length
|
||||||
|
.required("validation.required"), // Required field
|
||||||
|
username: Yup.string().required("validation.required"),
|
||||||
|
lat: Yup.string().required("validation.required"),
|
||||||
|
lng: Yup.string().required("validation.required"),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
44
src/Pages/ReSeller/Page.tsx
Normal file
44
src/Pages/ReSeller/Page.tsx
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
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 { useDeleteReSeller } from "../../api/ReSeller";
|
||||||
|
import MyMap from "./Model/field/MyMap";
|
||||||
|
|
||||||
|
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 = useDeleteReSeller();
|
||||||
|
|
||||||
|
useSetPageTitle(t(`page_header.ReSeller`));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="TableWithHeader">
|
||||||
|
<Suspense fallback={<Spin />}>
|
||||||
|
<header>
|
||||||
|
<h6>{t("models.ReSeller")}</h6>
|
||||||
|
</header>
|
||||||
|
<Table />
|
||||||
|
<AddModalForm />
|
||||||
|
<EditModalForm />
|
||||||
|
|
||||||
|
|
||||||
|
<DeleteModalForm
|
||||||
|
deleteMutation={deleteMutation}
|
||||||
|
ModelEnum={ModalEnum?.RE_SELLER_DELETE}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableHeader;
|
||||||
12
src/Pages/ReSeller/Table.tsx
Normal file
12
src/Pages/ReSeller/Table.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { useColumns } from "./useTableColumns";
|
||||||
|
import React from "react";
|
||||||
|
import DataTable from "../../Layout/Dashboard/Table/DataTable";
|
||||||
|
import { useGetAllReSeller } from "../../api/ReSeller";
|
||||||
|
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const response = useGetAllReSeller({ pagination: true });
|
||||||
|
|
||||||
|
return <DataTable response={response} useColumns={useColumns} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
||||||
98
src/Pages/ReSeller/useTableColumns.tsx
Normal file
98
src/Pages/ReSeller/useTableColumns.tsx
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
import { TableColumnsType } from "antd";
|
||||||
|
import { ReSeller } from "../../types/ReSeller";
|
||||||
|
import { FaPlus } from "react-icons/fa";
|
||||||
|
import useModalHandler from "../../utils/useModalHandler";
|
||||||
|
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 {
|
||||||
|
canAddReSeller,
|
||||||
|
canDeleteReSeller,
|
||||||
|
canEditReSeller,
|
||||||
|
canShowReSeller,
|
||||||
|
} from "../../utils/hasAbilityFn";
|
||||||
|
import ActionButtons from "../../Components/Table/ActionButtons";
|
||||||
|
import ColumnsImage from "../../Components/Columns/ColumnsImage";
|
||||||
|
|
||||||
|
export const useColumns = () => {
|
||||||
|
const { handel_open_model } = useModalHandler();
|
||||||
|
|
||||||
|
const { setObjectToEdit } = useObjectToEdit((state) => state);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
|
||||||
|
const handelDelete = (data: ReSeller) => {
|
||||||
|
setObjectToEdit(data);
|
||||||
|
handel_open_model(ModalEnum?.RE_SELLER_DELETE);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = (record: ReSeller) => {
|
||||||
|
setObjectToEdit(record);
|
||||||
|
handel_open_model(ModalEnum?.RE_SELLER_EDIT);
|
||||||
|
};
|
||||||
|
const [t] = useTranslation();
|
||||||
|
|
||||||
|
const columns: TableColumnsType<ReSeller> = [
|
||||||
|
{
|
||||||
|
title: t("columns.id"),
|
||||||
|
dataIndex: "id",
|
||||||
|
key: "id",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.first_name")}`,
|
||||||
|
dataIndex: "first_name",
|
||||||
|
key: "first_name",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.first_name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.last_name")}`,
|
||||||
|
dataIndex: "last_name",
|
||||||
|
key: "last_name",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.last_name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.username")}`,
|
||||||
|
dataIndex: "username",
|
||||||
|
key: "username",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.user?.username,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: canAddReSeller ? (
|
||||||
|
<button
|
||||||
|
onClick={() => handel_open_model(ModalEnum?.RE_SELLER_ADD)}
|
||||||
|
className="add_button"
|
||||||
|
>
|
||||||
|
{t("practical.add")} {t("models.ReSeller")} <FaPlus />
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
),
|
||||||
|
|
||||||
|
key: "actions",
|
||||||
|
align: "end",
|
||||||
|
width: "25vw",
|
||||||
|
render: (_text, record, index) => {
|
||||||
|
return (
|
||||||
|
<ActionButtons
|
||||||
|
canDelete={canDeleteReSeller}
|
||||||
|
canEdit={canEditReSeller}
|
||||||
|
|
||||||
|
index={index}
|
||||||
|
onDelete={() => handelDelete(record)}
|
||||||
|
onEdit={() => handleEdit(record)}
|
||||||
|
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return columns;
|
||||||
|
};
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { TCrudRoute, TMenuItem } from "./types/App";
|
import { TCrudRoute, TMenuItem } from "./types/App";
|
||||||
import { FaHome, FaKey, FaMoneyBill, FaUserGraduate } from "react-icons/fa";
|
import { FaHome, FaKey, FaMoneyBill, FaSellcast, FaUserGraduate } from "react-icons/fa";
|
||||||
import { LuPackage } from "react-icons/lu";
|
import { LuPackage } from "react-icons/lu";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
const Dummy = React.lazy(() => import("./Pages/Home/Dummy"));
|
const Dummy = React.lazy(() => import("./Pages/Home/Dummy"));
|
||||||
|
|
@ -11,6 +11,7 @@ const Grade = React.lazy(() => import("./Pages/Grade/Page"));
|
||||||
const Package = React.lazy(() => import("./Pages/Package/Page"));
|
const Package = React.lazy(() => import("./Pages/Package/Page"));
|
||||||
const Curriculum = React.lazy(() => import("./Pages/Curriculum/Page"));
|
const Curriculum = React.lazy(() => import("./Pages/Curriculum/Page"));
|
||||||
const PackageItemPage = React.lazy(() => import("./Pages/Package/PackageItem/Page"));
|
const PackageItemPage = React.lazy(() => import("./Pages/Package/PackageItem/Page"));
|
||||||
|
const ReSeller = React.lazy(() => import("./Pages/ReSeller/Page"));
|
||||||
|
|
||||||
const Unit = React.lazy(() => import("./Pages/Unit/Page"));
|
const Unit = React.lazy(() => import("./Pages/Unit/Page"));
|
||||||
const Lesson = React.lazy(() => import("./Pages/lesson/Page"));
|
const Lesson = React.lazy(() => import("./Pages/lesson/Page"));
|
||||||
|
|
@ -80,6 +81,16 @@ export const menuItems: TMenuItem[] = [
|
||||||
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
prevPath: 0,
|
prevPath: 0,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
header: "page_header.reSeller",
|
||||||
|
element: <ReSeller />,
|
||||||
|
icon: <FaSellcast />,
|
||||||
|
text: "sidebar.reSeller",
|
||||||
|
path: `/${ABILITIES_ENUM?.RE_SELLER}`,
|
||||||
|
abilities: ABILITIES_ENUM?.RE_SELLER,
|
||||||
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
|
prevPath: 0,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const CrudRoute: TCrudRoute[] = [
|
export const CrudRoute: TCrudRoute[] = [
|
||||||
|
|
|
||||||
9
src/Styles/Pages/Map.scss
Normal file
9
src/Styles/Pages/Map.scss
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
.MapInputs{
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.leaflet-right{
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -10,3 +10,4 @@
|
||||||
@import "./subject.scss";
|
@import "./subject.scss";
|
||||||
@import "./Marks.scss";
|
@import "./Marks.scss";
|
||||||
@import "./exercise.scss";
|
@import "./exercise.scss";
|
||||||
|
@import './Map.scss';
|
||||||
21
src/api/ReSeller.ts
Normal file
21
src/api/ReSeller.ts
Normal 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: "/reseller",
|
||||||
|
ADD: "/reseller",
|
||||||
|
DELETE: "/reseller",
|
||||||
|
UPDATE: "/reseller",
|
||||||
|
};
|
||||||
|
|
||||||
|
const KEY = "ReSeller";
|
||||||
|
|
||||||
|
export const useGetAllReSeller = (params?: any, options?: any) =>
|
||||||
|
useGetQuery(KEY, API.GET, params, options);
|
||||||
|
export const useAddReSeller = () => useAddMutation(KEY, API.ADD);
|
||||||
|
export const useUpdateReSeller = (params?: any) =>
|
||||||
|
useUpdateMutation(KEY, API.GET);
|
||||||
|
export const useDeleteReSeller = (params?: any) =>
|
||||||
|
useDeleteMutation(KEY, API.DELETE);
|
||||||
|
|
@ -155,8 +155,12 @@ export enum ModalEnum {
|
||||||
|
|
||||||
///package
|
///package
|
||||||
|
|
||||||
Package_EDIT = "Package.edit",
|
PACKAGE_EDIT = "Package.edit",
|
||||||
Package_ADD = "Package.add",
|
PACKAGE_ADD = "Package.add",
|
||||||
Package_DELETE = "Package.delete",
|
PACKAGE_DELETE = "Package.delete",
|
||||||
|
|
||||||
|
/// ReSeller
|
||||||
|
RE_SELLER_EDIT = "ReSeller.edit",
|
||||||
|
RE_SELLER_ADD = "ReSeller.add",
|
||||||
|
RE_SELLER_DELETE = "ReSeller.delete",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ export enum ABILITIES_ENUM {
|
||||||
ADMIN = "admin",
|
ADMIN = "admin",
|
||||||
CURRICULUM = "curriculum",
|
CURRICULUM = "curriculum",
|
||||||
PACKAGE_ITEM = "package_item",
|
PACKAGE_ITEM = "package_item",
|
||||||
|
RE_SELLER = "ReSeller"
|
||||||
////
|
////
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
"Email_is_required": "البريد الإلكتروني مطلوب",
|
"Email_is_required": "البريد الإلكتروني مطلوب",
|
||||||
"Password_is_required": "كلمة المرور مطلوبة",
|
"Password_is_required": "كلمة المرور مطلوبة",
|
||||||
"Password_must_be_at_least_8_characters_long": "يجب أن تكون كلمة المرور مكونة من 8 أحرف على الأقل",
|
"Password_must_be_at_least_8_characters_long": "يجب أن تكون كلمة المرور مكونة من 8 أحرف على الأقل",
|
||||||
|
"must_be_at_least_10_characters_long":"يجب أن تكون مكونة من 10 أحرف على الأقل",
|
||||||
"Nationality_is_required": "الجنسية مطلوبة",
|
"Nationality_is_required": "الجنسية مطلوبة",
|
||||||
"Address_is_required": "العنوان مطلوب",
|
"Address_is_required": "العنوان مطلوب",
|
||||||
"Place_of_birth_is_required": "مكان الميلاد مطلوب",
|
"Place_of_birth_is_required": "مكان الميلاد مطلوب",
|
||||||
|
|
@ -47,7 +48,8 @@
|
||||||
"grade_to_pass_must_be_less_than_max_grade": "يجب أن تكون درجة النجاح أقل من الحد الأقصى للدرجة",
|
"grade_to_pass_must_be_less_than_max_grade": "يجب أن تكون درجة النجاح أقل من الحد الأقصى للدرجة",
|
||||||
"max_mark_must_be_greater_than_min_mark_to_pass": "يجب ان تكون اكبر من علامة النجاح",
|
"max_mark_must_be_greater_than_min_mark_to_pass": "يجب ان تكون اكبر من علامة النجاح",
|
||||||
"Sorry, the question must have at least one option": "عذرًا، يجب أن يحتوي السؤال على خيار واحد على الأقل",
|
"Sorry, the question must have at least one option": "عذرًا، يجب أن يحتوي السؤال على خيار واحد على الأقل",
|
||||||
"must_have_on_item":"يجب ان يحتوي على عنصر واحد على الاقل"
|
"must_have_on_item":"يجب ان يحتوي على عنصر واحد على الاقل",
|
||||||
|
"Please enter a valid phone number (e.g., +1 123-456-7890)":"يرجى إدخال رقم هاتف صالح (مثل: +1 123-456-7890)"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"register_students": "تسجيل الطلاب",
|
"register_students": "تسجيل الطلاب",
|
||||||
|
|
@ -160,7 +162,8 @@
|
||||||
"question_options_count": "عدد الخيارات",
|
"question_options_count": "عدد الخيارات",
|
||||||
"canAnswersBeShuffled":"يمكن خلط الإجابات",
|
"canAnswersBeShuffled":"يمكن خلط الإجابات",
|
||||||
"price":"السعر",
|
"price":"السعر",
|
||||||
"grade_id":"رقم تعريف الدرجة"
|
"grade_id":"رقم تعريف الدرجة",
|
||||||
|
"first_name":"الاسم الأول"
|
||||||
},
|
},
|
||||||
"practical": {
|
"practical": {
|
||||||
"to_confirm_deletion_please_re_enter": "لتأكيد الحذف، يرجى إعادة الإدخال",
|
"to_confirm_deletion_please_re_enter": "لتأكيد الحذف، يرجى إعادة الإدخال",
|
||||||
|
|
@ -207,7 +210,10 @@
|
||||||
"delete_last":"حذف عنصر",
|
"delete_last":"حذف عنصر",
|
||||||
"key":"الاسم",
|
"key":"الاسم",
|
||||||
"value":"القيمة",
|
"value":"القيمة",
|
||||||
"delete_this_item":"حذف هذا العنصر"
|
"delete_this_item":"حذف هذا العنصر",
|
||||||
|
"Hide":"اخفاء",
|
||||||
|
"Show":"عرض",
|
||||||
|
"Map":"خريطة"
|
||||||
},
|
},
|
||||||
"Table": {
|
"Table": {
|
||||||
"header": "",
|
"header": "",
|
||||||
|
|
@ -272,7 +278,8 @@
|
||||||
"curriculum": "مقرر",
|
"curriculum": "مقرر",
|
||||||
"package":"حزمة",
|
"package":"حزمة",
|
||||||
"package_details":"تفاصيل الحزمة",
|
"package_details":"تفاصيل الحزمة",
|
||||||
"add_package":"اضافة حزمة"
|
"add_package":"اضافة حزمة",
|
||||||
|
"ReSeller":"بائع"
|
||||||
},
|
},
|
||||||
"education_class_actions": {
|
"education_class_actions": {
|
||||||
"Student_Records": "سجلات الطلاب",
|
"Student_Records": "سجلات الطلاب",
|
||||||
|
|
@ -378,7 +385,12 @@
|
||||||
"subject":"المادة",
|
"subject":"المادة",
|
||||||
"curriculum":"مقرر",
|
"curriculum":"مقرر",
|
||||||
"lesson":"الدرس",
|
"lesson":"الدرس",
|
||||||
"unit":"الوحدة"
|
"unit":"الوحدة",
|
||||||
|
"contact_number1":"رقم التواصل 1",
|
||||||
|
"contact_number2":"رقم التواصل 2",
|
||||||
|
"lat":"خط العرض",
|
||||||
|
"lng":" خط الطول "
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"select": {
|
"select": {
|
||||||
|
|
@ -681,7 +693,8 @@
|
||||||
"tags": "كلمات مفتاحية",
|
"tags": "كلمات مفتاحية",
|
||||||
"grade": "الدرجات",
|
"grade": "الدرجات",
|
||||||
"curriculum": "مقرر",
|
"curriculum": "مقرر",
|
||||||
"package":"حزمة"
|
"package":"حزمة",
|
||||||
|
"reSeller":"البائع"
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
"some_thing_went_wrong": "حدث خطأ ما",
|
"some_thing_went_wrong": "حدث خطأ ما",
|
||||||
|
|
@ -738,6 +751,7 @@
|
||||||
"edit_Question": "لوحة القيادة /تعديل اسئلة ",
|
"edit_Question": "لوحة القيادة /تعديل اسئلة ",
|
||||||
"grade": "لوحة القيادة /الدرجات ",
|
"grade": "لوحة القيادة /الدرجات ",
|
||||||
"curriculum": "لوحة القيادة / تعديل مقرر ",
|
"curriculum": "لوحة القيادة / تعديل مقرر ",
|
||||||
"package":"لوحة القيادة / الحزم "
|
"package":"لوحة القيادة / الحزم ",
|
||||||
|
"ReSeller":"لوحة القيادة / البائع "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
50
src/types/ReSeller.ts
Normal file
50
src/types/ReSeller.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import { Nullable } from "./App";
|
||||||
|
|
||||||
|
// Define the Teacher interface
|
||||||
|
|
||||||
|
|
||||||
|
interface ReSellerUser {
|
||||||
|
id: number;
|
||||||
|
username: string;
|
||||||
|
phone_number: string | null;
|
||||||
|
type: 'reseller' | 'other'; // Specify other types if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReSellerLocation {
|
||||||
|
lat: string;
|
||||||
|
lng: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ContactInfo {
|
||||||
|
contact_number1: string;
|
||||||
|
contact_number2: string;
|
||||||
|
card_number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ReSeller {
|
||||||
|
id: number;
|
||||||
|
user: ReSellerUser;
|
||||||
|
first_name: string;
|
||||||
|
last_name: string;
|
||||||
|
location: ReSellerLocation;
|
||||||
|
contact_info: ContactInfo;
|
||||||
|
contact_number1 : string | number
|
||||||
|
contact_number2 : string | number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InitialValues {
|
||||||
|
id: number;
|
||||||
|
user: ReSellerUser;
|
||||||
|
first_name: string;
|
||||||
|
last_name: string;
|
||||||
|
location: ReSellerLocation;
|
||||||
|
lat: string | Number;
|
||||||
|
lng: string | Number;
|
||||||
|
contact_info: ContactInfo;
|
||||||
|
contact_number1 : string | number
|
||||||
|
contact_number2 : string | number
|
||||||
|
username : string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ReSellerInitialValues = Partial<Nullable<InitialValues>>;
|
||||||
|
|
@ -583,3 +583,24 @@ export const canShowPackage = hasAbility(
|
||||||
ABILITIES_ENUM.Package,
|
ABILITIES_ENUM.Package,
|
||||||
ABILITIES_VALUES_ENUM.SHOW,
|
ABILITIES_VALUES_ENUM.SHOW,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/// ReSeller
|
||||||
|
|
||||||
|
export const canAddReSeller = hasAbility(
|
||||||
|
ABILITIES_ENUM.RE_SELLER,
|
||||||
|
ABILITIES_VALUES_ENUM.STORE,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const canEditReSeller = hasAbility(
|
||||||
|
ABILITIES_ENUM.RE_SELLER,
|
||||||
|
ABILITIES_VALUES_ENUM.UPDATE,
|
||||||
|
);
|
||||||
|
export const canDeleteReSeller = hasAbility(
|
||||||
|
ABILITIES_ENUM.RE_SELLER,
|
||||||
|
ABILITIES_VALUES_ENUM.DELETE,
|
||||||
|
);
|
||||||
|
export const canShowReSeller = hasAbility(
|
||||||
|
ABILITIES_ENUM.RE_SELLER,
|
||||||
|
ABILITIES_VALUES_ENUM.SHOW,
|
||||||
|
);
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,10 @@
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react-jsx"
|
"jsx": "react-jsx",
|
||||||
|
"types": ["node"]
|
||||||
|
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src"],
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user